mirror of
https://github.com/syncthing/syncthing.git
synced 2026-01-13 08:19:27 -05:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
612fdff377 | ||
|
|
8ccb7f1924 | ||
|
|
65d0ca8aa9 | ||
|
|
e82ed6e3d3 | ||
|
|
4b815fc086 | ||
|
|
7eaf843de2 | ||
|
|
110e1ae6f9 | ||
|
|
896f9725ec | ||
|
|
1a529e9d5d | ||
|
|
36ef17df8f | ||
|
|
955ac7775e | ||
|
|
8f69e874c4 | ||
|
|
ac06fd97e9 | ||
|
|
3726b7d112 | ||
|
|
377200591e | ||
|
|
4afc898c2f | ||
|
|
ff7e4fef55 | ||
|
|
9ffddb1923 | ||
|
|
896b857fc4 | ||
|
|
acc5d2675b | ||
|
|
6ece4c1fd2 | ||
|
|
cc09f0170d | ||
|
|
bb234d6c0e | ||
|
|
e6acc64758 | ||
|
|
f18cf545b9 |
82
.github/workflows/build-syncthing.yaml
vendored
82
.github/workflows/build-syncthing.yaml
vendored
@@ -725,6 +725,88 @@ jobs:
|
||||
with:
|
||||
args: sync objstore:${{ secrets.S3_BUCKET }}/release/${{ env.VERSION }} objstore:${{ secrets.S3_BUCKET }}/release/latest
|
||||
|
||||
#
|
||||
# Push Debian/APT archive
|
||||
#
|
||||
|
||||
publish-apt:
|
||||
name: Publish APT
|
||||
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
|
||||
environment: signing
|
||||
needs:
|
||||
- basics
|
||||
- package-debian
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: debian-packages
|
||||
path: packages
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "Version: $version"
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
# Decide whether packages should go to stable, candidate or nightly
|
||||
- name: Prepare packages
|
||||
run: |
|
||||
kind=stable
|
||||
if [[ $VERSION == *-rc.[0-9] ]] ; then
|
||||
kind=candidate
|
||||
elif [[ $VERSION == *-* ]] ; then
|
||||
kind=nightly
|
||||
fi
|
||||
echo "Kind: $kind"
|
||||
mkdir -p packages/syncthing/$kind
|
||||
mv packages/*.deb packages/syncthing/$kind
|
||||
|
||||
- name: Pull archive
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
env:
|
||||
RCLONE_CONFIG_OBJSTORE_TYPE: s3
|
||||
RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
|
||||
RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
|
||||
RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync objstore:syncthing-apt/dists dists
|
||||
|
||||
- name: Prepare signing key
|
||||
run: |
|
||||
echo "$APT_GPG_KEYRING_BASE64" | base64 -d > keyring.pgp
|
||||
env:
|
||||
APT_GPG_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }}
|
||||
|
||||
- name: Update archive
|
||||
uses: docker://ghcr.io/kastelo/ezapt:latest
|
||||
with:
|
||||
args:
|
||||
--add packages
|
||||
--dists dists
|
||||
--keyring keyring.pgp
|
||||
|
||||
- name: Push archive
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
env:
|
||||
RCLONE_CONFIG_OBJSTORE_TYPE: s3
|
||||
RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
|
||||
RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
|
||||
RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync dists -v objstore:syncthing-apt/dists
|
||||
|
||||
#
|
||||
# Build and push to Docker Hub
|
||||
#
|
||||
|
||||
@@ -48,6 +48,9 @@ approval_rules:
|
||||
count: 1
|
||||
teams:
|
||||
- syncthing/maintainers
|
||||
options:
|
||||
ignore_update_merges: true
|
||||
allow_contributor: true
|
||||
|
||||
# Regular pull requests require approval by an active contributor
|
||||
- name: is approved by a syncthing contributor
|
||||
@@ -55,6 +58,9 @@ approval_rules:
|
||||
count: 1
|
||||
teams:
|
||||
- syncthing/contributors
|
||||
options:
|
||||
ignore_update_merges: true
|
||||
allow_contributor: true
|
||||
|
||||
# Changes to some files (translations, dependencies, compatibility) do not
|
||||
# require approval if they were proposed by a contributor and have a
|
||||
|
||||
4
AUTHORS
4
AUTHORS
@@ -146,6 +146,7 @@ Han Boetes <han@boetes.org>
|
||||
HansK-p <42314815+HansK-p@users.noreply.github.com>
|
||||
Harrison Jones (harrisonhjones) <harrisonhjones@users.noreply.github.com>
|
||||
Heiko Zuerker (Smiley73) <heiko@zuerker.org>
|
||||
Hireworks <129852174+hireworksltd@users.noreply.github.com>
|
||||
Hugo Locurcio <hugo.locurcio@hugo.pro>
|
||||
Iain Barnett <iainspeed@gmail.com>
|
||||
Ian Johnson (anonymouse64) <ian.johnson@canonical.com> <person.uwsome@gmail.com>
|
||||
@@ -189,6 +190,7 @@ Jörg Thalheim <Mic92@users.noreply.github.com>
|
||||
Jędrzej Kula <kula.jedrek@gmail.com>
|
||||
K.B.Dharun Krishna <kbdharunkrishna@gmail.com>
|
||||
Kalle Laine <pahakalle@protonmail.com>
|
||||
Kapil Sareen <kapilsareen584@gmail.com>
|
||||
Karol Różycki (krozycki) <rozycki.karol@gmail.com>
|
||||
Kebin Liu <lkebin@gmail.com>
|
||||
Keith Harrison <keithh@protonmail.com>
|
||||
@@ -318,11 +320,13 @@ Sven Bachmann <dev@mcbachmann.de>
|
||||
Syncthing Automation <automation@syncthing.net>
|
||||
Syncthing Release Automation <release@syncthing.net>
|
||||
Taylor Khan (nelsonkhan) <nelsonkhan@gmail.com>
|
||||
Terrance <git@terrance.allofti.me>
|
||||
Thomas <9749173+uhthomas@users.noreply.github.com>
|
||||
Thomas Hipp <thomashipp@gmail.com>
|
||||
Tim Abell (timabell) <tim@timwise.co.uk>
|
||||
Tim Howes (timhowes) <timhowes@berkeley.edu>
|
||||
Tim Nordenfur <tim@gurka.se>
|
||||
Tobias Frölich <40638719+tobifroe@users.noreply.github.com>
|
||||
Tobias Klauser <tobias.klauser@gmail.com>
|
||||
Tobias Nygren (tnn2) <tnn@nygren.pp.se>
|
||||
Tobias Tom (tobiastom) <t.tom@succont.de>
|
||||
|
||||
144
build.go
144
build.go
@@ -97,40 +97,40 @@ var targets = map[string]target{
|
||||
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/syncthing"},
|
||||
binaryName: "syncthing", // .exe will be added automatically for Windows builds
|
||||
archiveFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0755},
|
||||
{src: "README.md", dst: "README.txt", perm: 0644},
|
||||
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0o755},
|
||||
{src: "README.md", dst: "README.txt", perm: 0o644},
|
||||
{src: "LICENSE", dst: "LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0o644},
|
||||
// All files from etc/ and extra/ added automatically in init().
|
||||
},
|
||||
systemdService: "syncthing@*.service",
|
||||
installationFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
|
||||
{src: "README.md", dst: "deb/usr/share/doc/syncthing/README.txt", perm: 0644},
|
||||
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing/LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing/AUTHORS.txt", perm: 0644},
|
||||
{src: "man/syncthing.1", dst: "deb/usr/share/man/man1/syncthing.1", perm: 0644},
|
||||
{src: "man/syncthing-config.5", dst: "deb/usr/share/man/man5/syncthing-config.5", perm: 0644},
|
||||
{src: "man/syncthing-stignore.5", dst: "deb/usr/share/man/man5/syncthing-stignore.5", perm: 0644},
|
||||
{src: "man/syncthing-device-ids.7", dst: "deb/usr/share/man/man7/syncthing-device-ids.7", perm: 0644},
|
||||
{src: "man/syncthing-event-api.7", dst: "deb/usr/share/man/man7/syncthing-event-api.7", perm: 0644},
|
||||
{src: "man/syncthing-faq.7", dst: "deb/usr/share/man/man7/syncthing-faq.7", perm: 0644},
|
||||
{src: "man/syncthing-networking.7", dst: "deb/usr/share/man/man7/syncthing-networking.7", perm: 0644},
|
||||
{src: "man/syncthing-rest-api.7", dst: "deb/usr/share/man/man7/syncthing-rest-api.7", perm: 0644},
|
||||
{src: "man/syncthing-security.7", dst: "deb/usr/share/man/man7/syncthing-security.7", perm: 0644},
|
||||
{src: "man/syncthing-versioning.7", dst: "deb/usr/share/man/man7/syncthing-versioning.7", perm: 0644},
|
||||
{src: "etc/linux-systemd/system/syncthing@.service", dst: "deb/lib/systemd/system/syncthing@.service", perm: 0644},
|
||||
{src: "etc/linux-systemd/user/syncthing.service", dst: "deb/usr/lib/systemd/user/syncthing.service", perm: 0644},
|
||||
{src: "etc/linux-sysctl/30-syncthing.conf", dst: "deb/usr/lib/sysctl.d/30-syncthing.conf", perm: 0644},
|
||||
{src: "etc/firewall-ufw/syncthing", dst: "deb/etc/ufw/applications.d/syncthing", perm: 0644},
|
||||
{src: "etc/linux-desktop/syncthing-start.desktop", dst: "deb/usr/share/applications/syncthing-start.desktop", perm: 0644},
|
||||
{src: "etc/linux-desktop/syncthing-ui.desktop", dst: "deb/usr/share/applications/syncthing-ui.desktop", perm: 0644},
|
||||
{src: "assets/logo-32.png", dst: "deb/usr/share/icons/hicolor/32x32/apps/syncthing.png", perm: 0644},
|
||||
{src: "assets/logo-64.png", dst: "deb/usr/share/icons/hicolor/64x64/apps/syncthing.png", perm: 0644},
|
||||
{src: "assets/logo-128.png", dst: "deb/usr/share/icons/hicolor/128x128/apps/syncthing.png", perm: 0644},
|
||||
{src: "assets/logo-256.png", dst: "deb/usr/share/icons/hicolor/256x256/apps/syncthing.png", perm: 0644},
|
||||
{src: "assets/logo-512.png", dst: "deb/usr/share/icons/hicolor/512x512/apps/syncthing.png", perm: 0644},
|
||||
{src: "assets/logo-only.svg", dst: "deb/usr/share/icons/hicolor/scalable/apps/syncthing.svg", perm: 0644},
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0o755},
|
||||
{src: "README.md", dst: "deb/usr/share/doc/syncthing/README.txt", perm: 0o644},
|
||||
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing/LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing/AUTHORS.txt", perm: 0o644},
|
||||
{src: "man/syncthing.1", dst: "deb/usr/share/man/man1/syncthing.1", perm: 0o644},
|
||||
{src: "man/syncthing-config.5", dst: "deb/usr/share/man/man5/syncthing-config.5", perm: 0o644},
|
||||
{src: "man/syncthing-stignore.5", dst: "deb/usr/share/man/man5/syncthing-stignore.5", perm: 0o644},
|
||||
{src: "man/syncthing-device-ids.7", dst: "deb/usr/share/man/man7/syncthing-device-ids.7", perm: 0o644},
|
||||
{src: "man/syncthing-event-api.7", dst: "deb/usr/share/man/man7/syncthing-event-api.7", perm: 0o644},
|
||||
{src: "man/syncthing-faq.7", dst: "deb/usr/share/man/man7/syncthing-faq.7", perm: 0o644},
|
||||
{src: "man/syncthing-networking.7", dst: "deb/usr/share/man/man7/syncthing-networking.7", perm: 0o644},
|
||||
{src: "man/syncthing-rest-api.7", dst: "deb/usr/share/man/man7/syncthing-rest-api.7", perm: 0o644},
|
||||
{src: "man/syncthing-security.7", dst: "deb/usr/share/man/man7/syncthing-security.7", perm: 0o644},
|
||||
{src: "man/syncthing-versioning.7", dst: "deb/usr/share/man/man7/syncthing-versioning.7", perm: 0o644},
|
||||
{src: "etc/linux-systemd/system/syncthing@.service", dst: "deb/lib/systemd/system/syncthing@.service", perm: 0o644},
|
||||
{src: "etc/linux-systemd/user/syncthing.service", dst: "deb/usr/lib/systemd/user/syncthing.service", perm: 0o644},
|
||||
{src: "etc/linux-sysctl/30-syncthing.conf", dst: "deb/usr/lib/sysctl.d/30-syncthing.conf", perm: 0o644},
|
||||
{src: "etc/firewall-ufw/syncthing", dst: "deb/etc/ufw/applications.d/syncthing", perm: 0o644},
|
||||
{src: "etc/linux-desktop/syncthing-start.desktop", dst: "deb/usr/share/applications/syncthing-start.desktop", perm: 0o644},
|
||||
{src: "etc/linux-desktop/syncthing-ui.desktop", dst: "deb/usr/share/applications/syncthing-ui.desktop", perm: 0o644},
|
||||
{src: "assets/logo-32.png", dst: "deb/usr/share/icons/hicolor/32x32/apps/syncthing.png", perm: 0o644},
|
||||
{src: "assets/logo-64.png", dst: "deb/usr/share/icons/hicolor/64x64/apps/syncthing.png", perm: 0o644},
|
||||
{src: "assets/logo-128.png", dst: "deb/usr/share/icons/hicolor/128x128/apps/syncthing.png", perm: 0o644},
|
||||
{src: "assets/logo-256.png", dst: "deb/usr/share/icons/hicolor/256x256/apps/syncthing.png", perm: 0o644},
|
||||
{src: "assets/logo-512.png", dst: "deb/usr/share/icons/hicolor/512x512/apps/syncthing.png", perm: 0o644},
|
||||
{src: "assets/logo-only.svg", dst: "deb/usr/share/icons/hicolor/scalable/apps/syncthing.svg", perm: 0o644},
|
||||
},
|
||||
},
|
||||
"stdiscosrv": {
|
||||
@@ -142,21 +142,21 @@ var targets = map[string]target{
|
||||
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/stdiscosrv"},
|
||||
binaryName: "stdiscosrv", // .exe will be added automatically for Windows builds
|
||||
archiveFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0755},
|
||||
{src: "cmd/stdiscosrv/README.md", dst: "README.txt", perm: 0644},
|
||||
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0o755},
|
||||
{src: "cmd/stdiscosrv/README.md", dst: "README.txt", perm: 0o644},
|
||||
{src: "LICENSE", dst: "LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0o644},
|
||||
},
|
||||
systemdService: "stdiscosrv.service",
|
||||
installationFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
|
||||
{src: "cmd/stdiscosrv/README.md", dst: "deb/usr/share/doc/syncthing-discosrv/README.txt", perm: 0644},
|
||||
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-discosrv/LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-discosrv/AUTHORS.txt", perm: 0644},
|
||||
{src: "man/stdiscosrv.1", dst: "deb/usr/share/man/man1/stdiscosrv.1", perm: 0644},
|
||||
{src: "cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service", dst: "deb/lib/systemd/system/stdiscosrv.service", perm: 0644},
|
||||
{src: "cmd/stdiscosrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-discosrv", perm: 0644},
|
||||
{src: "cmd/stdiscosrv/etc/firewall-ufw/stdiscosrv", dst: "deb/etc/ufw/applications.d/stdiscosrv", perm: 0644},
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0o755},
|
||||
{src: "cmd/stdiscosrv/README.md", dst: "deb/usr/share/doc/syncthing-discosrv/README.txt", perm: 0o644},
|
||||
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-discosrv/LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-discosrv/AUTHORS.txt", perm: 0o644},
|
||||
{src: "man/stdiscosrv.1", dst: "deb/usr/share/man/man1/stdiscosrv.1", perm: 0o644},
|
||||
{src: "cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service", dst: "deb/lib/systemd/system/stdiscosrv.service", perm: 0o644},
|
||||
{src: "cmd/stdiscosrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-discosrv", perm: 0o644},
|
||||
{src: "cmd/stdiscosrv/etc/firewall-ufw/stdiscosrv", dst: "deb/etc/ufw/applications.d/stdiscosrv", perm: 0o644},
|
||||
},
|
||||
tags: []string{"purego"},
|
||||
},
|
||||
@@ -169,23 +169,23 @@ var targets = map[string]target{
|
||||
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/strelaysrv"},
|
||||
binaryName: "strelaysrv", // .exe will be added automatically for Windows builds
|
||||
archiveFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0755},
|
||||
{src: "cmd/strelaysrv/README.md", dst: "README.txt", perm: 0644},
|
||||
{src: "cmd/strelaysrv/LICENSE", dst: "LICENSE.txt", perm: 0644},
|
||||
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0o755},
|
||||
{src: "cmd/strelaysrv/README.md", dst: "README.txt", perm: 0o644},
|
||||
{src: "cmd/strelaysrv/LICENSE", dst: "LICENSE.txt", perm: 0o644},
|
||||
{src: "LICENSE", dst: "LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0o644},
|
||||
},
|
||||
systemdService: "strelaysrv.service",
|
||||
installationFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
|
||||
{src: "cmd/strelaysrv/README.md", dst: "deb/usr/share/doc/syncthing-relaysrv/README.txt", perm: 0644},
|
||||
{src: "cmd/strelaysrv/LICENSE", dst: "deb/usr/share/doc/syncthing-relaysrv/LICENSE.txt", perm: 0644},
|
||||
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-relaysrv/LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaysrv/AUTHORS.txt", perm: 0644},
|
||||
{src: "man/strelaysrv.1", dst: "deb/usr/share/man/man1/strelaysrv.1", perm: 0644},
|
||||
{src: "cmd/strelaysrv/etc/linux-systemd/strelaysrv.service", dst: "deb/lib/systemd/system/strelaysrv.service", perm: 0644},
|
||||
{src: "cmd/strelaysrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-relaysrv", perm: 0644},
|
||||
{src: "cmd/strelaysrv/etc/firewall-ufw/strelaysrv", dst: "deb/etc/ufw/applications.d/strelaysrv", perm: 0644},
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0o755},
|
||||
{src: "cmd/strelaysrv/README.md", dst: "deb/usr/share/doc/syncthing-relaysrv/README.txt", perm: 0o644},
|
||||
{src: "cmd/strelaysrv/LICENSE", dst: "deb/usr/share/doc/syncthing-relaysrv/LICENSE.txt", perm: 0o644},
|
||||
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-relaysrv/LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaysrv/AUTHORS.txt", perm: 0o644},
|
||||
{src: "man/strelaysrv.1", dst: "deb/usr/share/man/man1/strelaysrv.1", perm: 0o644},
|
||||
{src: "cmd/strelaysrv/etc/linux-systemd/strelaysrv.service", dst: "deb/lib/systemd/system/strelaysrv.service", perm: 0o644},
|
||||
{src: "cmd/strelaysrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-relaysrv", perm: 0o644},
|
||||
{src: "cmd/strelaysrv/etc/firewall-ufw/strelaysrv", dst: "deb/etc/ufw/applications.d/strelaysrv", perm: 0o644},
|
||||
},
|
||||
},
|
||||
"strelaypoolsrv": {
|
||||
@@ -196,16 +196,16 @@ var targets = map[string]target{
|
||||
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/infra/strelaypoolsrv"},
|
||||
binaryName: "strelaypoolsrv", // .exe will be added automatically for Windows builds
|
||||
archiveFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0755},
|
||||
{src: "cmd/infra/strelaypoolsrv/README.md", dst: "README.txt", perm: 0644},
|
||||
{src: "cmd/infra/strelaypoolsrv/LICENSE", dst: "LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
|
||||
{src: "{{binary}}", dst: "{{binary}}", perm: 0o755},
|
||||
{src: "cmd/infra/strelaypoolsrv/README.md", dst: "README.txt", perm: 0o644},
|
||||
{src: "cmd/infra/strelaypoolsrv/LICENSE", dst: "LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0o644},
|
||||
},
|
||||
installationFiles: []archiveFile{
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
|
||||
{src: "cmd/infra/strelaypoolsrv/README.md", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/README.txt", perm: 0644},
|
||||
{src: "cmd/infra/strelaypoolsrv/LICENSE", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/LICENSE.txt", perm: 0644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/AUTHORS.txt", perm: 0644},
|
||||
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0o755},
|
||||
{src: "cmd/infra/strelaypoolsrv/README.md", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/README.txt", perm: 0o644},
|
||||
{src: "cmd/infra/strelaypoolsrv/LICENSE", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/LICENSE.txt", perm: 0o644},
|
||||
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/AUTHORS.txt", perm: 0o644},
|
||||
},
|
||||
},
|
||||
"stupgrades": {
|
||||
@@ -244,13 +244,13 @@ func initTargets() {
|
||||
// and "extra" dirs.
|
||||
syncthingPkg := targets["syncthing"]
|
||||
for _, file := range listFiles("etc") {
|
||||
syncthingPkg.archiveFiles = append(syncthingPkg.archiveFiles, archiveFile{src: file, dst: file, perm: 0644})
|
||||
syncthingPkg.archiveFiles = append(syncthingPkg.archiveFiles, archiveFile{src: file, dst: file, perm: 0o644})
|
||||
}
|
||||
for _, file := range listFiles("extra") {
|
||||
syncthingPkg.archiveFiles = append(syncthingPkg.archiveFiles, archiveFile{src: file, dst: file, perm: 0644})
|
||||
syncthingPkg.archiveFiles = append(syncthingPkg.archiveFiles, archiveFile{src: file, dst: file, perm: 0o644})
|
||||
}
|
||||
for _, file := range listFiles("extra") {
|
||||
syncthingPkg.installationFiles = append(syncthingPkg.installationFiles, archiveFile{src: file, dst: "deb/usr/share/doc/syncthing/" + filepath.Base(file), perm: 0644})
|
||||
syncthingPkg.installationFiles = append(syncthingPkg.installationFiles, archiveFile{src: file, dst: "deb/usr/share/doc/syncthing/" + filepath.Base(file), perm: 0o644})
|
||||
}
|
||||
targets["syncthing"] = syncthingPkg
|
||||
}
|
||||
@@ -750,7 +750,7 @@ func shouldBuildSyso(dir string) (string, error) {
|
||||
}
|
||||
|
||||
jsonPath := filepath.Join(dir, "versioninfo.json")
|
||||
err = os.WriteFile(jsonPath, bs, 0644)
|
||||
err = os.WriteFile(jsonPath, bs, 0o644)
|
||||
if err != nil {
|
||||
return "", errors.New("failed to create " + jsonPath + ": " + err.Error())
|
||||
}
|
||||
@@ -809,7 +809,7 @@ func copyFile(src, dst string, perm os.FileMode) error {
|
||||
}
|
||||
|
||||
copy:
|
||||
os.MkdirAll(filepath.Dir(dst), 0777)
|
||||
os.MkdirAll(filepath.Dir(dst), 0o777)
|
||||
if err := os.WriteFile(dst, in, perm); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -869,7 +869,7 @@ func buildNextGenGUI() bool {
|
||||
for _, src := range listFiles("next-gen-gui/dist") {
|
||||
rel, _ := filepath.Rel("next-gen-gui/dist", src)
|
||||
dst := filepath.Join("gui", rel)
|
||||
if err := copyFile(src, dst, 0644); err != nil {
|
||||
if err := copyFile(src, dst, 0o644); err != nil {
|
||||
fmt.Println("copy:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -930,7 +930,7 @@ func proto() {
|
||||
path := filepath.Join("repos", "protobuf")
|
||||
|
||||
runPrint(goCmd, "install", fmt.Sprintf("github.com/gogo/protobuf/protoc-gen-gogofast@%v", pv))
|
||||
os.MkdirAll("repos", 0755)
|
||||
os.MkdirAll("repos", 0o755)
|
||||
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
runPrint("git", "clone", repo, path)
|
||||
@@ -1427,7 +1427,7 @@ func windowsCodesign(file string) {
|
||||
log.Println("Codesign: signing failed: creating temp file:", err)
|
||||
return
|
||||
}
|
||||
_ = f.Chmod(0600) // best effort remove other users' access
|
||||
_ = f.Chmod(0o600) // best effort remove other users' access
|
||||
defer os.Remove(f.Name())
|
||||
if _, err := f.Write(bs); err != nil {
|
||||
log.Println("Codesign: signing failed: writing temp file:", err)
|
||||
|
||||
@@ -71,7 +71,6 @@ func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]b
|
||||
|
||||
url := urlPrefix + l.version + filename[idx:]
|
||||
resp, err := l.client.Get(url)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Loading source:", err)
|
||||
return nil, 0
|
||||
|
||||
@@ -52,5 +52,5 @@ func compressAndWrite(bs []byte, fullPath string) error {
|
||||
gw.Close()
|
||||
|
||||
// Create an output file with the compressed report
|
||||
return os.WriteFile(fullPath, buf.Bytes(), 0644)
|
||||
return os.WriteFile(fullPath, buf.Bytes(), 0o644)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ func findSession(key string) *session {
|
||||
ses, ok := pendingSessions[key]
|
||||
if !ok {
|
||||
return nil
|
||||
|
||||
}
|
||||
delete(pendingSessions, key)
|
||||
return ses
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("main", "Main package")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("main", "Main package")
|
||||
|
||||
@@ -140,7 +140,7 @@ func checkNotExist(t *testing.T, name string) {
|
||||
func TestAutoClosedFile(t *testing.T) {
|
||||
os.RemoveAll("_autoclose")
|
||||
defer os.RemoveAll("_autoclose")
|
||||
os.Mkdir("_autoclose", 0755)
|
||||
os.Mkdir("_autoclose", 0o755)
|
||||
file := filepath.FromSlash("_autoclose/tmp")
|
||||
data := []byte("hello, world\n")
|
||||
|
||||
|
||||
28
go.mod
28
go.mod
@@ -27,26 +27,26 @@ require (
|
||||
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
|
||||
github.com/oschwald/geoip2-golang v1.11.0
|
||||
github.com/pierrec/lz4/v4 v4.1.21
|
||||
github.com/prometheus/client_golang v1.20.4
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0
|
||||
github.com/quic-go/quic-go v0.47.0
|
||||
github.com/quic-go/quic-go v0.48.0
|
||||
github.com/rabbitmq/amqp091-go v1.10.0
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
|
||||
github.com/shirou/gopsutil/v4 v4.24.9
|
||||
github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
|
||||
github.com/thejerf/suture/v4 v4.0.5
|
||||
github.com/urfave/cli v1.22.15
|
||||
github.com/urfave/cli v1.22.16
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
|
||||
github.com/willabides/kongplete v0.4.0
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
golang.org/x/net v0.29.0
|
||||
golang.org/x/sys v0.25.0
|
||||
golang.org/x/text v0.18.0
|
||||
golang.org/x/time v0.6.0
|
||||
golang.org/x/tools v0.25.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/text v0.19.0
|
||||
golang.org/x/time v0.7.0
|
||||
golang.org/x/tools v0.26.0
|
||||
google.golang.org/protobuf v1.35.1
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
@@ -65,12 +65,12 @@ require (
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d // indirect
|
||||
github.com/google/pprof v0.0.0-20241009165004-a3522334989c // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/compress v1.17.10 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nxadm/tail v1.4.11 // indirect
|
||||
@@ -88,10 +88,10 @@ require (
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
github.com/tklauser/numcpus v0.9.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
59
go.sum
59
go.sum
@@ -2,7 +2,7 @@ github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f h1:GmH5
|
||||
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f/go.mod h1:Nhfib1j/VFnLrXL9cHgA+/n2O6P5THuWelOnbfPNd78=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZP/GkPY=
|
||||
github.com/alecthomas/assert/v2 v2.10.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/kong v1.2.1 h1:E8jH4Tsgv6wCRX2nGrdPyHDUCSG83WH2qE4XLACD33Q=
|
||||
@@ -34,7 +34,6 @@ github.com/chmduquesne/rollinghash v4.0.0+incompatible/go.mod h1:Uc2I36RRfTAf7Dg
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
|
||||
@@ -89,8 +88,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d h1:Jaz2JzpQaQXyET0AjLBXShrthbpqMkhGiEfkcQAiAUs=
|
||||
github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241009165004-a3522334989c h1:NDovD0SMpBYXlE1zJmS1q55vWB/fUQBcPAqAboZSccA=
|
||||
github.com/google/pprof v0.0.0-20241009165004-a3522334989c/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
@@ -138,8 +137,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
|
||||
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -196,8 +195,8 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
|
||||
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
|
||||
@@ -206,8 +205,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y=
|
||||
github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E=
|
||||
github.com/quic-go/quic-go v0.48.0 h1:2TCyvBrMu1Z25rvIAlnp2dPT4lgh/uTqLqiXVpp5AeU=
|
||||
github.com/quic-go/quic-go v0.48.0/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
@@ -244,11 +243,11 @@ github.com/thejerf/suture/v4 v4.0.5 h1:F1E/4FZwXWqvlWDKEUo6/ndLtxGAUzMmNqkrMknZb
|
||||
github.com/thejerf/suture/v4 v4.0.5/go.mod h1:gu9Y4dXNUWFrByqRt30Rm9/UZ0wzRSt9AJS6xu/ZGxU=
|
||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
|
||||
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM=
|
||||
github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
|
||||
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
|
||||
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 h1:okhMind4q9H1OxF44gNegWkiP4H/gsTFLalHFa4OOUI=
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0/go.mod h1:TTbGUfE+cXXceWtbTHq6lqcTvYPBKLNejBEbnUsQJtU=
|
||||
github.com/willabides/kongplete v0.4.0 h1:eivXxkp5ud5+4+NVN9e4goxC5mSh3n1RHov+gsblM2g=
|
||||
@@ -271,10 +270,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -298,8 +297,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -337,8 +336,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -352,10 +351,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
@@ -363,8 +362,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
|
||||
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -378,8 +377,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -224,7 +224,6 @@ code.ng-binding{
|
||||
}
|
||||
|
||||
.well, .form-control[readonly="readonly"], .popover { /* read-only fields*/
|
||||
color: #666 !important;
|
||||
border-color: #444 !important;
|
||||
background-color: #111 !important;
|
||||
}
|
||||
@@ -278,3 +277,17 @@ code.ng-binding{
|
||||
.reception {
|
||||
filter: invert(77%) sepia(0%) saturate(724%) hue-rotate(146deg) brightness(91%) contrast(85%);
|
||||
}
|
||||
|
||||
/* Disabled checkbox panels */
|
||||
|
||||
.checkbox[disabled] {
|
||||
background-color: #222222;
|
||||
}
|
||||
|
||||
.checkbox[disabled] * {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.checkbox[disabled] .help-block {
|
||||
color: #666666 !important;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@ code.ng-binding{
|
||||
}
|
||||
|
||||
.well, .form-control[readonly="readonly"], .popover { /* read-only fields*/
|
||||
color: #666 !important;
|
||||
border-color: #424242 !important;
|
||||
background-color: #3B3B3B !important;
|
||||
}
|
||||
@@ -289,4 +288,18 @@ code.ng-binding{
|
||||
/* Remote Devices 'connection type'-icon color set to #aaa */
|
||||
.reception {
|
||||
filter: invert(77%) sepia(0%) saturate(724%) hue-rotate(146deg) brightness(91%) contrast(85%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disabled checkbox panels */
|
||||
|
||||
.checkbox[disabled] {
|
||||
background-color: #3B3B3B;
|
||||
}
|
||||
|
||||
.checkbox[disabled] * {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.checkbox[disabled] .help-block {
|
||||
color: #999999 !important;
|
||||
}
|
||||
|
||||
@@ -448,7 +448,6 @@ ul.three-columns li, ul.two-columns li {
|
||||
}
|
||||
|
||||
@media (max-width:479px) {
|
||||
|
||||
nav .dropdown-toggle {
|
||||
font-size: 1em;
|
||||
}
|
||||
@@ -456,13 +455,7 @@ ul.three-columns li, ul.two-columns li {
|
||||
.navbar-nav .open .dropdown-menu > li > a {
|
||||
padding: 12px 15px 12px 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 419px) {
|
||||
/* The selectors are build to target only the content of folder and device
|
||||
panels as it would "destroy" e.g. out of sync or recent changes listings.
|
||||
The !important is needed to override .visible-xs that sets display to a
|
||||
@@ -513,6 +506,10 @@ ul.three-columns li, ul.two-columns li {
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.form-horizontal .form-group {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"Advanced Configuration": "Разширени настройки",
|
||||
"All Data": "Всички данни",
|
||||
"All Time": "През цялото време",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Всички папки, споделени с устройството трябва да бъдат защитени с парола, така че данните да са недостъпни без нея.",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Папките, споделени с устройството трябва да бъдат защитени с парола, така че данните да са недостъпни без нея.",
|
||||
"Allow Anonymous Usage Reporting?": "Разрешавате ли анонимно отчитане на употребата?",
|
||||
"Allowed Networks": "Разрешени мрежи",
|
||||
"Alphabetic": "Азбучен ред",
|
||||
@@ -111,7 +111,7 @@
|
||||
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Изключено периодично обхождане и грешка при започване на наблюдението за промени, прави се опит всяка минута:",
|
||||
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Изключва сравняването и синхронизацията на правата на файловете. Полезно за системи с липсващи или специфични права (като FAT, exFAT, Synology, Android).",
|
||||
"Discard": "Отказване",
|
||||
"Disconnected": "Не е свързано",
|
||||
"Disconnected": "Няма връзка",
|
||||
"Disconnected (Inactive)": "Не е свързано (неизползвано)",
|
||||
"Disconnected (Unused)": "Не е свързано (неизползвано)",
|
||||
"Discovered": "Открит",
|
||||
@@ -134,8 +134,8 @@
|
||||
"Edit Folder Defaults": "За нови папки",
|
||||
"Editing {%path%}.": "Променяне на {{path}}.",
|
||||
"Enable Crash Reporting": "Включване на доклад за срив",
|
||||
"Enable NAT traversal": "Преминаване през NAT",
|
||||
"Enable Relaying": "Препращане",
|
||||
"Enable NAT traversal": "Обхождане на NAT",
|
||||
"Enable Relaying": "Разрешаване на ретранслатори",
|
||||
"Enabled": "Включено",
|
||||
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "Когато е отметнато разширените атрибути се изпращат към другите устройства, а получените разширени атрибути се прилагат. Обикновено изисква съответните за целта права.",
|
||||
"Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when \"Sync Extended Attributes\" is enabled.": "Когато е отметнато разширените атрибути се изпращат към другите устройства, но получените разширени атрибути не се прилагат. Може да има значително неблагоприятно влияние върху производителността. Винаги е отметнато когато „Синхронизиране на разширени атрибути“ е отметнато.",
|
||||
@@ -158,8 +158,8 @@
|
||||
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Неуспешна връзка към сървъри по IPv6 може да се очаква ако няма свързаност по IPv6.",
|
||||
"File Pull Order": "Ред на изтегляне",
|
||||
"File Versioning": "Версии на файловете",
|
||||
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Файловете биват преместени в папка .stversions при заменяне или изтриване от Syncthing.",
|
||||
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Когато Syncthing замени или изтрие файл той бива преместен в папката .stversions и преименуван чрез добавяне на датата и часа.",
|
||||
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Когато Syncthing замени или премахне файл, негова версия се копира в папка .stversions.",
|
||||
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Когато Syncthing замени или премахне файл, негова версия се копира в папка .stversions, като в името му се добавят датата и часът.",
|
||||
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Предпазва местните файлове от промени, идващи от другите устройства, но местните промени се изпращат.",
|
||||
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Файловете се синхронизират от другите устройства, но местните промени не се изпращат.",
|
||||
"Filesystem Watcher Errors": "Грешка при наблюдаване на файловата система",
|
||||
@@ -205,7 +205,7 @@
|
||||
"Ignored Folders": "Пренебрегнати папки",
|
||||
"Ignored at": "Пренебрегнато на",
|
||||
"Included Software": "Използван софтуер",
|
||||
"Incoming Rate Limit (KiB/s)": "Ограничение при изтегляне (KiB/s)",
|
||||
"Incoming Rate Limit (KiB/s)": "Ограничение при изтегляне (КиБ/с)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Неправилни настройки могат да повредят файлове и да попречат на синхронизирането.",
|
||||
"Incorrect user name or password.": "Грешно потребителско име или парола.",
|
||||
"Internally used paths:": "Вътрешно използвани пътища:",
|
||||
@@ -215,7 +215,7 @@
|
||||
"Inversion of the given condition (i.e. do not exclude)": "Обръща значението на условието (напр. да не се отхвърля)",
|
||||
"Keep Versions": "Пазени версии",
|
||||
"LDAP": "LDAP",
|
||||
"Largest First": "Първо най-големи",
|
||||
"Largest First": "Първо най-големите",
|
||||
"Last 30 Days": "Последните 30 дена",
|
||||
"Last 7 Days": "Последните 7 дена",
|
||||
"Last Month": "Миналия месец",
|
||||
@@ -261,7 +261,7 @@
|
||||
"Never": "никога",
|
||||
"New Device": "Ново устройство",
|
||||
"New Folder": "Нова папка",
|
||||
"Newest First": "Първо най-нови",
|
||||
"Newest First": "Първо най-новите",
|
||||
"No": "Не",
|
||||
"No File Versioning": "Без пазене на версии",
|
||||
"No files will be deleted as a result of this operation.": "В резултат на операцията няма да бъдат премахнати файлове.",
|
||||
@@ -272,12 +272,12 @@
|
||||
"Number of Connections": "Брой на връзките",
|
||||
"OK": "Добре",
|
||||
"Off": "Изключено",
|
||||
"Oldest First": "Първо най-стари",
|
||||
"Oldest First": "Първо най-старите",
|
||||
"Optional descriptive label for the folder. Can be different on each device.": "Незадължително име на папката. Може да бъде различно на всяко устройство.",
|
||||
"Options": "Настройки",
|
||||
"Out of Sync": "Несинхронизирано",
|
||||
"Out of Sync Items": "Несинхронизирани елементи",
|
||||
"Outgoing Rate Limit (KiB/s)": "Ограничение при качване (KiB/s)",
|
||||
"Outgoing Rate Limit (KiB/s)": "Ограничение при качване (КиБ/с)",
|
||||
"Override": "Налагане",
|
||||
"Override Changes": "Налагане на местни промени",
|
||||
"Ownership": "Собственост",
|
||||
@@ -307,11 +307,11 @@
|
||||
"QUIC LAN": "QUIC LAN",
|
||||
"QUIC WAN": "QUIC WAN",
|
||||
"Quick guide to supported patterns": "Кратък наръчник на поддържаните шаблони",
|
||||
"Random": "Произволен",
|
||||
"Receive Encrypted": "Приема шифровани данни",
|
||||
"Random": "В случаен ред",
|
||||
"Receive Encrypted": "Получава шифровани данни",
|
||||
"Receive Only": "Само получава",
|
||||
"Received data is already encrypted": "Получените данни вече са шифровани",
|
||||
"Recent Changes": "Последни промени",
|
||||
"Recent Changes": "Скорошни промени",
|
||||
"Reduced by ignore patterns": "Наложени са шаблони за пренебрегване",
|
||||
"Relay LAN": "Препращане по LAN",
|
||||
"Relay WAN": "Препращане по WAN",
|
||||
@@ -374,7 +374,7 @@
|
||||
"Simple File Versioning": "Обикновени версии",
|
||||
"Single level wildcard (matches within a directory only)": "Заместващ символ за едно ниво (съвпада само с папка)",
|
||||
"Size": "Размер",
|
||||
"Smallest First": "Първо най-малки",
|
||||
"Smallest First": "Първо най-малките",
|
||||
"Some discovery methods could not be established for finding other devices or announcing this device:": "Следните методи за откриване не могат да бъдат използвани за намиране на други устройства или за обявяване на това устройство, за да бъде открито от останалите:",
|
||||
"Some items could not be restored:": "Някои елементи не могат да бъдат възстановени:",
|
||||
"Some listening addresses could not be enabled to accept connections:": "Някои от адресите, на които Syncthing очаква връзка не могат да бъдат настроени да получават входящи връзки:",
|
||||
@@ -384,7 +384,7 @@
|
||||
"Stable releases only": "Само стабилни версии",
|
||||
"Staggered": "Разпределени",
|
||||
"Staggered File Versioning": "Разпределени версии",
|
||||
"Start Browser": "Отваряне в мрежов четец",
|
||||
"Start Browser": "Отваряне на мрежов четец",
|
||||
"Statistics": "Статистика",
|
||||
"Stay logged in": "Оставане в системата",
|
||||
"Stopped": "Спряна",
|
||||
@@ -437,11 +437,11 @@
|
||||
"The interval must be a positive number of seconds.": "Интервалът трябва да е положителен брой секунди.",
|
||||
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "Интервал, в секунди, на почистване на папката с версии. Нула изключва периодичното почистване.",
|
||||
"The maximum age must be a number and cannot be blank.": "Максималната възраст трябва да е число, полето не може да бъде празно.",
|
||||
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Максимална продължителност за пазене на версия (в дни, за да не бъдат изтривани версии задайте 0).",
|
||||
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Максимален срок за пазене на версия (в дни, 0 – без ограничение).",
|
||||
"The number of connections must be a non-negative number.": "Броят на връзките трябва да бъде положително число.",
|
||||
"The number of days must be a number and cannot be blank.": "Броят дни трябва да бъде число и не може да бъде празно.",
|
||||
"The number of days to keep files in the trash can. Zero means forever.": "Брой дни за пазене на файловете в кошчето. Нула значи завинаги.",
|
||||
"The number of old versions to keep, per file.": "Брой стари версии, които да бъдат пазени за всеки файл.",
|
||||
"The number of old versions to keep, per file.": "Брой пазени стари версии на файл.",
|
||||
"The number of versions must be a number and cannot be blank.": "Броят версии трябва да бъде число и не може да бъде празно.",
|
||||
"The path cannot be blank.": "Пътят не може да бъде празен.",
|
||||
"The rate limit is applied to the accumulated traffic of all connections to this device.": "Ограничението се прилага към общия трафик от всички връзки към това устройство.",
|
||||
@@ -474,7 +474,7 @@
|
||||
"Unexpected Items": "Неочаквани елементи",
|
||||
"Unexpected items have been found in this folder.": "В папката са намерени неочаквани елементи.",
|
||||
"Unignore": "Отменяне на пренебрегване",
|
||||
"Unknown": "Неясно",
|
||||
"Unknown": "Неизвестно",
|
||||
"Unshared": "Несподелена",
|
||||
"Unshared Devices": "Устройства, с които не е споделена",
|
||||
"Unshared Folders": "Несподелени папки",
|
||||
@@ -498,7 +498,7 @@
|
||||
"Using a direct TCP connection over WAN": "Използване на директна свързаност с TCP през широкодостъпна мрежа",
|
||||
"Version": "Издание",
|
||||
"Versions": "Версии",
|
||||
"Versions Path": "Път до версиите",
|
||||
"Versions Path": "Папка с версиите",
|
||||
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Версиите биват изтривани автоматично ако са по-стари от максималната възраст или надминават броя разрешени версии за определено време.",
|
||||
"Waiting to Clean": "Изчаква за почистване",
|
||||
"Waiting to Scan": "Изчаква за обхождане",
|
||||
|
||||
@@ -221,13 +221,14 @@
|
||||
"Last seen": "Naposledy spatřen",
|
||||
"Latest Change": "Poslední změna",
|
||||
"Learn more": "Zjistěte více",
|
||||
"Learn more at {%url%}": "Více na {{url}}",
|
||||
"Limit": "Limit",
|
||||
"Listener Failures": "Selhání při naslouchání",
|
||||
"Listener Status": "Stav naslouchání",
|
||||
"Listeners": "Naslouchající",
|
||||
"Loading data...": "Načítání dat…",
|
||||
"Loading...": "Načítání…",
|
||||
"Local Additions": "Místní příbytky",
|
||||
"Local Additions": "Místní přebytky",
|
||||
"Local Discovery": "Místní objevování",
|
||||
"Local State": "Místní status",
|
||||
"Local State (Total)": "Místní status (Celkem)",
|
||||
@@ -236,11 +237,16 @@
|
||||
"Log File": "Soubor logů",
|
||||
"Log In": "Přihlásit se",
|
||||
"Log Out": "Odhlásit se",
|
||||
"Log in to see paths information.": "Pro zobrazení informací o cestě se přihlaste.",
|
||||
"Log in to see version information.": "Pro zobrazení informací o verzi se přihlaste.",
|
||||
"Log tailing paused. Scroll to the bottom to continue.": "Zaznamenávání událostí pozastaveno. Sjeďte dolů pro pokračování.",
|
||||
"Login failed, see Syncthing logs for details.": "Přihlášení selhalo, detaily najdete v Syncthing logu.",
|
||||
"Logs": "Záznamy událostí",
|
||||
"Major Upgrade": "Aktualizace hlavní verze",
|
||||
"Mass actions": "Hromadné akce",
|
||||
"Maximum Age": "Maximální časový limit",
|
||||
"Maximum single entry size": "Maximální velikost jedné položky",
|
||||
"Maximum total size": "Maximální celková velikost",
|
||||
"Metadata Only": "Pouze metadata",
|
||||
"Minimum Free Disk Space": "Minimální velikost volného místa na úložišti",
|
||||
"Mod. Device": "Zařízení, které provedlo změnu",
|
||||
@@ -410,15 +416,17 @@
|
||||
"The folder path cannot be blank.": "Popis umístění složky nemůže zůstat nevyplněný.",
|
||||
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "Jsou použity následující intervaly: za první hodinu jsou ponechány verze pro každých 30 sekund, za první den jsou ponechány verze pro každou hodinu, za prvních 30 dní jsou ponechány verze pro každý den a do nejvyššího nastaveného stáří jsou ponechány verze pro každý týden.",
|
||||
"The following items could not be synchronized.": "Následující položky nemohly být synchronizovány.",
|
||||
"The following items were changed locally.": "Tyto položky byly změněny lokálně",
|
||||
"The following items were changed locally.": "Tyto položky byly změněny lokálně.",
|
||||
"The following methods are used to discover other devices on the network and announce this device to be found by others:": "K objevování ostatních zařízení a oznamování tohoto zařízení se používají následující metody:",
|
||||
"The following text will automatically be inserted into a new message.": "Následující text bude automaticky vložen do nové zprávy.",
|
||||
"The following unexpected items were found.": "Byly nalezeny tyto neočekávané položky.",
|
||||
"The interval must be a positive number of seconds.": "Interval musí být kladný počet sekund.",
|
||||
"The interval, in seconds, for running cleanup in the versions directory. Zero to disable periodic cleaning.": "Interval (v sekundách) pro spouštění čištění ve složce s verzemi. Nula pravidelné čištění vypíná.",
|
||||
"The maximum age must be a number and cannot be blank.": "Nejvyšší stáří je třeba zadat v podobě čísla a nemůže být prázdné.",
|
||||
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Maximální doba pro zachování verze (dny, zapsáním hodnoty 0 bude ponecháno navždy).",
|
||||
"The number of days must be a number and cannot be blank.": "Je třeba, aby počet dní bylo číslo a nemůže zůstat nevyplněné.",
|
||||
"The number of days to keep files in the trash can. Zero means forever.": "Počet dní, po který budou soubory uchovány v koši. Nula znamená navždy.",
|
||||
"The number of connections must be a non-negative number.": "Počet spojení musí být nezáporné číslo.",
|
||||
"The number of days must be a number and cannot be blank.": "Počet dní musí být číslo a nemůže zůstat nevyplněné.",
|
||||
"The number of days to keep files in the trash can. Zero means forever.": "Počet dní, po které budou soubory uchovány v koši. Nula znamená navždy.",
|
||||
"The number of old versions to keep, per file.": "Počet uchovávaných starších verzí každého ze souborů.",
|
||||
"The number of versions must be a number and cannot be blank.": "Je třeba, aby počet verzí bylo číslo a nemůže zůstat nevyplněné.",
|
||||
"The path cannot be blank.": "Popis umístění nemůže zůstat nevyplněný.",
|
||||
@@ -501,6 +509,8 @@
|
||||
"folder": "složka",
|
||||
"full documentation": "úplná dokumentace",
|
||||
"items": "položky",
|
||||
"modified": "změněno",
|
||||
"permit": "povolit",
|
||||
"seconds": "sekund",
|
||||
"theme": {
|
||||
"name": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"Add Device": "기기 추가",
|
||||
"Add Folder": "폴더 추가",
|
||||
"Add Remote Device": "다른 기기 추가",
|
||||
"Add devices from the introducer to our device list, for mutually shared folders.": "상호 공유 폴더에 대해 소개자의 목록에 있는 기기를 현재 기기 목록에 추가됩니다.",
|
||||
"Add devices from the introducer to our device list, for mutually shared folders.": "상호 공유 폴더에 대해 소개자의 목록에 있는 기기를 현재 기기 목록에 추가합니다.",
|
||||
"Add filter entry": "필터 항목 추가",
|
||||
"Add ignore patterns": "무시 양식 추가",
|
||||
"Add new folder?": "새 폴더를 추가하시겠습니까?",
|
||||
@@ -46,7 +46,7 @@
|
||||
"Automatic upgrade now offers the choice between stable releases and release candidates.": "자동 업데이트가 안정 버전과 출시 후보 중 선택할 수 있게 변경되었습니다.",
|
||||
"Automatic upgrades": "자동 업데이트",
|
||||
"Automatic upgrades are always enabled for candidate releases.": "출시 후보는 자동 업데이트가 항상 활성화되어 있습니다.",
|
||||
"Automatically create or share folders that this device advertises at the default path.": "이 기기가 통보하는 폴더들이 기본 경로에서 자동으로 생성 또는 공유됩나다.",
|
||||
"Automatically create or share folders that this device advertises at the default path.": "이 기기가 통보하는 폴더를 기본 경로에서 자동으로 생성 또는 공유합나다.",
|
||||
"Available debug logging facilities:": "사용 가능한 디버그 기록 기능:",
|
||||
"Be careful!": "주의하십시오!",
|
||||
"Body:": "내용:",
|
||||
@@ -458,7 +458,7 @@
|
||||
"This can easily give hackers access to read and change any files on your computer.": "이로 인해서는 해커들이 현재 컴퓨터의 모든 파일을 손쉽게 읽고 변경할 수 있게 됩니다.",
|
||||
"This device cannot automatically discover other devices or announce its own address to be found by others. Only devices with statically configured addresses can connect.": "이 기기는 다른 기기를 자동으로 탐지하거나 다른 기기로부터 발견되도록 자신의 주소를 통보할 수 없습니다. 고정 주소로 설정한 기기만이 현재 기기에 접속할 수 있습니다.",
|
||||
"This is a major version upgrade.": "주요 버전 업데이트입니다.",
|
||||
"This setting controls the free space required on the home (i.e., index database) disk.": "이 설정은 홈(즉, 인덕스 데이터베이스) 저장 장치의 여유 공간을 관리합니다.",
|
||||
"This setting controls the free space required on the home (i.e., index database) disk.": "이 설정은 시스템(즉, 인덱스 데이터베이스가 있는) 저장 장치의 여유 공간을 관리합니다.",
|
||||
"Time": "시간",
|
||||
"Time the item was last modified": "항목이 가장 최근에 수정된 시간",
|
||||
"To connect with the Syncthing device named \"{%devicename%}\", add a new remote device on your end with this ID:": "\"{{devicename}}\" 기기와 연동하려면 아래의 식별자를 이용해 본인의 기기에서 새로운 기기를 추가하십시오.",
|
||||
|
||||
@@ -230,7 +230,7 @@
|
||||
"Listeners": "Lyssnare",
|
||||
"Loading data...": "Läser in data...",
|
||||
"Loading...": "Läser in...",
|
||||
"Local Additions": "Lokala tillägg",
|
||||
"Local Additions": "Lokalt tillägg",
|
||||
"Local Discovery": "Lokal annonsering",
|
||||
"Local State": "Lokalt tillstånd",
|
||||
"Local State (Total)": "Lokalt tillstånd (totalt)",
|
||||
@@ -369,7 +369,7 @@
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Visas istället för enhets-ID i klusterstatus. Kommer att annonseras på andra enheter som ett valfritt standardnamn.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Visas istället för enhets-ID i klusterstatusen. Kommer att uppdateras till det namn som enheten annonserar om det lämnas tomt.",
|
||||
"Shutdown": "Stäng av",
|
||||
"Shutdown Complete": "Avstängning klar",
|
||||
"Shutdown Complete": "Avstängning slutförd",
|
||||
"Simple": "Enkel",
|
||||
"Simple File Versioning": "Enkel filversionshantering",
|
||||
"Single level wildcard (matches within a directory only)": "Jokertecken på en nivå (matchar endast i en mapp)",
|
||||
@@ -398,7 +398,7 @@
|
||||
"Sync Status": "Synkroniseringsstatus",
|
||||
"Syncing": "Synkroniserar",
|
||||
"Syncthing device ID for \"{%devicename%}\"": "Synkronisera enhets-ID för \"{{devicename}}\"",
|
||||
"Syncthing has been shut down.": "Syncthing har stängts.",
|
||||
"Syncthing has been shut down.": "Synkronisering har stängts av.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing innehåller följande mjukvarupaket eller delar av dem:",
|
||||
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing har fri och öppen källkod licensierad som MPL v2.0.",
|
||||
"Syncthing is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it's transmitted over the internet.": "Syncthing är ett program för kontinuerlig filsynkronisering. Den synkroniserar filer mellan två eller flera datorer i realtid, säkert skyddade från nyfikna ögon. Dina data är enbart din data och du förtjänar att välja var den lagras, om den delas med någon tredje part och hur den överförs över internet.",
|
||||
@@ -408,7 +408,7 @@
|
||||
"Syncthing is saving changes.": "Syncthing sparar ändringar.",
|
||||
"Syncthing is upgrading.": "Syncthing uppgraderas.",
|
||||
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing stöder nu automatiskt kraschrapportering till utvecklarna. Denna funktion är aktiverad som standard.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing verkar vara avstängt, eller så finns det problem med din internetanslutning. Försöker igen…",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing verkar vara avstängd, eller så finns det problem med din internetanslutning. Försöker igen…",
|
||||
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing verkar ha drabbats av ett problem med behandlingen av din förfrågan. Uppdatera sidan eller starta om Syncthing om problemet kvarstår.",
|
||||
"TCP LAN": "TCP LAN",
|
||||
"TCP WAN": "TCP WAN",
|
||||
|
||||
@@ -1,186 +1,186 @@
|
||||
{
|
||||
"A device with that ID is already added.": "Пристрій з таким ID вже додано.",
|
||||
"A negative number of days doesn't make sense.": "Від'ємна кількість днів немає сенсу.",
|
||||
"A new major version may not be compatible with previous versions.": "Нова версія з великими змінвми може бути несумісною із попередніми версіями.",
|
||||
"A device with that ID is already added.": "Пристрій із таким ID вже додано.",
|
||||
"A negative number of days doesn't make sense.": "Від'ємна кількість днів не має сенсу.",
|
||||
"A new major version may not be compatible with previous versions.": "Нова головна версія може бути несумісною із попередніми версіями.",
|
||||
"API Key": "API ключ",
|
||||
"About": "Про програму",
|
||||
"About": "Про застосунок",
|
||||
"Action": "Дія",
|
||||
"Actions": "Дії",
|
||||
"Active filter rules": "Діючі правила фільтрування",
|
||||
"Active filter rules": "Активні правила фільтрування",
|
||||
"Add": "Додати",
|
||||
"Add Device": "Додати пристрій",
|
||||
"Add Folder": "Додати папку",
|
||||
"Add Folder": "Додати теку",
|
||||
"Add Remote Device": "Додати віддалений пристрій",
|
||||
"Add devices from the introducer to our device list, for mutually shared folders.": "Додавати пристрої з пристрою що рекомендує, до списку пристроїв для налаштування спільних папок.",
|
||||
"Add filter entry": "Додати правило фільтру",
|
||||
"Add devices from the introducer to our device list, for mutually shared folders.": "Додати пристрої від уповноваженого до нашого списку пристроїв для взаємно спільних папок.",
|
||||
"Add filter entry": "Додати запис фільтрування",
|
||||
"Add ignore patterns": "Додати шаблони ігнорування",
|
||||
"Add new folder?": "Додати нову папку?",
|
||||
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "Крім того, буде збільшений інтервал повного сканування (у 60 разів, тобто нове значення за замовчанням - 1 година). Ви також можете налаштувати його вручну для кожної папки пізніше після вибору \"Ні\".",
|
||||
"Add new folder?": "Додати нову теку?",
|
||||
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "Крім того, буде інтервал повного сканування буде збільшено (в 60 разів, тобто нове типове значення - 1 година). Ви також зможете налаштувати його вручну для кожної теки пізніше, вибравши \"Ні\".",
|
||||
"Address": "Адреса",
|
||||
"Addresses": "Адреси",
|
||||
"Advanced": "Розширені",
|
||||
"Advanced Configuration": "Розширена конфігурація",
|
||||
"Advanced Configuration": "Розширене налаштування",
|
||||
"All Data": "Усі дані",
|
||||
"All Time": "Весь час",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Ті папки, якими поділилися з цим пристроєм, мають бути захищені паролем, щоб усі надіслані дані неможливо було прочитати без вказаного пароля.",
|
||||
"Allow Anonymous Usage Reporting?": "Дозволити програмі збирати анонімну статистику використання?",
|
||||
"All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.": "Усі спільні теки з цим пристроєм, повинні бути захищені паролем, щоб усі надіслані дані неможливо було прочитати без вказаного пароля.",
|
||||
"Allow Anonymous Usage Reporting?": "Дозволити анонімне звітування про використання?",
|
||||
"Allowed Networks": "Дозволені мережі",
|
||||
"Alphabetic": "За абеткою",
|
||||
"Altered by ignoring deletes.": "Змінено шляхом ігнорування видалень.",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Зовнішня команда для керування версіями. Вона має видалити файл зі спільної папки. Якщо шлях до програми містить пробіли, його слід взяти в лапки.",
|
||||
"Anonymous Usage Reporting": "Анонімізована статистика використання",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Змінився формат анонімного звіту про користування. Бажаєте перейти на новий формат?",
|
||||
"Altered by ignoring deletes.": "Змінено, ігноруючи видалення.",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Зовнішня команда керує версіями. Вона повинна видалити файл із спільної теки. Якщо шлях до застосунку містить пробіли, його слід взяти в лапки.",
|
||||
"Anonymous Usage Reporting": "Анонімне звітування про використання",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Формат анонімного звітування про використання змінився. Бажаєте перейти на новий формат?",
|
||||
"Applied to LAN": "Застосовано до LAN",
|
||||
"Apply": "Застосувати",
|
||||
"Are you sure you want to override all remote changes?": "Ви впевнені, що бажаєте відхилити всі зміни у віддалених папках?",
|
||||
"Are you sure you want to permanently delete all these files?": "Ви впевнені, що бажаєте остаточно видалити всі ці файли?",
|
||||
"Are you sure you want to remove device {%name%}?": "Чи ви впевнені в необхідності видалити пристрій {{name}}?",
|
||||
"Are you sure you want to remove folder {%label%}?": "Ви впевнені, що хочете видалити папку {{label}}?",
|
||||
"Are you sure you want to restore {%count%} files?": "Чи ви впевнені в необхідності відновити наступну к-сть файлів: {{count}} ?",
|
||||
"Are you sure you want to revert all local changes?": "Ви впевнені, що бажаєте відкинути всі локальні зміни?",
|
||||
"Are you sure you want to upgrade?": "Напевно хочете оновити?",
|
||||
"Authentication Required": "Потрібна авторизація",
|
||||
"Are you sure you want to override all remote changes?": "Ви впевнені, що хочете перезаписати всі віддалені зміни?",
|
||||
"Are you sure you want to permanently delete all these files?": "Ви впевнені, що хочете остаточно видалити всі ці файли?",
|
||||
"Are you sure you want to remove device {%name%}?": "Ви впевнені, що хочете видалити пристрій {{name}}?",
|
||||
"Are you sure you want to remove folder {%label%}?": "Ви впевнені, що хочете видалити теку {{label}}?",
|
||||
"Are you sure you want to restore {%count%} files?": "Ви впевнені, що хочете відновити {{count}} файли(-ів)?",
|
||||
"Are you sure you want to revert all local changes?": "Ви впевнені, що хочете повернути всі локальні зміни?",
|
||||
"Are you sure you want to upgrade?": "Ви впевнені, що хочете оновити?",
|
||||
"Authentication Required": "Необхідна автентифікація",
|
||||
"Authors": "Автори",
|
||||
"Auto Accept": "Автоприймання",
|
||||
"Auto Accept": "Автоприйняття",
|
||||
"Automatic Crash Reporting": "Автоматичне звітування про збої",
|
||||
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Автоматиче оновлення зараз дозволяє обирати між стабільними випусками та реліз-кандидатами.",
|
||||
"Automatic upgrades": "Автоматичне оновлення",
|
||||
"Automatic upgrades are always enabled for candidate releases.": "Автоматичні оновлення завжди увімкнені для реліз-кандидатів.",
|
||||
"Automatically create or share folders that this device advertises at the default path.": "Автоматично створювати або поширювати каталоги, які цей пристрій декларує як створені по замовчанню.",
|
||||
"Available debug logging facilities:": "Доступні засоби журналу для відладки:",
|
||||
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Автоматичне оновлення тепер пропонує вибір між стабільними випусками та кандидатами на випуск.",
|
||||
"Automatic upgrades": "Автоматичні оновлення",
|
||||
"Automatic upgrades are always enabled for candidate releases.": "Автоматичні оновлення завжди ввімкнені для кандидатів на випуск.",
|
||||
"Automatically create or share folders that this device advertises at the default path.": "Автоматично створювати або ділитися теками, які цей пристрій пропонує типово.",
|
||||
"Available debug logging facilities:": "Доступні засоби ведення журналу налагодження:",
|
||||
"Be careful!": "Будьте обережні!",
|
||||
"Body:": "Повідомлення:",
|
||||
"Bugs": "Помилки",
|
||||
"Cancel": "Скасувати",
|
||||
"Changelog": "Перелік змін",
|
||||
"Changelog": "Журнал змін",
|
||||
"Clean out after": "Очистити після",
|
||||
"Cleaning Versions": "Очищення версій",
|
||||
"Cleanup Interval": "Інтервал очищення",
|
||||
"Click to see full identification string and QR code.": "Натисніть, щоб переглянути повний ідентифікаційний рядок та QR-код.",
|
||||
"Click to see full identification string and QR code.": "Натисніть, щоб переглянути повний ID та QR-код.",
|
||||
"Close": "Закрити",
|
||||
"Command": "Команда",
|
||||
"Comment, when used at the start of a line": "Коментар, якщо використовується на початку рядка",
|
||||
"Compression": "Стиснення",
|
||||
"Configuration Directory": "Директорія з конфігураційними файлами",
|
||||
"Configuration File": "Конфігураційний файл",
|
||||
"Configuration Directory": "Тека з налаштуваннями",
|
||||
"Configuration File": "Файл налаштувань",
|
||||
"Configured": "Налаштовано",
|
||||
"Connected (Unused)": "Під'єднано (не використовується)",
|
||||
"Connection Error": "Помилка з’єднання",
|
||||
"Connection Management": "Керування з'єднанням",
|
||||
"Connection Error": "Помилка під’єднання",
|
||||
"Connection Management": "Керування з'єднаннями",
|
||||
"Connection Type": "Тип з'єднання",
|
||||
"Connections": "З'єднання",
|
||||
"Connections via relays might be rate limited by the relay": "Швидкість з’єднання через реле може бути обмежена ним",
|
||||
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Постійне стеження за змінами наразі доступне у Syncthing. Це дозволить виявити зміни на диску та сканувати тільки модифіковані шляхи. Переваги полягають у тому, що зміни поширюються швидше і зменшується кількість повних пересканувань.",
|
||||
"Connections via relays might be rate limited by the relay": "З’єднання через реле можуть бути обмежені за швидкістю реле",
|
||||
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "У Syncthing тепер доступна функція безперервного відстеження змін. Це дозволить виявляти зміни на диску та сканувати лише модифіковані шляхи. Переваги полягають у тому, що зміни поширюються швидше й зменшується кількість повних сканувань.",
|
||||
"Copied from elsewhere": "Скопійовано з іншого місця",
|
||||
"Copied from original": "Скопійовано з оригіналу",
|
||||
"Copied!": "Скопійовано!",
|
||||
"Copy": "Копіювати",
|
||||
"Copy failed! Try to select and copy manually.": "Помилка копіювання! Спробуйте вибрати та скопіювати вручну.",
|
||||
"Currently Shared With Devices": "На даний момент є спільний доступ пристроїв",
|
||||
"Custom Range": "Вибрати діапазон",
|
||||
"Danger!": "Небезпека!",
|
||||
"Database Location": "Місцезнаходження бази даних",
|
||||
"Debugging Facilities": "Засоби відладки",
|
||||
"Default": "За замовчанням",
|
||||
"Default Configuration": "Конфігурація за замовчуванням",
|
||||
"Default Device": "Пристрій за замовчуванням",
|
||||
"Default Folder": "Папка за замовчуванням",
|
||||
"Default Ignore Patterns": "Шаблони ігнорування за замовчуванням",
|
||||
"Defaults": "Налаштування за замовчуванням",
|
||||
"Copy failed! Try to select and copy manually.": "Не вдалося скопіювати! Спробуйте виділити та скопіювати вручну.",
|
||||
"Currently Shared With Devices": "Наразі ділиться із пристроями",
|
||||
"Custom Range": "Обрати діапазон",
|
||||
"Danger!": "Небезпечно!",
|
||||
"Database Location": "Розташування бази даних",
|
||||
"Debugging Facilities": "Засоби налагодження",
|
||||
"Default": "Типово",
|
||||
"Default Configuration": "Типові налаштування",
|
||||
"Default Device": "Типовий пристрій",
|
||||
"Default Folder": "Типова тека",
|
||||
"Default Ignore Patterns": "Типові шаблони ігнорування",
|
||||
"Defaults": "Типово",
|
||||
"Delete": "Видалити",
|
||||
"Delete Unexpected Items": "Видалити неочікувані елементи",
|
||||
"Deleted {%file%}": "Видалено {{file}}",
|
||||
"Deleted {%file%}": "{{file}} видалено",
|
||||
"Deselect All": "Зняти вибір з усіх",
|
||||
"Deselect devices to stop sharing this folder with.": "Зніміть вибір з пристроїв, щоб припинити їх доступ до цієї папки.",
|
||||
"Deselect folders to stop sharing with this device.": "Зніміть галочки біля папок, щоб припинити обмін файлами з цим пристроєм.",
|
||||
"Deselect devices to stop sharing this folder with.": "Зніміть вибір із пристроїв, щоби припинити спільний доступ до цієї теки.",
|
||||
"Deselect folders to stop sharing with this device.": "Зніміть вибір із тек, щоби припинити спільний доступ із цим пристроєм.",
|
||||
"Device": "Пристрій",
|
||||
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Пристрій \"{{name}}\" ({{device}} за адресою {{address}}) намагається під’єднатися. Додати новий пристрій?",
|
||||
"Device Certificate": "Сертифікат пристрою",
|
||||
"Device ID": "ID пристрою",
|
||||
"Device Identification": "Ідентифікатор пристрою",
|
||||
"Device Identification": "Ідентифікація пристрою",
|
||||
"Device Name": "Назва пристрою",
|
||||
"Device Status": "Статус пристрою",
|
||||
"Device Status": "Стан пристрою",
|
||||
"Device is untrusted, enter encryption password": "Пристрій ненадійний, введіть пароль для шифрування",
|
||||
"Device rate limits": "Обмеження пристрою",
|
||||
"Device that last modified the item": "Пристрій, що останнім змінив елемент",
|
||||
"Device that last modified the item": "Пристрій, який останнім змінив елемент",
|
||||
"Devices": "Пристрої",
|
||||
"Disable Crash Reporting": "Вимкнути звітування про збої",
|
||||
"Disabled": "Вимкнено",
|
||||
"Disabled periodic scanning and disabled watching for changes": "Відключено періодичне сканування та відключено відстеження змін",
|
||||
"Disabled periodic scanning and enabled watching for changes": "Відключено періодичне сканування та увімкнене стеження за змінами",
|
||||
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Відключено періодичне сканування та не вдається налаштувати перегляд змін, повторення кожну 1 хв:",
|
||||
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Вимикає порівняння та синхронізацію дозволів на файли. Корисно для систем з відсутніми або особливими дозволами (наприклад: FAT, exFAT, Synology, Android).",
|
||||
"Discard": "Відхили",
|
||||
"Disconnected": "З’єднання відсутнє",
|
||||
"Disconnected (Inactive)": "Від'єднаний (неактивний)",
|
||||
"Disabled periodic scanning and disabled watching for changes": "Вимкнено періодичне сканування та вимкнено відстеження змін",
|
||||
"Disabled periodic scanning and enabled watching for changes": "Вимкнено періодичне сканування та ввімкнено відстеження змін",
|
||||
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Вимкнено періодичне сканування та не вдалося налаштувати відстеження змін, повторна спроба кожну 1хв:",
|
||||
"Disables comparing and syncing file permissions. Useful on systems with nonexistent or custom permissions (e.g. FAT, exFAT, Synology, Android).": "Вимикає порівняння та синхронізацію дозволів для файлів. Корисно на системах із відсутніми або нестандартними дозволами (наприклад: FAT, exFAT, Synology, Android).",
|
||||
"Discard": "Відхилити",
|
||||
"Disconnected": "Від'єднано",
|
||||
"Disconnected (Inactive)": "Від'єднано (неактивно)",
|
||||
"Disconnected (Unused)": "Від'єднано (не використовується)",
|
||||
"Discovered": "Виявлено",
|
||||
"Discovery": "Сервери координації NAT",
|
||||
"Discovery": "Виявлення",
|
||||
"Discovery Failures": "Помилки виявлення",
|
||||
"Discovery Status": "Стан виявлення",
|
||||
"Dismiss": "Відхилити",
|
||||
"Do not add it to the ignore list, so this notification may recur.": "Не додавати його до списку ігнорування, але тоді це сповіщення може повторюватися.",
|
||||
"Do not add it to the ignore list, so this notification may recur.": "Не додавайте це до списку ігнорування, тому це сповіщення може повторитися.",
|
||||
"Do not restore": "Не відновлювати",
|
||||
"Do not restore all": "Не відновлювати все",
|
||||
"Do you want to enable watching for changes for all your folders?": "Бажаєте увімкнути стеження за змінами у всіх ваших папках?",
|
||||
"Do you want to enable watching for changes for all your folders?": "Бажаєте ввімкнути відстеження змін для всіх ваших тек?",
|
||||
"Documentation": "Документація",
|
||||
"Download Rate": "Швидкість завантаження",
|
||||
"Downloaded": "Завантажено",
|
||||
"Downloading": "Завантажується",
|
||||
"Edit": "Редагуй",
|
||||
"Edit Device": "Налаштування пристрою",
|
||||
"Edit Device Defaults": "Редагувати параметри пристрою за замовчуванням",
|
||||
"Edit Folder": "Налаштування папки",
|
||||
"Edit Folder Defaults": "Редагувати параметри папки за замовчуванням",
|
||||
"Downloading": "Завантаження",
|
||||
"Edit": "Редагувати",
|
||||
"Edit Device": "Редагувати пристрій",
|
||||
"Edit Device Defaults": "Редагувати типові налаштування пристрою",
|
||||
"Edit Folder": "Редагувати теку",
|
||||
"Edit Folder Defaults": "Редагувати типові налаштування теки",
|
||||
"Editing {%path%}.": "Редагування {{path}}.",
|
||||
"Enable Crash Reporting": "Увімкнути звітування про збої",
|
||||
"Enable NAT traversal": "Увімкнути NAT traversal",
|
||||
"Enable Relaying": "Увімкнути ретрансляцію (relaying)",
|
||||
"Enabled": "Увімкнено",
|
||||
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "Дозволяє надсилати інформацію про розширені атрибути на інші пристрої та застосовувати отриману також. Може вимагати запуску з підвищеними привілеями.",
|
||||
"Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when \"Sync Extended Attributes\" is enabled.": "Дозволяє надсилати інформацію про розширені атрибути на інші пристрої, але не застосовувати отриману. Це може мати значний вплив на продуктивність. Завжди ввімкнено, коли ввімкнено «Синхронізувати розширені атрибути».",
|
||||
"Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.": "Дозволяє надсилати інформацію про права власності щодо файлів на інші пристрої, і застосовувати отриману також. Зазвичай вимагає запуску з підвищеними привілеями.",
|
||||
"Enables sending ownership information to other devices, but not applying incoming ownership information. This can have a significant performance impact. Always enabled when \"Sync Ownership\" is enabled.": "Дозволяє надсилати інформацію про права власності щодо файлів на інші пристрої, але не застосовувати отриману. Це може мати значний вплив на продуктивність. Завжди ввімкнено, якщо ввімкнено «Синхронізувати права власності».",
|
||||
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Введіть невід'ємне число (напр. \"2.35\") та виберіть пристрій. Проценти від загального дискового простору.",
|
||||
"Enables sending extended attributes to other devices, and applying incoming extended attributes. May require running with elevated privileges.": "Вмикає надсилання розширених атрибутів іншим пристроям та застосування вхідних. Може вимагати виконання із підвищеними привілеями.",
|
||||
"Enables sending extended attributes to other devices, but not applying incoming extended attributes. This can have a significant performance impact. Always enabled when \"Sync Extended Attributes\" is enabled.": "Вмикає надсилання розширених атрибутів іншим пристроям, але без застосування вхідних. Це може суттєво вплинути на продуктивність. Завжди ввімкнено, коли ввімкнено «Синхронізувати розширені атрибути».",
|
||||
"Enables sending ownership information to other devices, and applying incoming ownership information. Typically requires running with elevated privileges.": "Вмикає надсилання інформації про власність іншим пристроям та застосування вхідної. Зазвичай вимагає виконання із підвищеними привілеями.",
|
||||
"Enables sending ownership information to other devices, but not applying incoming ownership information. This can have a significant performance impact. Always enabled when \"Sync Ownership\" is enabled.": "Вмикає надсилання інформації про власність іншим пристроям, але без застосування вхідної. Це може суттєво вплинути на продуктивність. Завжди ввімкнено, якщо ввімкнено «Синхронізувати права власності».",
|
||||
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Введіть невід'ємне число (напр., \"2.35\") та виберіть одиницю вимірювання. Відсотки вказуються як частина загального розміру диска.",
|
||||
"Enter a non-privileged port number (1024 - 65535).": "Введіть номер непривілейованого порту (1024 - 65535).",
|
||||
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Введіть адреси, розділені комою (\"tcp://ip:port\", \"tcp://host:port\"), або лише \"dynamic\" для автоматичного визначення адреси.",
|
||||
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Введіть адреси, розділені комою (\"tcp://ip:port\", \"tcp://host:port\") або \"dynamic\" для автоматичного виявлення адреси.",
|
||||
"Enter ignore patterns, one per line.": "Введіть шаблони ігнорування, по одному на рядок.",
|
||||
"Enter up to three octal digits.": "Введіть до трьох вісімкових цифр.",
|
||||
"Error": "Помилка",
|
||||
"Extended Attributes": "Розширені атрибути",
|
||||
"Extended Attributes Filter": "Фільтр за розширеними атрибутами",
|
||||
"Extended Attributes Filter": "Фільтр розширених атрибутів",
|
||||
"External": "Зовнішній",
|
||||
"External File Versioning": "Зовнішне керування версіями",
|
||||
"External File Versioning": "Зовнішнє версіонування файлів",
|
||||
"Failed Items": "Невдалі",
|
||||
"Failed to load file versions.": "Не вдалося завантажити версії файлів.",
|
||||
"Failed to load ignore patterns.": "Не вдалося завантажити шаблони ігнорування.",
|
||||
"Failed to setup, retrying": "Помилка при налаштуванні, повторюємо",
|
||||
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "За відсутності IPv6-з'єднання очікується неможливість підключення до IPv6-серверів.",
|
||||
"Failed to setup, retrying": "Не вдалося налаштувати, повторна спроба",
|
||||
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "За відсутності з'єднання IPv6 очікується неможливість під'єднання до серверів IPv6.",
|
||||
"File Pull Order": "Порядок витягнення файлів",
|
||||
"File Versioning": "Керування версіями",
|
||||
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Файли, що замінюються або видаляються Syncthing, переміщуються у директорію .stversions. ",
|
||||
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Файли будуть поміщатися у директорію .stversions із відповідною позначкою часу, коли вони будуть замінятися або видалятися програмою.",
|
||||
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Вміст папки захищено від змін, зроблених на інших пристроях, але зміни зроблені на цьому пристрої можна розіслати решті пристроїв кластеру.",
|
||||
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Файли синхронізуються з кластера, але будь-які внесені локально зміни не надсилатимуться на інші пристрої.",
|
||||
"File Versioning": "Версіонування файлів",
|
||||
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Файли переміщуються до теки .stversions, коли вони замінюються або видаляються Syncthing.",
|
||||
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Файли переміщуються до версій із позначкою дати в теку .stversions, коли вони замінюються або видаляються Syncthing.",
|
||||
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Файли захищено від змін, внесених на інших пристроях, але зміни зроблені на цьому пристрої, будуть надіслані решті пристроїв кластеру.",
|
||||
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Файли синхронізовано з кластеру, але будь-які внесені локально зміни не будуть надіслані на інші пристрої.",
|
||||
"Filesystem Watcher Errors": "Помилки спостерігача файлової системи",
|
||||
"Filter by date": "Фільтрувати по даті",
|
||||
"Filter by name": "Фільтрувати по імені",
|
||||
"Folder": "Папка",
|
||||
"Folder ID": "ID папки",
|
||||
"Folder Label": "Назва папки",
|
||||
"Folder Path": "Шлях до папки",
|
||||
"Folder Status": "Статус папки",
|
||||
"Folder Type": "Тип папки",
|
||||
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Тип папки \"{{receiveEncrypted}}\" можна встановити лише під час додавання нової папки.",
|
||||
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Тип папки \"{{receiveEncrypted}}\" не можна змінити після її додавання. Потрібно видалити її спочатку, далі видалити або розшифрувати дані на диску, а потім додати папку знову.",
|
||||
"Folders": "Папки",
|
||||
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "Сталася помилка при спробі відслідковувати зміни у вищенаведених папках. Їх доступність перевірятиметься щохвилини, доки помилка не зникне. Якщо помилки не зникають, спробуйте виправити права доступу або попросіть допомоги.",
|
||||
"Filter by date": "Фільтрувати за датою",
|
||||
"Filter by name": "Фільтрувати за назвою",
|
||||
"Folder": "Тека",
|
||||
"Folder ID": "ID теки",
|
||||
"Folder Label": "Назва теки",
|
||||
"Folder Path": "Шлях до теки",
|
||||
"Folder Status": "Стан теки",
|
||||
"Folder Type": "Тип теки",
|
||||
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Тип теки \"{{receiveEncrypted}}\" можна встановити лише під час додавання нової теки.",
|
||||
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Тип теки \"{{receiveEncrypted}}\" не можна змінити після її додавання. Вам потрібно видалити теку, розшифрувати чи видалити дані на диску, а потім додати теку знову.",
|
||||
"Folders": "Теки",
|
||||
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "Для наступних тек сталася помилка під час початку відстеження змін. Перевірка тек відбувається щохвилини, тому помилки можуть незабаром зникнути. Якщо помилки залишилися, спробуйте виправити основну проблему та зверніться за допомогою, якщо не зможете.",
|
||||
"Forever": "Назавжди",
|
||||
"Full Rescan Interval (s)": "Інтервал повного пересканування (секунди)",
|
||||
"GUI": "Панель керування",
|
||||
"GUI / API HTTPS Certificate": "HTTPS-сертифікати панелі керування / API",
|
||||
"GUI Authentication Password": "Пароль для доступу до панелі керування",
|
||||
"GUI Authentication User": "Логін користувача для доступу до панелі керування",
|
||||
"Full Rescan Interval (s)": "Інтервал повного пересканування (у секундах)",
|
||||
"GUI": "Графічний інтерфейс",
|
||||
"GUI / API HTTPS Certificate": "HTTPS сертифікат для GUI / API",
|
||||
"GUI Authentication Password": "Пароль аутентифікації у графічному інтерфейсі",
|
||||
"GUI Authentication User": "Користувач аутентифікації у графічному інтерфейсі",
|
||||
"GUI Authentication: Set User and Password": "Доступ до панелі керування: встановіть ім'я користувача та пароль",
|
||||
"GUI Listen Address": "Адреса прослуховування для панелі керування",
|
||||
"GUI Override Directory": "Перевизначення адреси панелі керування",
|
||||
@@ -200,13 +200,13 @@
|
||||
"Ignore": "Ігнорувати",
|
||||
"Ignore Patterns": "Шаблони винятків",
|
||||
"Ignore Permissions": "Ігнорувати права доступу до файлів",
|
||||
"Ignore patterns can only be added after the folder is created. If checked, an input field to enter ignore patterns will be presented after saving.": "Шаблони ігнорування можна додати лише після створення папки. Якщо галочку поставлено, після збереження відображатиметься поле для введення шаблонів.",
|
||||
"Ignore patterns can only be added after the folder is created. If checked, an input field to enter ignore patterns will be presented after saving.": "Шаблони ігнорування можна додати лише після створення теки. Якщо галочку поставлено, після збереження відображатиметься поле для введення шаблонів.",
|
||||
"Ignored Devices": "Ігноровані пристрої",
|
||||
"Ignored Folders": "Ігноровані папки",
|
||||
"Ignored Folders": "Ігноровані теки",
|
||||
"Ignored at": "Ігноруються в",
|
||||
"Included Software": "Включене ПЗ",
|
||||
"Incoming Rate Limit (KiB/s)": "Ліміт швидкості завантаження (КіБ/с)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Невірна конфігурація може пошкодити вміст вашої папки та зробити Syncthing недієздатним.",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Невірна конфігурація може пошкодити вміст вашої теки та зробити Syncthing недієздатним.",
|
||||
"Incorrect user name or password.": "Невірний логін або пароль.",
|
||||
"Internally used paths:": "Шляхи, що використовуються внутрішньо:",
|
||||
"Introduced By": "Рекомендовано",
|
||||
@@ -260,7 +260,7 @@
|
||||
"Multi level wildcard (matches multiple directory levels)": "Багаторівнева маска (пошук збігів в усіх піддиректоріях) ",
|
||||
"Never": "Ніколи",
|
||||
"New Device": "Новий пристрій",
|
||||
"New Folder": "Нова папка",
|
||||
"New Folder": "Нова тека",
|
||||
"Newest First": "Спершу новіші",
|
||||
"No": "Ні",
|
||||
"No File Versioning": "Версіювання вимкнено",
|
||||
|
||||
@@ -118,10 +118,6 @@
|
||||
<li ng-if="authenticated"><a href="" ng-click="showSettings()"><span class="fa fa-fw fa-cog"></span> <span translate>Settings</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="showDeviceIdentification(thisDevice())"><span class="fa fa-fw fa-qrcode"></span> <span translate>Show ID</span></a></li>
|
||||
|
||||
<li ng-if="authenticated" class="divider" aria-hidden="true"></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="shutdown()"><span class="fa fa-fw fa-power-off"></span> <span translate>Shutdown</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="restart()"><span class="fa fa-fw fa-refresh"></span> <span translate>Restart</span></a></li>
|
||||
|
||||
<li ng-if="authenticated" class="divider" aria-hidden="true"></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="advanced()"><span class="fa fa-fw fa-cogs"></span> <span translate>Advanced</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="logging.show()"><span class="fa fa-fw fa-wrench"></span> <span translate>Logs</span></a></li>
|
||||
@@ -129,8 +125,10 @@
|
||||
<li class="divider" aria-hidden="true" ng-if="config.gui.debugging"></li>
|
||||
<li><a href="/rest/debug/support" target="_blank" ng-if="config.gui.debugging"><span class="fa fa-fw fa-user-md"></span> <span translate>Support Bundle</span></a></li>
|
||||
|
||||
<li ng-if="authenticated && isAuthEnabled()" class="divider" aria-hidden="true"></li>
|
||||
<li ng-if="authenticated" class="divider" aria-hidden="true"></li>
|
||||
<li ng-if="authenticated && isAuthEnabled()"><a href="" ng-click="logout()"><span class="far fa-fw fa-sign-out"></span> <span translate>Log Out</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="restart()"><span class="fa fa-fw fa-refresh"></span> <span translate>Restart</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="shutdown()"><span class="fa fa-fw fa-power-off"></span> <span translate>Shutdown</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<h4 class="text-center" translate>The Syncthing Authors</h4>
|
||||
<div class="row">
|
||||
<div class="col-md-12" id="contributor-list">
|
||||
Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Nate Morrison, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Wulf Weich, bt90, greatroar, Aaron Bieber, Adam Piggott, Adel Qalieh, Alan Pope, Alberto Donato, Aleksey Vasenev, Alessandro G., Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Anatoli Babenia, Andreas Sommer, Andrew Dunham, Andrew Meyer, Andrew Rabert, Andrey D, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benjamin Nater, Benno Fünfstück, Benny Ng, Boqin Qin, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Chris Tonkinson, Christian Kujau, Christian Prescott, Colin Kennedy, Cromefire_, Cyprien Devillez, Dale Visser, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Darshil Chanpura, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, DerRockWolf, Devon G. Redekopp, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, Gusted, Han Boetes, HansK-p, Harrison Jones, Heiko Zuerker, Hugo Locurcio, Iain Barnett, Ian Johnson, Ikko Ashimine, Ilya Brin, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jauder Ho, Jaya Chithra, Jaya Kumar, Jeffery To, Jens Diemer, Jerry Jacobs, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jonathan Cross, Jonta, Jose Manuel Delicado, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, K.B.Dharun Krishna, Kalle Laine, Karol Różycki, Kebin Liu, Keith Harrison, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., Kurt Fitzner, LSmithx2, Lars Lehtonen, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Lukas Lihotzki, Luke Hamburg, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Martin Polehla, Mateusz Naściszewski, Mateusz Ż, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maxime Thirouin, Maximilian, MichaIng, Michael Jephcote, Michael Rienstra, Michael Tilli, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, Naveen, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, Otiel, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Quentin Hibon, Rahmi Pruitt, Richard Hartmann, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, Ross Smith II, Ruslan Yevdokymov, Ryan Qian, Sacheendra Talluri, Scott Klupfel, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Taylor Khan, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tim Nordenfur, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy Thorn, Tommy van der Vorst, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, Vladimir Rusinov, WangXi, Will Rouesnel, William A. Kennington III, Xavier O., Yannic A., andresvia, andyleap, boomsquared, chenrui, chucic, cjc7373, cui fliter, d-volution, derekriemer, desbma, diemade, digital, entity0xfe, georgespatton, ghjklw, guangwu, gudvinr, ignacy123, janost, jaseg, jelle van der Waa, jtagcat, klemens, kylosus, luchenhan, luzpaz, marco-m, maxice8, mclang, mv1005, nf, orangekame3, otbutz, overkill, perewa, red_led, rubenbe, sec65, vapatel2, villekalliomaki, wangguoliang, wouter bolsterlee, xarx00, xjtdy888, 佛跳墙, 落心
|
||||
Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Nate Morrison, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Wulf Weich, bt90, greatroar, Aaron Bieber, Adam Piggott, Adel Qalieh, Alan Pope, Alberto Donato, Aleksey Vasenev, Alessandro G., Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Anatoli Babenia, Andreas Sommer, Andrew Dunham, Andrew Meyer, Andrew Rabert, Andrey D, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benjamin Nater, Benno Fünfstück, Benny Ng, Boqin Qin, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Chris Tonkinson, Christian Kujau, Christian Prescott, Colin Kennedy, Cromefire_, Cyprien Devillez, Dale Visser, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Darshil Chanpura, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, DerRockWolf, Devon G. Redekopp, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, Gusted, Han Boetes, HansK-p, Harrison Jones, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, Ikko Ashimine, Ilya Brin, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jauder Ho, Jaya Chithra, Jaya Kumar, Jeffery To, Jens Diemer, Jerry Jacobs, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jonathan Cross, Jonta, Jose Manuel Delicado, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, K.B.Dharun Krishna, Kalle Laine, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., Kurt Fitzner, LSmithx2, Lars Lehtonen, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Lukas Lihotzki, Luke Hamburg, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Martin Polehla, Mateusz Naściszewski, Mateusz Ż, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maxime Thirouin, Maximilian, MichaIng, Michael Jephcote, Michael Rienstra, Michael Tilli, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, Naveen, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, Otiel, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Quentin Hibon, Rahmi Pruitt, Richard Hartmann, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, Ross Smith II, Ruslan Yevdokymov, Ryan Qian, Sacheendra Talluri, Scott Klupfel, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Taylor Khan, Terrance, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tim Nordenfur, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy Thorn, Tommy van der Vorst, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, Vladimir Rusinov, WangXi, Will Rouesnel, William A. Kennington III, Xavier O., Yannic A., andresvia, andyleap, boomsquared, chenrui, chucic, cjc7373, cui fliter, d-volution, derekriemer, desbma, diemade, digital, entity0xfe, georgespatton, ghjklw, guangwu, gudvinr, ignacy123, janost, jaseg, jelle van der Waa, jtagcat, klemens, kylosus, luchenhan, luzpaz, marco-m, maxice8, mclang, mv1005, nf, orangekame3, otbutz, overkill, perewa, red_led, rubenbe, sec65, vapatel2, villekalliomaki, wangguoliang, wouter bolsterlee, xarx00, xjtdy888, 佛跳墙, 落心
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,12 @@ angular.module('syncthing.core')
|
||||
ctrl.$validators.folderPathErrors = function (viewValue) {
|
||||
// This function checks whether ydir is a subdirectory of xdir,
|
||||
// e.g. it would return true if xdir = "/home/a", ydir = "/home/a/b".
|
||||
// Tildes in both xdir and ydir are expanded for comparison
|
||||
// so that e.g. xdir = "home/a/", ydir = "~/b" will return true.
|
||||
function isSubDir(xdir, ydir) {
|
||||
var tildeExpansionRegex = new RegExp(`^~${scope.system.pathSeparator}|^~/`);
|
||||
xdir = xdir.replace(tildeExpansionRegex, `${scope.system.tilde}${scope.system.pathSeparator}`);
|
||||
ydir = ydir.replace(tildeExpansionRegex, `${scope.system.tilde}${scope.system.pathSeparator}`);
|
||||
var xdirArr = xdir.split(scope.system.pathSeparator);
|
||||
var ydirArr = ydir.split(scope.system.pathSeparator);
|
||||
if (xdirArr.slice(-1).pop() === "") {
|
||||
|
||||
@@ -3343,6 +3343,11 @@ angular.module('syncthing.core')
|
||||
return 'checkbox';
|
||||
}
|
||||
if (value instanceof Array) {
|
||||
if (value.some(function (element) {
|
||||
return typeof element !== 'number' && typeof element !== 'string';
|
||||
})) {
|
||||
return 'skip';
|
||||
}
|
||||
return 'list';
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<modal id="idqr" status="info" icon="fas fa-qrcode" heading="{{'Device Identification' | translate}} - {{deviceName(currentDevice)}}" large="yes" closeable="yes">
|
||||
<div class="modal-body text-center">
|
||||
<div class="well well-sm text-monospace select-on-click">{{currentDevice.deviceID}}</div>
|
||||
<div class="well well-sm text-monospace select-on-click"><strong>{{currentDevice.deviceID}}</strong></div>
|
||||
<div ng-if="currentDevice.deviceID">
|
||||
<img class="img-thumbnail" ng-src="qr/?text={{currentDevice.deviceID}}" height="328" width="328" alt="{{'QR code' | translate}}" />
|
||||
<div class="btn-group-vertical" style="vertical-align: top;">
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<div ng-repeat="(key, value) in advancedConfig.gui" ng-init="type = inputTypeFor(key, value)" ng-if="type != 'skip'" class="form-group">
|
||||
<label for="guiInput{{$index}}" class="col-sm-4 control-label">{{key | uncamel}} <a href="{{docsURL('users/config#config-option-gui.')}}{{key | lowercase}}" target="_blank"><span class="fas fa-question-circle"></span></a></label>
|
||||
<div class="col-sm-8">
|
||||
<input ng-if="inputTypeFor(key, value) == 'list'" id="guiInput{{$index}}" class="form-control" type="text" ng-model="advancedConfig.gui[key]" ng-list />
|
||||
<input ng-if="inputTypeFor(key, value) != 'list'" id="guiInput{{$index}}" class="form-control" type="{{inputTypeFor(key, value)}}" ng-model="advancedConfig.gui[key]" />
|
||||
<input ng-if="type == 'list'" id="guiInput{{$index}}" class="form-control" type="text" ng-model="advancedConfig.gui[key]" ng-list />
|
||||
<input ng-if="type != 'list'" id="guiInput{{$index}}" class="form-control" type="{{type}}" ng-model="advancedConfig.gui[key]" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1165,6 +1165,7 @@ type fileEntry struct {
|
||||
|
||||
func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
|
||||
var files []fileEntry
|
||||
const profilingDuration = 4 * time.Second
|
||||
|
||||
// Redacted configuration as a JSON
|
||||
if jsonConfig, err := json.MarshalIndent(getRedactedConfig(s), "", " "); err != nil {
|
||||
@@ -1231,10 +1232,10 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Metrics data as text
|
||||
buf := bytes.NewBuffer(nil)
|
||||
wr := bufferedResponseWriter{Writer: buf}
|
||||
var metricsBuf bytes.Buffer
|
||||
wr := bufferedResponseWriter{Writer: &metricsBuf}
|
||||
promhttp.Handler().ServeHTTP(wr, &http.Request{Method: http.MethodGet})
|
||||
files = append(files, fileEntry{name: "metrics.txt", data: buf.Bytes()})
|
||||
files = append(files, fileEntry{name: "metrics.txt", data: metricsBuf.Bytes()})
|
||||
|
||||
// Connection data as JSON
|
||||
connStats := s.model.ConnectionStats()
|
||||
@@ -1244,20 +1245,42 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
|
||||
files = append(files, fileEntry{name: "connection-stats.json.txt", data: connStatsJSON})
|
||||
}
|
||||
|
||||
// Heap and CPU Proofs as a pprof extension
|
||||
var heapBuffer, cpuBuffer bytes.Buffer
|
||||
filename := fmt.Sprintf("syncthing-heap-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
|
||||
runtime.GC()
|
||||
if err := pprof.WriteHeapProfile(&heapBuffer); err == nil {
|
||||
files = append(files, fileEntry{name: filename, data: heapBuffer.Bytes()})
|
||||
// Write a goroutine profile
|
||||
if p := pprof.Lookup("goroutine"); p != nil {
|
||||
var goroutineBuf bytes.Buffer
|
||||
_ = p.WriteTo(&goroutineBuf, 0)
|
||||
filename := fmt.Sprintf("syncthing-goroutines-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
|
||||
files = append(files, fileEntry{name: filename, data: goroutineBuf.Bytes()})
|
||||
}
|
||||
|
||||
const duration = 4 * time.Second
|
||||
filename = fmt.Sprintf("syncthing-cpu-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
|
||||
if err := pprof.StartCPUProfile(&cpuBuffer); err == nil {
|
||||
time.Sleep(duration)
|
||||
// Take a heap profile
|
||||
var heapBuf bytes.Buffer
|
||||
runtime.GC()
|
||||
if err := pprof.WriteHeapProfile(&heapBuf); err == nil {
|
||||
filename := fmt.Sprintf("syncthing-heap-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
|
||||
files = append(files, fileEntry{name: filename, data: heapBuf.Bytes()})
|
||||
}
|
||||
|
||||
// Enable block profiling
|
||||
runtime.SetBlockProfileRate(1)
|
||||
defer runtime.SetBlockProfileRate(0)
|
||||
|
||||
// Take a CPU profile, waiting for the profiling duration. This also
|
||||
// gives time for the block profile.
|
||||
var cpuBuf bytes.Buffer
|
||||
if err := pprof.StartCPUProfile(&cpuBuf); err == nil {
|
||||
time.Sleep(profilingDuration)
|
||||
pprof.StopCPUProfile()
|
||||
files = append(files, fileEntry{name: filename, data: cpuBuffer.Bytes()})
|
||||
filename := fmt.Sprintf("syncthing-cpu-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
|
||||
files = append(files, fileEntry{name: filename, data: cpuBuf.Bytes()})
|
||||
}
|
||||
|
||||
// Write the block profile
|
||||
if p := pprof.Lookup("block"); p != nil {
|
||||
var blockBuf bytes.Buffer
|
||||
_ = p.WriteTo(&blockBuf, 0)
|
||||
filename := fmt.Sprintf("syncthing-block-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
|
||||
files = append(files, fileEntry{name: filename, data: blockBuf.Bytes()})
|
||||
}
|
||||
|
||||
// Add buffer files to buffer zip
|
||||
@@ -1483,7 +1506,7 @@ func (*service) getDeviceID(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (*service) getLang(w http.ResponseWriter, r *http.Request) {
|
||||
lang := r.Header.Get("Accept-Language")
|
||||
var weights = make(map[string]float64)
|
||||
weights := make(map[string]float64)
|
||||
for _, l := range strings.Split(lang, ",") {
|
||||
parts := strings.SplitN(l, ";", 2)
|
||||
code := strings.ToLower(strings.TrimSpace(parts[0]))
|
||||
@@ -1502,7 +1525,7 @@ func (*service) getLang(w http.ResponseWriter, r *http.Request) {
|
||||
weights[code] = q
|
||||
}
|
||||
}
|
||||
var langs = make([]string, 0, len(weights))
|
||||
langs := make([]string, 0, len(weights))
|
||||
for code := range weights {
|
||||
langs = append(langs, code)
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ func readBroadcasts(ctx context.Context, outbox chan<- recv, port int) error {
|
||||
}
|
||||
|
||||
func bcast(ip *net.IPNet) *net.IPNet {
|
||||
var bc = &net.IPNet{}
|
||||
bc := &net.IPNet{}
|
||||
bc.IP = make([]byte, len(ip.IP))
|
||||
copy(bc.IP, ip.IP)
|
||||
bc.Mask = ip.Mask
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("beacon", "Multicast and broadcast discovery")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("beacon", "Multicast and broadcast discovery")
|
||||
|
||||
@@ -18,6 +18,7 @@ type requiresRestart struct {
|
||||
func (requiresRestart) VerifyConfiguration(_, _ Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c requiresRestart) CommitConfiguration(_, _ Configuration) bool {
|
||||
select {
|
||||
case c.committed <- struct{}{}:
|
||||
@@ -25,6 +26,7 @@ func (c requiresRestart) CommitConfiguration(_, _ Configuration) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (requiresRestart) String() string {
|
||||
return "requiresRestart"
|
||||
}
|
||||
@@ -34,9 +36,11 @@ type validationError struct{}
|
||||
func (validationError) VerifyConfiguration(_, _ Configuration) error {
|
||||
return errors.New("some error")
|
||||
}
|
||||
|
||||
func (validationError) CommitConfiguration(_, _ Configuration) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (validationError) String() string {
|
||||
return "validationError"
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ var (
|
||||
"dynamic+https://relays.syncthing.net/endpoint",
|
||||
netutil.AddressURL("quic", net.JoinHostPort("0.0.0.0", strconv.Itoa(DefaultQUICPort))),
|
||||
}
|
||||
DefaultGUIPort = 8384
|
||||
// DefaultDiscoveryServersV4 should be substituted when the configuration
|
||||
// contains <globalAnnounceServer>default-v4</globalAnnounceServer>.
|
||||
DefaultDiscoveryServersV4 = []string{
|
||||
@@ -116,11 +115,19 @@ func New(myID protocol.DeviceID) Configuration {
|
||||
}
|
||||
|
||||
func (cfg *Configuration) ProbeFreePorts() error {
|
||||
port, err := getFreePort("127.0.0.1", DefaultGUIPort)
|
||||
guiHost, guiPort, err := net.SplitHostPort(cfg.GUI.Address())
|
||||
if err != nil {
|
||||
return fmt.Errorf("get default port (GUI): %w", err)
|
||||
}
|
||||
port, err := strconv.Atoi(guiPort)
|
||||
if err != nil {
|
||||
return fmt.Errorf("convert default port (GUI): %w", err)
|
||||
}
|
||||
port, err = getFreePort(guiHost, port)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get free port (GUI): %w", err)
|
||||
}
|
||||
cfg.GUI.RawAddress = fmt.Sprintf("127.0.0.1:%d", port)
|
||||
cfg.GUI.RawAddress = net.JoinHostPort(guiHost, strconv.Itoa(port))
|
||||
|
||||
port, err = getFreePort("0.0.0.0", DefaultTCPPort)
|
||||
if err != nil {
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("config", "Configuration loading and saving")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("config", "Configuration loading and saving")
|
||||
|
||||
@@ -24,7 +24,7 @@ func ParseSize(s string) (Size, error) {
|
||||
for i := 0; i < len(s) && (s[i] >= '0' && s[i] <= '9' || s[i] == '.' || s[i] == ','); i++ {
|
||||
num = s[:i+1]
|
||||
}
|
||||
var i = len(num)
|
||||
i := len(num)
|
||||
for i < len(s) && s[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("connections", "Connection handling")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("connections", "Connection handling")
|
||||
|
||||
@@ -21,8 +21,10 @@ import (
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
var device1, device2, device3, device4 protocol.DeviceID
|
||||
var dev1Conf, dev2Conf, dev3Conf, dev4Conf config.DeviceConfiguration
|
||||
var (
|
||||
device1, device2, device3, device4 protocol.DeviceID
|
||||
dev1Conf, dev2Conf, dev3Conf, dev4Conf config.DeviceConfiguration
|
||||
)
|
||||
|
||||
func init() {
|
||||
device1, _ = protocol.DeviceIDFromString("AIR6LPZ7K4PTTUXQSMUUCPQ5YWOEDFIIQJUG7772YQXXR5YD6AWQ")
|
||||
|
||||
@@ -11,14 +11,12 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
var (
|
||||
metricDeviceActiveConnections = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: "syncthing",
|
||||
Subsystem: "connections",
|
||||
Name: "active",
|
||||
Help: "Number of currently active connections, per device. If value is 0, the device is disconnected.",
|
||||
}, []string{"device"})
|
||||
)
|
||||
var metricDeviceActiveConnections = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: "syncthing",
|
||||
Subsystem: "connections",
|
||||
Name: "active",
|
||||
Help: "Number of currently active connections, per device. If value is 0, the device is disconnected.",
|
||||
}, []string{"device"})
|
||||
|
||||
func registerDeviceMetrics(deviceID string) {
|
||||
// Register metrics for this device, so that counters & gauges are present even
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("backend", "The database backend")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("backend", "The database backend")
|
||||
|
||||
@@ -13,8 +13,10 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
var f1, f2, f3 protocol.FileInfo
|
||||
var folders = []string{"folder1", "folder2"}
|
||||
var (
|
||||
f1, f2, f3 protocol.FileInfo
|
||||
folders = []string{"folder1", "folder2"}
|
||||
)
|
||||
|
||||
func init() {
|
||||
blocks := genBlocks(30)
|
||||
|
||||
@@ -159,7 +159,6 @@ func init() {
|
||||
|
||||
func TestUpdate0to3(t *testing.T) {
|
||||
ldb, err := openJSONS("testdata/v0.14.45-update0to3.db.jsons")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("db", "The database layer")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("db", "The database layer")
|
||||
|
||||
func shouldDebug() bool {
|
||||
return l.ShouldDebug("db")
|
||||
|
||||
@@ -55,6 +55,7 @@ func globalList(t testing.TB, s *db.FileSet) []protocol.FileInfo {
|
||||
})
|
||||
return fs
|
||||
}
|
||||
|
||||
func globalListPrefixed(t testing.TB, s *db.FileSet, prefix string) []db.FileInfoTruncated {
|
||||
var fs []db.FileInfoTruncated
|
||||
snap := snapshot(t, s)
|
||||
|
||||
@@ -16,9 +16,7 @@ import (
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
var (
|
||||
noFallback = os.Getenv("ALL_PROXY_NO_FALLBACK") != ""
|
||||
)
|
||||
var noFallback = os.Getenv("ALL_PROXY_NO_FALLBACK") != ""
|
||||
|
||||
func init() {
|
||||
proxy.RegisterDialerType("socks", socksDialerFunction)
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("discover", "Remote device discovery")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("discover", "Remote device discovery")
|
||||
|
||||
@@ -244,6 +244,7 @@ type fakeAddressLister struct{}
|
||||
func (*fakeAddressLister) ExternalAddresses() []string {
|
||||
return []string{"tcp://0.0.0.0:22000"}
|
||||
}
|
||||
|
||||
func (*fakeAddressLister) AllAddresses() []string {
|
||||
return []string{"tcp://0.0.0.0:22000", "tcp://192.168.0.1:22000"}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
liblogger "github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
dl = liblogger.DefaultLogger.NewFacility("events", "Event generation and logging")
|
||||
)
|
||||
var dl = liblogger.DefaultLogger.NewFacility("events", "Event generation and logging")
|
||||
|
||||
@@ -81,7 +81,6 @@ func TestEventAfterSubscribe(t *testing.T) {
|
||||
l.Log(DeviceConnected, "foo")
|
||||
|
||||
ev, err := s.Poll(timeout)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error:", err)
|
||||
}
|
||||
|
||||
@@ -40,13 +40,13 @@ func (e basicFileInfo) Mode() FileMode {
|
||||
}
|
||||
// Set executable bits on files with executable extensions (.exe, .bat, etc).
|
||||
if isWindowsExecutable(e.Name()) {
|
||||
m |= 0111
|
||||
m |= 0o111
|
||||
}
|
||||
// There is no user/group/others in Windows' read-only attribute, and
|
||||
// all "w" bits are set if the file is not read-only. Do not send these
|
||||
// group/others-writable bits to other devices in order to avoid
|
||||
// unexpected world-writable files on other platforms.
|
||||
m &^= 0022
|
||||
m &^= 0o022
|
||||
return FileMode(m)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func readReparseTag(path string) (uint32, error) {
|
||||
}
|
||||
defer syscall.CloseHandle(h)
|
||||
|
||||
//https://docs.microsoft.com/windows/win32/api/winbase/ns-winbase-file_attribute_tag_info
|
||||
// https://docs.microsoft.com/windows/win32/api/winbase/ns-winbase-file_attribute_tag_info
|
||||
const fileAttributeTagInfo = 9
|
||||
type FILE_ATTRIBUTE_TAG_INFO struct {
|
||||
FileAttributes uint32
|
||||
@@ -67,7 +67,7 @@ type dirJunctFileInfo struct {
|
||||
func (fi *dirJunctFileInfo) Mode() os.FileMode {
|
||||
// Simulate a directory and not a symlink; also set the execute
|
||||
// bits so the directory can be traversed Unix-side.
|
||||
return fi.FileInfo.Mode() ^ junctionPointModeMask | os.ModeDir | 0111
|
||||
return fi.FileInfo.Mode()&^junctionPointModeMask | os.ModeDir | 0o111
|
||||
}
|
||||
|
||||
func (fi *dirJunctFileInfo) IsDir() bool {
|
||||
@@ -77,16 +77,19 @@ func (fi *dirJunctFileInfo) IsDir() bool {
|
||||
var junctionPointModeMask os.FileMode
|
||||
|
||||
func init() {
|
||||
// Per https://tip.golang.org/doc/go1.23#minor_library_changes
|
||||
// In go1.22 (and go1.23 when GODEBUG=winsymlink=0) Windows' directory
|
||||
// junctions (aka "mount points") always have ModeSymlink set.
|
||||
junctionPointModeMask = os.ModeSymlink
|
||||
if version.Compare(runtime.Version(), "go1.23") >= 0 {
|
||||
// if GODEBUG=winsymlink=0, then we are in g1.22 mode so let's check for
|
||||
// os.ModeSymlink as well, as it can't hurt.
|
||||
// In go1.23 Windows' directory junctions always have ModeIrregular set
|
||||
// (unless GODEBUG=winsymlink=0).
|
||||
junctionPointModeMask |= os.ModeIrregular
|
||||
}
|
||||
}
|
||||
|
||||
func (f *BasicFilesystem) underlyingLstat(name string) (os.FileInfo, error) {
|
||||
var fi, err = os.Lstat(name)
|
||||
fi, err := os.Lstat(name)
|
||||
|
||||
// There are cases where files are tagged as symlink, but they end up being
|
||||
// something else. Make sure we properly handle those types.
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestChmodFile(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "file")
|
||||
|
||||
defer os.Chmod(path, 0666)
|
||||
defer os.Chmod(path, 0o666)
|
||||
|
||||
fd, err := os.Create(path)
|
||||
if err != nil {
|
||||
@@ -42,19 +42,19 @@ func TestChmodFile(t *testing.T) {
|
||||
}
|
||||
fd.Close()
|
||||
|
||||
if err := os.Chmod(path, 0666); err != nil {
|
||||
if err := os.Chmod(path, 0o666); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(path); err != nil || stat.Mode()&os.ModePerm != 0666 {
|
||||
if stat, err := os.Stat(path); err != nil || stat.Mode()&os.ModePerm != 0o666 {
|
||||
t.Errorf("wrong perm: %t %#o", err == nil, stat.Mode()&os.ModePerm)
|
||||
}
|
||||
|
||||
if err := fs.Chmod("file", 0444); err != nil {
|
||||
if err := fs.Chmod("file", 0o444); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(path); err != nil || stat.Mode()&os.ModePerm != 0444 {
|
||||
if stat, err := os.Stat(path); err != nil || stat.Mode()&os.ModePerm != 0o444 {
|
||||
t.Errorf("wrong perm: %t %#o", err == nil, stat.Mode()&os.ModePerm)
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func TestChownFile(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "file")
|
||||
|
||||
defer os.Chmod(path, 0666)
|
||||
defer os.Chmod(path, 0o666)
|
||||
|
||||
fd, err := os.Create(path)
|
||||
if err != nil {
|
||||
@@ -110,9 +110,9 @@ func TestChmodDir(t *testing.T) {
|
||||
fs, dir := setup(t)
|
||||
path := filepath.Join(dir, "dir")
|
||||
|
||||
mode := os.FileMode(0755)
|
||||
mode := os.FileMode(0o755)
|
||||
if build.IsWindows {
|
||||
mode = os.FileMode(0777)
|
||||
mode = os.FileMode(0o777)
|
||||
}
|
||||
|
||||
defer os.Chmod(path, mode)
|
||||
@@ -129,11 +129,11 @@ func TestChmodDir(t *testing.T) {
|
||||
t.Errorf("wrong perm: %t %#o", err == nil, stat.Mode()&os.ModePerm)
|
||||
}
|
||||
|
||||
if err := fs.Chmod("dir", 0555); err != nil {
|
||||
if err := fs.Chmod("dir", 0o555); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(path); err != nil || stat.Mode()&os.ModePerm != 0555 {
|
||||
if stat, err := os.Stat(path); err != nil || stat.Mode()&os.ModePerm != 0o555 {
|
||||
t.Errorf("wrong perm: %t %#o", err == nil, stat.Mode()&os.ModePerm)
|
||||
}
|
||||
}
|
||||
@@ -221,7 +221,7 @@ func TestDirNames(t *testing.T) {
|
||||
sort.Strings(testCases)
|
||||
|
||||
for _, sub := range testCases {
|
||||
if err := os.Mkdir(filepath.Join(dir, sub), 0777); err != nil {
|
||||
if err := os.Mkdir(filepath.Join(dir, sub), 0o777); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -256,7 +256,7 @@ func TestNames(t *testing.T) {
|
||||
t.Errorf("incorrect %s != %s (%v)", stat.Name(), expected, err)
|
||||
}
|
||||
|
||||
if err := fs.Mkdir("dir", 0777); err != nil {
|
||||
if err := fs.Mkdir("dir", 0o777); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ func TestGlob(t *testing.T) {
|
||||
filepath.Join("a", "best", "b"),
|
||||
filepath.Join("a", "best", "c"),
|
||||
} {
|
||||
if err := fs.MkdirAll(dirToCreate, 0777); err != nil {
|
||||
if err := fs.MkdirAll(dirToCreate, 0o777); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -572,7 +572,7 @@ func TestRel(t *testing.T) {
|
||||
|
||||
func TestXattr(t *testing.T) {
|
||||
tfs, _ := setup(t)
|
||||
if err := tfs.Mkdir("/test", 0755); err != nil {
|
||||
if err := tfs.Mkdir("/test", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ func (f *BasicFilesystem) Remove(name string) error {
|
||||
err = os.Remove(name)
|
||||
if os.IsPermission(err) {
|
||||
// Try to remove the read-only attribute and try again
|
||||
if os.Chmod(name, 0600) == nil {
|
||||
if os.Chmod(name, 0o600) == nil {
|
||||
err = os.Remove(name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func testRealCase(t *testing.T, fsys Filesystem) {
|
||||
testFs := newCaseFilesystem(fsys)
|
||||
comps := []string{"Foo", "bar", "BAZ", "bAs"}
|
||||
path := filepath.Join(comps...)
|
||||
testFs.MkdirAll(filepath.Join(comps[:len(comps)-1]...), 0777)
|
||||
testFs.MkdirAll(filepath.Join(comps[:len(comps)-1]...), 0o777)
|
||||
fd, err := testFs.Create(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -93,7 +93,7 @@ func testRealCaseSensitive(t *testing.T, fsys Filesystem) {
|
||||
names[0] = "foo"
|
||||
names[1] = strings.ToUpper(names[0])
|
||||
for _, n := range names {
|
||||
if err := testFs.MkdirAll(n, 0777); err != nil {
|
||||
if err := testFs.MkdirAll(n, 0o777); err != nil {
|
||||
if IsErrCaseConflict(err) {
|
||||
t.Skip("Filesystem is case-insensitive")
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("fs", "Filesystem access")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("fs", "Filesystem access")
|
||||
|
||||
func init() {
|
||||
logger.DefaultLogger.NewFacility("walkfs", "Filesystem access while walking")
|
||||
|
||||
@@ -30,6 +30,7 @@ func (fs *errorFilesystem) DirNames(_ string) ([]string, error) { return nil, fs
|
||||
func (fs *errorFilesystem) GetXattr(_ string, _ XattrFilter) ([]protocol.Xattr, error) {
|
||||
return nil, fs.err
|
||||
}
|
||||
|
||||
func (fs *errorFilesystem) SetXattr(_ string, _ []protocol.Xattr, _ XattrFilter) error {
|
||||
return fs.err
|
||||
}
|
||||
@@ -60,6 +61,7 @@ func (*errorFilesystem) SameFile(_, _ FileInfo) bool { return false }
|
||||
func (fs *errorFilesystem) Watch(_ string, _ Matcher, _ context.Context, _ bool) (<-chan Event, <-chan error, error) {
|
||||
return nil, nil, fs.err
|
||||
}
|
||||
|
||||
func (fs *errorFilesystem) PlatformData(_ string, _, _ bool, _ XattrFilter) (protocol.PlatformData, error) {
|
||||
return protocol.PlatformData{}, fs.err
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestFakeFS(t *testing.T) {
|
||||
fs := newFakeFilesystem("/foo/bar/baz")
|
||||
|
||||
// MkdirAll
|
||||
err := fs.MkdirAll("dira/dirb", 0755)
|
||||
err := fs.MkdirAll("dira/dirb", 0o755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -37,7 +37,7 @@ func TestFakeFS(t *testing.T) {
|
||||
}
|
||||
|
||||
// Mkdir
|
||||
err = fs.Mkdir("dira/dirb/dirc", 0755)
|
||||
err = fs.Mkdir("dira/dirb/dirc", 0o755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -190,7 +190,7 @@ type test struct {
|
||||
}
|
||||
|
||||
func TestFakeFSCaseSensitive(t *testing.T) {
|
||||
var tests = []test{
|
||||
tests := []test{
|
||||
{"Read", testFakeFSRead},
|
||||
{"OpenFile", testFakeFSOpenFile},
|
||||
{"RemoveAll", testFakeFSRemoveAll},
|
||||
@@ -201,7 +201,7 @@ func TestFakeFSCaseSensitive(t *testing.T) {
|
||||
{"DirNames", testDirNames},
|
||||
{"FileName", testFakeFSFileName},
|
||||
}
|
||||
var filesystems = []testFS{
|
||||
filesystems := []testFS{
|
||||
{"fakeFS", newFakeFilesystem("/foo")},
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ func TestFakeFSCaseSensitive(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFakeFSCaseInsensitive(t *testing.T) {
|
||||
var tests = []test{
|
||||
tests := []test{
|
||||
{"Read", testFakeFSRead},
|
||||
{"OpenFile", testFakeFSOpenFile},
|
||||
{"RemoveAll", testFakeFSRemoveAll},
|
||||
@@ -236,7 +236,7 @@ func TestFakeFSCaseInsensitive(t *testing.T) {
|
||||
{"FileNameInsens", testFakeFSFileNameInsens},
|
||||
}
|
||||
|
||||
var filesystems = []testFS{
|
||||
filesystems := []testFS{
|
||||
{"fakeFS", newFakeFilesystem("/foobar?insens=true")},
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ func runTests(t *testing.T, tests []test, filesystems []testFS) {
|
||||
func testFakeFSCaseInsensitive(t *testing.T, fs Filesystem) {
|
||||
bs1 := []byte("test")
|
||||
|
||||
err := fs.Mkdir("/fUbar", 0755)
|
||||
err := fs.Mkdir("/fUbar", 0o755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -327,12 +327,12 @@ func testFakeFSCaseInsensitive(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSCaseInsensitiveMkdirAll(t *testing.T, fs Filesystem) {
|
||||
err := fs.MkdirAll("/fOO/Bar/bAz", 0755)
|
||||
err := fs.MkdirAll("/fOO/Bar/bAz", 0o755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fd, err := fs.OpenFile("/foo/BaR/BaZ/tESt", os.O_CREATE, 0644)
|
||||
fd, err := fs.OpenFile("/foo/BaR/BaZ/tESt", os.O_CREATE, 0o644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -430,7 +430,7 @@ func testFakeFSStatInsens(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSFileName(t *testing.T, fs Filesystem) {
|
||||
var testCases = []struct {
|
||||
testCases := []struct {
|
||||
create string
|
||||
open string
|
||||
}{
|
||||
@@ -458,7 +458,7 @@ func testFakeFSFileName(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSFileNameInsens(t *testing.T, fs Filesystem) {
|
||||
var testCases = []struct {
|
||||
testCases := []struct {
|
||||
create string
|
||||
open string
|
||||
}{
|
||||
@@ -486,7 +486,7 @@ func testFakeFSFileNameInsens(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSRename(t *testing.T, fs Filesystem) {
|
||||
if err := fs.MkdirAll("/foo/bar/baz", 0755); err != nil {
|
||||
if err := fs.MkdirAll("/foo/bar/baz", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -500,7 +500,7 @@ func testFakeFSRename(t *testing.T, fs Filesystem) {
|
||||
t.Errorf("rename to non-existent dir gave no error")
|
||||
}
|
||||
|
||||
if err := fs.MkdirAll("/baz/bar/foo", 0755); err != nil {
|
||||
if err := fs.MkdirAll("/baz/bar/foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ func testFakeFSRename(t *testing.T, fs Filesystem) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var dirs = []struct {
|
||||
dirs := []struct {
|
||||
dir string
|
||||
files []string
|
||||
}{
|
||||
@@ -531,11 +531,11 @@ func testFakeFSRename(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSRenameInsensitive(t *testing.T, fs Filesystem) {
|
||||
if err := fs.MkdirAll("/baz/bar/foo", 0755); err != nil {
|
||||
if err := fs.MkdirAll("/baz/bar/foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := fs.MkdirAll("/foO/baR/baZ", 0755); err != nil {
|
||||
if err := fs.MkdirAll("/foO/baR/baZ", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ func testFakeFSRenameInsensitive(t *testing.T, fs Filesystem) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var dirs = []struct {
|
||||
dirs := []struct {
|
||||
dir string
|
||||
files []string
|
||||
}{
|
||||
@@ -582,7 +582,7 @@ func testFakeFSRenameInsensitive(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSMkdir(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -590,13 +590,13 @@ func testFakeFSMkdir(t *testing.T, fs Filesystem) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := fs.Mkdir("/foo", 0755); err == nil {
|
||||
if err := fs.Mkdir("/foo", 0o755); err == nil {
|
||||
t.Errorf("got no error while creating existing directory")
|
||||
}
|
||||
}
|
||||
|
||||
func testFakeFSMkdirInsens(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -604,37 +604,37 @@ func testFakeFSMkdirInsens(t *testing.T, fs Filesystem) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := fs.Mkdir("/FOO", 0755); err == nil {
|
||||
if err := fs.Mkdir("/FOO", 0o755); err == nil {
|
||||
t.Errorf("got no error while creating existing directory")
|
||||
}
|
||||
}
|
||||
|
||||
func testFakeFSOpenFile(t *testing.T, fs Filesystem) {
|
||||
fd, err := fs.OpenFile("foobar", os.O_RDONLY, 0664)
|
||||
fd, err := fs.OpenFile("foobar", os.O_RDONLY, 0o664)
|
||||
if err == nil {
|
||||
fd.Close()
|
||||
t.Fatalf("got no error opening a non-existing file")
|
||||
}
|
||||
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR|os.O_CREATE, 0664)
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR|os.O_CREATE, 0o664)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fd.Close()
|
||||
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0664)
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o664)
|
||||
if err == nil {
|
||||
fd.Close()
|
||||
t.Fatalf("created an existing file while told not to")
|
||||
}
|
||||
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR|os.O_CREATE, 0664)
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR|os.O_CREATE, 0o664)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fd.Close()
|
||||
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR, 0664)
|
||||
fd, err = fs.OpenFile("foobar", os.O_RDWR, 0o664)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -642,31 +642,31 @@ func testFakeFSOpenFile(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSOpenFileInsens(t *testing.T, fs Filesystem) {
|
||||
fd, err := fs.OpenFile("FooBar", os.O_RDONLY, 0664)
|
||||
fd, err := fs.OpenFile("FooBar", os.O_RDONLY, 0o664)
|
||||
if err == nil {
|
||||
fd.Close()
|
||||
t.Fatalf("got no error opening a non-existing file")
|
||||
}
|
||||
|
||||
fd, err = fs.OpenFile("fOObar", os.O_RDWR|os.O_CREATE, 0664)
|
||||
fd, err = fs.OpenFile("fOObar", os.O_RDWR|os.O_CREATE, 0o664)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fd.Close()
|
||||
|
||||
fd, err = fs.OpenFile("fOoBaR", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0664)
|
||||
fd, err = fs.OpenFile("fOoBaR", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o664)
|
||||
if err == nil {
|
||||
fd.Close()
|
||||
t.Fatalf("created an existing file while told not to")
|
||||
}
|
||||
|
||||
fd, err = fs.OpenFile("FoObAr", os.O_RDWR|os.O_CREATE, 0664)
|
||||
fd, err = fs.OpenFile("FoObAr", os.O_RDWR|os.O_CREATE, 0o664)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fd.Close()
|
||||
|
||||
fd, err = fs.OpenFile("FOOBAR", os.O_RDWR, 0664)
|
||||
fd, err = fs.OpenFile("FOOBAR", os.O_RDWR, 0o664)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -674,7 +674,7 @@ func testFakeFSOpenFileInsens(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSRemoveAll(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -702,7 +702,7 @@ func testFakeFSRemoveAll(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSRemoveAllInsens(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/Foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/Foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -729,7 +729,7 @@ func testFakeFSRemoveAllInsens(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSRemove(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/Foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/Foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -754,7 +754,7 @@ func testFakeFSRemove(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSRemoveInsens(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/Foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/Foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -778,7 +778,7 @@ func testFakeFSRemoveInsens(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSSameFile(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/Foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/Foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -810,7 +810,7 @@ func testFakeFSSameFile(t *testing.T, fs Filesystem) {
|
||||
}
|
||||
|
||||
func testFakeFSSameFileInsens(t *testing.T, fs Filesystem) {
|
||||
if err := fs.Mkdir("/Foo", 0755); err != nil {
|
||||
if err := fs.Mkdir("/Foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ func TestCanonicalize(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileModeString(t *testing.T) {
|
||||
var fm FileMode = 0777
|
||||
var fm FileMode = 0o777
|
||||
exp := "-rwxrwxrwx"
|
||||
if fm.String() != exp {
|
||||
t.Fatalf("Got %v, expected %v", fm.String(), exp)
|
||||
|
||||
@@ -23,10 +23,10 @@ func testWalkSkipSymlink(t *testing.T, fsType FilesystemType, uri string) {
|
||||
|
||||
fs := NewFilesystem(fsType, uri)
|
||||
|
||||
if err := fs.MkdirAll("target/foo", 0755); err != nil {
|
||||
if err := fs.MkdirAll("target/foo", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := fs.Mkdir("towalk", 0755); err != nil {
|
||||
if err := fs.Mkdir("towalk", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := fs.CreateSymlink("target", "towalk/symlink"); err != nil {
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type blockPullReorderer interface {
|
||||
|
||||
@@ -14,9 +14,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
var (
|
||||
someBlocks = []protocol.BlockInfo{{Offset: 1}, {Offset: 2}, {Offset: 3}}
|
||||
)
|
||||
var someBlocks = []protocol.BlockInfo{{Offset: 1}, {Offset: 2}, {Offset: 3}}
|
||||
|
||||
func Test_chunk(t *testing.T) {
|
||||
type args struct {
|
||||
|
||||
@@ -10,9 +10,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("model", "The root hub")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("model", "The root hub")
|
||||
|
||||
func shouldDebug() bool {
|
||||
return l.ShouldDebug("model")
|
||||
|
||||
@@ -33,55 +33,56 @@ func TestDeviceDownloadState(t *testing.T) {
|
||||
shouldHaveIndexesFrom []protocol.FileDownloadProgressUpdate
|
||||
shouldNotHaveIndexesFrom []protocol.FileDownloadProgressUpdate
|
||||
}{
|
||||
{ //1
|
||||
{ // 1
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p2, f1v2p1, f1v2p2},
|
||||
},
|
||||
{ //2
|
||||
{ // 2
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v2p1, f1v2p2},
|
||||
},
|
||||
{ //3
|
||||
{ // 3
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v1del},
|
||||
nil,
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p1, f1v2p2}},
|
||||
{ //4
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p1, f1v2p2},
|
||||
},
|
||||
{ // 4
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2del},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v2p1, f1v2p2},
|
||||
},
|
||||
{ //5
|
||||
{ // 5
|
||||
// v2 replaces old v1 data
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v2p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p2},
|
||||
},
|
||||
{ //6
|
||||
{ // 6
|
||||
// v1 delete on v2 data does nothing
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p1, f1v1del},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v2p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p2},
|
||||
},
|
||||
{ //7
|
||||
{ // 7
|
||||
// v2 replacees v1, v2 gets deleted, and v2 part 2 gets added.
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p1, f1v2del, f1v2p2},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v2p2},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f1v1p2, f1v2p1},
|
||||
},
|
||||
// Multiple files in one go
|
||||
{ //8
|
||||
{ // 8
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f2v1p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f2v1p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p2, f2v1p2},
|
||||
},
|
||||
{ //9
|
||||
{ // 9
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f2v1p1, f2v1del},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f2v1p1, f2v1p1},
|
||||
},
|
||||
{ //10
|
||||
{ // 10
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f2v1del, f2v1p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p1, f2v1p1},
|
||||
[]protocol.FileDownloadProgressUpdate{f1v1p2, f2v1p2},
|
||||
|
||||
@@ -398,7 +398,7 @@ func (f *sendReceiveFolder) processNeeded(snap *db.Snapshot, dbUpdateChan chan<-
|
||||
f.queue.Push(file.Name, file.Size, file.ModTime())
|
||||
}
|
||||
|
||||
case build.IsWindows && file.IsSymlink():
|
||||
case (build.IsWindows || build.IsAndroid) && file.IsSymlink():
|
||||
if err := f.handleSymlinkCheckExisting(file, snap, scanChan); err != nil {
|
||||
f.newPullError(file.Name, fmt.Errorf("handling unsupported symlink: %w", err))
|
||||
break
|
||||
@@ -505,13 +505,10 @@ nextFile:
|
||||
continue nextFile
|
||||
}
|
||||
|
||||
devices := snap.Availability(fileName)
|
||||
for _, dev := range devices {
|
||||
if f.model.ConnectedTo(dev) {
|
||||
// Handle the file normally, by copying and pulling, etc.
|
||||
f.handleFile(fi, snap, copyChan)
|
||||
continue nextFile
|
||||
}
|
||||
devices := f.model.fileAvailability(f.FolderConfiguration, snap, fi)
|
||||
if len(devices) > 0 {
|
||||
f.handleFile(fi, snap, copyChan)
|
||||
continue
|
||||
}
|
||||
f.newPullError(fileName, errNotAvailable)
|
||||
f.queue.Done(fileName)
|
||||
@@ -1547,7 +1544,7 @@ func (f *sendReceiveFolder) pullBlock(state pullBlockState, snap *db.Snapshot, o
|
||||
}
|
||||
|
||||
var lastError error
|
||||
candidates := f.model.availabilityInSnapshot(f.FolderConfiguration, snap, state.file, state.block)
|
||||
candidates := f.model.blockAvailability(f.FolderConfiguration, snap, state.file, state.block)
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
|
||||
@@ -448,7 +448,7 @@ func (s *indexHandler) receive(fs []protocol.FileInfo, update bool, op string, p
|
||||
seq := fset.Sequence(deviceID)
|
||||
|
||||
// Check that the sequence we get back is what we put in...
|
||||
if lastSequence > 0 && seq != lastSequence {
|
||||
if lastSequence > 0 && len(fs) > 0 && seq != lastSequence {
|
||||
s.logSequenceAnomaly("unexpected sequence after update", map[string]any{
|
||||
"prevSeq": prevSequence,
|
||||
"lastSeq": lastSequence,
|
||||
|
||||
@@ -2882,16 +2882,31 @@ func (m *model) Availability(folder string, file protocol.FileInfo, block protoc
|
||||
}
|
||||
defer snap.Release()
|
||||
|
||||
return m.availabilityInSnapshotRLocked(cfg, snap, file, block), nil
|
||||
return m.blockAvailabilityRLocked(cfg, snap, file, block), nil
|
||||
}
|
||||
|
||||
func (m *model) availabilityInSnapshot(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
|
||||
func (m *model) blockAvailability(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
|
||||
m.mut.RLock()
|
||||
defer m.mut.RUnlock()
|
||||
return m.availabilityInSnapshotRLocked(cfg, snap, file, block)
|
||||
return m.blockAvailabilityRLocked(cfg, snap, file, block)
|
||||
}
|
||||
|
||||
func (m *model) availabilityInSnapshotRLocked(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
|
||||
func (m *model) blockAvailabilityRLocked(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
|
||||
var candidates []Availability
|
||||
|
||||
candidates = append(candidates, m.fileAvailabilityRLocked(cfg, snap, file)...)
|
||||
candidates = append(candidates, m.blockAvailabilityFromTemporaryRLocked(cfg, file, block)...)
|
||||
|
||||
return candidates
|
||||
}
|
||||
|
||||
func (m *model) fileAvailability(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo) []Availability {
|
||||
m.mut.RLock()
|
||||
defer m.mut.RUnlock()
|
||||
return m.fileAvailabilityRLocked(cfg, snap, file)
|
||||
}
|
||||
|
||||
func (m *model) fileAvailabilityRLocked(cfg config.FolderConfiguration, snap *db.Snapshot, file protocol.FileInfo) []Availability {
|
||||
var availabilities []Availability
|
||||
for _, device := range snap.Availability(file.Name) {
|
||||
if _, ok := m.remoteFolderStates[device]; !ok {
|
||||
@@ -2905,13 +2920,16 @@ func (m *model) availabilityInSnapshotRLocked(cfg config.FolderConfiguration, sn
|
||||
availabilities = append(availabilities, Availability{ID: device, FromTemporary: false})
|
||||
}
|
||||
}
|
||||
return availabilities
|
||||
}
|
||||
|
||||
func (m *model) blockAvailabilityFromTemporaryRLocked(cfg config.FolderConfiguration, file protocol.FileInfo, block protocol.BlockInfo) []Availability {
|
||||
var availabilities []Availability
|
||||
for _, device := range cfg.Devices {
|
||||
if m.deviceDownloads[device.DeviceID].Has(cfg.ID, file.Name, file.Version, int(block.Offset/int64(file.BlockSize()))) {
|
||||
availabilities = append(availabilities, Availability{ID: device.DeviceID, FromTemporary: true})
|
||||
}
|
||||
}
|
||||
|
||||
return availabilities
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("nat", "NAT discovery and port mapping")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("nat", "NAT discovery and port mapping")
|
||||
|
||||
@@ -259,7 +259,7 @@ func (s *Service) verifyExistingLocked(ctx context.Context, mapping *Mapping, na
|
||||
// entry always has the external port.
|
||||
responseAddrs, err := s.tryNATDevice(ctx, nat, mapping.address, extAddrs[0].Port, leaseTime)
|
||||
if err != nil {
|
||||
l.Debugf("Failed to renew %s -> %v open port on %s", mapping, extAddrs, id)
|
||||
l.Infof("Failed to renew %s -> %v open port on %s: %s", mapping, extAddrs, id, err)
|
||||
mapping.removeAddressLocked(id)
|
||||
change = true
|
||||
continue
|
||||
@@ -311,7 +311,7 @@ func (s *Service) acquireNewLocked(ctx context.Context, mapping *Mapping, nats m
|
||||
|
||||
addrs, err := s.tryNATDevice(ctx, nat, mapping.address, 0, leaseTime)
|
||||
if err != nil {
|
||||
l.Debugf("Failed to acquire %s open port on %s", mapping, id)
|
||||
l.Infof("Failed to acquire %s open port on %s: %s", mapping, id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -359,7 +359,7 @@ func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address
|
||||
extPort = port
|
||||
goto findIP
|
||||
}
|
||||
l.Debugln("Error extending lease on", natd.ID(), err)
|
||||
l.Debugf("Error extending lease on %v (external port %d -> internal port %d): %v", natd.ID(), extPort, intAddr.Port, err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
@@ -377,7 +377,8 @@ func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address
|
||||
extPort = port
|
||||
goto findIP
|
||||
}
|
||||
l.Debugf("Error getting new lease on %s: %s", natd.ID(), err)
|
||||
err = fmt.Errorf("getting new lease on %s (external port %d -> internal port %d): %w", natd.ID(), extPort, intAddr.Port, err)
|
||||
l.Debugf("Error %s", err)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
|
||||
@@ -101,7 +101,7 @@ func (w *AtomicWriter) Close() error {
|
||||
// On Windows, we might not be allowed to rename over the file
|
||||
// because it's read-only. Get us some write permissions and try
|
||||
// again.
|
||||
_ = w.fs.Chmod(w.path, 0644)
|
||||
_ = w.fs.Chmod(w.path, 0o644)
|
||||
err = w.fs.Rename(w.next.Name(), w.path)
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestCreateAtomicCreate(t *testing.T) {
|
||||
os.RemoveAll("testdata")
|
||||
defer os.RemoveAll("testdata")
|
||||
|
||||
if err := os.Mkdir("testdata", 0755); err != nil {
|
||||
if err := os.Mkdir("testdata", 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -52,10 +52,11 @@ func TestCreateAtomicCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreateAtomicReplace(t *testing.T) {
|
||||
testCreateAtomicReplace(t, 0666)
|
||||
testCreateAtomicReplace(t, 0o666)
|
||||
}
|
||||
|
||||
func TestCreateAtomicReplaceReadOnly(t *testing.T) {
|
||||
testCreateAtomicReplace(t, 0444) // windows compatible read-only bits
|
||||
testCreateAtomicReplace(t, 0o444) // windows compatible read-only bits
|
||||
}
|
||||
|
||||
func testCreateAtomicReplace(t *testing.T, oldPerms os.FileMode) {
|
||||
@@ -66,7 +67,7 @@ func testCreateAtomicReplace(t *testing.T, oldPerms os.FileMode) {
|
||||
|
||||
os.RemoveAll(testdir)
|
||||
|
||||
if err := os.Mkdir(testdir, 0755); err != nil {
|
||||
if err := os.Mkdir(testdir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestTempFilePermissions(t *testing.T) {
|
||||
// The temp file should have 0600 permissions at the most, or we have a
|
||||
// security problem in CreateAtomic.
|
||||
t.Logf("Got 0%03o", info.Mode())
|
||||
if info.Mode()&^0600 != 0 {
|
||||
if info.Mode()&^0o600 != 0 {
|
||||
t.Errorf("Permission 0%03o is too generous", info.Mode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,14 +84,14 @@ func Copy(method fs.CopyRangeMethod, src, dst fs.Filesystem, from, to string) (e
|
||||
func withPreparedTarget(filesystem fs.Filesystem, from, to string, f func() error) error {
|
||||
// Make sure the destination directory is writeable
|
||||
toDir := filepath.Dir(to)
|
||||
if info, err := filesystem.Stat(toDir); err == nil && info.IsDir() && info.Mode()&0200 == 0 {
|
||||
filesystem.Chmod(toDir, 0755)
|
||||
if info, err := filesystem.Stat(toDir); err == nil && info.IsDir() && info.Mode()&0o200 == 0 {
|
||||
filesystem.Chmod(toDir, 0o755)
|
||||
defer filesystem.Chmod(toDir, info.Mode())
|
||||
}
|
||||
|
||||
// On Windows, make sure the destination file is writeable (or we can't delete it)
|
||||
if build.IsWindows {
|
||||
filesystem.Chmod(to, 0666)
|
||||
filesystem.Chmod(to, 0o666)
|
||||
if !strings.EqualFold(from, to) {
|
||||
err := filesystem.Remove(to)
|
||||
if err != nil && !fs.IsNotExist(err) {
|
||||
|
||||
@@ -16,8 +16,10 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
)
|
||||
|
||||
var rand uint32
|
||||
var randmu sync.Mutex
|
||||
var (
|
||||
rand uint32
|
||||
randmu sync.Mutex
|
||||
)
|
||||
|
||||
func reseed() uint32 {
|
||||
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
||||
@@ -48,7 +50,7 @@ func TempFile(filesystem fs.Filesystem, dir, prefix string) (f fs.File, err erro
|
||||
nconflict := 0
|
||||
for i := 0; i < 10000; i++ {
|
||||
name := filepath.Join(dir, prefix+nextSuffix())
|
||||
f, err = filesystem.OpenFile(name, fs.OptReadWrite|fs.OptCreate|fs.OptExclusive, 0600)
|
||||
f, err = filesystem.OpenFile(name, fs.OptReadWrite|fs.OptCreate|fs.OptExclusive, 0o600)
|
||||
if fs.IsExist(err) {
|
||||
if nconflict++; nconflict > 10 {
|
||||
randmu.Lock()
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("pmp", "NAT-PMP discovery and port mapping")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("pmp", "NAT-PMP discovery and port mapping")
|
||||
|
||||
@@ -317,10 +317,10 @@ func PermsEqual(a, b uint32) bool {
|
||||
if build.IsWindows {
|
||||
// There is only writeable and read only, represented for user, group
|
||||
// and other equally. We only compare against user.
|
||||
return a&0600 == b&0600
|
||||
return a&0o600 == b&0o600
|
||||
}
|
||||
// All bits count
|
||||
return a&0777 == b&0777
|
||||
return a&0o777 == b&0o777
|
||||
}
|
||||
|
||||
// BlocksEqual returns true when the two files have identical block lists.
|
||||
|
||||
@@ -6,6 +6,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("protocol", "The BEP protocol")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("protocol", "The BEP protocol")
|
||||
|
||||
@@ -4,19 +4,21 @@ package protocol
|
||||
|
||||
import "testing"
|
||||
|
||||
var formatted = "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"
|
||||
var formatCases = []string{
|
||||
"P56IOI-7MZJNU-2IQGDR-EYDM2M-GTMGL3-BXNPQ6-W5BTBB-Z4TJXZ-WICQ",
|
||||
"P56IOI-7MZJNU2Y-IQGDR-EYDM2M-GTI-MGL3-BXNPQ6-W5BM-TBB-Z4TJXZ-WICQ2",
|
||||
"P56IOI7 MZJNU2I QGDREYD M2MGTMGL 3BXNPQ6W 5BTB BZ4T JXZWICQ",
|
||||
"P56IOI7 MZJNU2Y IQGDREY DM2MGTI MGL3BXN PQ6W5BM TBBZ4TJ XZWICQ2",
|
||||
"P56IOI7MZJNU2IQGDREYDM2MGTMGL3BXNPQ6W5BTBBZ4TJXZWICQ",
|
||||
"p56ioi7mzjnu2iqgdreydm2mgtmgl3bxnpq6w5btbbz4tjxzwicq",
|
||||
"P56IOI7MZJNU2YIQGDREYDM2MGTIMGL3BXNPQ6W5BMTBBZ4TJXZWICQ2",
|
||||
"P561017MZJNU2YIQGDREYDM2MGTIMGL3BXNPQ6W5BMT88Z4TJXZWICQ2",
|
||||
"p56ioi7mzjnu2yiqgdreydm2mgtimgl3bxnpq6w5bmtbbz4tjxzwicq2",
|
||||
"p561017mzjnu2yiqgdreydm2mgtimgl3bxnpq6w5bmt88z4tjxzwicq2",
|
||||
}
|
||||
var (
|
||||
formatted = "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"
|
||||
formatCases = []string{
|
||||
"P56IOI-7MZJNU-2IQGDR-EYDM2M-GTMGL3-BXNPQ6-W5BTBB-Z4TJXZ-WICQ",
|
||||
"P56IOI-7MZJNU2Y-IQGDR-EYDM2M-GTI-MGL3-BXNPQ6-W5BM-TBB-Z4TJXZ-WICQ2",
|
||||
"P56IOI7 MZJNU2I QGDREYD M2MGTMGL 3BXNPQ6W 5BTB BZ4T JXZWICQ",
|
||||
"P56IOI7 MZJNU2Y IQGDREY DM2MGTI MGL3BXN PQ6W5BM TBBZ4TJ XZWICQ2",
|
||||
"P56IOI7MZJNU2IQGDREYDM2MGTMGL3BXNPQ6W5BTBBZ4TJXZWICQ",
|
||||
"p56ioi7mzjnu2iqgdreydm2mgtmgl3bxnpq6w5btbbz4tjxzwicq",
|
||||
"P56IOI7MZJNU2YIQGDREYDM2MGTIMGL3BXNPQ6W5BMTBBZ4TJXZWICQ2",
|
||||
"P561017MZJNU2YIQGDREYDM2MGTIMGL3BXNPQ6W5BMT88Z4TJXZWICQ2",
|
||||
"p56ioi7mzjnu2yiqgdreydm2mgtimgl3bxnpq6w5bmtbbz4tjxzwicq2",
|
||||
"p561017mzjnu2yiqgdreydm2mgtimgl3bxnpq6w5bmt88z4tjxzwicq2",
|
||||
}
|
||||
)
|
||||
|
||||
func TestFormatDeviceID(t *testing.T) {
|
||||
for i, tc := range formatCases {
|
||||
|
||||
@@ -212,38 +212,44 @@ func (e encryptedConnection) Request(ctx context.Context, req *Request) ([]byte,
|
||||
if !ok {
|
||||
return e.conn.Request(ctx, req)
|
||||
}
|
||||
fileKey := e.keyGen.FileKey(req.Name, folderKey)
|
||||
|
||||
// Encrypt / adjust the request parameters.
|
||||
|
||||
origSize := req.Size
|
||||
origName := req.Name
|
||||
if req.Size < minPaddedSize {
|
||||
encSize := req.Size
|
||||
if encSize < minPaddedSize {
|
||||
// Make a request for minPaddedSize data instead of the smaller
|
||||
// block. We'll chop of the extra data later.
|
||||
req.Size = minPaddedSize
|
||||
encSize = minPaddedSize
|
||||
}
|
||||
encSize += blockOverhead
|
||||
encName := encryptName(req.Name, folderKey)
|
||||
encOffset := req.Offset + int64(req.BlockNo*blockOverhead)
|
||||
encSize := req.Size + blockOverhead
|
||||
encHash := encryptBlockHash(req.Hash, req.Offset, fileKey)
|
||||
|
||||
// Perform that request, getting back an encrypted block.
|
||||
|
||||
req.Name = encName
|
||||
req.Offset = encOffset
|
||||
req.Size = encSize
|
||||
bs, err := e.conn.Request(ctx, req)
|
||||
encReq := &Request{
|
||||
ID: req.ID,
|
||||
Folder: req.Folder,
|
||||
Name: encName,
|
||||
Offset: encOffset,
|
||||
Size: encSize,
|
||||
Hash: encHash,
|
||||
BlockNo: req.BlockNo,
|
||||
}
|
||||
bs, err := e.conn.Request(ctx, encReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the decrypted block (or an error if it fails decryption)
|
||||
|
||||
fileKey := e.keyGen.FileKey(origName, folderKey)
|
||||
bs, err = DecryptBytes(bs, fileKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bs[:origSize], nil
|
||||
return bs[:req.Size], nil
|
||||
}
|
||||
|
||||
func (e encryptedConnection) DownloadProgress(ctx context.Context, dp *DownloadProgress) {
|
||||
@@ -327,15 +333,7 @@ func encryptFileInfo(keyGen *KeyGenerator, fi FileInfo, folderKey *[keySize]byte
|
||||
b.Size = minPaddedSize
|
||||
}
|
||||
size := b.Size + blockOverhead
|
||||
|
||||
// The offset goes into the encrypted block hash as additional data,
|
||||
// essentially mixing in with the nonce. This means a block hash
|
||||
// remains stable for the same data at the same offset, but doesn't
|
||||
// reveal the existence of identical data blocks at other offsets.
|
||||
var additional [8]byte
|
||||
binary.BigEndian.PutUint64(additional[:], uint64(b.Offset))
|
||||
hash := encryptDeterministic(b.Hash, fileKey, additional[:])
|
||||
|
||||
hash := encryptBlockHash(b.Hash, b.Offset, fileKey)
|
||||
blocks[i] = BlockInfo{
|
||||
Hash: hash,
|
||||
Offset: offset,
|
||||
@@ -374,6 +372,16 @@ func encryptFileInfo(keyGen *KeyGenerator, fi FileInfo, folderKey *[keySize]byte
|
||||
return enc
|
||||
}
|
||||
|
||||
func encryptBlockHash(hash []byte, offset int64, fileKey *[keySize]byte) []byte {
|
||||
// The offset goes into the encrypted block hash as additional data,
|
||||
// essentially mixing in with the nonce. This means a block hash
|
||||
// remains stable for the same data at the same offset, but doesn't
|
||||
// reveal the existence of identical data blocks at other offsets.
|
||||
var additional [8]byte
|
||||
binary.BigEndian.PutUint64(additional[:], uint64(offset))
|
||||
return encryptDeterministic(hash, fileKey, additional[:])
|
||||
}
|
||||
|
||||
func decryptFileInfos(keyGen *KeyGenerator, files []FileInfo, folderKey *[keySize]byte) error {
|
||||
for i, fi := range files {
|
||||
decFI, err := DecryptFileInfo(keyGen, fi, folderKey)
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("rc", "Remote control package")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("rc", "Remote control package")
|
||||
|
||||
@@ -6,6 +6,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("relay", "")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("relay", "")
|
||||
|
||||
@@ -29,9 +29,11 @@ type header struct {
|
||||
messageLength int32
|
||||
}
|
||||
|
||||
type Ping struct{}
|
||||
type Pong struct{}
|
||||
type RelayFull struct{}
|
||||
type (
|
||||
Ping struct{}
|
||||
Pong struct{}
|
||||
RelayFull struct{}
|
||||
)
|
||||
|
||||
type JoinRelayRequest struct {
|
||||
Token string
|
||||
|
||||
@@ -60,6 +60,7 @@ func (o *header) UnmarshalXDR(bs []byte) error {
|
||||
u := &xdr.Unmarshaller{Data: bs}
|
||||
return o.UnmarshalXDRFrom(u)
|
||||
}
|
||||
|
||||
func (o *header) UnmarshalXDRFrom(u *xdr.Unmarshaller) error {
|
||||
o.magic = u.UnmarshalUint32()
|
||||
o.messageType = int32(u.UnmarshalUint32())
|
||||
@@ -81,6 +82,7 @@ struct Ping {
|
||||
func (Ping) XDRSize() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (Ping) MarshalXDR() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -115,6 +117,7 @@ struct Pong {
|
||||
func (Pong) XDRSize() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (Pong) MarshalXDR() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -149,6 +152,7 @@ struct RelayFull {
|
||||
func (RelayFull) XDRSize() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (RelayFull) MarshalXDR() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -215,6 +219,7 @@ func (o *JoinRelayRequest) UnmarshalXDR(bs []byte) error {
|
||||
u := &xdr.Unmarshaller{Data: bs}
|
||||
return o.UnmarshalXDRFrom(u)
|
||||
}
|
||||
|
||||
func (o *JoinRelayRequest) UnmarshalXDRFrom(u *xdr.Unmarshaller) error {
|
||||
o.Token = u.UnmarshalString()
|
||||
return u.Error
|
||||
@@ -269,6 +274,7 @@ func (o *JoinSessionRequest) UnmarshalXDR(bs []byte) error {
|
||||
u := &xdr.Unmarshaller{Data: bs}
|
||||
return o.UnmarshalXDRFrom(u)
|
||||
}
|
||||
|
||||
func (o *JoinSessionRequest) UnmarshalXDRFrom(u *xdr.Unmarshaller) error {
|
||||
o.Key = u.UnmarshalBytesMax(32)
|
||||
return u.Error
|
||||
@@ -325,6 +331,7 @@ func (o *Response) UnmarshalXDR(bs []byte) error {
|
||||
u := &xdr.Unmarshaller{Data: bs}
|
||||
return o.UnmarshalXDRFrom(u)
|
||||
}
|
||||
|
||||
func (o *Response) UnmarshalXDRFrom(u *xdr.Unmarshaller) error {
|
||||
o.Code = int32(u.UnmarshalUint32())
|
||||
o.Message = u.UnmarshalString()
|
||||
@@ -380,6 +387,7 @@ func (o *ConnectRequest) UnmarshalXDR(bs []byte) error {
|
||||
u := &xdr.Unmarshaller{Data: bs}
|
||||
return o.UnmarshalXDRFrom(u)
|
||||
}
|
||||
|
||||
func (o *ConnectRequest) UnmarshalXDRFrom(u *xdr.Unmarshaller) error {
|
||||
o.ID = u.UnmarshalBytesMax(32)
|
||||
return u.Error
|
||||
@@ -462,6 +470,7 @@ func (o *SessionInvitation) UnmarshalXDR(bs []byte) error {
|
||||
u := &xdr.Unmarshaller{Data: bs}
|
||||
return o.UnmarshalXDRFrom(u)
|
||||
}
|
||||
|
||||
func (o *SessionInvitation) UnmarshalXDRFrom(u *xdr.Unmarshaller) error {
|
||||
o.From = u.UnmarshalBytesMax(32)
|
||||
o.Key = u.UnmarshalBytesMax(32)
|
||||
|
||||
@@ -27,43 +27,67 @@ var blocksTestData = []struct {
|
||||
hash []string
|
||||
weakhash []uint32
|
||||
}{
|
||||
{[]byte(""), 1024, []string{
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
|
||||
{
|
||||
[]byte(""), 1024,
|
||||
[]string{
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
},
|
||||
[]uint32{0},
|
||||
},
|
||||
{[]byte("contents"), 1024, []string{
|
||||
"d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8"},
|
||||
{
|
||||
[]byte("contents"), 1024,
|
||||
[]string{
|
||||
"d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8",
|
||||
},
|
||||
[]uint32{0x0f3a036f},
|
||||
},
|
||||
{[]byte("contents"), 9, []string{
|
||||
"d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8"},
|
||||
{
|
||||
[]byte("contents"), 9,
|
||||
[]string{
|
||||
"d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8",
|
||||
},
|
||||
[]uint32{0x0f3a036f},
|
||||
},
|
||||
{[]byte("contents"), 8, []string{
|
||||
"d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8"},
|
||||
{
|
||||
[]byte("contents"), 8,
|
||||
[]string{
|
||||
"d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8",
|
||||
},
|
||||
[]uint32{0x0f3a036f},
|
||||
},
|
||||
{[]byte("contents"), 7, []string{
|
||||
"ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73",
|
||||
"043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89"},
|
||||
{
|
||||
[]byte("contents"), 7,
|
||||
[]string{
|
||||
"ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73",
|
||||
"043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89",
|
||||
},
|
||||
[]uint32{0x0bcb02fc, 0x00740074},
|
||||
},
|
||||
{[]byte("contents"), 3, []string{
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3",
|
||||
"44ad63f60af0f6db6fdde6d5186ef78176367df261fa06be3079b6c80c8adba4"},
|
||||
{
|
||||
[]byte("contents"), 3,
|
||||
[]string{
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3",
|
||||
"44ad63f60af0f6db6fdde6d5186ef78176367df261fa06be3079b6c80c8adba4",
|
||||
},
|
||||
[]uint32{0x02780141, 0x02970148, 0x015d00e8},
|
||||
},
|
||||
{[]byte("conconts"), 3, []string{
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"44ad63f60af0f6db6fdde6d5186ef78176367df261fa06be3079b6c80c8adba4"},
|
||||
{
|
||||
[]byte("conconts"), 3,
|
||||
[]string{
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"44ad63f60af0f6db6fdde6d5186ef78176367df261fa06be3079b6c80c8adba4",
|
||||
},
|
||||
[]uint32{0x02780141, 0x02780141, 0x015d00e8},
|
||||
},
|
||||
{[]byte("contenten"), 3, []string{
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3",
|
||||
"e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3"},
|
||||
{
|
||||
[]byte("contenten"), 3,
|
||||
[]string{
|
||||
"1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
|
||||
"e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3",
|
||||
"e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3",
|
||||
},
|
||||
[]uint32{0x02780141, 0x02970148, 0x02970148},
|
||||
},
|
||||
}
|
||||
@@ -72,7 +96,6 @@ func TestBlocks(t *testing.T) {
|
||||
for testNo, test := range blocksTestData {
|
||||
buf := bytes.NewBuffer(test.data)
|
||||
blocks, err := Blocks(context.TODO(), buf, test.blocksize, -1, nil, true)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("scanner", "File change detection and hashing")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("scanner", "File change detection and hashing")
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("stats", "Persistent device and folder statistics")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("stats", "Persistent device and folder statistics")
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("stun", "STUN functionality")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("stun", "STUN functionality")
|
||||
|
||||
@@ -10,9 +10,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("app", "Main run facility")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("app", "Main run facility")
|
||||
|
||||
func shouldDebug() bool {
|
||||
return l.ShouldDebug("app")
|
||||
|
||||
@@ -33,7 +33,7 @@ func EnsureDir(dir string, mode fs.FileMode) error {
|
||||
// Apparently the stat may fail even though the mkdirall passed. If it
|
||||
// does, we'll just assume things are in order and let other things
|
||||
// fail (like loading or creating the config...).
|
||||
currentMode := fi.Mode() & 0777
|
||||
currentMode := fi.Mode() & 0o777
|
||||
if currentMode != mode {
|
||||
err := fs.Chmod(".", mode)
|
||||
// This can fail on crappy filesystems, nothing we can do about it.
|
||||
@@ -63,6 +63,8 @@ func DefaultConfig(path string, myID protocol.DeviceID, evLogger events.Logger,
|
||||
|
||||
if skipPortProbing {
|
||||
l.Infoln("Using default network port numbers instead of probing for free ports")
|
||||
// Record address override initially
|
||||
newCfg.GUI.RawAddress = newCfg.GUI.Address()
|
||||
} else if err := newCfg.ProbeFreePorts(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -139,7 +141,7 @@ func copyFile(src, dst string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(dst, bs, 0600); err != nil {
|
||||
if err := os.WriteFile(dst, bs, 0o600); err != nil {
|
||||
// Attempt to clean up
|
||||
os.Remove(dst)
|
||||
return err
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("upgrade", "Binary upgrades")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("upgrade", "Binary upgrades")
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("upnp", "UPnP discovery and port mapping")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("upnp", "UPnP discovery and port mapping")
|
||||
|
||||
@@ -206,7 +206,7 @@ func (s *IGDService) AddPortMapping(ctx context.Context, protocol nat.Protocol,
|
||||
}
|
||||
|
||||
err = fmt.Errorf("UPnP Error: %s (%d)", envelope.ErrorDescription, envelope.ErrorCode)
|
||||
l.Infof("Couldn't add port mapping for %s (external port %d -> internal port %d/%s): %s", s.LocalIPv4, externalPort, internalPort, protocol, err)
|
||||
l.Debugf("Couldn't add port mapping for %s (external port %d -> internal port %d/%s): %s", s.LocalIPv4, externalPort, internalPort, protocol, err)
|
||||
}
|
||||
|
||||
return externalPort, err
|
||||
|
||||
@@ -210,7 +210,6 @@ USER-AGENT: syncthing/%s
|
||||
proto = "udp6"
|
||||
}
|
||||
socket, err := net.ListenMulticastUDP(proto, intf, &net.UDPAddr{IP: ssdp.IP})
|
||||
|
||||
if err != nil {
|
||||
if runtime.GOOS == "windows" && ip6 {
|
||||
// Requires https://github.com/golang/go/issues/63529 to be fixed.
|
||||
@@ -257,7 +256,7 @@ loop:
|
||||
if e, ok := err.(net.Error); ok && e.Timeout() {
|
||||
continue // continue reading
|
||||
}
|
||||
l.Infoln("UPnP read:", err) //legitimate error, not a timeout.
|
||||
l.Infoln("UPnP read:", err) // legitimate error, not a timeout.
|
||||
break
|
||||
}
|
||||
|
||||
@@ -411,7 +410,6 @@ func localIPv4Fallback(ctx context.Context, url *url.URL) (net.IP, error) {
|
||||
defer cancel()
|
||||
|
||||
conn, err := dialer.DialContext(timeoutCtx, "udp4", url.Host)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func TestExternalIPParsing(t *testing.T) {
|
||||
soapResponse :=
|
||||
[]byte(`<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
soapResponse := []byte(`<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<s:Body>
|
||||
<u:GetExternalIPAddressResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
|
||||
<NewExternalIPAddress>1.2.3.4</NewExternalIPAddress>
|
||||
@@ -34,8 +33,7 @@ func TestExternalIPParsing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSoapFaultParsing(t *testing.T) {
|
||||
soapResponse :=
|
||||
[]byte(`<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
soapResponse := []byte(`<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<s:Body>
|
||||
<s:Fault>
|
||||
<faultcode>s:Client</faultcode>
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("ur", "Usage reporting")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("ur", "Usage reporting")
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("versioner", "File versioning")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("versioner", "File versioning")
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
// └── remove21
|
||||
// └── remove22
|
||||
func TestEmptyDirs(t *testing.T) {
|
||||
var paths = []struct {
|
||||
paths := []struct {
|
||||
path string
|
||||
isFile bool
|
||||
}{
|
||||
@@ -44,7 +44,7 @@ func TestEmptyDirs(t *testing.T) {
|
||||
{"remove2/remove21/remove22", false},
|
||||
}
|
||||
|
||||
var expected = []string{
|
||||
expected := []string{
|
||||
"remove2/remove21/remove22",
|
||||
"remove2/remove21",
|
||||
"remove2",
|
||||
|
||||
@@ -81,10 +81,10 @@ func prepForRemoval(t *testing.T, file string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(file, []byte("hello\n"), 0644); err != nil {
|
||||
if err := os.WriteFile(file, []byte("hello\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type simple struct {
|
||||
}
|
||||
|
||||
func newSimple(cfg config.FolderConfiguration) Versioner {
|
||||
var keep, err = strconv.Atoi(cfg.Versioning.Params["keep"])
|
||||
keep, err := strconv.Atoi(cfg.Versioning.Params["keep"])
|
||||
cleanoutDays, _ := strconv.Atoi(cfg.Versioning.Params["cleanoutDays"])
|
||||
// On error we default to 0, "do not clean out the versioned items"
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ func TestCreateVersionPath(t *testing.T) {
|
||||
|
||||
// Create a test dir and file
|
||||
tmpDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(tmpDir, archiveFile), []byte("sup"), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(tmpDir, archiveFile), []byte("sup"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ func readFile(t *testing.T, filesystem fs.Filesystem, name string) string {
|
||||
}
|
||||
|
||||
func writeFile(t *testing.T, filesystem fs.Filesystem, name, content string) {
|
||||
fd, err := filesystem.OpenFile(name, fs.OptReadWrite|fs.OptCreate, 0777)
|
||||
fd, err := filesystem.OpenFile(name, fs.OptReadWrite|fs.OptCreate, 0o777)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -213,7 +213,7 @@ func TestTrashcanCleanOut(t *testing.T) {
|
||||
|
||||
v := newTrashcan(cfg)
|
||||
|
||||
var testcases = map[string]bool{
|
||||
testcases := map[string]bool{
|
||||
".stversions/file1": false,
|
||||
".stversions/file2": true,
|
||||
".stversions/keep1/file1": false,
|
||||
@@ -229,7 +229,7 @@ func TestTrashcanCleanOut(t *testing.T) {
|
||||
t.Run("trashcan versioner trashcan clean up", func(t *testing.T) {
|
||||
oldTime := time.Now().Add(-8 * 24 * time.Hour)
|
||||
for file, shouldRemove := range testcases {
|
||||
fs.MkdirAll(filepath.Dir(file), 0777)
|
||||
fs.MkdirAll(filepath.Dir(file), 0o777)
|
||||
|
||||
writeFile(t, fs, file, "some content")
|
||||
|
||||
|
||||
@@ -10,6 +10,4 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
l = logger.DefaultLogger.NewFacility("watchaggregator", "Filesystem event watcher")
|
||||
)
|
||||
var l = logger.DefaultLogger.NewFacility("watchaggregator", "Filesystem event watcher")
|
||||
|
||||
@@ -23,8 +23,10 @@ import (
|
||||
"github.com/chmduquesne/rollinghash/buzhash64"
|
||||
)
|
||||
|
||||
const testFile = "../model/testdata/tmpfile"
|
||||
const size = 128 << 10
|
||||
const (
|
||||
testFile = "../model/testdata/tmpfile"
|
||||
size = 128 << 10
|
||||
)
|
||||
|
||||
func BenchmarkFind1MFile(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
@@ -96,7 +98,6 @@ func BenchmarkBlock(b *testing.B) {
|
||||
bbb.SetBytes(testSize)
|
||||
bbb.ReportAllocs()
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -144,7 +145,6 @@ func BenchmarkRoll(b *testing.B) {
|
||||
bbb.SetBytes(testSize)
|
||||
bbb.ReportAllocs()
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "STDISCOSRV" "1" "Sep 13, 2024" "v1.27.11" "Syncthing"
|
||||
.TH "STDISCOSRV" "1" "Oct 23, 2024" "v1.28.0" "Syncthing"
|
||||
.SH NAME
|
||||
stdiscosrv \- Syncthing Discovery Server
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "STRELAYSRV" "1" "Sep 13, 2024" "v1.27.11" "Syncthing"
|
||||
.TH "STRELAYSRV" "1" "Oct 23, 2024" "v1.28.0" "Syncthing"
|
||||
.SH NAME
|
||||
strelaysrv \- Syncthing Relay Server
|
||||
.SH SYNOPSIS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user