Compare commits

...

316 Commits

Author SHA1 Message Date
Jakob Borg
325c3c1fa7 lib/db, lib/protocol: Compact FileInfo and BlockInfo alignment (#6215)
* lib/db, lib/protocol: Compact FileInfo and BlockInfo alignment

This fixes the following two lint warnings

    FileInfo: struct of size 160 bytes could be of size 136 bytes
    BlockInfo: struct of size 48 bytes could be of size 40 bytes

by reordering fields in alignment order (64 bit fields, then 32 bit
fields, then 16 bit fields (if any), then small ones). The end result is
a slightly less aesthetically pleasing struct field order, but since
these are the objects we often juggle in bulk and keep large queues of I
think it's worth it.

It's a micro optimization, but a cheap one.
2019-12-08 13:31:26 +01:00
Jakob Borg
be0508cf26 lib/model, lib/protocol: Use error handling to avoid panic on non-started folder (fixes #6174) (#6212)
This adds error returns to model methods called by the protocol layer.
Returning an error will cause the connection to be torn down as the
message couldn't be handled. Using this to signal that a folder isn't
currently available will then cause a reconnection a few moments later,
when it'll hopefully work better.

Tested manually by running with STRECHECKDBEVERY=0 on a nontrivially
sized setup. This panics reliably before this patch, but just causes a
disconnect/reconnect now.
2019-12-04 10:46:55 +01:00
Simon Frei
6fd5e78740 lib: Consistently unsubscribe from config-wrapper (fixes #6133) (#6205) 2019-12-04 07:15:00 +01:00
Jakob Borg
a9e490adfa cmd/ursrv: Show more architectures (fixes #6211) 2019-12-03 21:34:32 +01:00
Jakob Borg
d8e7e92512 build: Generalize code signing
Should, at the least, also codesign when building zip for mac.
2019-12-03 08:37:43 +01:00
Paul Brit
eca156fd7f lib/osutil: Increase maxfiles on macOS properly (fixes #6206) (#6207) 2019-12-03 07:26:22 +01:00
Marcus Legendre
b3fd9a8d53 lib/ignore: Don't create empty ".stignore" files (fixes #6190) (#6197)
This will:

1. prevent creation of a new .stignore if there are no ignore patterns
2. delete an existing .stignore if all ignore patterns are removed
2019-12-02 08:19:02 +01:00
Simon Frei
0bec01b827 lib/db: Remove *instance by making everything *Lowlevel (#6204) 2019-12-02 08:18:04 +01:00
Jakob Borg
e82a7e3dfa all: Propagate errors from NamespacedKV (#6203)
As foretold by the prophecy, "once the database refactor is merged, then
shall appear a request to propagate errors from the store known
throughout the land as the NamedspacedKV, and it shall be good".
2019-11-30 13:03:24 +01:00
Jakob Borg
928767e316 lib/model: gofmt lol :( 2019-11-29 09:29:59 +01:00
Evgeny Kuznetsov
1c277fc096 lib/fs: Add case-insensitive fakefs (#6074) 2019-11-29 09:17:42 +01:00
Jakob Borg
c71116ee94 Implement database abstraction, error checking (ref #5907) (#6107)
This PR does two things, because one lead to the other:

- Move the leveldb specific stuff into a small "backend" package that
defines a backend interface and the leveldb implementation. This allows,
potentially, in the future, switching the db implementation so another
KV store should we wish to do so.

- Add proper error handling all along the way. The db and backend
packages are now errcheck clean. However, I drew the line at modifying
the FileSet API in order to keep this manageable and not continue
refactoring all of the rest of Syncthing. As such, the FileSet methods
still panic on database errors, except for the "database is closed"
error which is instead handled by silently returning as quickly as
possible, with the assumption that we're anyway "on the way out".
2019-11-29 09:11:52 +01:00
Robin Schoonover
a5bbc12625 gui: Sort versions by date in restore dropdown (#6201) 2019-11-29 08:32:25 +01:00
Simon Frei
606154b183 lib/model: Also send folder summary from sync-preparing (ref #6028) (#6202) 2019-11-29 08:30:17 +01:00
Jakob Borg
f9c380d45b cmd/syncthing: Implement log rotation (fixes #6104) (#6198)
Since we've taken upon ourselves to create a log file by default on
Windows, this adds proper management of that log file. There are two new
options:

  -log-max-old-files="3"    Number of old files to keep (zero to keep only current).
  -log-max-size="10485760"  Maximum size of any file (zero to disable log rotation).

The default values result in four files (syncthing.log, synchting.0.log,
..., syncthing.3.log) each up to 10 MiB in size. To not use log rotation
at all, the user can say --log-max-size=0.
2019-11-28 12:26:14 +01:00
Aman Gupta
a04f54a16a lib/upnp: Use simple continue in loop (#6192) 2019-11-26 22:55:34 +00:00
Aman Gupta
509d123251 lib/upnp: Ensure uPnP http requests have trailing \r\n (#6193) 2019-11-26 22:54:46 +00:00
Simon Frei
b32821a586 lib/config, lib/connections: Remove ListenAddresses hack (#6188) 2019-11-26 17:07:25 +01:00
Otiel
8ced8ad562 github: bump Syncthing version to v1... (#6191) 2019-11-26 08:25:50 +00:00
Simon Frei
1bae4b7f50 all: Use context in lib/dialer (#6177)
* all: Use context in lib/dialer

* a bit slimmer

* https://github.com/syncthing/syncthing/pull/5753

* bot

* missed adding debug.go

* errors.Cause

* simultaneous dialing

* anti-leak
2019-11-26 07:39:51 +00:00
Jakob Borg
4e151d380c lib/versioner: Reduce surface area (#6186)
* lib/versioner: Reduce surface area

This is a refactor while I was anyway rooting around in the versioner.
Instead of exporting every possible implementation and the factory and
letting the caller do whatever, this now encapsulates all that and
exposes a New() that takes a config.VersioningConfiguration.

Given that and that we don't know (from the outside) how a versioner
works or what state it keeps, we now just construct it once per folder
and keep it around. Previously it was recreated for each restore
request.

* unparam

* wip
2019-11-26 07:39:31 +00:00
Simon Frei
f747ba6d69 lib/ignore: Keep skipping ignored dirs for rooted patterns (#6151)
* lib/ignore: Keep skipping ignored dirs for rooted patterns

* review

* clarify comment and lint

* glob.QuoteMeta

* review
2019-11-26 07:37:41 +00:00
Simon Frei
33258b06f4 lib/connections: Dialer code deduplication (#6187) 2019-11-26 07:36:58 +00:00
Jakob Borg
4340589501 Merge branch 'release'
Discarding the commit on that branch...
2019-11-25 11:10:09 +01:00
Simon Frei
4d368a37e2 lib/model, lib/protocol: Add contexts sending indexes and download-progress (#6176) 2019-11-25 11:07:36 +01:00
dependabot-preview[bot]
999647b7d6 build(deps): bump github.com/urfave/cli from 1.22.1 to 1.22.2 (#6183)
Bumps [github.com/urfave/cli](https://github.com/urfave/cli) from 1.22.1 to 1.22.2.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v1.22.1...v1.22.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-25 11:05:55 +01:00
Jakob Borg
45a711570e Revert "lib/model: Add folders on start in model (#6135)"
This reverts commit bee7cce081.
2019-11-24 09:33:58 +01:00
Simon Frei
cf312abc72 lib: Wrap errors with errors.Wrap instead of fmt.Errorf (#6181) 2019-11-23 15:20:54 +00:00
Mateusz Ż
e2f6d0d6c4 UI enhancements on mobile (#6180)
* Set fallback font for log viewer

* Enable logo scaling in About view

* Don't split "dependency list" into 2 columns on mobile
2019-11-23 12:25:25 +00:00
Simon Frei
65d4dd32cb lib/model: Also handle ServeBackground (#6173) 2019-11-22 21:30:16 +01:00
Simon Frei
de886b3f22 lib/relay: Prevent lock nil deref when creation dynamic client (#6175) 2019-11-21 17:45:06 +00:00
Jakob Borg
8c91e012c7 Merge branch 'release'
* release:
  gui: Prioritize non-idle folder states (fixes #6169) (#6170)
2019-11-21 09:36:03 +01:00
Simon Frei
6d27cf6563 gui: Prioritize non-idle folder states (fixes #6169) (#6170) 2019-11-21 09:33:39 +01:00
Simon Frei
57d668ed1d lib/config: Do introductions in a single config change (#6162) 2019-11-21 08:41:41 +01:00
Simon Frei
90d85fd0a2 lib: Replace done channel with contexts in and add names to util services (#6166) 2019-11-21 08:41:15 +01:00
Simon Frei
552ea68672 gui: Prioritize non-idle folder states (fixes #6169) (#6170) 2019-11-20 19:06:03 +01:00
Artur Zubilewicz
80eac473d9 gui: Make 'Nearby devices' look like links (fixes #6057) (#6165)
- The 'help-box' with nearby devices will appear only when there are
  any nearby devices
- IDs of nearby devices will look like links (i.e. underlined when
  hovered over)
2019-11-19 22:15:27 +01:00
Ruslan Yevdokymov
c1db8b2680 gui: Add upgrade confirmation dialog (fixes #5887) (#6167) 2019-11-19 22:05:41 +01:00
Jakob Borg
df866e10c8 gui: Increase padding a bit again (ref #6153)
I change my mind on this, the modals need *some* padding to not look weird.
2019-11-19 22:03:31 +01:00
Simon Frei
0d14ee4142 lib/model: Don't info log repeat pull errors (#6149) 2019-11-19 09:56:53 +01:00
Simon Frei
28edf2f5bb lib/model: Keep fmut locked while adding/starting/restarting folders (#6156) 2019-11-18 21:15:26 +01:00
Jakob Borg
e7100bc573 golang-ci: Skip "cognitive complexity" check for now 2019-11-17 08:54:59 +01:00
Simon Frei
5edf4660e2 lib/model: Prevent cleanup-race in testing (ref #6152) (#6155) 2019-11-14 23:08:40 +01:00
Domenic Horner
a5699d40a8 gui: Decrease padding on the panel and modal bodies (#6153)
This allows better viewing when on a condensed screen, and reduces screen real estate slightly.
2019-11-13 15:14:00 +01:00
Simon Frei
f80ce17497 lib/model: In tests prevent goroutine leaks and increase timeouts (#6152) 2019-11-13 10:21:54 +01:00
Simon Frei
ce72bee576 lib/model: Simplify pull error/retry logic (fixes #6139) (#6141) 2019-11-11 15:50:28 +01:00
Jacob
0cc77feabb docker: Add stdiscosrv and strelaysrv Dockerfiles (#6143) 2019-11-11 09:37:08 +01:00
Jakob Borg
d19b12d3fe lib/protocol: Buffer allocation when compressing (fixes #6146) (#6147)
We incorrectly gave a too small buffer to lz4.Compress, causing it to
allocate in some cases (when the data actually becomes larger when
compressed). This then panicked when passed to the buffer pool.

This ensures a buffer that is large enough, and adds tripwires closer to
the source in case this ever pops up again. There is a test that
exercises the issue.
2019-11-11 08:36:31 +00:00
Jakob Borg
1d406d62e3 golang-ci: Upgrade, skipping the white space complainer 2019-11-10 10:25:14 +01:00
Jakob Borg
1d99e5277a all: Cleanups enabled by Go 1.12 2019-11-10 10:16:10 +01:00
Jakob Borg
879f51b027 lib/tlsutil: Remove Go 1.12 TLS 1.3 beta opt-in
Go 1.13 enables this by default.
2019-11-10 09:32:48 +01:00
Audrius Butkevicius
d3d7408b17 lib/api: Make theme paths relative (#6142)
* Update theme.css

* Update syncthingController.js
2019-11-09 12:07:46 +00:00
Pablo
9b01e64c66 gui, lib/api: Adds support for prefers-color-scheme (fixes #6115)
* gui, lib/api: Adds support for prefers-color-scheme on default theme (fixes #6115)

- Renames current default theme into a new "light" theme
- Modifies assets serving to allow getting assets from different themes

* lib/api: Serve assets from arbitrary theme when path starts with "theme-assets"

* lib/api: Moves constant out of function

* Loads light theme in browsers without support for prefers-color-scheme

* gui: Disables dark theme when printing

* Prevents repeated injection and adds support for older browsers

The CSS is always loaded if there is no support for `matchMedia`.
2019-11-08 21:44:37 +00:00
Audrius Butkevicius
65c172cd8d lib/api: Reset mtime after theme change (fixes #5810) (#6140) 2019-11-08 22:37:42 +01:00
Simon Frei
85e6a77f25 lib/model: Remove some testing deadlocks (#6138) 2019-11-08 18:53:51 +01:00
Jakob Borg
88244b0c1f lib/model: Add test for previous commit 2019-11-08 17:03:25 +01:00
Simon Frei
cd290d2d05 lib/model: Add initial deviceStatRefs on model creation (fixes #6136) (#6137)
This is a regression introduced in PR #6005 / commit
f7b2e79fdc
2019-11-08 11:32:51 +00:00
Simon Frei
bee7cce081 lib/model: Add folders on start in model (#6135) 2019-11-08 10:56:16 +01:00
Jakob Borg
f15a1528fc cmd/stbench: rm -r cmd/stbench (#6131)
This is apparently an old benchmarking tool. I'd forgotten about it.
Since 67b8ef1f3e the build script tries to
build all binaries explicitly by default, and this fails on Windows as
this tool doesn't build on Windows.

Kill it with fire.
2019-11-07 07:20:21 +00:00
Jakob Borg
6be6de4b4a lib/api: Slightly unflake TestCSRFRequired by allowing longer timeout 2019-11-07 08:14:49 +01:00
Jakob Borg
6755a9ca63 Fix bufferpool puts (ref #4976) (#6125)
* Fix bufferpool puts (ref #4976)

There was a logic error in Put() which made us put all large blocks into
segment zero, where we subsequently did not look for them.

I also added a lowest threshold, as we otherwise allocate a 128KiB
buffer when we need 24 bytes for a header and such.

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* smaller stress

* cap/len

* wip

* wip
2019-11-06 10:53:10 +00:00
Audrius Butkevicius
98a1adebe1 all: Remove dead code, fix lost msgLen checks (#6129) 2019-11-06 07:09:58 +01:00
Aman Gupta
31569debeb lib/upnp: Fix outdated comment (#6110) 2019-11-05 18:56:51 +00:00
Simon Frei
cf420e135e gui: New folder state "Local Additions" for receive-only (fixes #5968) (#6117) 2019-11-01 20:44:23 +01:00
Ruslan Yevdokymov
3b5dff3f34 lib/model: Fix removal of a marker when there are still folders referencing it (#6114) 2019-10-30 15:11:07 +00:00
Jakob Borg
56cdf2f2d9 build: I like long, complicated things, ok? 2019-10-25 10:04:26 +02:00
dependabot-preview[bot]
b1dbe925d4 build(deps): bump github.com/prometheus/client_golang (#6099)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.1.0 to 1.2.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.1.0...v1.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-22 21:56:32 +02:00
Simon Frei
bbdda059bd lib/model: Check for symlinks before deleting during pull (fixes #6090) (#6100) 2019-10-22 21:55:51 +02:00
Simon Frei
72f26c1e45 gui: Fix loop selecting all devices (fixes #5980) (#6102) 2019-10-22 13:57:10 +01:00
Simon Frei
72194d137c lib/scanner: Don't scan if input path is below symlink (fixes #6090) (#6101) 2019-10-22 11:12:21 +02:00
André Colomb
8b5bd45a29 gui: Split device list in folder sharing options by shared / unshared (#5756) 2019-10-21 21:28:10 +02:00
Jakob Borg
9084510e1b cmd/stdiscosrv: Sort addresses before replication (fixes #6093) (#6094)
This makes sure addresses are sorted when coming in from the API. The
database merge operation still checks for correct ordering (which is
quick) and sorts if it isn't correct (legacy database record or
replication peer), but then does a copy first.

Tested with -race in production...
2019-10-18 10:50:19 +02:00
Audrius Butkevicius
c4f161d8c5 lib/connections: Rate limit quic accept loop (fixes #6081) (#6082) 2019-10-18 09:55:37 +02:00
Jakob Borg
ad2d3702ae all: Upgrade github.com/gogo/protobuf and regenerate (fixes #6085) 2019-10-18 09:53:59 +02:00
Jakob Borg
95acb26249 lib/syncthing: Fixup test after merge 2019-10-17 09:14:27 +02:00
Jakob Borg
4736cccda1 all: Update certificate lifetimes (fixes #6036) (#6078)
This adds a certificate lifetime parameter to our certificate generation
and hard codes it to twenty years in some uninteresting places. In the
main binary there are a couple of constants but it results in twenty
years for the device certificate and 820 days for the HTTPS one. 820 is
less than the 825 maximum Apple allows nowadays.

This also means we must be prepared for certificates to expire, so I add
some handling for that and generate a new certificate when needed. For
self signed certificates we regenerate a month ahead of time. For other
certificates we leave well enough alone.
2019-10-16 20:31:46 +02:00
Simon Frei
1a06ab68eb lib/sync: Cleanly fail instead of panic in tests (#6088) 2019-10-16 10:11:11 +02:00
Simon Frei
b8907b49f9 lib/syncthing: Prevent hangup on error during startup (fixes #6043) (#6047) 2019-10-16 10:10:42 +02:00
Simon Frei
7b33294955 gui, lib/model: Add new state FolderPreparingSync (fixes #6027) (#6028) 2019-10-16 09:08:54 +02:00
Simon Frei
031684116b lib/util: Add caller info to service (ref #5932) (#5973) 2019-10-16 09:06:16 +02:00
Simon Frei
a0c9db1d09 lib/api: Unify JSON marshalling of file infos (#6087) 2019-10-15 11:25:12 +02:00
dependabot-preview[bot]
aa4b918224 build(deps): bump github.com/lucas-clemente/quic-go (#6084)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.12.0 to 0.12.1.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.12.0...v0.12.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-14 18:30:00 +01:00
dependabot-preview[bot]
7043b1fbba build(deps): bump github.com/mattn/go-isatty from 0.0.9 to 0.0.10 (#6083)
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.9 to 0.0.10.
- [Release notes](https://github.com/mattn/go-isatty/releases)
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.9...v0.0.10)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-14 18:17:01 +01:00
chenrui
9d6b663d1c build: Update golangci for go v1.13 (#6042) 2019-10-13 16:32:20 +02:00
Arkadiusz Tymiński
7dc4ac6e1f gui: Hide select/deselect all buttons if there are no devices (fixes #6056) 2019-10-08 21:57:17 +01:00
Alan Pope
7bad9b3a11 snapcraft: Add desktop plug (#6069)
Without the desktop plug, launching the syncthing snap will not launch a browser window to the admin UI. Adding this one line will fix that. Tested here on my Ubuntu system with a build from tip of master.
2019-10-08 18:20:51 +01:00
Jakob Borg
6b570ee8dc lib/upgrade: Add html_url release field 2019-10-08 09:12:00 +02:00
Cyprien Devillez
6408a116f9 cmd/stdiscosrv: Add support for Traefik 2 as a reverse proxy (#6065) 2019-10-07 12:55:27 +01:00
Jakob Borg
67b8ef1f3e cmd/*, lib/build: Set correct LongVersion (fixes #5993) (#5997)
The relay and discosrv didn't use the new lib/build package, now they
do. Conversely the lib/build package wasn't aware there might be other
users and hard coded the program name - now it's set by the build
script
2019-10-07 13:30:25 +02:00
Evgeny Kuznetsov
999d4a0e23 gui: Better info for stalled and lengthy scans (fixes #5627) (#6061) 2019-10-05 11:34:42 +02:00
Lukas Lihotzki
96bb1c8e29 all, lib/logger: Refactor SetDebug calls (#6054) 2019-10-04 13:03:34 +02:00
Audrius Butkevicius
8fb576ed54 lib/model: Adjust blocks reported in usage reporting (fixes #5995) (#6037)
* lib/model: Adjust blocks reported in usage reporting (fixes #5995)

* Use variables, fix go.mod
2019-10-04 12:03:13 +01:00
Jakob Borg
5e31e6356f lib/api: Report actual listener address (fixes #6049) (#6060) 2019-10-04 11:25:41 +01:00
Jakob Borg
1b5a61e03e build: Upgrade github.com/syndtr/goleveldb
Newer is always better. Always.
2019-10-03 17:45:45 +02:00
Jakob Borg
755e689627 lib/db: Always use small db settings on 32 bit archs (#6053) 2019-10-03 13:40:14 +01:00
boomsquared
3f5c9b578c gui: Fix tab headers in black and dark themes (fixes #5583) 2019-10-01 20:09:52 +01:00
Simon Frei
a2a14c8424 lib/model: Set empty version when unignoring deleted files (fixes 6038) (#6039) 2019-10-01 15:34:59 +02:00
Lukas Lihotzki
cff7a091f5 gui: Don't show auth warning when listening on UNIX socket (fixes #6040) (#6041) 2019-10-01 13:22:33 +02:00
Jakob Borg
757d9a5333 Merge branch 'release'
* release:
  readme: Fix broken link to README-Docker.md (#6025)
  docker: Make it easy to disable the GUI, document it (#6021)
2019-10-01 07:46:59 +02:00
Ilya Brin
2c88e473cb readme: Fix broken link to README-Docker.md (#6025) 2019-10-01 07:34:58 +02:00
Jakob Borg
875377981d docker: Make it easy to disable the GUI, document it (#6021) 2019-10-01 07:31:48 +02:00
Jakob Borg
52d80d8144 lib/fs: Improve root check (#6033)
The root check would allow things like c:\foobar\baz if the root was
c:\foo, because string wise that's a prefix. Now it doesn't.
2019-09-29 23:38:11 +08:00
Ilya Brin
fd2e91c82d readme: Fix broken link to README-Docker.md (#6025) 2019-09-23 13:28:42 +09:00
Jakob Borg
c744a75cdd docker: Make it easy to disable the GUI, document it (#6021) 2019-09-22 11:33:29 +01:00
Simon Frei
35b699dc77 lib/fs: Check events against both the user and eval root (#6013) 2019-09-22 08:03:22 +01:00
Jakob Borg
7127c13f18 build: Tweak golang-ci config to build (#6022) 2019-09-22 07:57:58 +01:00
Jakob Borg
dab29287da Merge branch 'release'
* release:
  gui, lib/api: Use effective listen address for no auth warning
  docker: Build using Go 1.13
2019-09-21 12:10:04 +02:00
Jakob Borg
c0b5a70ce3 gui, lib/api: Use effective listen address for no auth warning
This adds a field `guiAddressUsed` to the system status response, that
holds the current listening address actually in use. This may be
different from the one stored in the config because it may have been
overridden by environment or command line flag.

The GUI now checks this field to see if we are listening on localhost.
If we are not, the authentication required warning is displayed,
regardless of the *configured* listening address.
2019-09-21 12:07:10 +02:00
Jakob Borg
7bcdc5b08e docker: Build using Go 1.13 2019-09-21 12:07:07 +02:00
Jakob Borg
db0ba2555a gui, lib/api: Use effective listen address for no auth warning
This adds a field `guiAddressUsed` to the system status response, that
holds the current listening address actually in use. This may be
different from the one stored in the config because it may have been
overridden by environment or command line flag.

The GUI now checks this field to see if we are listening on localhost.
If we are not, the authentication required warning is displayed,
regardless of the *configured* listening address.
2019-09-20 16:23:33 +02:00
Jakob Borg
1398fbb681 docker: Build using Go 1.13 2019-09-20 11:02:43 +02:00
dependabot-preview[bot]
f653f540f8 build(deps): bump github.com/urfave/cli from 1.21.0 to 1.22.1 (#6015)
Bumps [github.com/urfave/cli](https://github.com/urfave/cli) from 1.21.0 to 1.22.1.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v1.21.0...v1.22.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-16 08:31:00 +01:00
dependabot-preview[bot]
078923bd1a build(deps): bump github.com/minio/sha256-simd from 0.1.0 to 0.1.1 (#6014)
Bumps [github.com/minio/sha256-simd](https://github.com/minio/sha256-simd) from 0.1.0 to 0.1.1.
- [Release notes](https://github.com/minio/sha256-simd/releases)
- [Commits](https://github.com/minio/sha256-simd/compare/v0.1.0...v0.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-16 08:28:46 +01:00
ghjklw
80a83b605c lib/config: Remove stun.voxgratia.org (fixes #6010) (#6011)
DNS resolution fails for this server:
named[9495]: REFUSED unexpected RCODE resolving 'stun.voxgratia.org/A/IN': 2600:9000:5303:ae00::1#53
named[9495]: REFUSED unexpected RCODE resolving 'stun.voxgratia.org/A/IN': 205.251.198.31#53
2019-09-13 09:05:25 +01:00
Simon Frei
28b6e8b063 lib/db: Update db when only local flags change (fixes #6008) (#6007) 2019-09-12 08:47:39 +02:00
Simon Frei
f7b2e79fdc lib/model: Use read-locks wherever possible (#6005) 2019-09-12 05:55:23 +01:00
Jakob Borg
c0b3de2680 build: Correct hash for quic package 2019-09-11 15:31:43 +02:00
jelle van der Waa
9a9bcff3e9 build: Add EXTRA_LDFLAGS environment variable handling (fixes #5999) (#6000)
Allow extending LDFLAGS by setting EXTRA_LDFLAGS to be able to pass
-extldflags=-zrelro -ldflags=-extldflags=-znow for Arch Linux packaging
to get full relro.
2019-09-07 19:21:09 +01:00
Jakob Borg
88482b29ee build: Upgrade dependencies
go get -u ./...
go mod tidy
2019-09-05 15:13:51 +02:00
Jakob Borg
22dff7207c lib/api: Refactor to run tests in parallel (#5998)
This is an experiment in testing, based on the advise to always call
t.Parallel() at the start of every test. Doing so makes tests run in
parallel, which is usually faster, but also exposes package level state
and potential race conditions better.

To support this I had to redesign the CSRF manager to not be package
global, which was indeed an improvement. And tests run five times faster
now.
2019-09-05 12:35:51 +01:00
Jakob Borg
0104e78589 lib/connections: Improve write rate limiting (fixes #5138) (#5996)
This splits large writes into smaller ones when using a rate limit,
making them into a legitimate trickle rather than large bursts with a
long time in between.
2019-09-04 11:12:17 +01:00
Jakob Borg
80894948f6 build: Upgrade github.com/gogo/protobuf (#5994)
This is the result of:

- Changing build.go to take the protobuf version from the modules
  instead of hardcoded
- `go get github.com/gogo/protobuf@v1.3.0` to upgrade
- `go run build.go proto` to regenerate our code
2019-09-04 07:33:29 +01:00
Jakob Borg
e945e65b13 lib/api: Skip an IPv6 specific test inside Docker (fixes #5991) (#5992)
Isn't this just the most beautiful thing you've ever seen?
2019-09-03 21:14:36 +01:00
Jakob Borg
ebd2e5bf30 lib/model: Correctly handle manual rescan with ignore error (fixes #5985) (#5987)
Assume a folder error was set due to bad ignores on the latest scan.
Previously, doing a manual rescan would result in:

1. Clearing the folder error, which schedules (immediately) an fs
   watcher restart

2. Attempting to load the ignores, which fails, so we set a folder
   error and bail.

3. Now the fs watcher restarts, as scheduled, so we trigger a scan.
   Goto 1.

This change fixes this by not clearing the error until the error is
actually cleared, that is, if both the health check and ignore loading
succeeds.
2019-08-30 13:27:26 +01:00
Jakob Borg
60c07b259e lib/ignore: Don't crash in partial #include line (ref #5985) (#5986)
If the line is just "#include" with nothing following it we would crash
with an index out of bounds error. Now it's a little more careful.
2019-08-30 11:36:31 +02:00
Jakob Borg
fe50f1a158 cmd/usrv: Use better caching 2019-08-29 19:49:27 +02:00
Jakob Borg
5851aabe02 lib/upgrade: Include browser_download_url field 2019-08-29 16:10:13 +02:00
Jakob Borg
0832285d79 lib/ur: Prevent trivial race in CPU bench 2019-08-25 23:43:28 +02:00
Jakob Borg
c2ea9d119d lib/connections: Upgrade QUIC package, use contexts for timeout (#5972) 2019-08-23 10:15:52 +02:00
Simon Frei
534f07d9ca lib/discover: Don't leak goroutines (#5950) 2019-08-22 12:30:57 +02:00
Jakob Borg
24d4290d03 lib/model, lib/scanner: Pass a valid event logger (fixes #5970) (#5971) 2019-08-21 08:05:43 +02:00
Jakob Borg
09b872cef4 build: go mod tidy 2019-08-21 07:47:05 +02:00
Simon Frei
2d124e053c test: Get integration tests up to speed (config, build and test fixes) (#5962) 2019-08-20 10:17:11 +02:00
Jakob Borg
90b70c7a16 lib/db: Use different defaults for larger databases (fixes #5966) (#5967)
This introduces a better set of defaults for large databases. I've
experimentally determined that it results in much better throughput in a
couple of scenarios with large databases, but I can't give any
guarantees the values are always optimal. They're probably no worse than
the defaults though.
2019-08-20 09:41:41 +02:00
dependabot-preview[bot]
e910acdc17 build(deps): bump github.com/mattn/go-isatty from 0.0.7 to 0.0.9 (#5965)
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.7 to 0.0.9.
- [Release notes](https://github.com/mattn/go-isatty/releases)
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.7...v0.0.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-19 12:13:26 +01:00
Jakob Borg
96350d7600 cmd/stupgrades: Generate appropriate upgrade data (fixes #5924) (#5960)
This is a tiny tool to grab the GitHub releases info and generate a
more concise version of it. The conciseness comes from two aspects:

- We select only the latest stable and pre. There is no need to offer
  upgrades to versions that are older than the latest. (There might be, in
  the future, when we hit 2.0. We can revisit this at that time.)

- We use our structs to deserialize and reserialize the data. This means
  we remove all attributes that we don't understand and hence don't
  require.

All in all the new response is about 10% the size of the previous one and
avoids the issue where we only serve a bunch of release candidates and
no stable.
2019-08-16 10:04:10 +02:00
Simon Frei
77a5980747 lib/model: Do free disk space check later on pull (fixes #5948) (#5949) 2019-08-16 09:40:53 +02:00
Simon Frei
b677464dfa lib/model: Optimise locking around conn-close and puller states (#5954) 2019-08-16 09:35:19 +02:00
Simon Frei
b1c74860e8 all: Remove global events.Default (ref #4085) (#5886) 2019-08-15 16:29:37 +02:00
Simon Frei
f6f696c6c5 lib/config: Prevent nil deref in debug logging (fixes #5955) (#5956) 2019-08-15 15:51:09 +02:00
Simon Frei
cf40ed6cec lib/connections: Return exported intf from exported function (#5947) 2019-08-13 09:33:33 +02:00
Simon Frei
6fa02d5081 lib/model: Fix a few more problematic locks (ref #5929) (#5944) 2019-08-13 09:04:43 +02:00
Simon Frei
86e35f1879 lib/model: Less locking in ClusterConfig (#5943) 2019-08-11 19:30:24 +02:00
Jakob Borg
720a6bf62e lib/tlsutil: Remove hardcoded curve preferences (fixes #5940) (#5942)
They are arguable outdated and we are better off trusting the standard
library than trying to keep up with it ourselves.
2019-08-11 19:01:57 +02:00
Simon Frei
4a619e74f2 lib/model: Fix incorrect locking (#5939) 2019-08-11 16:10:30 +02:00
Audrius Butkevicius
58ef5368f8 lib/connections: Validate device id before assuming success (fixes #5934) (#5935)
* lib/connections: Validate device id before assuming success (fixes #5934)

* Vet
2019-08-09 12:31:42 +01:00
Cromefire_
7b37d453f9 build, etc: Add systemd units and ufw rules for relay and discovery (fixes #5115) (#5350) 2019-08-08 18:04:52 +02:00
Oliver Freyermuth
edf2399ce6 Add NATSymmetricUDPFirewall to punchable NATs (#5931)
NATSymmetricUDPFirewall actually is not NAT at all, but means the machine has a global IP address and an UDP firewall in front (RFC calls it Symmetric UDP Firewall). This is punchable fine, both theoretically and also practically in testing.
2019-08-06 12:26:02 +01:00
dependabot-preview[bot]
d43b0a4395 build(deps): bump github.com/urfave/cli from 1.20.0 to 1.21.0 (#5928)
Bumps [github.com/urfave/cli](https://github.com/urfave/cli) from 1.20.0 to 1.21.0.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v1.20.0...v1.21.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-05 12:18:35 +02:00
Jakob Borg
f2efd08e0f Merge branch 'release'
* release:
  cmd/syncthing: Print version information early (fixes #5891) (#5893)
2019-08-05 07:16:07 +02:00
Jakob Borg
61b9f7bd55 lib/config: Format bytes in insufficient space errors (fixes #5920) (#5921) 2019-08-02 14:43:05 +02:00
Simon Frei
1475c0344a gui: Parse strings before copying options object (fixes #5824) (#5922) 2019-08-02 12:46:27 +02:00
Simon Frei
77cc87dfca lib/connections: Log errors in relay clients (#5917) 2019-08-01 17:37:58 +02:00
Jakob Borg
bc7dd02e2b authors: Update carstenhag (Moter8) (fixes #5919) 2019-08-01 17:35:45 +02:00
Simon Frei
8a06cf0973 lib/model: Unflake TestPullInvalidIgnored (#5918) 2019-08-01 11:07:41 +02:00
Simon Frei
05835ed81f all: Remove potentially problematic errors from panics (fixes #5839) (#5912) 2019-07-31 10:53:35 +02:00
Simon Frei
df522576ac lib/model: Don't call t.Fatal in goroutines (fixes #5901) (#5903) 2019-07-30 17:50:51 +02:00
Simon Frei
d681ac11fe lib/config: Handle empty Fstype for mtime-window (#5906) 2019-07-30 15:23:00 +02:00
Simon Frei
7d5f7d508d lib/syncthing: Stop only once (fixes #5908) (#5909) 2019-07-29 20:07:19 +02:00
Simon Frei
1d182e4631 lib/fs: Use gopsutils for disk usage (#5905) 2019-07-29 20:06:17 +02:00
Simon Frei
710f5c199f lib/db: Don't use global fileset in benchmarks (#5902) 2019-07-28 22:31:24 +02:00
Simon Frei
fd847d4efe lib/model: Fix flakyness of TestRequestRemoteRenameChanged (#5904) 2019-07-28 22:29:31 +02:00
Jakob Borg
15e51fc045 cmd/stcrashreceiver: Store and serve compressed reports (#5892)
This changes the on disk format for new raw reports to be gzip
compressed. Also adds the ability to serve these reports in plain text,
to insulate web browsers from the change (previously we just served the
raw reports from disk using Caddy).
2019-07-28 11:13:04 +02:00
Jakob Borg
c1c976aa2b lib/model: Don't panic on failed chmod-back on directory (fixes #5836) (#5896)
* lib/model: Don't panic on failed chmod-back on directory (fixes #5836)

This makes the "in writable dir"-wrapper log chmod-back errors instead
of panicking. To do that we need a logger so the function moved into the
model package which is also the only place it's used. The tests came
along.

(The test also exercised osutil.RenameOrCopy like some sort of
piggybacking. I removed that.)
2019-07-28 10:25:05 +02:00
Jakob Borg
159d1a68e1 lib/api: Don't log random stuff in the HTTP server (fixes #5738) (#5897) 2019-07-28 09:49:07 +02:00
Simon Frei
dd850f66bb lib/api: Close server before exiting serve (fixes #5866) (#5895) 2019-07-28 08:03:55 +02:00
Jakob Borg
d0c3697152 cmd/syncthing: Print version information early (fixes #5891) (#5893) 2019-07-27 20:36:33 +02:00
Jakob Borg
669bcb748f lib/config, lib/model: Don't save on every pending folder/device update (fixes #5888) (#5890)
Wrapper methods generally don't save by themselves.
2019-07-27 11:05:00 +01:00
Jakob Borg
4e22a96602 cmd/syncthing: Print version information early (fixes #5891) (#5893) 2019-07-27 10:58:39 +01:00
Jakob Borg
a992559abc lib/db: Add hacky way to adjust database parameters (#5889)
This adds a set of magical environment variables that can be used to
tweak the database parameters. It's totally undocumented and not
intended to be a long term or supported thing.

It's ugly, but there is a backstory. I have a couple of large
installations where the database options are inefficient or otherwise
suboptimal (24/7 compaction going on and stuff like that). I don't
*know* the correct database parameters, nor yet the formula or method to
derive them by, so this requires experimentation. Experimentation needs
to happen partly in production, and rolling out new builds for every
tweak isn't practical. This provides override points for all reasonable
values, while not changing anything by default.

Ideally, at the end of such experimentation, we'll know which values are
relevant to change and in what manner, and can provide a more user
friendly knob to do so - or do it automatically based on the database
size.
2019-07-26 22:18:42 +02:00
Simon Frei
46e72d76b5 cmd/syncthing, lib/syncthing: Create library utils (ref #4085) (#5871) 2019-07-23 23:39:20 +02:00
Simon Frei
7a4c88d4e4 lib: Add mtime window when comparing files (#5852) 2019-07-23 21:48:53 +02:00
Simon Frei
35f40e9a58 lib/model: Create new file-set after stopping folder (fixes #5882) (#5883) 2019-07-23 20:39:25 +02:00
Simon Frei
5de9b677c2 lib/fs: Fix kqueue event list (fixes #5308) (#5885) 2019-07-23 14:11:15 +02:00
Simon Frei
6f08162376 lib/model: Remove incorrect/useless panics (#5881) 2019-07-23 10:51:16 +02:00
Simon Frei
7b3d9a8dca lib/syncthing: Refactor to use util.AsService (#5858) 2019-07-23 10:50:37 +02:00
Simon Frei
942659fb06 lib/model, lib/nat: More service termination speedup (#5884) 2019-07-23 10:49:22 +02:00
dependabot-preview[bot]
15c262184b build(deps): bump github.com/maruel/panicparse from 1.2.1 to 1.3.0 (#5879)
Bumps [github.com/maruel/panicparse](https://github.com/maruel/panicparse) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/maruel/panicparse/releases)
- [Commits](https://github.com/maruel/panicparse/compare/v1.2.1...v1.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-07-22 19:46:52 +01:00
dependabot-preview[bot]
484fa0592e build(deps): bump github.com/lib/pq from 1.1.1 to 1.2.0 (#5878)
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.1.1...v1.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-07-22 08:07:21 +01:00
Simon Frei
b5b54ff057 lib/model: No watch-error on missing folder (fixes #5833) (#5876) 2019-07-19 19:41:16 +02:00
Simon Frei
4d3432af3e lib: Ensure timely service termination (fixes #5860) (#5863) 2019-07-19 19:40:40 +02:00
Simon Frei
1cb55904bc lib/model: Prevent panic in NeedFolderFiles (fixes #5872) (#5875) 2019-07-19 19:39:52 +02:00
Simon Frei
2b622d0774 lib/model: Close conn on dev pause (fixes #5873) (#5874) 2019-07-19 19:37:29 +02:00
Simon Frei
1894123d3c lib/syncthing: Modify exit status before stopping (fixes #5869) (#5870) 2019-07-18 20:49:00 +02:00
Jakob Borg
e7e177a6fa lib/relay: Prevent spurious relay error message (fixes #5861) (#5864) 2019-07-17 10:55:28 +02:00
Simon Frei
eed1edcca0 cmd/syncthing: Ensure myID is set by making it local (fixes #5859) (#5862) 2019-07-17 07:19:14 +02:00
Simon Frei
0025e9ccfb all: Refactor cmd/syncthing creating lib/syncthing (ref #4085) (#5805)
* add skeleton for lib/syncthing

* copy syncthingMain to lib/syncthing (verbatim)

* Remove code to deduplicate copies of syncthingMain

* fix simple build errors

* move stuff from main to syncthing with minimal mod

* merge runtime options

* actually use syncthing.App

* pass io.writer to lib/syncthing for auditing

* get rid of env stuff in lib/syncthing

* add .Error() and comments

* review: Remove fs interactions from lib

* and go 1.13 happened

* utility functions
2019-07-14 11:43:13 +01:00
Simon Frei
82b70b9fae lib/model, lib/protocol: Track closing connections (fixes #5828) (#5829) 2019-07-14 11:03:55 +02:00
Simon Frei
def4b8cee5 lib/config: Error on empty folder path (fixes #5853) (#5854) 2019-07-14 11:03:14 +02:00
Aurélien Rainone
f1a7dd766e all: Add comment to ensure correct atomics alignment (fixes #5813)
Per the sync/atomic bug note:

> On ARM, x86-32, and 32-bit MIPS, it is the caller's
> responsibility to arrange for 64-bit alignment of 64-bit words
> accessed atomically. The first word in a variable or in an
> allocated struct, array, or slice can be relied upon to be
> 64-bit aligned.

All atomic accesses of 64-bit variables in syncthing code base are
currently ok (i.e they are all 64-bit aligned).

Generally, the bug is triggered because of incorrect alignement
of struct fields. Free variables (declared in a function) are
guaranteed to be 64-bit aligned by the Go compiler.

To ensure the code remains correct upon further addition/removal
of fields, which would change the currently correct alignment, I
added the following comment where required:

     // atomic, must remain 64-bit aligned

See https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
2019-07-13 14:05:39 +01:00
Simon Frei
20c8dbd9ed lib/model: Fix integer conversion (fixes #5837) (#5851) 2019-07-12 16:37:12 +02:00
xduugu
4b3f9b1af9 lib/versioner: Replace multiple placeholders in a single token in external command (fixes #5849)
* lib/versioner: Add placeholder to provide the absolute file path to external commands

This commit adds support for a new placeholder, %FILE_PATH_FULL%, to the
command of the external versioner. The placeholder will be replaced by
the absolute path of the file that should be deleted.

* Revert "lib/versioner: Add placeholder to provide the absolute file path to external commands"

This reverts commit fb48962b94.

* lib/versioner: Replace all placeholders in external command (fixes #5849)

Before this commit, only these placeholders were replaced that span a
whole word, for example "%FOLDER_PATH%". Words that consisted of more
than one placeholder or additional characters, for example
"%FOLDER_PATH%/%FILE_PATH%", were left untouched.

* fixup! lib/versioner: Replace all placeholders in external command (fixes #5849)
2019-07-12 08:45:39 +01:00
Simon Frei
3446d50201 lib/model: Remove pointless error that watch hasn't started (fixes #5833) (#5834) 2019-07-10 11:00:06 +02:00
Simon Frei
9fef1552fc lib/db, lib/model: Remove folder info from panics (ref #5839) (#5840) 2019-07-10 10:57:49 +02:00
Simon Frei
85318f3b82 gui: On update setting don't show RC msg when disabled (fixes #5803) (#5842) 2019-07-09 22:30:22 +01:00
Simon Frei
485acda63b lib/relay: Call the proper Error method (ref #5806) (#5841) 2019-07-09 22:29:19 +01:00
Simon Frei
05e9e0bfa9 build: Update notify dependency (#5838) 2019-07-09 21:33:22 +01:00
Simon Frei
ba056578ec lib: Add util.Service as suture.Service template (fixes #5801) (#5806) 2019-07-09 11:40:30 +02:00
Jakob Borg
d0ab65a178 cmd/stcrashreceiver: Don't leak clients
Use a global raven.Client because they allocate an http.Client for each,
with a separate CA bundle and infinite connection idle time. Infinite
connection idle time means that if the client is never used again it
will always keep the connection around, not verifying whether it's
closed server side or not. This leaks about a megabyte of memory for
each client every created.

client.Close() doesn't help with this because the http.Client is still
around, retained by its own goroutines.

The thing with the map is just to retain the API on sendReport, even
though there will in practice only ever be one DSN per process
instance...
2019-07-09 11:11:06 +02:00
Simon Frei
4cba433852 build: Add go major version to go.mod (#5822) 2019-06-30 13:18:34 +02:00
Simon Frei
863fe23347 gui, lib/model: Fix download progress accounting (fixes #5811) (#5815) 2019-06-30 09:23:47 +02:00
Jakob Borg
43b6ac9501 cmd/stcrashreceiver: Add source code loader (#5779) 2019-06-29 08:50:09 +02:00
Simon Frei
1cf352a722 lib/model: NewFileSet outside fmut (#5818) 2019-06-29 08:49:30 +02:00
Simon Frei
b58f6ca886 lib/model: Correct/unify check if item changed (#5819) 2019-06-29 07:45:41 +02:00
Jakob Borg
5cbc9089fd Merge branch 'release'
* release:
  go.mod: Update AudriusButkevicius/pfilter (fixes #5820)
2019-06-28 08:21:00 +02:00
Jakob Borg
20eab36a33 go.mod: Update AudriusButkevicius/pfilter (fixes #5820) 2019-06-28 08:03:29 +02:00
Jakob Borg
2b4df6b874 go.mod: Update AudriusButkevicius/pfilter (fixes #5820) 2019-06-28 07:38:52 +02:00
Simon Frei
3c7e7e971d lib/model: Make jobQueue.Jobs paginated (fixes #5754) (#5804)
* lib/model: Make jobQueue.Jobs paginated (fixes #5754)

* fix, no test yet

* add test
2019-06-27 19:25:38 +01:00
Audrius Butkevicius
afde0727fe lib/versioner: Revert naming change (fixes #5807) (#5808) 2019-06-25 08:56:11 +03:00
Simon Frei
bf744ded31 cmd/syncthing, lib/db: Exit/close db faster (fixes #5781) (#5782)
This adds a 10s timeout on closing the db and additionally cancels active
db iterators and waits for them to terminate before closing the db.
2019-06-17 15:27:25 +03:00
Wulf Weich
0d86166890 gui: Optimize folder/device info for small screens (fixes #5774) (#5787)
break table layout and add button margin on small screens
2019-06-17 15:24:45 +03:00
Simon Frei
cea5962417 lib/model: Unflake TestPullInvalidIgnoredSR/SO (fixes #5796) (#5799) 2019-06-17 15:23:28 +03:00
Simon Frei
02752af862 lib/protocol: Don't block on Close (fixes #5794) (#5795) 2019-06-14 19:04:41 +02:00
Simon Frei
6b1d7ac727 gui: Check data before calling .reverse() (#5793) 2019-06-14 13:14:15 +02:00
Simon Frei
abd363e8bb lib/model: Don't error on pulling deletion of invalid file (fixes #5791) (#5792) 2019-06-14 08:48:14 +02:00
Jakob Borg
bff1a5f5e4 build: Upgrade github.com/syndtr/goleveldb 2019-06-14 06:56:52 +02:00
Simon Frei
38302270d4 build: Include cross-package test coverage (#5735) 2019-06-13 19:28:14 +02:00
desbma
1b4fe39a89 etc: Remove Systemd hardening options unsupported in user mode (#5788) 2019-06-12 10:31:19 +02:00
Jakob Borg
6b74cdc613 gui, man, authors: Update docs, translations, and contributors 2019-06-12 07:45:26 +02:00
Simon Frei
13a746e0fb lib/model: Prevent nil deref if folder stopped (fixes #5780) (#5778) 2019-06-11 11:48:51 +02:00
Audrius Butkevicius
21f50e2f8f lib/versioner: Use mtime for version cleanup (fixes #5765) (#5769) 2019-06-11 09:16:55 +02:00
Audrius Butkevicius
b7c70a9817 lib/fs: Enhance mtimefs, use everywhere (fixes #5777) (#5776) 2019-06-11 08:27:12 +02:00
Jakob Borg
42ce6be9b9 lib/ur: Implement crash (panic) reporting (fixes #959) (#5702)
* lib/ur: Implement crash (panic) reporting (fixes #959)

This implements a simple crash reporting method. It piggybacks on the
panic log files created by the monitor process, picking these up and
uploading them from the usage reporting routine.

A new config value points to the crash receiver base URL, which defaults
to "https://crash.syncthing.net/newcrash" (following the pattern of
"https://data.syncthing.net/newdata" for usage reports, but allowing us
to separate the service as required).
2019-06-11 08:19:11 +02:00
dependabot-preview[bot]
93e57bd357 build(deps): bump github.com/prometheus/client_golang (#5775)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 0.9.3 to 0.9.4.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v0.9.3...v0.9.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-10 19:06:25 +02:00
Mingxuan Lin
eb4fe808c5 lib/fs: Fallback EvalSymlinks method on windows (fixes #5609) (#5611) 2019-06-10 14:33:53 +02:00
Simon Frei
1054ce9354 lib/model: Refactor sending indexes as suture service (#5757) 2019-06-10 13:27:22 +02:00
Simon Frei
97ad575b1f gui: Enable rescan button with failed items (fixes #5770) (#5771) 2019-06-10 10:12:30 +02:00
Audrius Butkevicius
ee746263fb lib/connections: Do not leak FDs, fix address copy (fixes #5767) (#5768)
* lib/connections: Do not leak FDs, fix address copy (fixes #5767)

* build

* Update quic_listen.go

* Update quic_listen.go
2019-06-09 22:14:00 +01:00
Jakob Borg
41ff4b323e lib/api: Correct logic for errors.jons in support bundle (fixes #5766)
The err check should always be done with != and have the error case
first, to follow the pattern and avoid mistakes like these.
2019-06-09 09:35:05 +02:00
Jakob Borg
997bb5e7e1 all: Remove "large blocks" config (#5763)
We now always use large / variable blocks.
2019-06-06 15:57:38 +01:00
Jakob Borg
ca2fa8de4e lib/build: Version 1.2 will be the Fermium Flea 2019-06-06 14:45:07 +02:00
Jakob Borg
64185484b2 readme: Remove old, dead link (fixes #5760) 2019-06-06 08:35:03 +02:00
Simon Frei
5541697d18 gui: Don't call API when no modal is open (fixes #5652) (#5759) 2019-06-05 14:03:52 +08:00
Simon Frei
e39d3f95dd lib/protocol: Prioritize close msg and add close timeout (#5746) 2019-06-05 14:01:59 +08:00
Jakob Borg
6e8aa0ec25 gui, man, authors: Update docs, translations, and contributors 2019-06-05 07:45:26 +02:00
dependabot-preview[bot]
97057eb9de build(deps): bump github.com/lucas-clemente/quic-go (#5761)
Bumps [github.com/lucas-clemente/quic-go](https://github.com/lucas-clemente/quic-go) from 0.11.1 to 0.11.2.
- [Release notes](https://github.com/lucas-clemente/quic-go/releases)
- [Changelog](https://github.com/lucas-clemente/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/lucas-clemente/quic-go/compare/v0.11.1...v0.11.2)
2019-06-03 12:42:23 +01:00
Simon Frei
6664e01acf lib/protocol: Return from ClusterConfig when closed (#5752) 2019-05-29 12:14:00 +02:00
dependabot-preview[bot]
e2a647a6a4 build(deps): bump golang.org/x/text from 0.3.0 to 0.3.2 (#5751)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.0 to 0.3.2.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.0...v0.3.2)
2019-05-29 11:42:07 +02:00
Jakob Borg
5ce5b2c94a lib/config: Refactor migrations a bit (#5750)
This breaks out config migrations to a separate concept, making it
(imho) slightly easier to maintain and get an overview.
2019-05-29 11:37:44 +02:00
Audrius Butkevicius
e714df013f lib/connections: Add QUIC protocol support (fixes #5377) (#5737) 2019-05-29 09:56:40 +02:00
Kalle Laine
d8fa61e27c github: Create SECURITY.md (#5749)
Now that github has added the security section why not use it.
2019-05-29 09:39:00 +02:00
Jakob Borg
d3f583c8c9 gui, man, authors: Update docs, translations, and contributors 2019-05-29 07:45:25 +02:00
Jakob Borg
e096a14ff5 golang-ci: Disable confused scopelint check 2019-05-27 12:54:08 +02:00
Simon Frei
3775a64d5c lib/protocol: Don't send anything else before cluster config (#5741) 2019-05-27 11:15:34 +01:00
Simon Frei
129df0613b lib/model: Unflake folder restart with blocking conn test (ref #5707) (#5744) 2019-05-27 10:58:09 +01:00
Simon Frei
486230768e lib/fs, lib/model: Add error channel to Watch to avoid panics (fixes #5697) (#5734)
* lib/fs, lib/model: Add error channel to Watch to avoid panics (fixes #5697)

* forgot unsupported watch

* and more non(-standard)-unixy fixes

* and windows test

* review
2019-05-25 20:08:26 +01:00
Simon Frei
9e6db72535 lib/protocol: Don't call receiver after calling Closed (fixes #4170) (#5742)
* lib/protocol: Don't call receiver after calling Closed (fixes #4170)

* review
2019-05-25 20:08:07 +01:00
Simon Frei
d91da8feee lib/model: Readd special handling of conn close in TestIssue5063 (#5743)
This partially reverts commit 64518b0f7e.
2019-05-25 18:51:13 +01:00
Simon Frei
64518b0f7e lib/model: Close connections when model is stopped (#5733) 2019-05-25 16:00:32 +02:00
Simon Frei
5d35b2c540 lib/protocol: Test for Close on blocking send deadlock (ref #5442) (#5732) 2019-05-23 21:42:02 +01:00
Jakob Borg
224775ca81 golang-ci: Not as good at modules as you'd hope 2019-05-23 17:34:32 +02:00
Jakob Borg
98cda96b1c gui, man, authors: Update docs, translations, and contributors 2019-05-22 07:45:27 +02:00
Simon Frei
5b306510a0 lib/model: Consistently cleanup model in tests (#5724) 2019-05-19 14:29:07 +02:00
Jakob Borg
f593ac387c golang-ci: Turn up the heat 2019-05-18 12:51:49 +02:00
Jakob Borg
eb8df7f632 cmd/ursrv: Lint fixes 2019-05-18 11:59:32 +02:00
dependabot[bot]
78d6eee74a build(deps): bump github.com/prometheus/client_golang (#5729)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 0.9.2 to 0.9.3.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v0.9.2...v0.9.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-18 09:57:35 +02:00
Simon Frei
1b2b970f32 lib/model, lib/testutils: Test closing a connection on folder restart (#5707) 2019-05-18 08:53:59 +02:00
Simon Frei
5ffbb7668d lib/model: Fix test flakyness regression (ref #5592) (#5718) 2019-05-18 08:52:50 +02:00
Simon Frei
1df8701c46 test: Report time per MiB on transfer benchs (#5711) 2019-05-18 08:46:08 +02:00
Tom Jakubowski
cc36621b11 docker: Create entrypoint script (fixes #5631) (#5635) 2019-05-18 08:43:53 +02:00
Simon Frei
441ea109a1 lib/model: Refactor file deletions when pulling (#5699) 2019-05-17 18:29:54 +02:00
Jakob Borg
8015f3f937 cmd/ursrv: Add F-droid and some third party distributors to the distrubtion summary 2019-05-17 10:18:37 +02:00
Jakob Borg
2c866277a2 lib/api, lib/connections, gui: Show connection error for disconnected devices (fixes #3345) (#5727)
* lib/api, lib/connections, gui: Show connection error for disconnected devices (fixes #3345)

This adds functionality in the connetions service to track the last
error per address. That is in turn exposed in the /rest/system/status
API method, as that is also where we already show the listener status
from the connection service.

The GUI uses this info where it lists addresses, showing errors (if any)
in red underneath each address.

I also slightly refactored the existing status method on the connection
service to have a better name and return typed information.

* ok

* review

* formatting

* review
2019-05-16 22:11:45 +01:00
Jakob Borg
1da9317a09 authors: Update acolomb (fixes #5726) 2019-05-15 14:47:35 +02:00
Jakob Borg
e16a65bacb cmd/ursrv: Summarize known distribution channels
That is, whether the binary was downloaded from GitHub, from our APT
repository, etc.
2019-05-15 13:42:55 +02:00
Jakob Borg
c02aed0a21 gui, man, authors: Update docs, translations, and contributors 2019-05-15 07:45:24 +02:00
André Colomb
e4956358fb lib/model: Remove superfluous check for IndexID in remote ClusterConfig (#5717)
The check in ClusterConfig() when iterating through announced devices
in a folder explicitly skips entries without a non-zero IndexID.
Therefore, the check for IndexID == 0 just below will never be true
and the intended cleanup of local index data will not happen.

Plainly remove that check to make the intended case distinction work.
2019-05-12 21:17:55 +02:00
dependabot[bot]
ad44d77a21 build(deps): bump github.com/lib/pq from 1.0.0 to 1.1.1 (#5714)
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.0.0 to 1.1.1.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.0.0...v1.1.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-11 22:15:30 +02:00
dependabot[bot]
6bb5d140fa build(deps): bump github.com/oschwald/geoip2-golang from 1.1.0 to 1.3.0 (#5713)
Bumps [github.com/oschwald/geoip2-golang](https://github.com/oschwald/geoip2-golang) from 1.1.0 to 1.3.0.
- [Release notes](https://github.com/oschwald/geoip2-golang/releases)
- [Commits](https://github.com/oschwald/geoip2-golang/compare/v1.1.0...v1.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-11 21:02:49 +01:00
dependabot[bot]
d082b2ba4c build(deps): bump github.com/mattn/go-isatty from 0.0.4 to 0.0.7 (#5712)
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.4 to 0.0.7.
- [Release notes](https://github.com/mattn/go-isatty/releases)
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.4...v0.0.7)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-11 21:00:00 +01:00
dependabot[bot]
638789899c build(deps): bump github.com/gogo/protobuf from 1.2.0 to 1.2.1 (#5715)
Bumps [github.com/gogo/protobuf](https://github.com/gogo/protobuf) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/gogo/protobuf/releases)
- [Commits](https://github.com/gogo/protobuf/compare/v1.2.0...v1.2.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-11 20:59:44 +01:00
Simon Frei
dfbbb286fc lib/fs: Consider win83 for root path as well when watching (ref #5706) (#5709) 2019-05-11 10:06:04 +02:00
Simon Frei
fbd445fe0a lib/api: Clean up after test, enables test caching (#5710) 2019-05-11 08:41:32 +02:00
Simon Frei
2b246eeb52 lib/model: Move test utilities to separate files (#5694) 2019-05-10 13:33:45 +02:00
Simon Frei
2558b021e5 lib/fs: Remove \\?\ for drive letters when watching (fixes #5578) (#5701) 2019-05-10 09:09:58 +02:00
Jakob Borg
31be810eb6 lib/model: Don't fail operation when fsync() fails (fixes #5704) (#5705) 2019-05-09 21:20:29 +01:00
Jakob Borg
62a6d619e7 Merge branch 'release'
* release:
  lib/fs: Revert removal of \\?\ for drive letters (fixes #5695)
2019-05-08 17:38:08 +02:00
Jakob Borg
a04fcfe749 lib/fs: Revert removal of \\?\ for drive letters (fixes #5695)
This reverts commit ca823bd591 from #5633.

This un-fixes bug #5578.
2019-05-08 17:31:52 +02:00
Simon Frei
283f39ae5f lib/protocol: Revert unreleased changes related to closing connections (#5688)
This reverts commits:
    ec7c88ca55
    19b51c9b92
    5da41f75fa
    04b927104f
2019-05-08 08:08:26 +02:00
Jakob Borg
59e1349499 gui, man, authors: Update docs, translations, and contributors 2019-05-08 07:45:28 +02:00
Simon Frei
b45d77b6be lib/model: Fix regression deleting directories on pull (ref #5690) (#5691) 2019-05-06 20:55:26 +02:00
Simon Frei
79e67b7f79 lib/model: Remove individual pull errors on retry (fixes #5659) (#5690) 2019-05-06 17:21:56 +02:00
Jakob Borg
36a4a9fd34 Merge branch 'release'
* release:
  etc: Revert systemd After=multi-user.target addition (fixes #5676)
2019-05-06 12:24:39 +02:00
Nitroretro
92ed31fe21 gui: Fix typo in log viewer modal (#5687) 2019-05-03 07:28:17 +02:00
Simon Frei
5fa8467756 lib/model: Consistent use of locks (#5684) 2019-05-02 18:55:39 +01:00
Simon Frei
5954b105cd lib/model: Let fakeConnection call Model.Closed on close (#5682) 2019-05-02 14:24:55 +02:00
Simon Frei
defc5dca65 lib/model: Use correct lock (#5683) 2019-05-02 14:09:42 +02:00
Simon Frei
9f358ecae0 lib/protocol: Refactor to pass only relevant argument to writeMessage (#5681) 2019-05-02 14:09:19 +02:00
Simon Frei
fe4daf242b cmd, lib/db: Actually close goleveldb (fixes #5505) (#5671) 2019-05-02 11:15:00 +02:00
Simon Frei
ec7c88ca55 lib/protocol: Fix yet another deadlock (fixes #5678) (#5679)
* lib/protocol: Fix yet another deadlock (fixes #5678)

* more consistency

* read deadlock

* naming

* more naming
2019-05-02 09:21:07 +01:00
Jakob Borg
26e6d94c00 gui, man, authors: Update docs, translations, and contributors 2019-05-01 07:45:25 +02:00
Jakob Borg
e2470c8bc8 etc: Revert systemd After=multi-user.target addition (fixes #5676)
This reverts commit 84fe285659.
2019-04-29 21:45:01 +02:00
Simon Frei
19b51c9b92 lib/protocol: Don't close asyncMessage.done on success (fixes #5674) (#5675) 2019-04-29 17:52:57 +02:00
Audrius Butkevicius
0ca1f26ff8 lib/versioner: Restore for all versioners, cross-device support (#5514)
* lib/versioner: Restore for all versioners, cross-device support

Fixes #4631
Fixes #4586
Fixes #1634
Fixes #5338
Fixes #5419
2019-04-28 23:30:16 +01:00
Jakob Borg
2984d40641 lib/ignore: Additional test case (#5672) 2019-04-28 21:20:11 +01:00
Simon Frei
5da41f75fa lib/model, lib/protocol: Wait for reader/writer loops on close (fixes #4170) (#5657)
* lib/protocol: Wait for reader/writer loops on close (fixes #4170)

* waitgroup

* lib/model: Don't hold lock while closing connection

* fix comments

* review (lock once, func argument) and naming
2019-04-28 11:58:51 +01:00
Jakob Borg
32dec4a00d gui, man, authors: Update docs, translations, and contributors 2019-04-24 07:45:24 +02:00
Simon Frei
04b927104f lib/protocol: Don't send any messages before cluster config (#5646)
* lib/model: Send cluster config before releasing pmut

* reshuffle

* add model.connReady to track cluster-config status

* Corrected comments/strings

* do it in protocol
2019-04-23 20:47:11 +01:00
Simon Frei
110806842c lib/model: Pass the old not new fileinfo to deleteItemOnDisk (fixes #5654) (#5655) 2019-04-23 20:46:28 +01:00
Jonas Thelemann
d9b3415dec gui: Semicolon insertion (#5666) 2019-04-23 18:37:51 +01:00
Jonas Thelemann
d3d43d90f6 gui: Remove superfluous trailing argument (#5668) 2019-04-23 18:37:20 +01:00
Jonas Thelemann
e7d11adf3c gui: Remove unused variables (#5665) 2019-04-23 18:36:12 +01:00
Jonas Thelemann
afeb606b5b gui: Use of AngularJS markup in URL-valued attribute (#5667)
Using AngularJS markup (that is, AngularJS expressions enclosed in double curly braces) in HTML attributes that reference URLs is not recommended: the browser may attempt to fetch the URL before the AngularJS compiler evaluates the markup, resulting in a request for an invalid URL.
2019-04-23 18:33:40 +01:00
Jonas Thelemann
c6a179fa4d cmd/strelaypoolsrv: Missing explicit dependency injection (#5669)
https://lgtm.com/rules/1505800326162/
2019-04-23 12:17:27 +01:00
Simon Frei
e302ccf4b4 lib/fs: Improve IsParent (#5658) 2019-04-22 11:12:32 +02:00
Simon Frei
926e9228ed lib/scanner, lib/model: File -> item when logging error (#5664) 2019-04-21 16:19:59 +01:00
Simon Frei
86e72d9973 lib/model: Use RLock and legacy polish (#5663) 2019-04-21 13:21:36 +01:00
otbutz
952c8becf5 gui: Adjust table column width to content size (fixes #4531) (#5565) 2019-04-18 18:35:44 +02:00
Jakob Borg
32ee8d783d gui, man, authors: Update docs, translations, and contributors 2019-04-17 07:45:24 +02:00
Simon Frei
3bea59b0d9 lib/model: Refactor progressEmitter to de-/activate by config (fixes #4613) (#5623) 2019-04-13 14:20:51 +02:00
Simon Frei
8a4b65b937 gui: Fix setting page size on failed and locally changed modals (fixes #5421) (#5650) 2019-04-13 14:05:39 +02:00
Simon Frei
fca895a632 lib/model: Fix block index calculation for recheckFile (fixes #5649) (#5648) 2019-04-12 15:21:07 +02:00
Simon Frei
79360e2205 lib/fs: Add test that symlinks are skipped on walk (#5644) 2019-04-10 22:36:37 +02:00
Simon Frei
9b2a73f9ab lib/model: Pause pull for at least as long as failed pull took (fixes #5641) (#5643) 2019-04-10 16:22:23 +02:00
Simon Frei
c305265c62 lib/model: Request errors conforming to BEP specs (#5642) 2019-04-10 11:47:24 +02:00
Jakob Borg
1954239ffa gui, man, authors: Update docs, translations, and contributors 2019-04-10 07:45:25 +02:00
361 changed files with 19563 additions and 9577 deletions

View File

@@ -36,7 +36,7 @@ its entirety.
### Version Information
Syncthing Version: v0.x.y
Syncthing Version: v1.x.y
OS Version: Windows 7 / Ubuntu 14.04 / ...
Browser Version: (if applicable, for GUI issues)

48
.github/SECURITY.md vendored Normal file
View File

@@ -0,0 +1,48 @@
## Reporting a Vulnerability
If you believe that you've found a Syncthing-related security vulnerability, please report it by sending email to the address security@syncthing.net. The PGP key for security@syncthing.net (B683AD7B76CAB013) below can be used to send encrypted mail or to verify responses received from that address.
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFShFlIBCACsW346HYskhKhxrdZMjyU5Ntsjvg6/ogqINDPoL10/oaIP0G+t
7zzC0K5Cq29ix43kNNLKTJNyPkdTeaJEcqslMUt6tovjHwoKJ073GP0W3KsNvBRg
ffCZOAexGfOsBSL9KHaYGK67Py3TFgtN1H/EmboU1arrLfAMrmqOip++EGqOxjse
gH0qk7Mk1TqEC5Xh3NGE7r1UobAlqdUv5E3v7U11NhAdP1zu/XZ/zvP5mwVQJMLv
iZyeWGliNI8nEeRjYw+S85f4gq7H2mgoeNBN4WwwK1hhz9qpvCsgPW3XqlExTPI4
1vM4PxpiFIuF0zuy2OwsmjrpTCZeBscr4Tj5ABEBAAG0K1N5bmN0aGluZyBTZWN1
cml0eSA8c2VjdXJpdHlAc3luY3RoaW5nLm5ldD6JATgEEwECACIFAlShFlICGwMG
CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJELaDrXt2yrATB1UH/jnnIa6DekCA
2V36N/2+pFSNLVWeoZQxZ9ne9S7WSubaoK4oCWiuChPSAy5hagnKnNA3a9wrz5iN
0hgCA88NnTU18biZW6HX8xWEd3dnY3fX1sG0XdHuKlFria8ByfcrbShf/CttXkEd
Y5qPHH9aLIMtksBS1MIsRYrOCHiLNYFCKlbjDDCGT3tuk/yaU7aBAFVPIag54afC
zZAIvTIgRruLWkNT/sSEJx9ekhJzO/+pXNbSSHwhoj5OJh7sQjZWwPzNazelk48R
+ku8VpB5Wxgk2MnJPf1RxF+7saBAaeAVZsJcPN+Jp7u9LCFelIRn1ISsHbhLhyqL
cPXqllltLCKJAhwEEAECAAYFAlShFlsACgkQSfWuwLzlJMcEpA//VvZYHGZgZMM0
bBkYnjManYnJkHSQ2pHsjquSFH+fbfq2FxxTk/nQ/IAvBzt8NDTT3ylPOmsl4A8q
r8BxsRNENhU7zDQrKC5NtYUrzXhPGo8qfDwkeLyqd2msUvHn7EH3PNgiN2QaFWxE
21FqoXIpERKJRgRtv1SYZoMyNGjmT2hta1ZbwEfrPJnzjYhneoUGsRApG7p+uPqe
4LRpbG3Fa2vBm/UWUrOe+6jPzvMokjIJbdK0IjXamFAzwYW5fSZaFa94mR6L5f5m
X8Dhp66mBRTx7qk6ldEqptvaYGqihaWP1xbDaApQsGHQujtcBYGp+edlkabuW5h7
stl/7QTFkEPqHT4ybxEX0rLoFUGq56WUlKp27z40keStaXMgfrsxJtkz66Xs8vU4
7qZcLAcPsin+y0toqavtwtM/L7uCMu1yhbFRGJ+JL6saJAqzwS8l7r6E2R7OnVj1
BdASgxx1TgzW6ZFW5p1Iy6mtpkBypsnp8s3UcP3GFRnQe9gi1EXHjzuZAUGafe4Q
juvJ8t8xIcQMFuAylNIVyXvIWJoehqsVY9EBgVtE4y1SRh8XTT3Tddn8ab5fl7uh
HWAY8cRlv6WIOhK8w8oroiYx0SID8jMeEwJBS4DL7qWtJMkDo8ZEJiB+Pkd963MX
05QXt33AvJJ9PmbGCHkcH7198tCmA+e5AQ0EVKEWUgEIAPGczHpa6NdxY0pm+tIp
btiA6gdPE70pJYgJTKX7siCQ2w770H3CBSKmqEXadr7WnfIgUYIDaSxadeGzB/Mn
3SHCYRCqbA7mwu2k4wNNvCEM0xZqFAvaDJ4avlZ5oiMT8IFHKsjC77nkhmfXaIGt
hn10H2MFADjvJYul7vR+Ghg1wGhTGWo2u7VVj9BI+AfvnWaouFI0cx2KNWEI/Ocj
z6jk8nmC3yOEFQECM/hF4lkAOv9CQUa8UcvAr31trzawmV1iSsKjmVZgqd0N4T8f
hUikqUPZGNCRcqEUffTzggIyGPbedFnZw9Di7o1xByxyTrZycemAVqaVGF+9nFLG
pccAEQEAAYkBHwQYAQIACQUCVKEWUgIbDAAKCRC2g617dsqwEzrjB/9q0T8A4XUE
p0g6xq86jhmh4jlEedxrfXUL3R6ejFtuKMThulxEP0xiQ7xLzBhOnvyxLCsVbjp8
0JtJTVCq44UzUiIBuVNRoYG29uXuTUL2UtI27VhjFxMzLDwZL97tbGR6lzdM/+U5
9PC+PIvS0yz13z2t3/x3KUOnBgxZnpy9h4AdKwjrNVtnQdGDXSKlJBLb57TFcS94
f3roZ5Gpw3AWYSmSSiZWbhks2UNzYSQ84LAKlV1NkktO+qRc/pUqr6IxMjOKc7XP
e8u1Nst6fN3GNqZOV+jUYs/fqrJgp1TUWjNTuf22Rl0Idz7XLPJKYFh9W7T/4MbU
M7Q8GZuww1rk
=No/v
-----END PGP PUBLIC KEY BLOCK-----
```

View File

@@ -1,5 +1,25 @@
linters-settings:
maligned:
suggest-new: true
linters:
enable-all: true
disable:
- goimports
- depguard
- lll
- gochecknoinits
- gochecknoglobals
- gofmt
- scopelint
- gocyclo
- funlen
- wsl
- gocognit
service:
golangci-lint-version: 1.13.x
golangci-lint-version: 1.21.x
prepare:
- rm -f go.sum # 1.12 -> 1.13 issues with QUIC-go
- GO111MODULE=on go mod vendor
- go run build.go assets
- GO111MODULE=on go mod vendor

11
AUTHORS
View File

@@ -24,12 +24,13 @@ andresvia <andres.via@gmail.com>
Andrew Dunham (andrew-d) <andrew@du.nham.ca>
Andrew Rabert (nvllsvm) <ar@nullsum.net> <6550543+nvllsvm@users.noreply.github.com>
Andrey D (scienmind) <scintertech@cryptolab.net> <scienmind@users.noreply.github.com>
André Colomb (acolomb) <src@andre.colomb.de> <github.com@andre.colomb.de>
andyleap <andyleap@gmail.com>
Antoine Lamielle (0x010C) <antoine.lamielle@0x010c.fr> <gh@0x010c.fr>
Antony Male (canton7) <antony.male@gmail.com>
Aranjedeath <Aranjedeath@users.noreply.github.com>
Arthur Axel fREW Schmidt (frioux) <frew@afoolishmanifesto.com> <frioux@gmail.com>
Audrius Butkevicius (AudriusButkevicius) <audrius.butkevicius@gmail.com>
Audrius Butkevicius (AudriusButkevicius) <audrius.butkevicius@gmail.com> <github@audrius.rocks>
BAHADIR YILMAZ <bahadiryilmaz32@gmail.com>
Bart De Vries (mogwa1) <devriesb@gmail.com>
Ben Curthoys (bencurthoys) <ben@bencurthoys.com>
@@ -45,7 +46,7 @@ Brandon Philips (philips) <brandon@ifup.org>
Brendan Long (brendanlong) <self@brendanlong.com>
Brian R. Becker (brbecker) <brbecker@gmail.com>
Caleb Callaway (cqcallaw) <enlightened.despot@gmail.com>
Carsten Hagemann (Moter8) <moter8@gmail.com>
Carsten Hagemann (carstenhag) <moter8@gmail.com> <carsten@chagemann.de>
Cathryne Linenweaver (Cathryne) <cathryne.linenweaver@gmail.com> <Cathryne@users.noreply.github.com> <katrinleinweber@MAC.local>
Cedric Staniewski (xduugu) <cedric@gmx.ca>
Chris Howie (cdhowie) <me@chrishowie.com>
@@ -62,6 +63,8 @@ Darshil Chanpura (dtchanpura) <dtchanpura@gmail.com> <dcprime314@gmail.com>
David Rimmer (dinosore) <dinosore@dbrsoftware.co.uk>
Denis A. (dva) <denisva@gmail.com>
Dennis Wilson (snnd) <dw@risu.io>
dependabot-preview[bot] <dependabot-preview[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com>
derekriemer <derek.riemer@colorado.edu>
desbma <desbma@users.noreply.github.com>
Dmitry Saveliev (dsaveliev) <d.e.saveliev@gmail.com>
@@ -105,6 +108,7 @@ Jonas Thelemann <e-mail@jonas-thelemann.de>
Jonathan Cross <jcross@gmail.com>
Jose Manuel Delicado (jmdaweb) <jmdaweb@hotmail.com> <jmdaweb@users.noreply.github.com>
Jörg Thalheim <Mic92@users.noreply.github.com>
Kalle Laine <pahakalle@protonmail.com>
Karol Różycki (krozycki) <rozycki.karol@gmail.com>
Keith Turner <kturner@apache.org>
Kelong Cong (kc1212) <kc04bc@gmx.com> <kc1212@users.noreply.github.com>
@@ -140,12 +144,14 @@ Michael Ploujnikov (plouj) <ploujj@gmail.com>
Michael Tilli (pyfisch) <pyfisch@gmail.com>
Mike Boone <mike@boonedocks.net>
MikeLund <MikeLund@users.noreply.github.com>
Mingxuan Lin <gdlmx@users.noreply.github.com>
Nate Morrison (nrm21) <natemorrison@gmail.com>
Nicholas Rishel (PrototypeNM1) <rishel.nick@gmail.com> <PrototypeNM1@users.noreply.github.com>
Nico Stapelbroek <3368018+nstapelbroek@users.noreply.github.com>
Nicolas Braud-Santoni <nicolas@braud-santoni.eu>
Niels Peter Roest (Niller303) <nielsproest@hotmail.com> <seje.niels@hotmail.com>
Nils Jakobi (thunderstorm99) <jakobi.nils@gmail.com>
Nitroretro <43112364+Nitroretro@users.noreply.github.com>
NoLooseEnds <jon.koslung@gmail.com>
otbutz <tbutz@optitool.de>
Oyebanji Jacob Mayowa <oyebanji05@gmail.com>
@@ -183,6 +189,7 @@ Tim Abell (timabell) <tim@timwise.co.uk>
Tim Howes (timhowes) <timhowes@berkeley.edu>
Tobias Nygren (tnn2) <tnn@nygren.pp.se>
Tobias Tom (tobiastom) <t.tom@succont.de>
Tom Jakubowski <tom@crystae.net>
Tomas Cerveny (kozec) <kozec@kozec.com>
Tommy Thorn <tommy-github-email@thorn.ws>
Tully Robinson (tojrobinson) <tully@tojr.org>

View File

@@ -1,4 +1,4 @@
FROM golang:1.12 AS builder
FROM golang:1.13 AS builder
WORKDIR /src
COPY . .
@@ -17,16 +17,12 @@ VOLUME ["/var/syncthing"]
RUN apk add --no-cache ca-certificates su-exec
COPY --from=builder /src/syncthing /bin/syncthing
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000
ENV PUID=1000 PGID=1000 HOME=/var/syncthing
HEALTHCHECK --interval=1m --timeout=10s \
CMD nc -z localhost 8384 || exit 1
ENTRYPOINT \
chown "${PUID}:${PGID}" /var/syncthing \
&& su-exec "${PUID}:${PGID}" \
env HOME=/var/syncthing \
/bin/syncthing \
-home /var/syncthing/config \
-gui-address 0.0.0.0:8384
ENV STGUIADDRESS=0.0.0.0:8384
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/syncthing", "-home", "/var/syncthing/config"]

28
Dockerfile.stdiscosrv Normal file
View File

@@ -0,0 +1,28 @@
FROM golang:1.13 AS builder
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f stdiscosrv && go run build.go -no-upgrade build stdiscosrv
FROM alpine
EXPOSE 19200 8443
VOLUME ["/var/stdiscosrv"]
RUN apk add --no-cache ca-certificates su-exec
COPY --from=builder /src/stdiscosrv /bin/stdiscosrv
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/stdiscosrv
HEALTHCHECK --interval=1m --timeout=10s \
CMD nc -z localhost 8443 || exit 1
WORKDIR /var/stdiscosrv
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/stdiscosrv"]

28
Dockerfile.strelaysrv Normal file
View File

@@ -0,0 +1,28 @@
FROM golang:1.13 AS builder
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f strelaysrv && go run build.go -no-upgrade build strelaysrv
FROM alpine
EXPOSE 22067 22070
VOLUME ["/var/strelaysrv"]
RUN apk add --no-cache ca-certificates su-exec
COPY --from=builder /src/strelaysrv /bin/strelaysrv
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/strelaysrv
HEALTHCHECK --interval=1m --timeout=10s \
CMD nc -z localhost 22067 || exit 1
WORKDIR /var/strelaysrv
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/strelaysrv"]

View File

@@ -18,7 +18,11 @@ $ docker run -p 8384:8384 -p 22000:22000 \
syncthing/syncthing:latest
```
Note that local device discovery will not work with the above command, resulting in poor local transfer rates if local device addresses are not manually configured.
## Discovery
Note that local device discovery will not work with the above command,
resulting in poor local transfer rates if local device addresses are not
manually configured.
To allow local discovery, the docker host network can be used instead:
@@ -32,3 +36,24 @@ $ docker run --network=host \
Be aware that syncthing alone is now in control of what interfaces and ports it
listens on. You can edit the syncthing configuration to change the defaults if
there are conflicts.
## GUI Security
By default Syncthing inside the Docker image listens on 0.0.0.0:8384 to
allow GUI connections via the Docker proxy. This is set by the
`STGUIADDRESS` environment variable in the Dockerfile, as it differs from
what Syncthing would otherwise use by default. This means you should set up
authentication in the GUI, like for any other externally reachable Syncthing
instance. If you do not require the GUI, or you use host networking, you can
unset the `STGUIADDRESS` variable to have Syncthing fall back to listening
on 127.0.0.1:
```
$ docker pull syncthing/syncthing
$ docker run -e STGUIADDRESS= \
-v /wherever/st-sync:/var/syncthing \
syncthing/syncthing:latest
```
With the environment variable unset Syncthing will follow what is set in the
configuration file / GUI settings dialog.

View File

@@ -2,7 +2,6 @@
---
[![Latest Downloads](https://img.shields.io/badge/latest-downloads-brightgreen.svg?style=flat-square)](https://build.syncthing.net/latest/)
[![Latest Linux & Cross Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildLinuxCross.svg?style=flat-square&label=linux+%26+cross+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildLinuxCross&guest=1)
[![Latest Windows Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildWindows.svg?style=flat-square&label=windows+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildWindows&guest=1)
[![Latest Mac Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildMac.svg?style=flat-square&label=mac+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildMac&guest=1)
@@ -63,6 +62,10 @@ There are a few examples for keeping Syncthing running in the background
on your system in [the etc directory][3]. There are also several [GUI
implementations][11] for Windows, Mac and Linux.
## Docker
To run Syncthing in Docker, see [the Docker README][16].
## Vote on features/bugs
We'd like to encourage you to [vote][12] on issues that matter to you.
@@ -111,4 +114,5 @@ All code is licensed under the [MPLv2 License][7].
[13]: https://github.com/syncthing/syncthing/blob/master/GOALS.md
[14]: assets/logo-text-128.png
[15]: https://syncthing.net/
[16]: https://github.com/syncthing/syncthing/blob/master/README-Docker.md

156
build.go
View File

@@ -24,6 +24,7 @@ import (
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"regexp"
"runtime"
@@ -34,34 +35,35 @@ import (
)
var (
versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
goarch string
goos string
noupgrade bool
version string
goCmd string
goVersion float64
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
debugBinary bool
coverage bool
timeout = "120s"
gogoProtoVersion = "v1.2.0"
versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
goarch string
goos string
noupgrade bool
version string
goCmd string
goVersion float64
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
debugBinary bool
coverage bool
timeout = "120s"
)
type target struct {
name string
debname string
debdeps []string
debpre string
debpost string
description string
buildPkg string
buildPkgs []string
binaryName string
archiveFiles []archiveFile
systemdServices []string
installationFiles []archiveFile
tags []string
}
@@ -75,9 +77,8 @@ type archiveFile struct {
var targets = map[string]target{
"all": {
// Only valid for the "build" and "install" commands as it lacks all
// the archive creation stuff.
buildPkg: "github.com/syncthing/syncthing/cmd/...",
tags: []string{"purego"},
// the archive creation stuff. buildPkgs gets filled out in init()
tags: []string{"purego"},
},
"syncthing": {
// The default target for "build", "install", "tar", "zip", "deb", etc.
@@ -86,7 +87,7 @@ var targets = map[string]target{
debdeps: []string{"libc6", "procps"},
debpost: "script/post-upgrade",
description: "Open Source Continuous File Synchronization",
buildPkg: "github.com/syncthing/syncthing/cmd/syncthing",
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},
@@ -128,8 +129,9 @@ var targets = map[string]target{
name: "stdiscosrv",
debname: "syncthing-discosrv",
debdeps: []string{"libc6"},
debpre: "cmd/stdiscosrv/scripts/preinst",
description: "Syncthing Discovery Server",
buildPkg: "github.com/syncthing/syncthing/cmd/stdiscosrv",
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},
@@ -137,12 +139,17 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdServices: []string{
"cmd/stdiscosrv/etc/linux-systemd/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/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},
},
tags: []string{"purego"},
},
@@ -150,8 +157,9 @@ var targets = map[string]target{
name: "strelaysrv",
debname: "syncthing-relaysrv",
debdeps: []string{"libc6"},
debpre: "cmd/strelaysrv/scripts/preinst",
description: "Syncthing Relay Server",
buildPkg: "github.com/syncthing/syncthing/cmd/strelaysrv",
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},
@@ -160,6 +168,9 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdServices: []string{
"cmd/strelaysrv/etc/linux-systemd/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},
@@ -167,6 +178,8 @@ var targets = map[string]target{
{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/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},
},
},
"strelaypoolsrv": {
@@ -174,7 +187,7 @@ var targets = map[string]target{
debname: "syncthing-relaypoolsrv",
debdeps: []string{"libc6"},
description: "Syncthing Relay Pool Server",
buildPkg: "github.com/syncthing/syncthing/cmd/strelaypoolsrv",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/strelaypoolsrv"},
binaryName: "strelaypoolsrv", // .exe will be added automatically for Windows builds
archiveFiles: []archiveFile{
{src: "{{binary}}", dst: "{{binary}}", perm: 0755},
@@ -200,11 +213,22 @@ type dependencyRepo struct {
}
var dependencyRepos = []dependencyRepo{
{path: "protobuf", repo: "https://github.com/gogo/protobuf.git", commit: gogoProtoVersion},
{path: "xdr", repo: "https://github.com/calmh/xdr.git", commit: "08e072f9cb16"},
}
func init() {
all := targets["all"]
pkgs, _ := filepath.Glob("cmd/*")
for _, pkg := range pkgs {
pkg = filepath.Base(pkg)
if strings.HasPrefix(pkg, ".") {
// ignore dotfiles
continue
}
all.buildPkgs = append(all.buildPkgs, fmt.Sprintf("github.com/syncthing/syncthing/cmd/%s", pkg))
}
targets["all"] = all
// The "syncthing" target includes a few more files found in the "etc"
// and "extra" dirs.
syncthingPkg := targets["syncthing"]
@@ -348,7 +372,7 @@ func test(pkgs ...string) {
}
if coverage {
args = append(args, "-covermode", "atomic", "-coverprofile", "coverage.txt")
args = append(args, "-covermode", "atomic", "-coverprofile", "coverage.txt", "-coverpkg", strings.Join(pkgs, ","))
}
runPrint(goCmd, append(args, pkgs...)...)
@@ -370,9 +394,6 @@ func install(target target, tags []string) {
}
os.Setenv("GOBIN", filepath.Join(cwd, "bin"))
args := []string{"install", "-v"}
args = appendParameters(args, tags, target)
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
os.Setenv("CC", cc)
@@ -388,19 +409,20 @@ func install(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
runPrint(goCmd, args...)
for _, pkg := range target.buildPkgs {
args := []string{"install", "-v"}
args = appendParameters(args, tags, pkg)
runPrint(goCmd, args...)
}
}
func build(target target, tags []string) {
lazyRebuildAssets()
tags = append(target.tags, tags...)
rmr(target.BinaryName())
args := []string{"build", "-v"}
args = appendParameters(args, tags, target)
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
os.Setenv("CC", cc)
@@ -420,10 +442,15 @@ func build(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
runPrint(goCmd, args...)
for _, pkg := range target.buildPkgs {
args := []string{"build", "-v"}
args = appendParameters(args, tags, pkg)
runPrint(goCmd, args...)
}
}
func appendParameters(args []string, tags []string, target target) []string {
func appendParameters(args []string, tags []string, pkg string) []string {
if pkgdir != "" {
args = append(args, "-pkgdir", pkgdir)
}
@@ -439,7 +466,7 @@ func appendParameters(args []string, tags []string, target target) []string {
if !debugBinary {
// Regular binaries get version tagged and skip some debug symbols
args = append(args, "-ldflags", ldflags())
args = append(args, "-ldflags", ldflags(path.Base(pkg)))
} else {
// -gcflags to disable optimizations and inlining. Skip -ldflags
// because `Could not launch program: decoding dwarf section info at
@@ -448,7 +475,7 @@ func appendParameters(args []string, tags []string, target target) []string {
args = append(args, "-gcflags", "-N -l")
}
return append(args, target.buildPkg)
return append(args, pkg)
}
func buildTar(target target) {
@@ -462,10 +489,7 @@ func buildTar(target target) {
}
build(target, tags)
if goos == "darwin" {
macosCodesign(target.BinaryName())
}
codesign(target)
for i := range target.archiveFiles {
target.archiveFiles[i].src = strings.Replace(target.archiveFiles[i].src, "{{binary}}", target.BinaryName(), 1)
@@ -488,10 +512,7 @@ func buildZip(target target) {
}
build(target, tags)
if goos == "windows" {
windowsCodesign(target.BinaryName())
}
codesign(target)
for i := range target.archiveFiles {
target.archiveFiles[i].src = strings.Replace(target.archiveFiles[i].src, "{{binary}}", target.BinaryName(), 1)
@@ -555,9 +576,15 @@ func buildDeb(target target) {
for _, dep := range target.debdeps {
args = append(args, "-d", dep)
}
for _, service := range target.systemdServices {
args = append(args, "--deb-systemd", service)
}
if target.debpost != "" {
args = append(args, "--after-upgrade", target.debpost)
}
if target.debpre != "" {
args = append(args, "--before-install", target.debpre)
}
runPrint("fpm", args...)
}
@@ -690,6 +717,7 @@ func listFiles(dir string) []string {
if err != nil {
return err
}
if fi.Mode().IsRegular() {
res = append(res, path)
}
@@ -736,14 +764,21 @@ func shouldRebuildAssets(target, srcdir string) bool {
}
func proto() {
runPrint(goCmd, "get", fmt.Sprintf("github.com/gogo/protobuf/protoc-gen-gogofast@%v", gogoProtoVersion))
pv := protobufVersion()
dependencyRepos = append(dependencyRepos,
dependencyRepo{path: "protobuf", repo: "https://github.com/gogo/protobuf.git", commit: pv},
)
runPrint(goCmd, "get", fmt.Sprintf("github.com/gogo/protobuf/protoc-gen-gogofast@%v", pv))
os.MkdirAll("repos", 0755)
for _, dep := range dependencyRepos {
path := filepath.Join("repos", dep.path)
if _, err := os.Stat(path); err != nil {
runPrintInDir("repos", "git", "clone", dep.repo, dep.path)
runPrintInDir(path, "git", "checkout", dep.commit)
} else {
runPrintInDir(path, "git", "fetch")
}
runPrintInDir(path, "git", "checkout", dep.commit)
}
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/stdiscosrv")
}
@@ -764,7 +799,7 @@ func transifex() {
runPrint(goCmd, "run", "../../../../script/transifexdl.go")
}
func ldflags() string {
func ldflags(program string) string {
sep := '='
if goVersion > 0 && goVersion < 1.5 {
sep = ' '
@@ -776,6 +811,10 @@ func ldflags() string {
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Stamp%c%d", sep, buildStamp())
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.User%c%s", sep, buildUser())
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Host%c%s", sep, buildHost())
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Program%c%s", sep, program)
if v := os.Getenv("EXTRA_LDFLAGS"); v != "" {
fmt.Fprintf(b, " %s", v)
}
return b.String()
}
@@ -1134,6 +1173,15 @@ func zipFile(out string, files []archiveFile) {
}
}
func codesign(target target) {
switch goos {
case "windows":
windowsCodesign(target.BinaryName())
case "darwin":
macosCodesign(target.BinaryName())
}
}
func macosCodesign(file string) {
if pass := os.Getenv("CODESIGN_KEYCHAIN_PASS"); pass != "" {
bs, err := runError("security", "unlock-keychain", "-p", pass)
@@ -1232,3 +1280,11 @@ func (t target) BinaryName() string {
}
return t.binaryName
}
func protobufVersion() string {
bs, err := runError(goCmd, "list", "-f", "{{.Version}}", "-m", "github.com/gogo/protobuf")
if err != nil {
log.Fatal("Getting protobuf version:", err)
}
return string(bs)
}

View File

@@ -1,143 +0,0 @@
// Copyright (C) 2016 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
// This doesn't build on Windows due to the Rusage stuff.
// +build !windows
package main
import (
"flag"
"fmt"
"log"
"runtime"
"syscall"
"time"
"github.com/syncthing/syncthing/lib/rc"
)
var homeDir = "h1"
var syncthingBin = "./bin/syncthing"
var test = "scan"
func main() {
flag.StringVar(&homeDir, "home", homeDir, "Home directory location")
flag.StringVar(&syncthingBin, "bin", syncthingBin, "Binary location")
flag.StringVar(&test, "test", test, "Test to run")
flag.Parse()
switch test {
case "scan":
// scan measures the resource usage required to perform the initial
// scan, without cleaning away the database first.
testScan()
}
}
// testScan starts a process and reports on the resource usage required to
// perform the initial scan.
func testScan() {
log.Println("Starting...")
p := rc.NewProcess("127.0.0.1:8081")
if err := p.Start(syncthingBin, "-home", homeDir, "-no-browser"); err != nil {
log.Println(err)
return
}
defer p.Stop()
wallTime := awaitScanComplete(p)
report(p, wallTime)
}
// awaitScanComplete waits for a folder to transition idle->scanning and
// then scanning->idle and returns the time taken for the scan.
func awaitScanComplete(p *rc.Process) time.Duration {
log.Println("Awaiting scan completion...")
var t0, t1 time.Time
lastEvent := 0
loop:
for {
evs, err := p.Events(lastEvent)
if err != nil {
continue
}
for _, ev := range evs {
if ev.Type == "StateChanged" {
data := ev.Data.(map[string]interface{})
log.Println(ev)
if data["to"].(string) == "scanning" {
t0 = ev.Time
continue
}
if !t0.IsZero() && data["to"].(string) == "idle" {
t1 = ev.Time
break loop
}
}
lastEvent = ev.ID
}
time.Sleep(250 * time.Millisecond)
}
return t1.Sub(t0)
}
// report stops the given process and reports on its resource usage in two
// ways: human readable to stderr, and CSV to stdout.
func report(p *rc.Process, wallTime time.Duration) {
sv, err := p.SystemVersion()
if err != nil {
log.Println(err)
return
}
ss, err := p.SystemStatus()
if err != nil {
log.Println(err)
return
}
proc, err := p.Stop()
if err != nil {
return
}
rusage, ok := proc.SysUsage().(*syscall.Rusage)
if !ok {
return
}
log.Println("Version:", sv.Version)
log.Println("Alloc:", ss.Alloc/1024, "KiB")
log.Println("Sys:", ss.Sys/1024, "KiB")
log.Println("Goroutines:", ss.Goroutines)
log.Println("Wall time:", wallTime)
log.Println("Utime:", time.Duration(rusage.Utime.Nano()))
log.Println("Stime:", time.Duration(rusage.Stime.Nano()))
if runtime.GOOS == "darwin" {
// Darwin reports in bytes, Linux seems to report in KiB even
// though the manpage says otherwise.
rusage.Maxrss /= 1024
}
log.Println("MaxRSS:", rusage.Maxrss, "KiB")
fmt.Printf("%s,%d,%d,%d,%.02f,%.02f,%.02f,%d\n",
sv.Version,
ss.Alloc/1024,
ss.Sys/1024,
ss.Goroutines,
wallTime.Seconds(),
time.Duration(rusage.Utime.Nano()).Seconds(),
time.Duration(rusage.Stime.Nano()).Seconds(),
rusage.Maxrss)
}

View File

@@ -14,7 +14,6 @@ import (
"log"
"os"
"reflect"
"strings"
"github.com/AudriusButkevicius/recli"
"github.com/flynn-archive/go-shlex"
@@ -22,6 +21,7 @@ import (
"github.com/pkg/errors"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/urfave/cli"
@@ -85,7 +85,7 @@ func main() {
myID := protocol.NewDeviceID(cert.Certificate[0])
// Load the config
cfg, err := config.Load(locations.Get(locations.ConfigFile), myID)
cfg, err := config.Load(locations.Get(locations.ConfigFile), myID, events.NoopLogger)
if err != nil {
log.Fatalln(errors.Wrap(err, "loading config"))
}
@@ -127,7 +127,7 @@ func main() {
app.HelpName = app.Name
app.Author = "The Syncthing Authors"
app.Usage = "Syncthing command line interface"
app.Version = strings.Replace(build.LongVersion, "syncthing", app.Name, 1)
app.Version = build.Version
app.Flags = fakeFlags
app.Metadata = map[string]interface{}{
"client": client,

View File

@@ -12,7 +12,6 @@ import (
"io/ioutil"
"net/http"
"os"
"text/tabwriter"
"github.com/syncthing/syncthing/lib/config"
"github.com/urfave/cli"
@@ -45,12 +44,6 @@ func dumpOutput(url string) cli.ActionFunc {
}
}
func newTableWriter() *tabwriter.Writer {
writer := new(tabwriter.Writer)
writer.Init(os.Stdout, 0, 8, 0, '\t', 0)
return writer
}
func getConfig(c *APIClient) (config.Configuration, error) {
cfg := config.Configuration{}
response, err := c.Get("system/config")

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"bytes"
"errors"
"io/ioutil"
"regexp"
"strings"
"sync"
raven "github.com/getsentry/raven-go"
"github.com/maruel/panicparse/stack"
)
const reportServer = "https://crash.syncthing.net/report/"
var loader = newGithubSourceCodeLoader()
func init() {
raven.SetSourceCodeLoader(loader)
}
var (
clients = make(map[string]*raven.Client)
clientsMut sync.Mutex
)
func sendReport(dsn, path string, report []byte) error {
pkt, err := parseReport(path, report)
if err != nil {
return err
}
clientsMut.Lock()
defer clientsMut.Unlock()
cli, ok := clients[dsn]
if !ok {
cli, err = raven.New(dsn)
if err != nil {
return err
}
clients[dsn] = cli
}
// The client sets release and such on the packet before sending, in the
// misguided idea that it knows this better than than the packet we give
// it. So we copy the values from the packet to the client first...
cli.SetRelease(pkt.Release)
cli.SetEnvironment(pkt.Environment)
defer cli.Wait()
_, errC := cli.Capture(pkt, nil)
return <-errC
}
func parseReport(path string, report []byte) (*raven.Packet, error) {
parts := bytes.SplitN(report, []byte("\n"), 2)
if len(parts) != 2 {
return nil, errors.New("no first line")
}
version, err := parseVersion(string(parts[0]))
if err != nil {
return nil, err
}
report = parts[1]
foundPanic := false
var subjectLine []byte
for {
parts = bytes.SplitN(report, []byte("\n"), 2)
if len(parts) != 2 {
return nil, errors.New("no panic line found")
}
line := parts[0]
report = parts[1]
if foundPanic {
// The previous line was our "Panic at ..." header. We are now
// at the beginning of the real panic trace and this is our
// subject line.
subjectLine = line
break
} else if bytes.HasPrefix(line, []byte("Panic at")) {
foundPanic = true
}
}
r := bytes.NewReader(report)
ctx, err := stack.ParseDump(r, ioutil.Discard, false)
if err != nil {
return nil, err
}
// Lock the source code loader to the version we are processing here.
if version.commit != "" {
// We have a commit hash, so we know exactly which source to use
loader.LockWithVersion(version.commit)
} else if strings.HasPrefix(version.tag, "v") {
// Lets hope the tag is close enough
loader.LockWithVersion(version.tag)
} else {
// Last resort
loader.LockWithVersion("master")
}
defer loader.Unlock()
var trace raven.Stacktrace
for _, gr := range ctx.Goroutines {
if gr.First {
trace.Frames = make([]*raven.StacktraceFrame, len(gr.Stack.Calls))
for i, sc := range gr.Stack.Calls {
trace.Frames[len(trace.Frames)-1-i] = raven.NewStacktraceFrame(0, sc.Func.Name(), sc.SrcPath, sc.Line, 3, nil)
}
break
}
}
pkt := &raven.Packet{
Message: string(subjectLine),
Platform: "go",
Release: version.tag,
Environment: version.environment(),
Tags: raven.Tags{
raven.Tag{Key: "version", Value: version.version},
raven.Tag{Key: "tag", Value: version.tag},
raven.Tag{Key: "codename", Value: version.codename},
raven.Tag{Key: "runtime", Value: version.runtime},
raven.Tag{Key: "goos", Value: version.goos},
raven.Tag{Key: "goarch", Value: version.goarch},
raven.Tag{Key: "builder", Value: version.builder},
},
Extra: raven.Extra{
"url": reportServer + path,
},
Interfaces: []raven.Interface{&trace},
}
if version.commit != "" {
pkt.Tags = append(pkt.Tags, raven.Tag{Key: "commit", Value: version.commit})
}
return pkt, nil
}
// syncthing v1.1.4-rc.1+30-g6aaae618-dirty-crashrep "Erbium Earthworm" (go1.12.5 darwin-amd64) jb@kvin.kastelo.net 2019-05-23 16:08:14 UTC
var longVersionRE = regexp.MustCompile(`syncthing\s+(v[^\s]+)\s+"([^"]+)"\s\(([^\s]+)\s+([^-]+)-([^)]+)\)\s+([^\s]+)`)
type version struct {
version string // "v1.1.4-rc.1+30-g6aaae618-dirty-crashrep"
tag string // "v1.1.4-rc.1"
commit string // "6aaae618", blank when absent
codename string // "Erbium Earthworm"
runtime string // "go1.12.5"
goos string // "darwin"
goarch string // "amd64"
builder string // "jb@kvin.kastelo.net"
}
func (v version) environment() string {
if v.commit != "" {
return "Development"
}
if strings.Contains(v.tag, "-rc.") {
return "Candidate"
}
if strings.Contains(v.tag, "-") {
return "Beta"
}
return "Stable"
}
func parseVersion(line string) (version, error) {
m := longVersionRE.FindStringSubmatch(line)
if len(m) == 0 {
return version{}, errors.New("unintelligeble version string")
}
v := version{
version: m[1],
codename: m[2],
runtime: m[3],
goos: m[4],
goarch: m[5],
builder: m[6],
}
parts := strings.Split(v.version, "+")
v.tag = parts[0]
if len(parts) > 1 {
fields := strings.Split(parts[1], "-")
if len(fields) >= 2 && strings.HasPrefix(fields[1], "g") {
v.commit = fields[1][1:]
}
}
return v, nil
}

View File

@@ -0,0 +1,64 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"fmt"
"io/ioutil"
"testing"
)
func TestParseVersion(t *testing.T) {
cases := []struct {
longVersion string
parsed version
}{
{
longVersion: `syncthing v1.1.4-rc.1+30-g6aaae618-dirty-crashrep "Erbium Earthworm" (go1.12.5 darwin-amd64) jb@kvin.kastelo.net 2019-05-23 16:08:14 UTC`,
parsed: version{
version: "v1.1.4-rc.1+30-g6aaae618-dirty-crashrep",
tag: "v1.1.4-rc.1",
commit: "6aaae618",
codename: "Erbium Earthworm",
runtime: "go1.12.5",
goos: "darwin",
goarch: "amd64",
builder: "jb@kvin.kastelo.net",
},
},
}
for _, tc := range cases {
v, err := parseVersion(tc.longVersion)
if err != nil {
t.Error(err)
continue
}
if v != tc.parsed {
t.Error(v)
}
}
}
func TestParseReport(t *testing.T) {
bs, err := ioutil.ReadFile("_testdata/panic.log")
if err != nil {
t.Fatal(err)
}
pkt, err := parseReport("1/2/345", bs)
if err != nil {
t.Fatal(err)
}
bs, err = pkt.JSON()
if err != nil {
t.Fatal(err)
}
fmt.Printf("%s\n", bs)
}

View File

@@ -0,0 +1,114 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
"sync"
"time"
)
const (
urlPrefix = "https://raw.githubusercontent.com/syncthing/syncthing/"
httpTimeout = 10 * time.Second
)
type githubSourceCodeLoader struct {
mut sync.Mutex
version string
cache map[string]map[string][][]byte // version -> file -> lines
client *http.Client
}
func newGithubSourceCodeLoader() *githubSourceCodeLoader {
return &githubSourceCodeLoader{
cache: make(map[string]map[string][][]byte),
client: &http.Client{Timeout: httpTimeout},
}
}
func (l *githubSourceCodeLoader) LockWithVersion(version string) {
l.mut.Lock()
l.version = version
if _, ok := l.cache[version]; !ok {
l.cache[version] = make(map[string][][]byte)
}
}
func (l *githubSourceCodeLoader) Unlock() {
l.mut.Unlock()
}
func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]byte, int) {
filename = filepath.ToSlash(filename)
lines, ok := l.cache[l.version][filename]
if !ok {
// Cache whatever we managed to find (or nil if nothing, so we don't try again)
defer func() {
l.cache[l.version][filename] = lines
}()
knownPrefixes := []string{"/lib/", "/cmd/"}
var idx int
for _, pref := range knownPrefixes {
idx = strings.Index(filename, pref)
if idx >= 0 {
break
}
}
if idx == -1 {
return nil, 0
}
url := urlPrefix + l.version + filename[idx:]
resp, err := l.client.Get(url)
if err != nil || resp.StatusCode != http.StatusOK {
fmt.Println("Loading source:", err.Error())
return nil, 0
}
data, err := ioutil.ReadAll(resp.Body)
_ = resp.Body.Close()
if err != nil {
fmt.Println("Loading source:", err.Error())
return nil, 0
}
lines = bytes.Split(data, []byte{'\n'})
}
return getLineFromLines(lines, line, context)
}
func getLineFromLines(lines [][]byte, line, context int) ([][]byte, int) {
if lines == nil {
// cached error from ReadFile: return no lines
return nil, 0
}
line-- // stack trace lines are 1-indexed
start := line - context
var idx int
if start < 0 {
start = 0
idx = line
} else {
idx = context
}
end := line + context + 1
if line >= len(lines) {
return nil, 0
}
if end > len(lines) {
end = len(lines)
}
return lines[start:end], idx
}

View File

@@ -0,0 +1,160 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
// Command stcrashreceiver is a trivial HTTP server that allows two things:
//
// - uploading files (crash reports) named like a SHA256 hash using a PUT request
// - checking whether such file exists using a HEAD request
//
// Typically this should be deployed behind something that manages HTTPS.
package main
import (
"bytes"
"compress/gzip"
"flag"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
const maxRequestSize = 1 << 20 // 1 MiB
func main() {
dir := flag.String("dir", ".", "Directory to store reports in")
dsn := flag.String("dsn", "", "Sentry DSN")
listen := flag.String("listen", ":22039", "HTTP listen address")
flag.Parse()
cr := &crashReceiver{
dir: *dir,
dsn: *dsn,
}
log.SetOutput(os.Stdout)
if err := http.ListenAndServe(*listen, cr); err != nil {
log.Fatalln("HTTP serve:", err)
}
}
type crashReceiver struct {
dir string
dsn string
}
func (r *crashReceiver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// The final path component should be a SHA256 hash in hex, so 64 hex
// characters. We don't care about case on the request but use lower
// case internally.
reportID := strings.ToLower(path.Base(req.URL.Path))
if len(reportID) != 64 {
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
for _, c := range reportID {
if c >= 'a' && c <= 'f' {
continue
}
if c >= '0' && c <= '9' {
continue
}
http.Error(w, "Bad request", http.StatusBadRequest)
return
}
// The location of the report on disk, compressed
fullPath := filepath.Join(r.dir, r.dirFor(reportID), reportID) + ".gz"
switch req.Method {
case http.MethodGet:
r.serveGet(fullPath, w, req)
case http.MethodHead:
r.serveHead(fullPath, w, req)
case http.MethodPut:
r.servePut(reportID, fullPath, w, req)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
// serveGet responds to GET requests by serving the uncompressed report.
func (r *crashReceiver) serveGet(fullPath string, w http.ResponseWriter, _ *http.Request) {
fd, err := os.Open(fullPath)
if err != nil {
http.Error(w, "Not found", http.StatusNotFound)
return
}
defer fd.Close()
gr, err := gzip.NewReader(fd)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
_, _ = io.Copy(w, gr) // best effort
}
// serveHead responds to HEAD requests by checking if the named report
// already exists in the system.
func (r *crashReceiver) serveHead(fullPath string, w http.ResponseWriter, _ *http.Request) {
if _, err := os.Lstat(fullPath); err != nil {
http.Error(w, "Not found", http.StatusNotFound)
}
}
// servePut accepts and stores the given report.
func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWriter, req *http.Request) {
// Ensure the destination directory exists
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
log.Println("Creating directory:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// Read at most maxRequestSize of report data.
log.Println("Receiving report", reportID)
lr := io.LimitReader(req.Body, maxRequestSize)
bs, err := ioutil.ReadAll(lr)
if err != nil {
log.Println("Reading report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// Compress the report for storage
buf := new(bytes.Buffer)
gw := gzip.NewWriter(buf)
_, _ = gw.Write(bs) // can't fail
gw.Close()
// Create an output file with the compressed report
err = ioutil.WriteFile(fullPath, buf.Bytes(), 0644)
if err != nil {
log.Println("Saving report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// Send the report to Sentry
if r.dsn != "" {
go func() {
// There's no need for the client to have to wait for this part.
if err := sendReport(r.dsn, reportID, bs); err != nil {
log.Println("Failed to send report:", err)
}
}()
}
}
// 01234567890abcdef... => 01/23
func (r *crashReceiver) dirFor(base string) string {
return filepath.Join(base[0:2], base[2:4])
}

View File

@@ -18,6 +18,7 @@ import (
"net"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"sync"
@@ -279,6 +280,10 @@ func (s *apiSrv) handleAnnounce(remote net.IP, deviceID protocol.DeviceID, addre
dbAddrs[i].Expires = expire
}
// The address slice must always be sorted for database merges to work
// properly.
sort.Sort(databaseAddressOrder(dbAddrs))
seen := now.UnixNano()
if s.repl != nil {
s.repl.send(key, dbAddrs, seen)
@@ -295,28 +300,66 @@ func certificateBytes(req *http.Request) []byte {
return req.TLS.PeerCertificates[0].Raw
}
var bs []byte
if hdr := req.Header.Get("X-SSL-Cert"); hdr != "" {
bs := []byte(hdr)
// The certificate is in PEM format but with spaces for newlines. We
// need to reinstate the newlines for the PEM decoder. But we need to
// leave the spaces in the BEGIN and END lines - the first and last
// space - alone.
firstSpace := bytes.Index(bs, []byte(" "))
lastSpace := bytes.LastIndex(bs, []byte(" "))
for i := firstSpace + 1; i < lastSpace; i++ {
if bs[i] == ' ' {
bs[i] = '\n'
if strings.Contains(hdr, "%") {
// Nginx using $ssl_client_escaped_cert
// The certificate is in PEM format with url encoding.
// We need to decode for the PEM decoder
hdr, err := url.QueryUnescape(hdr)
if err != nil {
// Decoding failed
return nil
}
bs = []byte(hdr)
} else {
// Nginx using $ssl_client_cert
// The certificate is in PEM format but with spaces for newlines. We
// need to reinstate the newlines for the PEM decoder. But we need to
// leave the spaces in the BEGIN and END lines - the first and last
// space - alone.
bs = []byte(hdr)
firstSpace := bytes.Index(bs, []byte(" "))
lastSpace := bytes.LastIndex(bs, []byte(" "))
for i := firstSpace + 1; i < lastSpace; i++ {
if bs[i] == ' ' {
bs[i] = '\n'
}
}
}
block, _ := pem.Decode(bs)
if block == nil {
} else if hdr := req.Header.Get("X-Forwarded-Tls-Client-Cert"); hdr != "" {
// Traefik 2 passtlsclientcert
// The certificate is in PEM format with url encoding but without newlines
// and start/end statements. We need to decode, reinstate the newlines every 64
// character and add statements for the PEM decoder
hdr, err := url.QueryUnescape(hdr)
if err != nil {
// Decoding failed
return nil
}
return block.Bytes
for i := 64; i < len(hdr); i += 65 {
hdr = hdr[:i] + "\n" + hdr[i:]
}
hdr = "-----BEGIN CERTIFICATE-----\n" + hdr
hdr = hdr + "\n-----END CERTIFICATE-----\n"
bs = []byte(hdr)
}
return nil
if bs == nil {
return nil
}
block, _ := pem.Decode(bs)
if block == nil {
// Decoding failed
return nil
}
return block.Bytes
}
// fixupAddresses checks the list of addresses, removing invalid ones and

View File

@@ -10,6 +10,7 @@
package main
import (
"log"
"sort"
"time"
@@ -263,12 +264,15 @@ func (s *levelDBStore) Stop() {
// chosen for any duplicates.
func merge(a, b DatabaseRecord) DatabaseRecord {
// Both lists must be sorted for this to work.
sort.Slice(a.Addresses, func(i, j int) bool {
return a.Addresses[i].Address < a.Addresses[j].Address
})
sort.Slice(b.Addresses, func(i, j int) bool {
return b.Addresses[i].Address < b.Addresses[j].Address
})
if !sort.IsSorted(databaseAddressOrder(a.Addresses)) {
log.Println("Warning: bug: addresses not correctly sorted in merge")
a.Addresses = sortedAddressCopy(a.Addresses)
}
if !sort.IsSorted(databaseAddressOrder(b.Addresses)) {
// no warning because this is the side we read from disk and it may
// legitimately predate correct sorting.
b.Addresses = sortedAddressCopy(b.Addresses)
}
res := DatabaseRecord{
Addresses: make([]DatabaseAddress, 0, len(a.Addresses)+len(b.Addresses)),
@@ -352,3 +356,24 @@ func expire(addrs []DatabaseAddress, now int64) []DatabaseAddress {
}
return addrs
}
func sortedAddressCopy(addrs []DatabaseAddress) []DatabaseAddress {
sorted := make([]DatabaseAddress, len(addrs))
copy(sorted, addrs)
sort.Sort(databaseAddressOrder(sorted))
return sorted
}
type databaseAddressOrder []DatabaseAddress
func (s databaseAddressOrder) Less(a, b int) bool {
return s[a].Address < s[b].Address
}
func (s databaseAddressOrder) Swap(a, b int) {
s[a], s[b] = s[b], s[a]
}
func (s databaseAddressOrder) Len() int {
return len(s)
}

View File

@@ -3,12 +3,14 @@
package main
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -19,7 +21,7 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type DatabaseRecord struct {
Addresses []DatabaseAddress `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses"`
@@ -32,7 +34,7 @@ func (m *DatabaseRecord) Reset() { *m = DatabaseRecord{} }
func (m *DatabaseRecord) String() string { return proto.CompactTextString(m) }
func (*DatabaseRecord) ProtoMessage() {}
func (*DatabaseRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_database_0f49e029703a04f5, []int{0}
return fileDescriptor_b90fe3356ea5df07, []int{0}
}
func (m *DatabaseRecord) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -42,15 +44,15 @@ func (m *DatabaseRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro
return xxx_messageInfo_DatabaseRecord.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *DatabaseRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_DatabaseRecord.Merge(dst, src)
func (m *DatabaseRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_DatabaseRecord.Merge(m, src)
}
func (m *DatabaseRecord) XXX_Size() int {
return m.Size()
@@ -71,7 +73,7 @@ func (m *ReplicationRecord) Reset() { *m = ReplicationRecord{} }
func (m *ReplicationRecord) String() string { return proto.CompactTextString(m) }
func (*ReplicationRecord) ProtoMessage() {}
func (*ReplicationRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_database_0f49e029703a04f5, []int{1}
return fileDescriptor_b90fe3356ea5df07, []int{1}
}
func (m *ReplicationRecord) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -81,15 +83,15 @@ func (m *ReplicationRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, e
return xxx_messageInfo_ReplicationRecord.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *ReplicationRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReplicationRecord.Merge(dst, src)
func (m *ReplicationRecord) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReplicationRecord.Merge(m, src)
}
func (m *ReplicationRecord) XXX_Size() int {
return m.Size()
@@ -109,7 +111,7 @@ func (m *DatabaseAddress) Reset() { *m = DatabaseAddress{} }
func (m *DatabaseAddress) String() string { return proto.CompactTextString(m) }
func (*DatabaseAddress) ProtoMessage() {}
func (*DatabaseAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_database_0f49e029703a04f5, []int{2}
return fileDescriptor_b90fe3356ea5df07, []int{2}
}
func (m *DatabaseAddress) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -119,15 +121,15 @@ func (m *DatabaseAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, err
return xxx_messageInfo_DatabaseAddress.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *DatabaseAddress) XXX_Merge(src proto.Message) {
xxx_messageInfo_DatabaseAddress.Merge(dst, src)
func (m *DatabaseAddress) XXX_Merge(src proto.Message) {
xxx_messageInfo_DatabaseAddress.Merge(m, src)
}
func (m *DatabaseAddress) XXX_Size() int {
return m.Size()
@@ -143,10 +145,34 @@ func init() {
proto.RegisterType((*ReplicationRecord)(nil), "main.ReplicationRecord")
proto.RegisterType((*DatabaseAddress)(nil), "main.DatabaseAddress")
}
func init() { proto.RegisterFile("database.proto", fileDescriptor_b90fe3356ea5df07) }
var fileDescriptor_b90fe3356ea5df07 = []byte{
// 270 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x90, 0x41, 0x4a, 0xc4, 0x30,
0x18, 0x85, 0x9b, 0x49, 0x1d, 0x99, 0x08, 0xa3, 0x06, 0x94, 0x20, 0x12, 0x4b, 0xdd, 0x74, 0xd5,
0x01, 0x5d, 0xb9, 0x74, 0xd0, 0x0b, 0xe4, 0x06, 0xe9, 0xe4, 0x77, 0x08, 0x3a, 0x4d, 0x49, 0x2a,
0xe8, 0x29, 0xf4, 0x58, 0x5d, 0xce, 0xd2, 0x95, 0x68, 0x7b, 0x11, 0x69, 0x26, 0x55, 0x14, 0x37,
0xb3, 0x7b, 0xdf, 0xff, 0xbf, 0x97, 0xbc, 0x84, 0x4c, 0x95, 0xac, 0x65, 0x21, 0x1d, 0xe4, 0x95,
0x35, 0xb5, 0xa1, 0xf1, 0x4a, 0xea, 0xf2, 0xe4, 0xdc, 0x42, 0x65, 0xdc, 0xcc, 0x8f, 0x8a, 0xc7,
0xbb, 0xd9, 0xd2, 0x2c, 0x8d, 0x07, 0xaf, 0x36, 0xd6, 0xf4, 0x05, 0x91, 0xe9, 0x4d, 0x48, 0x0b,
0x58, 0x18, 0xab, 0xe8, 0x15, 0x99, 0x48, 0xa5, 0x2c, 0x38, 0x07, 0x8e, 0xa1, 0x04, 0x67, 0x7b,
0x17, 0x47, 0x79, 0x7f, 0x62, 0x3e, 0x18, 0xaf, 0x37, 0xeb, 0x79, 0xdc, 0xbc, 0x9f, 0x45, 0xe2,
0xc7, 0x4d, 0x8f, 0xc9, 0x78, 0xa5, 0x7d, 0x6e, 0x94, 0xa0, 0x6c, 0x47, 0x04, 0xa2, 0x94, 0xc4,
0x0e, 0xa0, 0x64, 0x38, 0x41, 0x19, 0x16, 0x5e, 0x7f, 0x7b, 0x15, 0x8b, 0xfd, 0x34, 0x50, 0x5a,
0x93, 0x43, 0x01, 0xd5, 0x83, 0x5e, 0xc8, 0x5a, 0x9b, 0x32, 0x74, 0x3a, 0x20, 0xf8, 0x1e, 0x9e,
0x19, 0x4a, 0x50, 0x36, 0x11, 0xbd, 0xfc, 0xdd, 0x72, 0xb4, 0x55, 0xcb, 0x7f, 0xda, 0xa4, 0xb7,
0x64, 0xff, 0x4f, 0x8e, 0x32, 0xb2, 0x1b, 0x32, 0xe1, 0xde, 0x01, 0xfb, 0x0d, 0x3c, 0x55, 0xda,
0x86, 0x77, 0x62, 0x31, 0xe0, 0xfc, 0xb4, 0xf9, 0xe4, 0x51, 0xd3, 0x72, 0xb4, 0x6e, 0x39, 0xfa,
0x68, 0x39, 0x7a, 0xed, 0x78, 0xb4, 0xee, 0x78, 0xf4, 0xd6, 0xf1, 0xa8, 0x18, 0xfb, 0x3f, 0xbf,
0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x7a, 0xa2, 0xf6, 0x1e, 0xb0, 0x01, 0x00, 0x00,
}
func (m *DatabaseRecord) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
@@ -154,44 +180,51 @@ func (m *DatabaseRecord) Marshal() (dAtA []byte, err error) {
}
func (m *DatabaseRecord) MarshalTo(dAtA []byte) (int, error) {
var i int
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *DatabaseRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Addresses) > 0 {
for _, msg := range m.Addresses {
dAtA[i] = 0xa
i++
i = encodeVarintDatabase(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
if m.Misses != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintDatabase(dAtA, i, uint64(m.Misses))
if m.Missed != 0 {
i = encodeVarintDatabase(dAtA, i, uint64(m.Missed))
i--
dAtA[i] = 0x20
}
if m.Seen != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintDatabase(dAtA, i, uint64(m.Seen))
i--
dAtA[i] = 0x18
}
if m.Missed != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintDatabase(dAtA, i, uint64(m.Missed))
if m.Misses != 0 {
i = encodeVarintDatabase(dAtA, i, uint64(m.Misses))
i--
dAtA[i] = 0x10
}
return i, nil
if len(m.Addresses) > 0 {
for iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Addresses[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintDatabase(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *ReplicationRecord) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
@@ -199,40 +232,48 @@ func (m *ReplicationRecord) Marshal() (dAtA []byte, err error) {
}
func (m *ReplicationRecord) MarshalTo(dAtA []byte) (int, error) {
var i int
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *ReplicationRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Key) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintDatabase(dAtA, i, uint64(len(m.Key)))
i += copy(dAtA[i:], m.Key)
if m.Seen != 0 {
i = encodeVarintDatabase(dAtA, i, uint64(m.Seen))
i--
dAtA[i] = 0x18
}
if len(m.Addresses) > 0 {
for _, msg := range m.Addresses {
dAtA[i] = 0x12
i++
i = encodeVarintDatabase(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
for iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Addresses[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintDatabase(dAtA, i, uint64(size))
}
i += n
i--
dAtA[i] = 0x12
}
}
if m.Seen != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintDatabase(dAtA, i, uint64(m.Seen))
if len(m.Key) > 0 {
i -= len(m.Key)
copy(dAtA[i:], m.Key)
i = encodeVarintDatabase(dAtA, i, uint64(len(m.Key)))
i--
dAtA[i] = 0xa
}
return i, nil
return len(dAtA) - i, nil
}
func (m *DatabaseAddress) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
@@ -240,32 +281,40 @@ func (m *DatabaseAddress) Marshal() (dAtA []byte, err error) {
}
func (m *DatabaseAddress) MarshalTo(dAtA []byte) (int, error) {
var i int
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *DatabaseAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Address) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintDatabase(dAtA, i, uint64(len(m.Address)))
i += copy(dAtA[i:], m.Address)
}
if m.Expires != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintDatabase(dAtA, i, uint64(m.Expires))
i--
dAtA[i] = 0x10
}
return i, nil
if len(m.Address) > 0 {
i -= len(m.Address)
copy(dAtA[i:], m.Address)
i = encodeVarintDatabase(dAtA, i, uint64(len(m.Address)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintDatabase(dAtA []byte, offset int, v uint64) int {
offset -= sovDatabase(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
return base
}
func (m *DatabaseRecord) Size() (n int) {
if m == nil {
@@ -330,14 +379,7 @@ func (m *DatabaseAddress) Size() (n int) {
}
func sovDatabase(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
return (math_bits.Len64(x|1) + 6) / 7
}
func sozDatabase(x uint64) (n int) {
return sovDatabase(uint64((x << 1) ^ uint64((int64(x) >> 63))))
@@ -357,7 +399,7 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -385,7 +427,7 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -394,6 +436,9 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
return ErrInvalidLengthDatabase
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthDatabase
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
@@ -416,7 +461,7 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.Misses |= (int32(b) & 0x7F) << shift
m.Misses |= int32(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -435,7 +480,7 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.Seen |= (int64(b) & 0x7F) << shift
m.Seen |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -454,7 +499,7 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.Missed |= (int64(b) & 0x7F) << shift
m.Missed |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -468,6 +513,9 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
@@ -495,7 +543,7 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -523,7 +571,7 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -533,6 +581,9 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
return ErrInvalidLengthDatabase
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthDatabase
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
@@ -552,7 +603,7 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -561,6 +612,9 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
return ErrInvalidLengthDatabase
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthDatabase
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
@@ -583,7 +637,7 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.Seen |= (int64(b) & 0x7F) << shift
m.Seen |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -597,6 +651,9 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
@@ -624,7 +681,7 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -652,7 +709,7 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -662,6 +719,9 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
return ErrInvalidLengthDatabase
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthDatabase
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
@@ -681,7 +741,7 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.Expires |= (int64(b) & 0x7F) << shift
m.Expires |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
@@ -695,6 +755,9 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
@@ -710,6 +773,7 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
func skipDatabase(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
@@ -741,10 +805,8 @@ func skipDatabase(dAtA []byte) (n int, err error) {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
@@ -761,76 +823,34 @@ func skipDatabase(dAtA []byte) (n int, err error) {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthDatabase
}
return iNdEx, nil
iNdEx += length
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowDatabase
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipDatabase(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
depth++
case 4:
return iNdEx, nil
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupDatabase
}
depth--
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthDatabase
}
if depth == 0 {
return iNdEx, nil
}
}
panic("unreachable")
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthDatabase = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowDatabase = fmt.Errorf("proto: integer overflow")
ErrInvalidLengthDatabase = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowDatabase = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupDatabase = fmt.Errorf("proto: unexpected end of group")
)
func init() { proto.RegisterFile("database.proto", fileDescriptor_database_0f49e029703a04f5) }
var fileDescriptor_database_0f49e029703a04f5 = []byte{
// 270 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x90, 0x41, 0x4a, 0xc4, 0x30,
0x18, 0x85, 0x9b, 0x49, 0x1d, 0x99, 0x08, 0xa3, 0x06, 0x94, 0x20, 0x12, 0x4b, 0xdd, 0x74, 0xd5,
0x01, 0x5d, 0xb9, 0x74, 0xd0, 0x0b, 0xe4, 0x06, 0xe9, 0xe4, 0x77, 0x08, 0x3a, 0x4d, 0x49, 0x2a,
0xe8, 0x29, 0xf4, 0x58, 0x5d, 0xce, 0xd2, 0x95, 0x68, 0x7b, 0x11, 0x69, 0x26, 0x55, 0x14, 0x37,
0xb3, 0x7b, 0xdf, 0xff, 0xbf, 0x97, 0xbc, 0x84, 0x4c, 0x95, 0xac, 0x65, 0x21, 0x1d, 0xe4, 0x95,
0x35, 0xb5, 0xa1, 0xf1, 0x4a, 0xea, 0xf2, 0xe4, 0xdc, 0x42, 0x65, 0xdc, 0xcc, 0x8f, 0x8a, 0xc7,
0xbb, 0xd9, 0xd2, 0x2c, 0x8d, 0x07, 0xaf, 0x36, 0xd6, 0xf4, 0x05, 0x91, 0xe9, 0x4d, 0x48, 0x0b,
0x58, 0x18, 0xab, 0xe8, 0x15, 0x99, 0x48, 0xa5, 0x2c, 0x38, 0x07, 0x8e, 0xa1, 0x04, 0x67, 0x7b,
0x17, 0x47, 0x79, 0x7f, 0x62, 0x3e, 0x18, 0xaf, 0x37, 0xeb, 0x79, 0xdc, 0xbc, 0x9f, 0x45, 0xe2,
0xc7, 0x4d, 0x8f, 0xc9, 0x78, 0xa5, 0x7d, 0x6e, 0x94, 0xa0, 0x6c, 0x47, 0x04, 0xa2, 0x94, 0xc4,
0x0e, 0xa0, 0x64, 0x38, 0x41, 0x19, 0x16, 0x5e, 0x7f, 0x7b, 0x15, 0x8b, 0xfd, 0x34, 0x50, 0x5a,
0x93, 0x43, 0x01, 0xd5, 0x83, 0x5e, 0xc8, 0x5a, 0x9b, 0x32, 0x74, 0x3a, 0x20, 0xf8, 0x1e, 0x9e,
0x19, 0x4a, 0x50, 0x36, 0x11, 0xbd, 0xfc, 0xdd, 0x72, 0xb4, 0x55, 0xcb, 0x7f, 0xda, 0xa4, 0xb7,
0x64, 0xff, 0x4f, 0x8e, 0x32, 0xb2, 0x1b, 0x32, 0xe1, 0xde, 0x01, 0xfb, 0x0d, 0x3c, 0x55, 0xda,
0x86, 0x77, 0x62, 0x31, 0xe0, 0xfc, 0xb4, 0xf9, 0xe4, 0x51, 0xd3, 0x72, 0xb4, 0x6e, 0x39, 0xfa,
0x68, 0x39, 0x7a, 0xed, 0x78, 0xb4, 0xee, 0x78, 0xf4, 0xd6, 0xf1, 0xa8, 0x18, 0xfb, 0x3f, 0xbf,
0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x7a, 0xa2, 0xf6, 0x1e, 0xb0, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,4 @@
[stdiscosrv]
title=Syncthing discovery server
description=Lets syncthing clients discover each other
ports=8443/tcp

View File

@@ -0,0 +1,3 @@
# Default settings for syncthing-relaysrv (strelaysrv).
## Add Options here:
DISCOSRV_OPTS=

View File

@@ -0,0 +1,25 @@
[Unit]
Description=Syncthing Discovery Server
After=network.target
Documentation=man:stdiscosrv(1)
[Service]
WorkingDirectory=/var/lib/syncthing-discosrv
EnvironmentFile=/etc/default/syncthing-discosrv
ExecStart=/usr/bin/stdiscosrv $DISCOSRV_OPTS
# Hardening
User=syncthing-discosrv
Group=syncthing
ProtectSystem=strict
ReadWritePaths=/var/lib/syncthing-discosrv
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
[Install]
WantedBy=multi-user.target
Alias=syncthing-discosrv.service

View File

@@ -9,17 +9,15 @@ package main
import (
"crypto/tls"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"runtime"
"strconv"
"strings"
"time"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syndtr/goleveldb/leveldb/opt"
@@ -65,24 +63,6 @@ var levelDBOptions = &opt.Options{
WriteBuffer: 32 << 20, // default 4<<20
}
var (
Version string
BuildStamp string
BuildUser string
BuildHost string
BuildDate time.Time
LongVersion string
)
func init() {
stamp, _ := strconv.Atoi(BuildStamp)
BuildDate = time.Unix(int64(stamp), 0)
date := BuildDate.UTC().Format("2006-01-02 15:04:05 MST")
LongVersion = fmt.Sprintf(`stdiscosrv %s (%s %s-%s) %s@%s %s`, Version, runtime.Version(), runtime.GOOS, runtime.GOARCH, BuildUser, BuildHost, date)
}
var (
debug = false
)
@@ -109,14 +89,18 @@ func main() {
flag.StringVar(&metricsListen, "metrics-listen", "", "Metrics listen address")
flag.StringVar(&replicationPeers, "replicate", "", "Replication peers, id@address, comma separated")
flag.StringVar(&replicationListen, "replication-listen", ":19200", "Replication listen address")
showVersion := flag.Bool("version", false, "Show version")
flag.Parse()
log.Println(LongVersion)
log.Println(build.LongVersion)
if *showVersion {
return
}
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Println("Failed to load keypair. Generating one, this might take a while...")
cert, err = tlsutil.NewCertificate(certFile, keyFile, "stdiscosrv")
cert, err = tlsutil.NewCertificate(certFile, keyFile, "stdiscosrv", 20*365)
if err != nil {
log.Fatalln("Failed to generate X509 key pair:", err)
}

View File

@@ -0,0 +1,4 @@
#!/bin/bash
addgroup --system syncthing
adduser --system --home /var/lib/syncthing-discosrv --ingroup syncthing syncthing-discosrv

View File

@@ -17,6 +17,7 @@ import (
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/discover"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/protocol"
)
@@ -82,7 +83,7 @@ func checkServers(deviceID protocol.DeviceID, servers ...string) {
}
func checkServer(deviceID protocol.DeviceID, server string) checkResult {
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil)
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger)
if err != nil {
return checkResult{error: err}
}

View File

@@ -13,11 +13,15 @@ import (
"time"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/protocol"
)
func dump(ldb *db.Lowlevel) {
it := ldb.NewIterator(nil, nil)
func dump(ldb backend.Backend) {
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
}
for it.Next() {
key := it.Key()
switch key[0] {

View File

@@ -10,8 +10,10 @@ import (
"container/heap"
"encoding/binary"
"fmt"
"log"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
)
type SizedElement struct {
@@ -37,11 +39,14 @@ func (h *ElementHeap) Pop() interface{} {
return x
}
func dumpsize(ldb *db.Lowlevel) {
func dumpsize(ldb backend.Backend) {
h := &ElementHeap{}
heap.Init(h)
it := ldb.NewIterator(nil, nil)
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
}
var ele SizedElement
for it.Next() {
key := it.Key()

View File

@@ -10,8 +10,10 @@ import (
"bytes"
"encoding/binary"
"fmt"
"log"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/protocol"
)
@@ -31,7 +33,7 @@ type sequenceKey struct {
sequence uint64
}
func idxck(ldb *db.Lowlevel) (success bool) {
func idxck(ldb backend.Backend) (success bool) {
folders := make(map[uint32]string)
devices := make(map[uint32]string)
deviceToIDs := make(map[string]uint32)
@@ -42,7 +44,10 @@ func idxck(ldb *db.Lowlevel) (success bool) {
var localDeviceKey uint32
success = true
it := ldb.NewIterator(nil, nil)
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
}
for it.Next() {
key := it.Key()
switch key[0] {

View File

@@ -13,7 +13,7 @@ import (
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
)
func main() {
@@ -30,7 +30,7 @@ func main() {
path = filepath.Join(defaultConfigDir(), "index-v0.14.0.db")
}
ldb, err := db.OpenRO(path)
ldb, err := backend.OpenLevelDBRO(path)
if err != nil {
log.Fatal(err)
}

View File

@@ -193,9 +193,9 @@
<script>
angular.module('syncthing', [
])
.config(function($httpProvider) {
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.timeout = 5000;
})
}])
.filter('bytes', function() {
return function(bytes, precision) {
if (isNaN(parseFloat(bytes)) || !isFinite(bytes)) return '-';

View File

@@ -7,13 +7,13 @@ package main
import (
"bytes"
"compress/gzip"
"context"
"crypto/tls"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"math/rand"
"mime"
"net"
"net/http"
@@ -29,6 +29,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/syncthing/syncthing/cmd/strelaypoolsrv/auto"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/relay/client"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
@@ -370,10 +371,7 @@ func handleGetRequest(w http.ResponseWriter, r *http.Request) {
mut.RUnlock()
// Shuffle
for i := range relays {
j := rand.Intn(i + 1)
relays[i], relays[j] = relays[j], relays[i]
}
rand.Shuffle(relays)
json.NewEncoder(w).Encode(map[string][]*relay{
"relays": relays,
@@ -483,7 +481,7 @@ func handleRelayTest(request request) {
if debug {
log.Println("Request for", request.relay)
}
if !client.TestRelay(request.relay.uri, []tls.Certificate{testCert}, time.Second, 2*time.Second, 3) {
if !client.TestRelay(context.TODO(), request.relay.uri, []tls.Certificate{testCert}, time.Second, 2*time.Second, 3) {
if debug {
log.Println("Test for relay", request.relay, "failed")
}
@@ -636,7 +634,7 @@ func createTestCertificate() tls.Certificate {
}
certFile, keyFile := filepath.Join(tmpDir, "cert.pem"), filepath.Join(tmpDir, "key.pem")
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv")
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv", 20*365)
if err != nil {
log.Fatalln("Failed to create test X509 key pair:", err)
}

View File

@@ -0,0 +1,9 @@
[strelaysrv]
title=Syncthing relay server
description=Proxies traffic of syncthing client behind firewalls
ports=22067/tcp
[strelaysrv-metrics]
title=Syncthing relay metrics
description=Provides metrics about the syncthing relay server
ports=22070/tcp

View File

@@ -0,0 +1,5 @@
# Default settings for syncthing-relaysrv (strelaysrv).
NAT=true
## Add Options here:
RELAYSRV_OPTS=

View File

@@ -1,17 +1,25 @@
[Unit]
Description=Syncthing relay server
Description=Syncthing Relay Server
After=network.target
Documentation=man:strelaysrv(1)
[Service]
User=strelaysrv
Group=strelaysrv
ExecStart=/usr/bin/strelaysrv
WorkingDirectory=/var/lib/strelaysrv
WorkingDirectory=/var/lib/syncthing-relaysrv
EnvironmentFile=/etc/default/syncthing-relaysrv
ExecStart=/usr/bin/strelaysrv -nat=${NAT} $RELAYSRV_OPTS
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
# Hardening
User=syncthing-relaysrv
Group=syncthing
ProtectSystem=strict
ReadWritePaths=/var/lib/syncthing-relaysrv
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
[Install]
WantedBy=multi-user.target
Alias=syncthing-relaysrv.service

View File

@@ -14,12 +14,13 @@ import (
"os/signal"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync/atomic"
"syscall"
"time"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/relay/protocol"
"github.com/syncthing/syncthing/lib/tlsutil"
@@ -33,24 +34,6 @@ import (
syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
)
var (
Version string
BuildStamp string
BuildUser string
BuildHost string
BuildDate time.Time
LongVersion string
)
func init() {
stamp, _ := strconv.Atoi(BuildStamp)
BuildDate = time.Unix(int64(stamp), 0)
date := BuildDate.UTC().Format("2006-01-02 15:04:05 MST")
LongVersion = fmt.Sprintf(`strelaysrv %s (%s %s-%s) %s@%s %s`, Version, runtime.Version(), runtime.GOOS, runtime.GOARCH, BuildUser, BuildHost, date)
}
var (
listen string
debug bool
@@ -116,8 +99,14 @@ func main() {
flag.IntVar(&natTimeout, "nat-timeout", 10, "NAT discovery timeout in seconds")
flag.BoolVar(&pprofEnabled, "pprof", false, "Enable the built in profiling on the status server")
flag.IntVar(&networkBufferSize, "network-buffer", 2048, "Network buffer size (two of these per proxied connection)")
showVersion := flag.Bool("version", false, "Show version")
flag.Parse()
if *showVersion {
fmt.Println(build.LongVersion)
return
}
if extAddress == "" {
extAddress = listen
}
@@ -146,7 +135,7 @@ func main() {
}
}
log.Println(LongVersion)
log.Println(build.LongVersion)
maxDescriptors, err := osutil.MaximizeOpenFileLimit()
if maxDescriptors > 0 {
@@ -166,7 +155,7 @@ func main() {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Println("Failed to load keypair. Generating one, this might take a while...")
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv")
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv", 20*365)
if err != nil {
log.Fatalln("Failed to generate X509 key pair:", err)
}
@@ -194,7 +183,7 @@ func main() {
log.Println("ID:", id)
}
wrapper := config.Wrap("config", config.New(id))
wrapper := config.Wrap("config", config.New(id), events.NoopLogger)
wrapper.SetOptions(config.OptionsConfiguration{
NATLeaseM: natLease,
NATRenewalM: natRenewal,

View File

@@ -0,0 +1,4 @@
#!/bin/bash
addgroup --system syncthing
adduser --system --home /var/lib/syncthing-relaysrv --ingroup syncthing syncthing-relaysrv

View File

@@ -10,6 +10,8 @@ import (
"runtime"
"sync/atomic"
"time"
"github.com/syncthing/syncthing/lib/build"
)
var rc *rateCalculator
@@ -40,10 +42,10 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
sessionMut.Lock()
// This can potentially be double the number of pending sessions, as each session has two keys, one for each side.
status["version"] = Version
status["buildHost"] = BuildHost
status["buildUser"] = BuildUser
status["buildDate"] = BuildDate
status["version"] = build.Version
status["buildHost"] = build.Host
status["buildUser"] = build.User
status["buildDate"] = build.Date
status["startTime"] = rc.startTime
status["uptimeSeconds"] = time.Since(rc.startTime) / time.Second
status["numPendingSessionKeys"] = len(pendingSessions)
@@ -86,9 +88,9 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
}
type rateCalculator struct {
counter *int64 // atomic, must remain 64-bit aligned
rates []int64
prev int64
counter *int64
startTime time.Time
}

View File

@@ -4,6 +4,7 @@ package main
import (
"bufio"
"context"
"crypto/tls"
"flag"
"log"
@@ -19,6 +20,8 @@ import (
)
func main() {
ctx := context.Background()
log.SetOutput(os.Stdout)
log.SetFlags(log.LstdFlags | log.Lshortfile)
@@ -76,7 +79,7 @@ func main() {
}()
for {
conn, err := client.JoinSession(<-recv)
conn, err := client.JoinSession(ctx, <-recv)
if err != nil {
log.Fatalln("Failed to join", err)
}
@@ -90,13 +93,13 @@ func main() {
log.Fatal(err)
}
invite, err := client.GetInvitationFromRelay(uri, id, []tls.Certificate{cert}, 10*time.Second)
invite, err := client.GetInvitationFromRelay(ctx, uri, id, []tls.Certificate{cert}, 10*time.Second)
if err != nil {
log.Fatal(err)
}
log.Println("Received invitation", invite)
conn, err := client.JoinSession(invite)
conn, err := client.JoinSession(ctx, invite)
if err != nil {
log.Fatalln("Failed to join", err)
}
@@ -104,7 +107,7 @@ func main() {
connectToStdio(stdin, conn)
log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr())
} else if test {
if client.TestRelay(uri, []tls.Certificate{cert}, time.Second, 2*time.Second, 4) {
if client.TestRelay(ctx, uri, []tls.Certificate{cert}, time.Second, 2*time.Second, 4) {
log.Println("OK")
} else {
log.Println("FAIL")

57
cmd/stupgrades/main.go Normal file
View File

@@ -0,0 +1,57 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"encoding/json"
"flag"
"os"
"sort"
"github.com/syncthing/syncthing/lib/upgrade"
)
const defaultURL = "https://api.github.com/repos/syncthing/syncthing/releases?per_page=25"
func main() {
url := flag.String("u", defaultURL, "GitHub releases url")
flag.Parse()
rels := upgrade.FetchLatestReleases(*url, "")
if rels == nil {
// An error was already logged
os.Exit(1)
}
sort.Sort(upgrade.SortByRelease(rels))
rels = filterForLatest(rels)
if err := json.NewEncoder(os.Stdout).Encode(rels); err != nil {
os.Exit(1)
}
}
// filterForLatest returns the latest stable and prerelease only. If the
// stable version is newer (comes first in the list) there is no need to go
// looking for a prerelease at all.
func filterForLatest(rels []upgrade.Release) []upgrade.Release {
var filtered []upgrade.Release
var havePre bool
for _, rel := range rels {
if !rel.Prerelease {
// We found a stable version, we're good now.
filtered = append(filtered, rel)
break
}
if rel.Prerelease && !havePre {
// We remember the first prerelease we find.
filtered = append(filtered, rel)
havePre = true
}
}
return filtered
}

View File

@@ -1,69 +0,0 @@
// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"encoding/json"
"io"
"github.com/syncthing/syncthing/lib/events"
)
// The auditService subscribes to events and writes these in JSON format, one
// event per line, to the specified writer.
type auditService struct {
w io.Writer // audit destination
stop chan struct{} // signals time to stop
started chan struct{} // signals startup complete
stopped chan struct{} // signals stop complete
}
func newAuditService(w io.Writer) *auditService {
return &auditService{
w: w,
stop: make(chan struct{}),
started: make(chan struct{}),
stopped: make(chan struct{}),
}
}
// Serve runs the audit service.
func (s *auditService) Serve() {
defer close(s.stopped)
sub := events.Default.Subscribe(events.AllEvents)
defer events.Default.Unsubscribe(sub)
enc := json.NewEncoder(s.w)
// We're ready to start processing events.
close(s.started)
for {
select {
case ev := <-sub.C():
enc.Encode(ev)
case <-s.stop:
return
}
}
}
// Stop stops the audit service.
func (s *auditService) Stop() {
close(s.stop)
}
// WaitForStart returns once the audit service is ready to receive events, or
// immediately if it's already running.
func (s *auditService) WaitForStart() {
<-s.started
}
// WaitForStop returns once the audit service has stopped.
// (Needed by the tests.)
func (s *auditService) WaitForStop() {
<-s.stopped
}

View File

@@ -22,11 +22,15 @@ func init() {
panic("Couldn't find block profiler")
}
l.Debugln("Starting block profiling")
go saveBlockingProfiles(profiler)
go func() {
err := saveBlockingProfiles(profiler) // Only returns on error
l.Warnln("Block profiler failed:", err)
panic("Block profiler failed")
}()
}
}
func saveBlockingProfiles(profiler *pprof.Profile) {
func saveBlockingProfiles(profiler *pprof.Profile) error {
runtime.SetBlockProfileRate(1)
t0 := time.Now()
@@ -35,16 +39,16 @@ func saveBlockingProfiles(profiler *pprof.Profile) {
fd, err := os.Create(fmt.Sprintf("block-%05d-%07d.pprof", syscall.Getpid(), startms))
if err != nil {
panic(err)
return err
}
err = profiler.WriteTo(fd, 0)
if err != nil {
panic(err)
return err
}
err = fd.Close()
if err != nil {
panic(err)
return err
}
}
return nil
}

View File

@@ -0,0 +1,152 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"sort"
"strings"
"time"
"github.com/syncthing/syncthing/lib/sha256"
)
const (
headRequestTimeout = 10 * time.Second
putRequestTimeout = time.Minute
)
// uploadPanicLogs attempts to upload all the panic logs in the named
// directory to the crash reporting server as urlBase. Uploads are attempted
// with the newest log first.
//
// This can can block for a long time. The context can set a final deadline
// for this.
func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
files, err := filepath.Glob(filepath.Join(dir, "panic-*.log"))
if err != nil {
l.Warnln("Failed to list panic logs:", err)
return
}
sort.Sort(sort.Reverse(sort.StringSlice(files)))
for _, file := range files {
if strings.Contains(file, ".reported.") {
// We've already sent this file. It'll be cleaned out at some
// point.
continue
}
if err := uploadPanicLog(ctx, urlBase, file); err != nil {
l.Warnln("Reporting crash:", err)
} else {
// Rename the log so we don't have to try to report it again. This
// succeeds, or it does not. There is no point complaining about it.
_ = os.Rename(file, strings.Replace(file, ".log", ".reported.log", 1))
}
}
}
// uploadPanicLog attempts to upload the named panic log to the crash
// reporting server at urlBase. The panic ID is constructed as the sha256 of
// the log contents. A HEAD request is made to see if the log has already
// been reported. If not, a PUT is made with the log contents.
func uploadPanicLog(ctx context.Context, urlBase, file string) error {
data, err := ioutil.ReadFile(file)
if err != nil {
return err
}
// Remove log lines, for privacy.
data = filterLogLines(data)
hash := fmt.Sprintf("%x", sha256.Sum256(data))
l.Infof("Reporting crash found in %s (report ID %s) ...\n", filepath.Base(file), hash[:8])
url := fmt.Sprintf("%s/%s", urlBase, hash)
headReq, err := http.NewRequest(http.MethodHead, url, nil)
if err != nil {
return err
}
// Set a reasonable timeout on the HEAD request
headCtx, headCancel := context.WithTimeout(ctx, headRequestTimeout)
defer headCancel()
headReq = headReq.WithContext(headCtx)
resp, err := http.DefaultClient.Do(headReq)
if err != nil {
return err
}
resp.Body.Close()
if resp.StatusCode == http.StatusOK {
// It's known, we're done
return nil
}
putReq, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
if err != nil {
return err
}
// Set a reasonable timeout on the PUT request
putCtx, putCancel := context.WithTimeout(ctx, putRequestTimeout)
defer putCancel()
putReq = putReq.WithContext(putCtx)
resp, err = http.DefaultClient.Do(putReq)
if err != nil {
return err
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("upload: %s", resp.Status)
}
return nil
}
// filterLogLines returns the data without any log lines between the first
// line and the panic trace. This is done in-place: the original data slice
// is destroyed.
func filterLogLines(data []byte) []byte {
filtered := data[:0]
matched := false
for _, line := range bytes.Split(data, []byte("\n")) {
switch {
case !matched && bytes.HasPrefix(line, []byte("Panic ")):
// This begins the panic trace, set the matched flag and append.
matched = true
fallthrough
case len(filtered) == 0 || matched:
// This is the first line or inside the panic trace.
if len(filtered) > 0 {
// We add the newline before rather than after because
// bytes.Split sees the \n as *separator* and not line
// ender, so ir will generate a last empty line that we
// don't really want. (We want to keep blank lines in the
// middle of the trace though.)
filtered = append(filtered, '\n')
}
// Remove the device ID prefix. The "plus two" stuff is because
// the line will look like "[foo] whatever" and the end variable
// will end up pointing at the ] and we want to step over that
// and the following space.
if end := bytes.Index(line, []byte("]")); end > 1 && end < len(line)-2 && bytes.HasPrefix(line, []byte("[")) {
line = line[end+2:]
}
filtered = append(filtered, line...)
}
}
return filtered
}

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"bytes"
"testing"
)
func TestFilterLogLines(t *testing.T) {
in := []byte(`[ABCD123] syncthing version whatever
here is more log data
and more
...
and some more
yet more
Panic detected at like right now
here is panic data
and yet more panic stuff
`)
filtered := []byte(`syncthing version whatever
Panic detected at like right now
here is panic data
and yet more panic stuff
`)
result := filterLogLines(in)
if !bytes.Equal(result, filtered) {
t.Logf("%q\n", result)
t.Error("it should have been filtered")
}
}

View File

@@ -7,16 +7,9 @@
package main
import (
"os"
"strings"
"github.com/syncthing/syncthing/lib/logger"
)
var (
l = logger.DefaultLogger.NewFacility("main", "Main package")
)
func init() {
l.SetDebug("main", strings.Contains(os.Getenv("STTRACE"), "main") || os.Getenv("STTRACE") == "all")
}

View File

@@ -23,11 +23,15 @@ func init() {
rate = i
}
l.Debugln("Starting heap profiling")
go saveHeapProfiles(rate)
go func() {
err := saveHeapProfiles(rate) // Only returns on error
l.Warnln("Heap profiler failed:", err)
panic("Heap profiler failed")
}()
}
}
func saveHeapProfiles(rate int) {
func saveHeapProfiles(rate int) error {
runtime.MemProfileRate = rate
var memstats, prevMemstats runtime.MemStats
@@ -38,21 +42,21 @@ func saveHeapProfiles(rate int) {
if memstats.HeapInuse > prevMemstats.HeapInuse {
fd, err := os.Create(name + ".tmp")
if err != nil {
panic(err)
return err
}
err = pprof.WriteHeapProfile(fd)
if err != nil {
panic(err)
return err
}
err = fd.Close()
if err != nil {
panic(err)
return err
}
os.Remove(name) // Error deliberately ignored
err = os.Rename(name+".tmp", name)
if err != nil {
panic(err)
return err
}
prevMemstats = memstats

View File

@@ -25,52 +25,30 @@ import (
"runtime/pprof"
"sort"
"strconv"
"strings"
"syscall"
"time"
"github.com/syncthing/syncthing/lib/api"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/connections"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/dialer"
"github.com/syncthing/syncthing/lib/discover"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/logger"
"github.com/syncthing/syncthing/lib/model"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/sha256"
"github.com/syncthing/syncthing/lib/syncthing"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/ur"
"github.com/pkg/errors"
"github.com/thejerf/suture"
)
const (
exitSuccess = 0
exitError = 1
exitNoUpgradeAvailable = 2
exitRestarting = 3
exitUpgrading = 4
tlsDefaultCommonName = "syncthing"
deviceCertLifetimeDays = 20 * 365
)
const (
bepProtocolName = "bep/1.0"
tlsDefaultCommonName = "syncthing"
maxSystemErrors = 5
initialSystemLog = 10
maxSystemLog = 250
)
var myID protocol.DeviceID
const (
usage = "syncthing [options]"
extraUsage = `
@@ -158,15 +136,14 @@ The following are valid values for the STTRACE variable:
// Environment options
var (
noUpgradeFromEnv = os.Getenv("STNOUPGRADE") != ""
innerProcess = os.Getenv("STNORESTART") != "" || os.Getenv("STMONITORED") != ""
noDefaultFolder = os.Getenv("STNODEFAULTFOLDER") != ""
innerProcess = os.Getenv("STNORESTART") != "" || os.Getenv("STMONITORED") != ""
noDefaultFolder = os.Getenv("STNODEFAULTFOLDER") != ""
)
type RuntimeOptions struct {
syncthing.Options
confDir string
resetDatabase bool
resetDeltaIdxs bool
showVersion bool
showPaths bool
showDeviceId bool
@@ -177,17 +154,16 @@ type RuntimeOptions struct {
browserOnly bool
hideConsole bool
logFile string
logMaxSize int
logMaxFiles int
auditEnabled bool
auditFile string
verbose bool
paused bool
unpaused bool
guiAddress string
guiAPIKey string
generateDir string
noRestart bool
profiler string
assetDir string
cpuProfile bool
stRestarting bool
logFlags int
@@ -197,12 +173,17 @@ type RuntimeOptions struct {
func defaultRuntimeOptions() RuntimeOptions {
options := RuntimeOptions{
Options: syncthing.Options{
AssetDir: os.Getenv("STGUIASSETS"),
NoUpgrade: os.Getenv("STNOUPGRADE") != "",
ProfilerURL: os.Getenv("STPROFILER"),
},
noRestart: os.Getenv("STNORESTART") != "",
profiler: os.Getenv("STPROFILER"),
assetDir: os.Getenv("STGUIASSETS"),
cpuProfile: os.Getenv("STCPUPROFILE") != "",
stRestarting: os.Getenv("STRESTART") != "",
logFlags: log.Ltime,
logMaxSize: 10 << 20, // 10 MiB
logMaxFiles: 3, // plus the current one
}
if os.Getenv("STTRACE") != "" {
@@ -232,7 +213,7 @@ func parseCommandLineOptions() RuntimeOptions {
flag.BoolVar(&options.browserOnly, "browser-only", false, "Open GUI in browser")
flag.BoolVar(&options.noRestart, "no-restart", options.noRestart, "Disable monitor process, managed restarts and log file writing")
flag.BoolVar(&options.resetDatabase, "reset-database", false, "Reset the database, forcing a full rescan and resync")
flag.BoolVar(&options.resetDeltaIdxs, "reset-deltas", false, "Reset delta index IDs, forcing a full index exchange")
flag.BoolVar(&options.ResetDeltaIdxs, "reset-deltas", false, "Reset delta index IDs, forcing a full index exchange")
flag.BoolVar(&options.doUpgrade, "upgrade", false, "Perform upgrade")
flag.BoolVar(&options.doUpgradeCheck, "upgrade-check", false, "Check for available upgrade")
flag.BoolVar(&options.showVersion, "version", false, "Show version")
@@ -241,10 +222,12 @@ func parseCommandLineOptions() RuntimeOptions {
flag.BoolVar(&options.showDeviceId, "device-id", false, "Show the device ID")
flag.StringVar(&options.upgradeTo, "upgrade-to", options.upgradeTo, "Force upgrade directly from specified URL")
flag.BoolVar(&options.auditEnabled, "audit", false, "Write events to audit file")
flag.BoolVar(&options.verbose, "verbose", false, "Print verbose log output")
flag.BoolVar(&options.Verbose, "verbose", false, "Print verbose log output")
flag.BoolVar(&options.paused, "paused", false, "Start with all devices and folders paused")
flag.BoolVar(&options.unpaused, "unpaused", false, "Start with all devices and folders unpaused")
flag.StringVar(&options.logFile, "logfile", options.logFile, "Log file name (still always logs to stdout). Cannot be used together with -no-restart/STNORESTART environment variable.")
flag.IntVar(&options.logMaxSize, "log-max-size", options.logMaxSize, "Maximum size of any file (zero to disable log rotation).")
flag.IntVar(&options.logMaxFiles, "log-max-old-files", options.logMaxFiles, "Number of old files to keep (zero to keep only current).")
flag.StringVar(&options.auditFile, "auditfile", options.auditFile, "Specify audit file (use \"-\" for stdout, \"--\" for stderr)")
flag.BoolVar(&options.allowNewerConfig, "allow-newer-config", false, "Allow loading newer than current config version")
if runtime.GOOS == "windows" {
@@ -264,33 +247,6 @@ func parseCommandLineOptions() RuntimeOptions {
return options
}
// exiter implements api.Controller
type exiter struct {
stop chan int
}
func (e *exiter) Restart() {
l.Infoln("Restarting")
e.stop <- exitRestarting
}
func (e *exiter) Shutdown() {
l.Infoln("Shutting down")
e.stop <- exitSuccess
}
func (e *exiter) ExitUpgrading() {
l.Infoln("Shutting down after upgrade")
e.stop <- exitUpgrading
}
// waitForExit must be called synchronously.
func (e *exiter) waitForExit() int {
return <-e.stop
}
var exit = &exiter{make(chan int)}
func main() {
options := parseCommandLineOptions()
l.SetFlags(options.logFlags)
@@ -310,7 +266,7 @@ func main() {
// default location
if options.noRestart && (options.logFile != "" && options.logFile != "-") {
l.Warnln("-logfile may not be used with -no-restart or STNORESTART")
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
if options.hideConsole {
@@ -324,12 +280,12 @@ func main() {
options.confDir, err = filepath.Abs(options.confDir)
if err != nil {
l.Warnln("Failed to make options path absolute:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
}
if err := locations.SetBaseDir(locations.ConfigBaseDir, options.confDir); err != nil {
l.Warnln(err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
}
@@ -339,10 +295,10 @@ func main() {
options.logFile = locations.Get(locations.LogFile)
}
if options.assetDir == "" {
if options.AssetDir == "" {
// The asset dir is blank if STGUIASSETS wasn't set, in which case we
// should look for extra assets in the default place.
options.assetDir = locations.Get(locations.GUIAssets)
options.AssetDir = locations.Get(locations.GUIAssets)
}
if options.showVersion {
@@ -367,18 +323,17 @@ func main() {
)
if err != nil {
l.Warnln("Error reading device ID:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
myID = protocol.NewDeviceID(cert.Certificate[0])
fmt.Println(myID)
fmt.Println(protocol.NewDeviceID(cert.Certificate[0]))
return
}
if options.browserOnly {
if err := openGUI(); err != nil {
if err := openGUI(protocol.EmptyDeviceID); err != nil {
l.Warnln("Failed to open web UI:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
return
}
@@ -386,7 +341,7 @@ func main() {
if options.generateDir != "" {
if err := generate(options.generateDir); err != nil {
l.Warnln("Failed to generate config and keys:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
return
}
@@ -394,14 +349,14 @@ func main() {
// Ensure that our home directory exists.
if err := ensureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
l.Warnln("Failure on home directory:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
if options.upgradeTo != "" {
err := upgrade.ToURL(options.upgradeTo)
if err != nil {
l.Warnln("Error while Upgrading:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
l.Infoln("Upgraded from", options.upgradeTo)
return
@@ -421,7 +376,7 @@ func main() {
if options.resetDatabase {
if err := resetDB(); err != nil {
l.Warnln("Resetting database:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
return
}
@@ -433,8 +388,8 @@ func main() {
}
}
func openGUI() error {
cfg, err := loadOrDefaultConfig()
func openGUI(myID protocol.DeviceID) error {
cfg, err := loadOrDefaultConfig(myID, events.NoopLogger)
if err != nil {
return err
}
@@ -458,31 +413,26 @@ func generate(generateDir string) error {
return err
}
var myID protocol.DeviceID
certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
l.Warnln("Key exists; will not overwrite.")
l.Infoln("Device ID:", protocol.NewDeviceID(cert.Certificate[0]))
} else {
cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName)
cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName, deviceCertLifetimeDays)
if err != nil {
return errors.Wrap(err, "create certificate")
}
myID = protocol.NewDeviceID(cert.Certificate[0])
if err != nil {
return errors.Wrap(err, "load certificate")
}
if err == nil {
l.Infoln("Device ID:", protocol.NewDeviceID(cert.Certificate[0]))
}
}
myID = protocol.NewDeviceID(cert.Certificate[0])
l.Infoln("Device ID:", myID)
cfgFile := filepath.Join(dir, "config.xml")
if _, err := os.Stat(cfgFile); err == nil {
l.Warnln("Config exists; will not overwrite.")
return nil
}
cfg, err := defaultConfig(cfgFile)
cfg, err := syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder)
if err != nil {
return err
}
@@ -516,18 +466,18 @@ func debugFacilities() string {
}
func checkUpgrade() upgrade.Release {
cfg, _ := loadOrDefaultConfig()
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
opts := cfg.Options()
release, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
if err != nil {
l.Warnln("Upgrade:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
if upgrade.CompareVersions(release.Tag, build.Version) <= 0 {
noUpgradeMessage := "No upgrade available (current %q >= latest %q)."
l.Infof(noUpgradeMessage, build.Version, release.Tag)
os.Exit(exitNoUpgradeAvailable)
os.Exit(syncthing.ExitNoUpgradeAvailable.AsInt())
}
l.Infof("Upgrade available (current %q < latest %q)", build.Version, release.Tag)
@@ -536,12 +486,12 @@ func checkUpgrade() upgrade.Release {
func performUpgrade(release upgrade.Release) {
// Use leveldb database locks to protect against concurrent upgrades
_, err := db.Open(locations.Get(locations.Database))
_, err := syncthing.OpenGoleveldb(locations.Get(locations.Database), config.TuningAuto)
if err == nil {
err = upgrade.To(release)
if err != nil {
l.Warnln("Upgrade:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
l.Infof("Upgraded to %q", release.Tag)
} else {
@@ -549,15 +499,15 @@ func performUpgrade(release upgrade.Release) {
err = upgradeViaRest()
if err != nil {
l.Warnln("Upgrade:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
l.Infoln("Syncthing upgrading")
os.Exit(exitUpgrading)
os.Exit(syncthing.ExitUpgrade.AsInt())
}
}
func upgradeViaRest() error {
cfg, _ := loadOrDefaultConfig()
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
u, err := url.Parse(cfg.GUI().URL())
if err != nil {
return err
@@ -568,7 +518,7 @@ func upgradeViaRest() error {
r.Header.Set("X-API-Key", cfg.GUI().APIKey)
tr := &http.Transport{
Dial: dialer.Dial,
DialContext: dialer.DialContext,
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
@@ -593,174 +543,32 @@ func upgradeViaRest() error {
}
func syncthingMain(runtimeOptions RuntimeOptions) {
setupSignalHandling()
// Create a main service manager. We'll add things to this as we go along.
// We want any logging it does to go through our log system.
mainService := suture.New("main", suture.Spec{
Log: func(line string) {
l.Debugln(line)
},
PassThroughPanics: true,
})
mainService.ServeBackground()
// Set a log prefix similar to the ID we will have later on, or early log
// lines look ugly.
l.SetPrefix("[start] ")
if runtimeOptions.auditEnabled {
startAuditing(mainService, runtimeOptions.auditFile)
}
if runtimeOptions.verbose {
mainService.Add(newVerboseService())
}
errors := logger.NewRecorder(l, logger.LevelWarn, maxSystemErrors, 0)
systemLog := logger.NewRecorder(l, logger.LevelDebug, maxSystemLog, initialSystemLog)
// Event subscription for the API; must start early to catch the early
// events. The LocalChangeDetected event might overwhelm the event
// receiver in some situations so we will not subscribe to it here.
defaultSub := events.NewBufferedSubscription(events.Default.Subscribe(api.DefaultEventMask), api.EventSubBufferSize)
diskSub := events.NewBufferedSubscription(events.Default.Subscribe(api.DiskEventMask), api.EventSubBufferSize)
if len(os.Getenv("GOMAXPROCS")) == 0 {
runtime.GOMAXPROCS(runtime.NumCPU())
}
// Attempt to increase the limit on number of open files to the maximum
// allowed, in case we have many peers. We don't really care enough to
// report the error if there is one.
osutil.MaximizeOpenFileLimit()
// Print our version information up front, so any crash that happens
// early etc. will have it available.
l.Infoln(build.LongVersion)
// Ensure that we have a certificate and key.
cert, err := tls.LoadX509KeyPair(
cert, err := syncthing.LoadOrGenerateCertificate(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
)
if err != nil {
l.Infof("Generating ECDSA key and certificate for %s...", tlsDefaultCommonName)
cert, err = tlsutil.NewCertificate(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
tlsDefaultCommonName,
)
if err != nil {
l.Infoln("Failed to generate certificate:", err)
os.Exit(exitError)
}
l.Warnln("Failed to load/generate certificate:", err)
os.Exit(1)
}
myID = protocol.NewDeviceID(cert.Certificate[0])
l.SetPrefix(fmt.Sprintf("[%s] ", myID.String()[:5]))
evLogger := events.NewLogger()
go evLogger.Serve()
defer evLogger.Stop()
l.Infoln(build.LongVersion)
l.Infoln("My ID:", myID)
// Select SHA256 implementation and report. Affected by the
// STHASHING environment variable.
sha256.SelectAlgo()
sha256.Report()
// Emit the Starting event, now that we know who we are.
events.Default.Log(events.Starting, map[string]string{
"home": locations.GetBaseDir(locations.ConfigBaseDir),
"myID": myID.String(),
})
cfg, err := loadConfigAtStartup(runtimeOptions.allowNewerConfig)
cfg, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, runtimeOptions.allowNewerConfig, noDefaultFolder)
if err != nil {
l.Warnln("Failed to initialize config:", err)
os.Exit(exitError)
}
if err := checkShortIDs(cfg); err != nil {
l.Warnln("Short device IDs are in conflict. Unlucky!\n Regenerate the device ID of one of the following:\n ", err)
os.Exit(exitError)
}
if len(runtimeOptions.profiler) > 0 {
go func() {
l.Debugln("Starting profiler on", runtimeOptions.profiler)
runtime.SetBlockProfileRate(1)
err := http.ListenAndServe(runtimeOptions.profiler, nil)
if err != nil {
l.Warnln(err)
os.Exit(exitError)
}
}()
}
perf := ur.CpuBench(3, 150*time.Millisecond, true)
l.Infof("Hashing performance is %.02f MB/s", perf)
dbFile := locations.Get(locations.Database)
ldb, err := db.Open(dbFile)
if err != nil {
l.Warnln("Error opening database:", err)
os.Exit(exitError)
}
if err := db.UpdateSchema(ldb); err != nil {
l.Warnln("Database schema:", err)
os.Exit(exitError)
}
if runtimeOptions.resetDeltaIdxs {
l.Infoln("Reinitializing delta index IDs")
db.DropDeltaIndexIDs(ldb)
}
protectedFiles := []string{
locations.Get(locations.Database),
locations.Get(locations.ConfigFile),
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
}
// Remove database entries for folders that no longer exist in the config
folders := cfg.Folders()
for _, folder := range ldb.ListFolders() {
if _, ok := folders[folder]; !ok {
l.Infof("Cleaning data for dropped folder %q", folder)
db.DropFolder(ldb, folder)
}
}
// Grab the previously running version string from the database.
miscDB := db.NewMiscDataNamespace(ldb)
prevVersion, _ := miscDB.String("prevVersion")
// Strip away prerelease/beta stuff and just compare the release
// numbers. 0.14.44 to 0.14.45-banana is an upgrade, 0.14.45-banana to
// 0.14.45-pineapple is not.
prevParts := strings.Split(prevVersion, "-")
curParts := strings.Split(build.Version, "-")
if prevParts[0] != curParts[0] {
if prevVersion != "" {
l.Infoln("Detected upgrade from", prevVersion, "to", build.Version)
}
// Drop delta indexes in case we've changed random stuff we
// shouldn't have. We will resend our index on next connect.
db.DropDeltaIndexIDs(ldb)
// Remember the new version.
miscDB.PutString("prevVersion", build.Version)
}
m := model.NewModel(cfg, myID, "syncthing", build.Version, ldb, protectedFiles)
if t := os.Getenv("STDEADLOCKTIMEOUT"); t != "" {
if secs, _ := strconv.Atoi(t); secs > 0 {
m.StartDeadlockDetector(time.Duration(secs) * time.Second)
}
} else if !build.IsRelease || build.IsBeta {
m.StartDeadlockDetector(20 * time.Minute)
os.Exit(syncthing.ExitError.AsInt())
}
if runtimeOptions.unpaused {
@@ -769,126 +577,51 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
setPauseState(cfg, true)
}
// Add and start folders
for _, folderCfg := range cfg.Folders() {
if folderCfg.Paused {
folderCfg.CreateRoot()
continue
}
m.AddFolder(folderCfg)
m.StartFolder(folderCfg.ID)
dbFile := locations.Get(locations.Database)
ldb, err := syncthing.OpenGoleveldb(dbFile, cfg.Options().DatabaseTuning)
if err != nil {
l.Warnln("Error opening database:", err)
os.Exit(1)
}
mainService.Add(m)
// Start discovery
cachedDiscovery := discover.NewCachingMux()
mainService.Add(cachedDiscovery)
// The TLS configuration is used for both the listening socket and outgoing
// connections.
tlsCfg := tlsutil.SecureDefault()
tlsCfg.Certificates = []tls.Certificate{cert}
tlsCfg.NextProtos = []string{bepProtocolName}
tlsCfg.ClientAuth = tls.RequestClientCert
tlsCfg.SessionTicketsDisabled = true
tlsCfg.InsecureSkipVerify = true
// Start connection management
connectionsService := connections.NewService(cfg, myID, m, tlsCfg, cachedDiscovery, bepProtocolName, tlsDefaultCommonName)
mainService.Add(connectionsService)
if cfg.Options().GlobalAnnEnabled {
for _, srv := range cfg.GlobalDiscoveryServers() {
l.Infoln("Using discovery server", srv)
gd, err := discover.NewGlobal(srv, cert, connectionsService)
if err != nil {
l.Warnln("Global discovery:", err)
continue
}
// Each global discovery server gets its results cached for five
// minutes, and is not asked again for a minute when it's returned
// unsuccessfully.
cachedDiscovery.Add(gd, 5*time.Minute, time.Minute)
}
appOpts := runtimeOptions.Options
if runtimeOptions.auditEnabled {
appOpts.AuditWriter = auditWriter(runtimeOptions.auditFile)
}
if t := os.Getenv("STDEADLOCKTIMEOUT"); t != "" {
secs, _ := strconv.Atoi(t)
appOpts.DeadlockTimeoutS = secs
}
if cfg.Options().LocalAnnEnabled {
// v4 broadcasts
bcd, err := discover.NewLocal(myID, fmt.Sprintf(":%d", cfg.Options().LocalAnnPort), connectionsService)
if err != nil {
l.Warnln("IPv4 local discovery:", err)
} else {
cachedDiscovery.Add(bcd, 0, 0)
}
// v6 multicasts
mcd, err := discover.NewLocal(myID, cfg.Options().LocalAnnMCAddr, connectionsService)
if err != nil {
l.Warnln("IPv6 local discovery:", err)
} else {
cachedDiscovery.Add(mcd, 0, 0)
}
app := syncthing.New(cfg, ldb, evLogger, cert, appOpts)
setupSignalHandling(app)
if len(os.Getenv("GOMAXPROCS")) == 0 {
runtime.GOMAXPROCS(runtime.NumCPU())
}
if runtimeOptions.cpuProfile {
f, err := os.Create(fmt.Sprintf("cpu-%d.pprof", os.Getpid()))
if err != nil {
l.Warnln("Creating profile:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
if err := pprof.StartCPUProfile(f); err != nil {
l.Warnln("Starting profile:", err)
os.Exit(exitError)
}
}
// Candidate builds always run with usage reporting.
if opts := cfg.Options(); build.IsCandidate {
l.Infoln("Anonymous usage reporting is always enabled for candidate releases.")
if opts.URAccepted != ur.Version {
opts.URAccepted = ur.Version
cfg.SetOptions(opts)
cfg.Save()
// Unique ID will be set and config saved below if necessary.
}
}
// If we are going to do usage reporting, ensure we have a valid unique ID.
if opts := cfg.Options(); opts.URAccepted > 0 && opts.URUniqueID == "" {
opts.URUniqueID = rand.String(8)
cfg.SetOptions(opts)
cfg.Save()
}
usageReportingSvc := ur.New(cfg, m, connectionsService, noUpgradeFromEnv)
mainService.Add(usageReportingSvc)
// GUI
setupGUI(mainService, cfg, m, defaultSub, diskSub, cachedDiscovery, connectionsService, usageReportingSvc, errors, systemLog, runtimeOptions)
myDev, _ := cfg.Device(myID)
l.Infof(`My name is "%v"`, myDev.Name)
for _, device := range cfg.Devices() {
if device.DeviceID != myID {
l.Infof(`Device %s is "%v" at %v`, device.DeviceID, device.Name, device.Addresses)
os.Exit(syncthing.ExitError.AsInt())
}
}
if opts := cfg.Options(); opts.RestartOnWakeup {
go standbyMonitor()
go standbyMonitor(app)
}
// Candidate builds should auto upgrade. Make sure the option is set,
// unless we are in a build where it's disabled or the STNOUPGRADE
// environment variable is set.
if build.IsCandidate && !upgrade.DisabledByCompilation && !noUpgradeFromEnv {
if build.IsCandidate && !upgrade.DisabledByCompilation && !runtimeOptions.NoUpgrade {
l.Infoln("Automatic upgrade is always enabled for candidate releases.")
if opts := cfg.Options(); opts.AutoUpgradeIntervalH == 0 || opts.AutoUpgradeIntervalH > 24 {
opts.AutoUpgradeIntervalH = 12
@@ -902,43 +635,35 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
}
if opts := cfg.Options(); opts.AutoUpgradeIntervalH > 0 {
if noUpgradeFromEnv {
if runtimeOptions.NoUpgrade {
l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.")
} else {
go autoUpgrade(cfg)
go autoUpgrade(cfg, app, evLogger)
}
}
if isSuperUser() {
l.Warnln("Syncthing should not run as a privileged or system user. Please consider using a normal user account.")
if err := app.Start(); err != nil {
os.Exit(syncthing.ExitError.AsInt())
}
events.Default.Log(events.StartupComplete, map[string]string{
"myID": myID.String(),
})
cleanConfigDirectory()
if cfg.Options().SetLowPriority {
if err := osutil.SetLowPriority(); err != nil {
l.Warnln("Failed to lower process priority:", err)
}
if cfg.Options().StartBrowser && !runtimeOptions.noBrowser && !runtimeOptions.stRestarting {
// Can potentially block if the utility we are invoking doesn't
// fork, and just execs, hence keep it in its own routine.
go func() { _ = openURL(cfg.GUI().URL()) }()
}
code := exit.waitForExit()
mainService.Stop()
l.Infoln("Exiting")
status := app.Wait()
if runtimeOptions.cpuProfile {
pprof.StopCPUProfile()
}
os.Exit(code)
os.Exit(int(status))
}
func setupSignalHandling() {
func setupSignalHandling(app *syncthing.App) {
// Exit cleanly with "restarting" code on SIGHUP.
restartSign := make(chan os.Signal, 1)
@@ -946,7 +671,7 @@ func setupSignalHandling() {
signal.Notify(restartSign, sigHup)
go func() {
<-restartSign
exit.Restart()
app.Stop(syncthing.ExitRestart)
}()
// Exit with "success" code (no restart) on INT/TERM
@@ -956,85 +681,22 @@ func setupSignalHandling() {
signal.Notify(stopSign, os.Interrupt, sigTerm)
go func() {
<-stopSign
exit.Shutdown()
app.Stop(syncthing.ExitSuccess)
}()
}
func loadOrDefaultConfig() (config.Wrapper, error) {
func loadOrDefaultConfig(myID protocol.DeviceID, evLogger events.Logger) (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, err := config.Load(cfgFile, myID)
cfg, err := config.Load(cfgFile, myID, evLogger)
if err != nil {
cfg, err = defaultConfig(cfgFile)
cfg, err = syncthing.DefaultConfig(cfgFile, myID, evLogger, noDefaultFolder)
}
return cfg, err
}
func loadConfigAtStartup(allowNewerConfig bool) (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, err := config.Load(cfgFile, myID)
if os.IsNotExist(err) {
cfg, err = defaultConfig(cfgFile)
if err != nil {
return nil, errors.Wrap(err, "failed to generate default config")
}
err = cfg.Save()
if err != nil {
return nil, errors.Wrap(err, "failed to save default config")
}
l.Infof("Default config saved. Edit %s to taste (with Syncthing stopped) or use the GUI", cfg.ConfigPath())
} else if err == io.EOF {
return nil, errors.New("Failed to load config: unexpected end of file. Truncated or empty configuration?")
} else if err != nil {
return nil, errors.Wrap(err, "failed to load config")
}
if cfg.RawCopy().OriginalVersion != config.CurrentVersion {
if cfg.RawCopy().OriginalVersion == config.CurrentVersion+1101 {
l.Infof("Now, THAT's what we call a config from the future! Don't worry. As long as you hit that wire with the connecting hook at precisely eighty-eight miles per hour the instant the lightning strikes the tower... everything will be fine.")
}
if cfg.RawCopy().OriginalVersion > config.CurrentVersion && !allowNewerConfig {
return nil, fmt.Errorf("Config file version (%d) is newer than supported version (%d). If this is expected, use -allow-newer-config to override.", cfg.RawCopy().OriginalVersion, config.CurrentVersion)
}
err = archiveAndSaveConfig(cfg)
if err != nil {
return nil, errors.Wrap(err, "config archive")
}
}
return cfg, nil
}
func archiveAndSaveConfig(cfg config.Wrapper) error {
// Copy the existing config to an archive copy
archivePath := cfg.ConfigPath() + fmt.Sprintf(".v%d", cfg.RawCopy().OriginalVersion)
l.Infoln("Archiving a copy of old config file format at:", archivePath)
if err := copyFile(cfg.ConfigPath(), archivePath); err != nil {
return err
}
// Do a regular atomic config sve
return cfg.Save()
}
func copyFile(src, dst string) error {
bs, err := ioutil.ReadFile(src)
if err != nil {
return err
}
if err := ioutil.WriteFile(dst, bs, 0600); err != nil {
// Attempt to clean up
os.Remove(dst)
return err
}
return nil
}
func startAuditing(mainService *suture.Supervisor, auditFile string) {
func auditWriter(auditFile string) io.Writer {
var fd io.Writer
var err error
var auditDest string
@@ -1056,67 +718,14 @@ func startAuditing(mainService *suture.Supervisor, auditFile string) {
fd, err = os.OpenFile(auditFile, auditFlags, 0600)
if err != nil {
l.Warnln("Audit:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
auditDest = auditFile
}
auditService := newAuditService(fd)
mainService.Add(auditService)
// We wait for the audit service to fully start before we return, to
// ensure we capture all events from the start.
auditService.WaitForStart()
l.Infoln("Audit log in", auditDest)
}
func setupGUI(mainService *suture.Supervisor, cfg config.Wrapper, m model.Model, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connections.Service, urService *ur.Service, errors, systemLog logger.Recorder, runtimeOptions RuntimeOptions) {
guiCfg := cfg.GUI()
if !guiCfg.Enabled {
return
}
if guiCfg.InsecureAdminAccess {
l.Warnln("Insecure admin access is enabled.")
}
cpu := newCPUService()
mainService.Add(cpu)
summaryService := model.NewFolderSummaryService(cfg, m, myID)
mainService.Add(summaryService)
apiSvc := api.New(myID, cfg, runtimeOptions.assetDir, tlsDefaultCommonName, m, defaultSub, diskSub, discoverer, connectionsService, urService, summaryService, errors, systemLog, cpu, exit, noUpgradeFromEnv)
mainService.Add(apiSvc)
if err := apiSvc.WaitForStart(); err != nil {
l.Warnln("Failed starting API:", err)
os.Exit(exitError)
}
if cfg.Options().StartBrowser && !runtimeOptions.noBrowser && !runtimeOptions.stRestarting {
// Can potentially block if the utility we are invoking doesn't
// fork, and just execs, hence keep it in its own routine.
go func() { _ = openURL(guiCfg.URL()) }()
}
}
func defaultConfig(cfgFile string) (config.Wrapper, error) {
newCfg, err := config.NewWithFreePorts(myID)
if err != nil {
return nil, err
}
if noDefaultFolder {
l.Infoln("We will skip creation of a default folder on first start since the proper envvar is set")
return config.Wrap(cfgFile, newCfg), nil
}
newCfg.Folders = append(newCfg.Folders, config.NewFolderConfiguration(myID, "default", "Default Folder", fs.FilesystemTypeBasic, locations.Get(locations.DefFolder)))
l.Infoln("Default folder created and/or linked to new config")
return config.Wrap(cfgFile, newCfg), nil
return fd
}
func resetDB() error {
@@ -1146,7 +755,7 @@ func ensureDir(dir string, mode fs.FileMode) error {
return nil
}
func standbyMonitor() {
func standbyMonitor(app *syncthing.App) {
restartDelay := 60 * time.Second
now := time.Now()
for {
@@ -1159,16 +768,16 @@ func standbyMonitor() {
// things a moment to stabilize.
time.Sleep(restartDelay)
exit.Restart()
app.Stop(syncthing.ExitRestart)
return
}
now = time.Now()
}
}
func autoUpgrade(cfg config.Wrapper) {
func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger) {
timer := time.NewTimer(0)
sub := events.Default.Subscribe(events.DeviceConnected)
sub := evLogger.Subscribe(events.DeviceConnected)
for {
select {
case event := <-sub.C():
@@ -1190,7 +799,7 @@ func autoUpgrade(cfg config.Wrapper) {
rel, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
if err == upgrade.ErrUpgradeUnsupported {
events.Default.Unsubscribe(sub)
sub.Unsubscribe()
return
}
if err != nil {
@@ -1214,10 +823,10 @@ func autoUpgrade(cfg config.Wrapper) {
timer.Reset(checkInterval)
continue
}
events.Default.Unsubscribe(sub)
sub.Unsubscribe()
l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
time.Sleep(time.Minute)
exit.ExitUpgrading()
app.Stop(syncthing.ExitUpgrade)
return
}
}
@@ -1265,28 +874,13 @@ func cleanConfigDirectory() {
}
}
// checkShortIDs verifies that the configuration won't result in duplicate
// short ID:s; that is, that the devices in the cluster all have unique
// initial 64 bits.
func checkShortIDs(cfg config.Wrapper) error {
exists := make(map[protocol.ShortID]protocol.DeviceID)
for deviceID := range cfg.Devices() {
shortID := deviceID.Short()
if otherID, ok := exists[shortID]; ok {
return fmt.Errorf("%v in conflict with %v", deviceID, otherID)
}
exists[shortID] = deviceID
}
return nil
}
func showPaths(options RuntimeOptions) {
fmt.Printf("Configuration file:\n\t%s\n\n", locations.Get(locations.ConfigFile))
fmt.Printf("Database directory:\n\t%s\n\n", locations.Get(locations.Database))
fmt.Printf("Device private key & certificate files:\n\t%s\n\t%s\n\n", locations.Get(locations.KeyFile), locations.Get(locations.CertFile))
fmt.Printf("HTTPS private key & certificate files:\n\t%s\n\t%s\n\n", locations.Get(locations.HTTPSKeyFile), locations.Get(locations.HTTPSCertFile))
fmt.Printf("Log file:\n\t%s\n\n", options.logFile)
fmt.Printf("GUI override directory:\n\t%s\n\n", options.assetDir)
fmt.Printf("GUI override directory:\n\t%s\n\n", options.AssetDir)
fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations.Get(locations.DefFolder))
}
@@ -1300,6 +894,6 @@ func setPauseState(cfg config.Wrapper, paused bool) {
}
if _, err := cfg.Replace(raw); err != nil {
l.Warnln("Cannot adjust paused state:", err)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
}

View File

@@ -1,38 +0,0 @@
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"testing"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/protocol"
)
func TestShortIDCheck(t *testing.T) {
cfg := config.Wrap("/tmp/test", config.Configuration{
Devices: []config.DeviceConfiguration{
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 0, 0}},
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 1, 1}}, // first 56 bits same, differ in the first 64 bits
},
})
if err := checkShortIDs(cfg); err != nil {
t.Error("Unexpected error:", err)
}
cfg = config.Wrap("/tmp/test", config.Configuration{
Devices: []config.DeviceConfiguration{
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 0}},
{DeviceID: protocol.DeviceID{8, 16, 24, 32, 40, 48, 56, 64, 1}}, // first 64 bits same
},
})
if err := checkShortIDs(cfg); err == nil {
t.Error("Should have gotten an error")
}
}

View File

@@ -8,18 +8,24 @@ package main
import (
"bufio"
"context"
"fmt"
"io"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/syncthing"
)
var (
@@ -33,6 +39,8 @@ const (
loopThreshold = 60 * time.Second
logFileAutoCloseDelay = 5 * time.Second
logFileMaxOpenTime = time.Minute
panicUploadMaxWait = 30 * time.Second
panicUploadNoticeWait = 10 * time.Second
)
func monitorMain(runtimeOptions RuntimeOptions) {
@@ -42,7 +50,15 @@ func monitorMain(runtimeOptions RuntimeOptions) {
logFile := runtimeOptions.logFile
if logFile != "-" {
var fileDst io.Writer = newAutoclosedFile(logFile, logFileAutoCloseDelay, logFileMaxOpenTime)
var fileDst io.Writer
if runtimeOptions.logMaxSize > 0 {
open := func(name string) (io.WriteCloser, error) {
return newAutoclosedFile(name, logFileAutoCloseDelay, logFileMaxOpenTime), nil
}
fileDst = newRotatedFile(logFile, open, int64(runtimeOptions.logMaxSize), runtimeOptions.logMaxFiles)
} else {
fileDst = newAutoclosedFile(logFile, logFileAutoCloseDelay, logFileMaxOpenTime)
}
if runtime.GOOS == "windows" {
// Translate line breaks to Windows standard
@@ -72,9 +88,11 @@ func monitorMain(runtimeOptions RuntimeOptions) {
childEnv := childEnv()
first := true
for {
maybeReportPanics()
if t := time.Since(restarts[0]); t < loopThreshold {
l.Warnf("%d restarts in %v; not retrying further", countRestarts, t)
os.Exit(exitError)
os.Exit(syncthing.ExitError.AsInt())
}
copy(restarts[0:], restarts[1:])
@@ -96,7 +114,8 @@ func monitorMain(runtimeOptions RuntimeOptions) {
l.Infoln("Starting syncthing")
err = cmd.Start()
if err != nil {
panic(err)
l.Warnln("Error starting the main Syncthing process:", err)
panic("Error starting the main Syncthing process")
}
stdoutMut.Lock()
@@ -142,17 +161,14 @@ func monitorMain(runtimeOptions RuntimeOptions) {
// Successful exit indicates an intentional shutdown
return
} else if exiterr, ok := err.(*exec.ExitError); ok {
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
switch status.ExitStatus() {
case exitUpgrading:
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
l.Infoln("Restarting monitor...")
if err = restartMonitor(args); err != nil {
l.Warnln("Restart:", err)
}
return
if exiterr.ExitCode() == syncthing.ExitUpgrade.AsInt() {
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
l.Infoln("Restarting monitor...")
if err = restartMonitor(args); err != nil {
l.Warnln("Restart:", err)
}
return
}
}
}
@@ -173,6 +189,13 @@ func copyStderr(stderr io.Reader, dst io.Writer) {
br := bufio.NewReader(stderr)
var panicFd *os.File
defer func() {
if panicFd != nil {
_ = panicFd.Close()
maybeReportPanics()
}
}()
for {
line, err := br.ReadString('\n')
if err != nil {
@@ -304,6 +327,81 @@ func restartMonitorWindows(args []string) error {
return cmd.Start()
}
// rotatedFile keeps a set of rotating logs. There will be the base file plus up
// to maxFiles rotated ones, each ~ maxSize bytes large.
type rotatedFile struct {
name string
create createFn
maxSize int64 // bytes
maxFiles int
currentFile io.WriteCloser
currentSize int64
}
// the createFn should act equivalently to os.Create
type createFn func(name string) (io.WriteCloser, error)
func newRotatedFile(name string, create createFn, maxSize int64, maxFiles int) *rotatedFile {
return &rotatedFile{
name: name,
create: create,
maxSize: maxSize,
maxFiles: maxFiles,
}
}
func (r *rotatedFile) Write(bs []byte) (int, error) {
// Check if we're about to exceed the max size, and if so close this
// file so we'll start on a new one.
if r.currentSize+int64(len(bs)) > r.maxSize {
r.currentFile.Close()
r.currentFile = nil
r.currentSize = 0
}
// If we have no current log, rotate old files out of the way and create
// a new one.
if r.currentFile == nil {
r.rotate()
fd, err := r.create(r.name)
if err != nil {
return 0, err
}
r.currentFile = fd
}
n, err := r.currentFile.Write(bs)
r.currentSize += int64(n)
return n, err
}
func (r *rotatedFile) rotate() {
// The files are named "name", "name.0", "name.1", ...
// "name.(r.maxFiles-1)". Increase the numbers on the
// suffixed ones.
for i := r.maxFiles - 1; i > 0; i-- {
from := numberedFile(r.name, i-1)
to := numberedFile(r.name, i)
err := os.Rename(from, to)
if err != nil && !os.IsNotExist(err) {
fmt.Println("LOG: Rotating logs:", err)
}
}
// Rename the base to base.0
err := os.Rename(r.name, numberedFile(r.name, 0))
if err != nil && !os.IsNotExist(err) {
fmt.Println("LOG: Rotating logs:", err)
}
}
// numberedFile adds the number between the file name and the extension.
func numberedFile(name string, num int) string {
ext := filepath.Ext(name) // contains the dot
withoutExt := name[:len(name)-len(ext)]
return fmt.Sprintf("%s.%d%s", withoutExt, num, ext)
}
// An autoclosedFile is an io.WriteCloser that opens itself for appending on
// Write() and closes itself after an interval of no writes (closeDelay) or
// when the file has been open for too long (maxOpenTime). A call to Write()
@@ -430,3 +528,39 @@ func childEnv() []string {
env = append(env, "STMONITORED=yes")
return env
}
// maybeReportPanics tries to figure out if crash reporting is on or off,
// and reports any panics it can find if it's enabled. We spend at most
// panicUploadMaxWait uploading panics...
func maybeReportPanics() {
// Try to get a config to see if/where panics should be reported.
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
if err != nil {
l.Warnln("Couldn't load config; not reporting crash")
return
}
// Bail if we're not supposed to report panics.
opts := cfg.Options()
if !opts.CREnabled {
return
}
// Set up a timeout on the whole operation.
ctx, cancel := context.WithTimeout(context.Background(), panicUploadMaxWait)
defer cancel()
// Print a notice if the upload takes a long time.
go func() {
select {
case <-ctx.Done():
return
case <-time.After(panicUploadNoticeWait):
l.Warnln("Uploading crash reports is taking a while, please wait...")
}
}()
// Report the panics.
dir := locations.GetBaseDir(locations.ConfigBaseDir)
uploadPanicLogs(ctx, opts.CRURL, dir)
}

View File

@@ -7,6 +7,7 @@
package main
import (
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -14,6 +15,123 @@ import (
"time"
)
func TestRotatedFile(t *testing.T) {
// Verify that log rotation happens.
dir, err := ioutil.TempDir("", "syncthing")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
open := func(name string) (io.WriteCloser, error) {
return os.Create(name)
}
logName := filepath.Join(dir, "log.txt")
testData := []byte("12345678\n")
maxSize := int64(len(testData) + len(testData)/2)
// We allow the log file plus two rotated copies.
rf := newRotatedFile(logName, open, maxSize, 2)
// Write some bytes.
if _, err := rf.Write(testData); err != nil {
t.Fatal(err)
}
// They should be in the log.
checkSize(t, logName, len(testData))
checkNotExist(t, logName+".0")
// Write some more bytes. We should rotate and write into a new file as the
// new bytes don't fit.
if _, err := rf.Write(testData); err != nil {
t.Fatal(err)
}
checkSize(t, logName, len(testData))
checkSize(t, numberedFile(logName, 0), len(testData))
checkNotExist(t, logName+".1")
// Write another byte. That should fit without causing an extra rotate.
_, _ = rf.Write([]byte{42})
checkSize(t, logName, len(testData)+1)
checkSize(t, numberedFile(logName, 0), len(testData))
checkNotExist(t, numberedFile(logName, 1))
// Write some more bytes. We should rotate and write into a new file as the
// new bytes don't fit.
if _, err := rf.Write(testData); err != nil {
t.Fatal(err)
}
checkSize(t, logName, len(testData))
checkSize(t, numberedFile(logName, 0), len(testData)+1) // the one we wrote extra to, now rotated
checkSize(t, numberedFile(logName, 1), len(testData))
checkNotExist(t, numberedFile(logName, 2))
// Write some more bytes. We should rotate and write into a new file as the
// new bytes don't fit.
if _, err := rf.Write(testData); err != nil {
t.Fatal(err)
}
checkSize(t, logName, len(testData))
checkSize(t, numberedFile(logName, 0), len(testData))
checkSize(t, numberedFile(logName, 1), len(testData)+1)
checkNotExist(t, numberedFile(logName, 2)) // exceeds maxFiles so deleted
}
func TestNumberedFile(t *testing.T) {
// Mostly just illustrates where the number ends up and makes sure it
// doesn't crash without an extension.
cases := []struct {
in string
num int
out string
}{
{
in: "syncthing.log",
num: 42,
out: "syncthing.42.log",
},
{
in: filepath.Join("asdfasdf", "syncthing.log.txt"),
num: 42,
out: filepath.Join("asdfasdf", "syncthing.log.42.txt"),
},
{
in: "syncthing-log",
num: 42,
out: "syncthing-log.42",
},
}
for _, tc := range cases {
res := numberedFile(tc.in, tc.num)
if res != tc.out {
t.Errorf("numberedFile(%q, %d) => %q, expected %q", tc.in, tc.num, res, tc.out)
}
}
}
func checkSize(t *testing.T, name string, size int) {
t.Helper()
info, err := os.Lstat(name)
if err != nil {
t.Fatal(err)
}
if info.Size() != int64(size) {
t.Errorf("%s wrong size: %d != expected %d", name, info.Size(), size)
}
}
func checkNotExist(t *testing.T, name string) {
t.Helper()
_, err := os.Lstat(name)
if !os.IsNotExist(err) {
t.Errorf("%s should not exist", name)
}
}
func TestAutoClosedFile(t *testing.T) {
os.RemoveAll("_autoclose")
defer os.RemoveAll("_autoclose")

View File

@@ -1,39 +0,0 @@
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
// +build ignore
package main
import (
"bytes"
"fmt"
"io"
"os"
)
func main() {
buf := make([]byte, 4096)
var err error
for err == nil {
n, err := io.ReadFull(os.Stdin, buf)
if n > 0 {
buf = buf[:n]
repl := bytes.Replace(buf, []byte("\n"), []byte("\r\n"), -1)
_, err = os.Stdout.Write(repl)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
if err == io.EOF {
return
}
buf = buf[:cap(buf)]
}
fmt.Println(err)
os.Exit(1)
}

View File

@@ -24,10 +24,10 @@ type analyticList []analytic
func (l analyticList) Less(a, b int) bool {
if l[a].Key == "Others" {
return true
return false
}
if l[b].Key == "Others" {
return false
return true
}
return l[b].Count < l[a].Count // inverse
}

View File

@@ -21,11 +21,14 @@ const (
)
func number(ntype NumberType, v float64) string {
if ntype == NumberDuration {
switch ntype {
case NumberMetric:
return metric(v)
case NumberDuration:
return duration(v)
} else if ntype == NumberBinary {
case NumberBinary:
return binary(v)
} else {
default:
return metric(v)
}
}

View File

@@ -33,20 +33,41 @@ import (
)
var (
useHTTP = os.Getenv("UR_USE_HTTP") != ""
debug = os.Getenv("UR_DEBUG") != ""
keyFile = getEnvDefault("UR_KEY_FILE", "key.pem")
certFile = getEnvDefault("UR_CRT_FILE", "crt.pem")
dbConn = getEnvDefault("UR_DB_URL", "postgres://user:password@localhost/ur?sslmode=disable")
listenAddr = getEnvDefault("UR_LISTEN", "0.0.0.0:8443")
geoIPPath = getEnvDefault("UR_GEOIP", "GeoLite2-City.mmdb")
tpl *template.Template
compilerRe = regexp.MustCompile(`\(([A-Za-z0-9()., -]+) \w+-\w+(?:| android| default)\) ([\w@.-]+)`)
progressBarClass = []string{"", "progress-bar-success", "progress-bar-info", "progress-bar-warning", "progress-bar-danger"}
featureOrder = []string{"Various", "Folder", "Device", "Connection", "GUI"}
knownVersions = []string{"v2", "v3"}
useHTTP = os.Getenv("UR_USE_HTTP") != ""
debug = os.Getenv("UR_DEBUG") != ""
keyFile = getEnvDefault("UR_KEY_FILE", "key.pem")
certFile = getEnvDefault("UR_CRT_FILE", "crt.pem")
dbConn = getEnvDefault("UR_DB_URL", "postgres://user:password@localhost/ur?sslmode=disable")
listenAddr = getEnvDefault("UR_LISTEN", "0.0.0.0:8443")
geoIPPath = getEnvDefault("UR_GEOIP", "GeoLite2-City.mmdb")
tpl *template.Template
compilerRe = regexp.MustCompile(`\(([A-Za-z0-9()., -]+) \w+-\w+(?:| android| default)\) ([\w@.-]+)`)
progressBarClass = []string{"", "progress-bar-success", "progress-bar-info", "progress-bar-warning", "progress-bar-danger"}
featureOrder = []string{"Various", "Folder", "Device", "Connection", "GUI"}
knownVersions = []string{"v2", "v3"}
knownDistributions = []distributionMatch{
// Maps well known builders to the official distribution method that
// they represent
{regexp.MustCompile("android-.*teamcity@build.syncthing.net"), "Google Play"},
{regexp.MustCompile("teamcity@build.syncthing.net"), "GitHub"},
{regexp.MustCompile("deb@build.syncthing.net"), "APT"},
{regexp.MustCompile("docker@syncthing.net"), "Docker Hub"},
{regexp.MustCompile("jenkins@build.syncthing.net"), "GitHub"},
{regexp.MustCompile("snap@build.syncthing.net"), "Snapcraft"},
{regexp.MustCompile("android-.*vagrant@basebox-stretch64"), "F-Droid"},
{regexp.MustCompile("builduser@svetlemodry"), "Arch (3rd party)"},
{regexp.MustCompile("@debian"), "Debian (3rd party)"},
{regexp.MustCompile("@fedora"), "Fedora (3rd party)"},
{regexp.MustCompile(`\bbrew@`), "Homebrew (3rd party)"},
{regexp.MustCompile("."), "Others"},
}
)
type distributionMatch struct {
matcher *regexp.Regexp
distribution string
}
var funcs = map[string]interface{}{
"commatize": commatize,
"number": number,
@@ -705,7 +726,8 @@ func main() {
if useHTTP {
listener, err = net.Listen("tcp", listenAddr)
} else {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
var cert tls.Certificate
cert, err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatalln("tls:", err)
}
@@ -733,6 +755,8 @@ func main() {
http.HandleFunc("/blockstats.json", withDB(db, blockStatsHandler))
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
go cacheRefresher(db)
err = srv.Serve(listener)
if err != nil {
log.Fatalln("https:", err)
@@ -745,7 +769,31 @@ var (
cacheMut sync.Mutex
)
const maxCacheTime = 5 * 60 * time.Second
const maxCacheTime = 15 * time.Minute
func cacheRefresher(db *sql.DB) {
ticker := time.NewTicker(maxCacheTime - time.Minute)
defer ticker.Stop()
for range ticker.C {
cacheMut.Lock()
if err := refreshCacheLocked(db); err != nil {
log.Println(err)
}
cacheMut.Unlock()
}
}
func refreshCacheLocked(db *sql.DB) error {
rep := getReport(db)
buf := new(bytes.Buffer)
err := tpl.Execute(buf, rep)
if err != nil {
return err
}
cacheData = buf.Bytes()
cacheTime = time.Now()
return nil
}
func rootHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
@@ -753,16 +801,11 @@ func rootHandler(db *sql.DB, w http.ResponseWriter, r *http.Request) {
defer cacheMut.Unlock()
if time.Since(cacheTime) > maxCacheTime {
rep := getReport(db)
buf := new(bytes.Buffer)
err := tpl.Execute(buf, rep)
if err != nil {
if err := refreshCacheLocked(db); err != nil {
log.Println(err)
http.Error(w, "Template Error", http.StatusInternalServerError)
return
}
cacheData = buf.Bytes()
cacheTime = time.Now()
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
@@ -1001,6 +1044,7 @@ func getReport(db *sql.DB) map[string]interface{} {
var uptime []int
var compilers []string
var builders []string
var distributions []string
locations := make(map[location]int)
countries := make(map[string]int)
@@ -1070,10 +1114,19 @@ func getReport(db *sql.DB) map[string]interface{} {
nodes++
versions = append(versions, transformVersion(rep.Version))
platforms = append(platforms, rep.Platform)
if m := compilerRe.FindStringSubmatch(rep.LongVersion); len(m) == 3 {
compilers = append(compilers, m[1])
builders = append(builders, m[2])
loop:
for _, d := range knownDistributions {
if d.matcher.MatchString(rep.LongVersion) {
distributions = append(distributions, d.distribution)
break loop
}
}
}
if rep.NumFolders > 0 {
numFolders = append(numFolders, rep.NumFolders)
}
@@ -1363,9 +1416,10 @@ func getReport(db *sql.DB) map[string]interface{} {
r["categories"] = categories
r["versions"] = group(byVersion, analyticsFor(versions, 2000), 10)
r["versionPenetrations"] = penetrationLevels(analyticsFor(versions, 2000), []float64{50, 75, 90, 95})
r["platforms"] = group(byPlatform, analyticsFor(platforms, 2000), 5)
r["platforms"] = group(byPlatform, analyticsFor(platforms, 2000), 10)
r["compilers"] = group(byCompiler, analyticsFor(compilers, 2000), 5)
r["builders"] = analyticsFor(builders, 12)
r["distributions"] = analyticsFor(distributions, 10)
r["featureOrder"] = featureOrder
r["locations"] = locations
r["contries"] = countryList
@@ -1373,15 +1427,6 @@ func getReport(db *sql.DB) map[string]interface{} {
return r
}
func ensureDir(dir string, mode int) {
fi, err := os.Stat(dir)
if os.IsNotExist(err) {
os.MkdirAll(dir, 0700)
} else if mode >= 0 && err == nil && int(fi.Mode()&0777) != mode {
os.Chmod(dir, os.FileMode(mode))
}
}
var (
plusRe = regexp.MustCompile(`\+.*$`)
plusStr = "(+dev)"

View File

@@ -506,6 +506,27 @@ found in the LICENSE file.
</table>
</div>
<div class="col-md-6">
<table class="table table-striped">
<thead>
<tr>
<th>Distribution Channel</th>
<th class="text-right">Devices</th>
<th class="text-right">Share</th>
</tr>
</thead>
<tbody>
{{range .distributions}}
<tr>
<td>{{.Key}}</td>
<td class="text-right">{{.Count}}</td>
<td class="text-right">{{.Percentage | printf "%.01f"}}%</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
<div class="row">

View File

@@ -9,8 +9,6 @@ SuccessExitStatus=3 4
RestartForceExitStatus=3 4
# Hardening
ProtectSystem=full
PrivateTmp=true
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
NoNewPrivileges=true

64
go.mod
View File

@@ -2,46 +2,52 @@ module github.com/syncthing/syncthing
require (
github.com/AudriusButkevicius/go-nat-pmp v0.0.0-20160522074932-452c97607362
github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6
github.com/AudriusButkevicius/recli v0.0.5
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/bkaradzic/go-lz4 v0.0.0-20160924222819-7224d8d8f27e
github.com/calmh/du v1.0.1
github.com/calmh/xdr v1.1.0
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 // indirect
github.com/chmduquesne/rollinghash v0.0.0-20180912150627-a60f8e7142b5
github.com/d4l3k/messagediff v1.2.1
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568
github.com/gobwas/glob v0.0.0-20170212200151-51eb1ee00b6d
github.com/gogo/protobuf v1.2.0
github.com/golang/groupcache v0.0.0-20171101203131-84a468cf14b4
github.com/golang/snappy v0.0.0-20170215233205-553a64147049 // indirect
github.com/jackpal/gateway v0.0.0-20161225004348-5795ac81146e
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657
github.com/getsentry/raven-go v0.2.0
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/gobwas/glob v0.2.3
github.com/gogo/protobuf v1.3.1
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6
github.com/golang/mock v1.3.1 // indirect
github.com/jackpal/gateway v1.0.5
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/kr/pretty v0.1.0 // indirect
github.com/lib/pq v1.0.0
github.com/mattn/go-isatty v0.0.4
github.com/minio/sha256-simd v0.0.0-20190117184323-cc1980cb0338
github.com/onsi/ginkgo v0.0.0-20171221013426-6c46eb8334b3 // indirect
github.com/onsi/gomega v0.0.0-20171227184521-ba3724c94e4d // indirect
github.com/oschwald/geoip2-golang v1.1.0
github.com/oschwald/maxminddb-golang v0.0.0-20170901134056-26fe5ace1c70 // indirect
github.com/petermattis/goid v0.0.0-20170816195418-3db12ebb2a59 // indirect
github.com/lib/pq v1.2.0
github.com/lucas-clemente/quic-go v0.12.1
github.com/maruel/panicparse v1.3.0
github.com/mattn/go-isatty v0.0.10
github.com/minio/sha256-simd v0.1.1
github.com/onsi/ginkgo v1.9.0 // indirect
github.com/onsi/gomega v1.6.0 // indirect
github.com/oschwald/geoip2-golang v1.3.0
github.com/oschwald/maxminddb-golang v1.4.0 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pkg/errors v0.8.1
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v0.9.2
github.com/rcrowley/go-metrics v0.0.0-20171128170426-e181e095bae9
github.com/prometheus/client_golang v1.2.1
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563
github.com/sasha-s/go-deadlock v0.2.0
github.com/stretchr/testify v1.2.2 // indirect
github.com/syncthing/notify v0.0.0-20181107104724-4e389ea6c0d8
github.com/syndtr/goleveldb v0.0.0-20171214120811-34011bf325bc
github.com/shirou/gopsutil v0.0.0-20190714054239-47ef3260b6bf
github.com/syncthing/notify v0.0.0-20190709140112-69c7a957d3e2
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
github.com/thejerf/suture v3.0.2+incompatible
github.com/urfave/cli v1.20.0
github.com/urfave/cli v1.22.2
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc
golang.org/x/text v0.0.0-20171227012246-e19ae1496984
golang.org/x/time v0.0.0-20170927054726-6dc17368e09b
gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225 // indirect
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
golang.org/x/text v0.3.2
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/ldap.v2 v2.5.1
gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab // indirect
)
go 1.12

281
go.sum
View File

@@ -1,110 +1,279 @@
github.com/AudriusButkevicius/go-nat-pmp v0.0.0-20160522074932-452c97607362 h1:l4qGIzSY0WhdXdR74XMYAtfc0Ri/RJVM4p6x/E/+WkA=
github.com/AudriusButkevicius/go-nat-pmp v0.0.0-20160522074932-452c97607362/go.mod h1:CEaBhA5lh1spxbPOELh5wNLKGsVQoahjUhVrJViVK8s=
github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6 h1:Apvc4kyfdrOxG+F5dn8osz+45kwGJa6CySQn0tB38SU=
github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6/go.mod h1:1N0EEx/irz4B1qV17wW82TFbjQrE7oX316Cki6eDY0Q=
github.com/AudriusButkevicius/recli v0.0.5 h1:xUa55PvWTHBm17T6RvjElRO3y5tALpdceH86vhzQ5wg=
github.com/AudriusButkevicius/recli v0.0.5/go.mod h1:Q2E26yc6RvWWEz/TJ/goUp6yXvipYdJI096hpoaqsNs=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bkaradzic/go-lz4 v0.0.0-20160924222819-7224d8d8f27e h1:2augTYh6E+XoNrrivZJBadpThP/dsvYKj0nzqfQ8tM4=
github.com/bkaradzic/go-lz4 v0.0.0-20160924222819-7224d8d8f27e/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/calmh/du v1.0.1 h1:uDCrDbXVVPrzxSNRkpj6nqSfwrl5uRWH3zvrJgl7RRo=
github.com/calmh/du v1.0.1/go.mod h1:pHNccp4cXQeyDaiV3S7t5GN+eGOgynF0VSLxJjk9tLU=
github.com/calmh/xdr v1.1.0 h1:U/Dd4CXNLoo8EiQ4ulJUXkgO1/EyQLgDKLgpY1SOoJE=
github.com/calmh/xdr v1.1.0/go.mod h1:E8sz2ByAdXC8MbANf1LCRYzedSnnc+/sXXJs/PVqoeg=
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 h1:8k9FLYBLKT+9v2HQJ/a95ZemmTx+/ltJcAiRhVushG8=
github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/chmduquesne/rollinghash v0.0.0-20180912150627-a60f8e7142b5 h1:Wg96Dh0MLTanEaPO0OkGtUIaa2jOnShAIOVUIzRHUxo=
github.com/chmduquesne/rollinghash v0.0.0-20180912150627-a60f8e7142b5/go.mod h1:Uc2I36RRfTAf7Dge82bi3RU0OQUmXT9iweIcPqvr8A0=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BMXYYRWTLOJKlh+lOBt6nUQgXAfB7oVIQt5cNreqSLI=
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
github.com/gobwas/glob v0.0.0-20170212200151-51eb1ee00b6d h1:IngNQgbqr5ZOU0exk395Szrvkzes9Ilk1fmJfkw7d+M=
github.com/gobwas/glob v0.0.0-20170212200151-51eb1ee00b6d/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/groupcache v0.0.0-20171101203131-84a468cf14b4 h1:6o8aP0LGMKzo3NzwhhX6EJsiJ3ejmj+9yA/3p8Fjjlw=
github.com/golang/groupcache v0.0.0-20171101203131-84a468cf14b4/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0aZrsoHpLJlZsBrGMFWbgLDGnPZk=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/jackpal/gateway v0.0.0-20161225004348-5795ac81146e h1:lS8IitpqG4RkZbEDlZg5Z7FvBdWLVjSVfsPGOKafEkI=
github.com/jackpal/gateway v0.0.0-20161225004348-5795ac81146e/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7cCpiRVEIr1B5ccDxRpbPsWT5JU3if2Di5nE4=
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lucas-clemente/quic-go v0.12.0 h1:TRbvZ6F++sofeGbh+Z2IIyIOhl8KyGnYuA06g2yrHdI=
github.com/lucas-clemente/quic-go v0.12.0/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s=
github.com/lucas-clemente/quic-go v0.12.1 h1:BPITli+6KnKogtTxBk2aS4okr5dUHz2LtIDAP1b8UL4=
github.com/lucas-clemente/quic-go v0.12.1/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s=
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
github.com/marten-seemann/qtls v0.3.2 h1:O7awy4bHEzSX/K3h+fZig3/Vo03s/RxlxgsAk9sYamI=
github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
github.com/maruel/panicparse v1.3.0 h1:1Ep/RaYoSL1r5rTILHQQbyzHG8T4UP5ZbQTYTo4bdDc=
github.com/maruel/panicparse v1.3.0/go.mod h1:vszMjr5QQ4F5FSRfraldcIA/BCw5xrdLL+zEcU2nRBs=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/minio/sha256-simd v0.0.0-20190117184323-cc1980cb0338 h1:USW1+zAUkUSvk097CAX/i8KR3r6f+DHNhk6Xe025Oyw=
github.com/minio/sha256-simd v0.0.0-20190117184323-cc1980cb0338/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/onsi/ginkgo v0.0.0-20171221013426-6c46eb8334b3 h1:ZN7kHmC0iunA+4UPmERwsuMQan4lUnntO6WX6H1jOO8=
github.com/onsi/ginkgo v0.0.0-20171221013426-6c46eb8334b3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20171227184521-ba3724c94e4d h1:r351oUAFgdsydkt/g+XR/iJWRwyxVpy6nkNdEl/QdAs=
github.com/onsi/gomega v0.0.0-20171227184521-ba3724c94e4d/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/oschwald/geoip2-golang v1.1.0 h1:ACVPz5YqH4/jZkQdsp/PZc9shQVZmreCzAVNss5y3bo=
github.com/oschwald/geoip2-golang v1.1.0/go.mod h1:0LTTzix/Ao1uMvOhAV4iLU0Lz7eCrP94qZWBTDKf0iE=
github.com/oschwald/maxminddb-golang v0.0.0-20170901134056-26fe5ace1c70 h1:XGLYUmodtNzThosQ8GkMvj9TiIB/uWsP8NfxKSa3aDc=
github.com/oschwald/maxminddb-golang v0.0.0-20170901134056-26fe5ace1c70/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
github.com/petermattis/goid v0.0.0-20170816195418-3db12ebb2a59 h1:2pHcLyJYXivxVvpoCc29uo3GDU1qFfJ1ggXKGYMrM0E=
github.com/petermattis/goid v0.0.0-20170816195418-3db12ebb2a59/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.9.0 h1:SZjF721BByVj8QH636/8S2DnX4n0Re3SteMmw3N+tzc=
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.6.0 h1:8XTW0fcJZEq9q+Upcyws4JSGua2MFysCL5xkaSgHc+M=
github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/oschwald/geoip2-golang v1.3.0 h1:D+Hsdos1NARPbzZ2aInUHZL+dApIzo8E0ErJVsWcku8=
github.com/oschwald/geoip2-golang v1.3.0/go.mod h1:0LTTzix/Ao1uMvOhAV4iLU0Lz7eCrP94qZWBTDKf0iE=
github.com/oschwald/maxminddb-golang v1.4.0 h1:5/rpmW41qrgSed4wK32rdznbkTSXHcraY2LOMJX4DMc=
github.com/oschwald/maxminddb-golang v1.4.0/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rcrowley/go-metrics v0.0.0-20171128170426-e181e095bae9 h1:jmLW6izPBVlIbk4d+XgK9+sChGbVKxxOPmd9eqRHCjw=
github.com/rcrowley/go-metrics v0.0.0-20171128170426-e181e095bae9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.4 h1:w8DjqFMJDjuVwdZBQoOozr4MVWOnwF7RcL/7uxBjY78=
github.com/prometheus/procfs v0.0.4/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
github.com/shirou/gopsutil v0.0.0-20190714054239-47ef3260b6bf h1:c9SV5NzG4KOk448TUE7iqCmb4E4y79CZF4zDdc1Jx3Q=
github.com/shirou/gopsutil v0.0.0-20190714054239-47ef3260b6bf/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/syncthing/notify v0.0.0-20181107104724-4e389ea6c0d8 h1:ewsMW/a4xDpqHyIteoD29ayMn6GdkFZc2T0PX2K6PAg=
github.com/syncthing/notify v0.0.0-20181107104724-4e389ea6c0d8/go.mod h1:Sn4ChoS7e4FxjCN1XHPVBT43AgnRLbuaB8pEc1Zcdjg=
github.com/syndtr/goleveldb v0.0.0-20171214120811-34011bf325bc h1:yhWARKbbDg8UBRi/M5bVcVOBg2viFKcNJEAtHMYbRBo=
github.com/syndtr/goleveldb v0.0.0-20171214120811-34011bf325bc/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/syncthing/notify v0.0.0-20190709140112-69c7a957d3e2 h1:6tuEEEpg+mxM82E0YingzoXzXXISYR/o/7I9n573LWI=
github.com/syncthing/notify v0.0.0-20190709140112-69c7a957d3e2/go.mod h1:Sn4ChoS7e4FxjCN1XHPVBT43AgnRLbuaB8pEc1Zcdjg=
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw=
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/thejerf/suture v3.0.2+incompatible h1:GtMydYcnK4zBJ0KL6Lx9vLzl6Oozb65wh252FTBxrvM=
github.com/thejerf/suture v3.0.2+incompatible/go.mod h1:ibKwrVj+Uzf3XZdAiNWUouPaAbSoemxOHLmJmwheEMc=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
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=
golang.org/x/crypto v0.0.0-20171231215028-0fcca4842a8d h1:GrqEEc3+MtHKTsZrdIGVoYDgLpbSRzW1EF+nLu0PcHE=
golang.org/x/crypto v0.0.0-20171231215028-0fcca4842a8d/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06 h1:0oC8rFnE+74kEmuHZ46F6KHsMr5Gx2gUQPuNz28iQZM=
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.0.0-20171227012246-e19ae1496984 h1:ulYJn/BqO4fMRe1xAQzWjokgjsQLPpb21GltxXHI3fQ=
golang.org/x/text v0.0.0-20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20170927054726-6dc17368e09b h1:3X+R0qq1+64izd8es+EttB6qcY+JDlVmAhpRXl7gpzU=
golang.org/x/time v0.0.0-20170927054726-6dc17368e09b/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225 h1:JBwmEvLfCqgPcIq8MjVMQxsF3LVL4XG/HH0qiG0+IFY=
gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab h1:yZ6iByf7GKeJ3gsd1Dr/xaj1DyJ//wxKX1Cdh8LhoAw=
gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -24,6 +24,27 @@ a:hover,a:focus,a.focus{
border-width: 2px !important;
}
.nav-tabs > li.active > a,
.nav-tabs > li.active > a:hover,
.nav-tabs > li.active > a:focus {
color: #3498db !important;
background-color: #222222 !important;
border: 1px solid #222222 !important;
border-bottom-color: transparent !important;
cursor: default;
}
.nav-tabs{
border-bottom: 1px solid #333;
}
.nav-tabs > li > a:hover,
.nav-tabs > li > a:focus {
background-color: #222222 !important;
border: none !important;
}
.navbar-text, .dropdown>a, .dropdown-menu>li>a, .hidden-xs>a, .navbar-link {
color: #aaa !important;
}

View File

@@ -28,6 +28,27 @@ a:hover,a:focus,a.focus{
}
.nav-tabs > li.active > a,
.nav-tabs > li.active > a:hover,
.nav-tabs > li.active > a:focus {
color: #3498db !important;
background-color: #424242 !important;
border: 1px solid #424242 !important;
border-bottom-color: transparent !important;
cursor: default;
}
.nav-tabs{
border-bottom: 1px solid #333;
}
.nav-tabs > li > a:hover,
.nav-tabs > li > a:focus {
background-color: #424242 !important;
border: none !important;
}
.navbar-text, .dropdown>a, .dropdown-menu>li>a, .hidden-xs>a, .navbar-link {
color: #aaa !important;
}

View File

@@ -124,6 +124,18 @@ table.table-condensed td.no-overflow-ellipse {
white-space: normal;
}
table.table-auto {
table-layout: auto;
}
table.table-auto th {
width: 1px;
}
table.table-auto td {
max-width: 0px;
}
.folder-advanced {
padding: 1rem;
margin-bottom: 15px;
@@ -234,6 +246,14 @@ a.toggler:hover {
text-decoration: none;
}
/**
* Panel padding decrease
*/
.panel-collapse .panel-body {
padding: 5px;
}
/**
* Progress bars with centered text
*/
@@ -336,6 +356,12 @@ ul.three-columns li, ul.two-columns li {
* columns. */
white-space: normal;
}
.two-columns {
-webkit-column-count: 1;
-moz-column-count: 1;
column-count: 1;
}
}
@media (max-width:479px) {
@@ -360,3 +386,32 @@ ul.three-columns li, ul.two-columns li {
.fancytree-ext-table {
width: 100% !important;
}
@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 */
div[id^='device-'].panel-collapse table,
div[id^='folder-'].panel-collapse table,
div[id^='device-'].panel-collapse tbody,
div[id^='folder-'].panel-collapse tbody,
div[id^='device-'].panel-collapse tr,
div[id^='folder-'].panel-collapse tr {
display: block;
}
div[id^='device-'].panel-collapse th,
div[id^='folder-'].panel-collapse th,
div[id^='device-'].panel-collapse td,
div[id^='folder-'].panel-collapse td {
display: block;
max-width: 100%;
width: 100%;
}
/* all buttons, except panel headings, get bottom margin, as they won't fit
beside each other anymore */
.btn:not(.panel-heading),
/* this "+"-selector is needed to override some bootstrap defaults */
.btn:not(.panel-heading) + .btn:not(.panel-heading) {
margin-bottom: 1rem;
}
}

View File

@@ -7,29 +7,5 @@
*/
.panel-progress {
background: #3498db;
}
.identicon rect {
fill: #333;
}
.panel-warning .identicon rect {
fill: #fff;
}
.li-column {
background-color: rgb(236, 240, 241);
border-radius: 3px;
}
.panel-heading:hover, .panel-heading:focus {
text-decoration: none;
}
.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title,
.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title {
color: black !important;
font-weight: lighter !important;
}
@import "../../theme-assets/dark/assets/css/theme.css" screen and (prefers-color-scheme: dark);
@import "../../theme-assets/light/assets/css/theme.css" (prefers-color-scheme: light), (prefers-color-scheme: no-preference);

View File

@@ -171,6 +171,7 @@
"Log": "Доклад",
"Log tailing paused. Click here to continue.": "Докладът е замразен. Натиснете, за да продължите.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Доклади",
"Major Upgrade": "Основно Обновяване",
"Mass actions": "Действия за всички",
@@ -295,6 +296,7 @@
"Syncing": "Синхронизиране",
"Syncthing has been shut down.": "Syncthing е спрян.",
"Syncthing includes the following software or portions thereof:": "Syncthing уползотворява частично или изцяло следните софтуерни продукти:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing се рестартира",
"Syncthing is upgrading.": "Syncthing се обновява.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Изглежда, че Syncthing не е включен, или има проблем с връзката с Интернет. Повторен опит...",

View File

@@ -34,7 +34,7 @@
"Auto Accept": "Auto Acceptar",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "L'actualització automàtica ara ofereix l'elecció entre les versions estables i les versions candidates.",
"Automatic upgrades": "Actualitzacions automàtiques",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Les actualitzacions automàtiques sempre estàn activades per a les versions candidates.",
"Automatically create or share folders that this device advertises at the default path.": "Crear o compartir automàticament les carpetes que aquest dispositiu anuncia en la ruta per defecte.",
"Available debug logging facilities:": "Hi han disponibles les següents utilitats per a depurar el registre:",
"Be careful!": "Tin precaució!",
@@ -56,13 +56,13 @@
"Copied from original": "Copiat de l'original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 els següents Col·laboradors:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 els següents Col·laboradors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 els següents Col·laboradors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creant patrons a ignorar, sobreescriguent un fitxer que ja existeix a {{path}}.",
"Danger!": "Perill!",
"Debugging Facilities": "Utilitats de Depuració",
"Default Folder Path": "Carpeta de la Ruta per Defecte",
"Deleted": "Esborrat",
"Deselect All": "Deselect All",
"Deselect All": "Anul·lar tota la selecció",
"Device": "Dispositiu",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Dispositiu \"{{name}}\" ({{device}} a l'adreça {{address}}) vol connectar. Afegir nou dispositiu?",
"Device ID": "ID del dispositiu",
@@ -75,7 +75,7 @@
"Disabled periodic scanning and disabled watching for changes": "Desactivat l'escaneig periòdic i el rastreig continu de canvis",
"Disabled periodic scanning and enabled watching for changes": "Desactivat l'escaneig periòdic i activat el rastreig continu de canvis",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Desactivat l'escaneig periòdic i errada al rastreig continu de canvis, es reintentarà cada 1 minut:",
"Discard": "Discard",
"Discard": "Descartar",
"Disconnected": "Desconnectat",
"Discovered": "Descobert",
"Discovery": "Descobriment",
@@ -98,7 +98,7 @@
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Introdueix un nombre no negatiu (per exemple, \"2.35\") i selecciona una unitat. Els percentatges són com a part del tamany total del disc.",
"Enter a non-privileged port number (1024 - 65535).": "Introdueix un nombre de port sense privilegis (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introdueix adreces separades per coma (\"tcp://ip:port\", \"tcp://host:port\") o \"dynamic\" per a realitzar el descobriment automàtic de l'adreça.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduïr adreces separades per coma (\"tcp://ip:port\", \"tcp://host:port\") o dinàmiques per al descobriment automàtic de l'adreça.",
"Enter ignore patterns, one per line.": "Introduïr patrons a ignorar, un per línia.",
"Error": "Error",
"External File Versioning": "Versionat extern de fitxers",
@@ -144,9 +144,9 @@
"Ignore": "Ignorar",
"Ignore Patterns": "Patrons a ignorar",
"Ignore Permissions": "Permisos a ignorar",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored at": "Ignored at",
"Ignored Devices": "Dispositius Ignorats",
"Ignored Folders": "Carpetes Ignorades",
"Ignored at": "Ignorat en",
"Incoming Rate Limit (KiB/s)": "Límit de descàrrega (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "La configuración incorrecta pot danyar el contingut de la teua carpeta i deixar Syncthing inoperatiu.",
"Introduced By": "Introduït Per",
@@ -160,17 +160,18 @@
"Later": "Més tard",
"Latest Change": "Últim Canvi",
"Learn more": "Saber més",
"Limit": "Limit",
"Limit": "Límit",
"Listeners": "Escoltants",
"Loading data...": "Carregant dades...",
"Loading...": "Carregant...",
"Local Discovery": "Descobriment local",
"Local State": "Estat local",
"Local State (Total)": "Estat Local (Total)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "Dispositius Canviats Localment",
"Log": "Registre",
"Log tailing paused. Click here to continue.": "Pausada l'adició de dades al registre. Polsa ací per continuar.",
"Log tailing paused. Scroll to bottom continue.": "Pausat el seguiment del registre. Es continua fins al final.",
"Log tailing paused. Scroll to the bottom to continue.": "Pausada l'anotació al registre. Baixeu fins al final per continuar.",
"Logs": "Registres",
"Major Upgrade": "Actualització important",
"Mass actions": "Accions en masa",
@@ -209,7 +210,7 @@
"Pause": "Pausa",
"Pause All": "Pausa Tot",
"Paused": "Pausat",
"Pending changes": "Pending changes",
"Pending changes": "Canvis pendents",
"Periodic scanning at given interval and disabled watching for changes": "Escaneig periòdic a l'interval determinat i desactivat el rastreig continu de canvis",
"Periodic scanning at given interval and enabled watching for changes": "Escaneig periòdic a l'interval determinat i activat el rastreig continu de canvis",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Escaneig periòdic a l'interval determinat i errada al activar el rastreig continu de canvis, reintentant cada 1 minut:",
@@ -224,7 +225,7 @@
"Quick guide to supported patterns": "Guía ràpida de patrons suportats",
"RAM Utilization": "Utilització de la RAM",
"Random": "Aleatori",
"Receive Only": "Només recivir",
"Receive Only": "Només rebre",
"Recent Changes": "Canvis Recents",
"Reduced by ignore patterns": "Reduït ignorant patrons",
"Release Notes": "Notes de la versió",
@@ -253,7 +254,7 @@
"Scanning": "Rastrejant",
"See external versioner help for supported templated command line parameters.": "Consulta l'ajuda externa sobre versions per a conéixer els paràmetres de la plantilla de la línia de comandaments.",
"See external versioning help for supported templated command line parameters.": "Consulta l'ajuda externa sobre versions per a conéixer els paràmetres de la plantilla de la línia de comandaments.",
"Select All": "Select All",
"Select All": "Sel·leccionar Tot",
"Select a version": "Seleccionar una versió",
"Select latest version": "Seleccionar l'última versió",
"Select oldest version": "Seleccionar la versió més antiga",
@@ -290,17 +291,18 @@
"Statistics": "Estadístiques",
"Stopped": "Parat",
"Support": "Suport",
"Support Bundle": "Support Bundle",
"Support Bundle": "Lot de Suport",
"Sync Protocol Listen Addresses": "Direccions d'escolta del protocol de sincronització",
"Syncing": "Sincronitzant",
"Syncthing has been shut down.": "Syncthing s'ha apagat",
"Syncthing includes the following software or portions thereof:": "Syncthing inclou el següent software o parts d'ell:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing és Software Gratuït i Open Source llicenciat com MPL v2.0.",
"Syncthing is restarting.": "Syncthing està reiniciant.",
"Syncthing is upgrading.": "Syncthing està actualitzant-se.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing pareix apagat o hi ha un problema amb la connexió a Internet. Tornant a intentar...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing pareix que té un problema processant la seua sol·licitud. Per favor, refresque la pàgina o reinicie Syncthing si el problema persistix.",
"Take me back": "Take me back",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.",
"Take me back": "Porta'm enrere",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "L'adreça del GUI és sobreescrita per les opcions d'inici. Els canvis ací no surtiràn efecte mentre la sobreescritura estiga en marxa.",
"The Syncthing admin interface is configured to allow remote access without a password.": "L'interfície d'administració de Syncthing està configurat per a permetre l'accés remot sense una contrasenya.",
"The aggregated statistics are publicly available at the URL below.": "Les estadístiques agregades estàn disponibles en la URL que figura a continuació.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuració ha sigut gravada però no activada. Syncthing deu reiniciar per tal d'activar la nova configuració.",
@@ -314,7 +316,7 @@
"The folder path cannot be blank.": "La ruta de la carpeta no pot estar buida.",
"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.": "S'utilitzen els següents intervals: per a la primera hora es guarda una versió cada 30 segons, per al primer dia es guarda una versió cada hora, per als primers 30 dies es guarda una versió diaria, fins l'edat màxima es guarda una versió cada setmana.",
"The following items could not be synchronized.": "Els següents objectes no s'han pogut sincronitzar.",
"The following items were changed locally.": "The following items were changed locally.",
"The following items were changed locally.": "Els següents ítems es canviaren localment.",
"The maximum age must be a number and cannot be blank.": "L'edat màxima deu ser un nombre i no pot estar buida.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "El temps màxim per a guardar una versió (en dies, ficar 0 per a guardar les versions per a sempre).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "El porcentatge d'espai mínim lliure en el disc deu ser un nombre no negatiu entre 0 i 100 (ambdós inclosos).",
@@ -337,7 +339,7 @@
"Unavailable": "No disponible",
"Unavailable/Disabled by administrator or maintainer": "No disponible/Desactivar per l'administrador o mantenedor",
"Undecided (will prompt)": "No decidit (es preguntarà)",
"Unignore": "Unignore",
"Unignore": "Designorar",
"Unknown": "Desconegut",
"Unshared": "No compartit",
"Unused": "No utilitzat",
@@ -350,14 +352,14 @@
"Uptime": "Temps de funcionament",
"Usage reporting is always enabled for candidate releases.": "Els informes d'ús sempre estan activats per a les versions candidates.",
"Use HTTPS for GUI": "Utilitzar HTTPS per a l'Interfície Gràfica d'Usuari (GUI)",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Use notifications from the filesystem to detect changed items.": "Usar notificacions del sistema de fitxers per a detectar els ítems canviats.",
"Variable Size Blocks": "Blocs de Tamany Variable",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Els blocs de tamany variable (també coneguts com \"blocs grans\") són més eficients per als fitxers grans.",
"Version": "Versió",
"Versions": "Versions",
"Versions Path": "Ruta de les versions",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Les versions s'esborren automàticament si són més antigues que l'edat màxima o excedixen el nombre de fitxer permesos en un interval.",
"Waiting to scan": "Waiting to scan",
"Waiting to scan": "Esperant per a escanetjar",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Perill! Esta ruta és un directori pare d'una carpeta ja existent \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Perill! Esta ruta és un directori pare d'una carpeta existent \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Perill! Esta ruta és un subdirectori d'una carpeta que ja existeix nomenada \"{{otherFolder}}\".",
@@ -365,16 +367,16 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "AVÍS: Si estàs utilitzant un observador extern com {{syncthingInotify}}, deus assegurar-te de que està desactivat.",
"Watch for Changes": "Vigilar els Canvis",
"Watching for Changes": "Vigilant els Canvis",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"Watching for changes discovers most changes without periodic scanning.": "Vigil·lar els canvis detecta més canvis sense escanetjar periòdicament.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Quant s'afig un nou dispositiu, hi ha que tindre en compte que aquest dispositiu deu ser afegit també en l'altre costat.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Quant s'afig una nova carpeta, hi ha que tindre en compte que l'ID de la carpeta s'utilitza per a juntar les carpetes entre dispositius. Són sensibles a les majúscules i deuen coincidir exactament entre tots els dispositius.",
"Yes": "Sí",
"You can also select one of these nearby devices:": "Pots seleccionar també un d'aquestos dispositius propers:",
"You can change your choice at any time in the Settings dialog.": "Pots canviar la teua elecció en qualsevol moment en el dialog Ajustos",
"You can read more about the two release channels at the link below.": "Pots llegir més sobre els dos canals de versions en l'enllaç de baix.",
"You have no ignored devices.": "You have no ignored devices.",
"You have no ignored folders.": "You have no ignored folders.",
"You have unsaved changes. Do you really want to discard them?": "You have unsaved changes. Do you really want to discard them?",
"You have no ignored devices.": "No tens dispositius ignorats.",
"You have no ignored folders.": "No tens carpetes ignorades.",
"You have unsaved changes. Do you really want to discard them?": "Tens canvis sense guardar. Realment vols descartar-los?",
"You must keep at least one version.": "Es deu mantindre al menys una versió.",
"days": "dies",
"directories": "directoris",

View File

@@ -56,7 +56,7 @@
"Copied from original": "Zkopírováno z originálu",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 následující přispěvatelé:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 následující přispěvatelé:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 následující přispěvatelé:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Vytváření ignorovaných vzorů, přepisování existujícího souboru v {{path}}.",
"Danger!": "Pozor!",
"Debugging Facilities": "Nástroje pro ladění",
@@ -171,6 +171,7 @@
"Log": "Log",
"Log tailing paused. Click here to continue.": "Log pozastaven. Klikněte zde pro pokračování.",
"Log tailing paused. Scroll to bottom continue.": "Log pozastaven. Sjeďte dolů pro pokračování.",
"Log tailing paused. Scroll to the bottom to continue.": "Sledování logu pozastaveno. Sjeďte dolů pro pokračování.",
"Logs": "Logy",
"Major Upgrade": "Důležitá aktualizace",
"Mass actions": "Hromadné akce",
@@ -295,6 +296,7 @@
"Syncing": "Synchronizuje se",
"Syncthing has been shut down.": "Syncthing byl vypnut.",
"Syncthing includes the following software or portions thereof:": "Syncthing obsahuje následující software nebo jejich část:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing je svobodný a open source software licencovaný jako MPL v2.0.",
"Syncthing is restarting.": "Syncthing se restartuje.",
"Syncthing is upgrading.": "Syncthing se aktualizuje.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing se zdá být nefunkční, nebo je problém s připojením k Internetu. Opakuji...",

View File

@@ -171,6 +171,7 @@
"Log": "Logbog",
"Log tailing paused. Click here to continue.": "Logfølgning på pause. Klik her for at fortsætte.",
"Log tailing paused. Scroll to bottom continue.": "Logfølgning på pause. Rul til bunden for at fortsætte.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Logbog",
"Major Upgrade": "Opgradering til ny hovedversion",
"Mass actions": "Massehandlinger",
@@ -295,6 +296,7 @@
"Syncing": "Synkroniserer",
"Syncthing has been shut down.": "Syncthing er lukket ned.",
"Syncthing includes the following software or portions thereof:": "Syncthing indeholder følgende software eller dele heraf:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing genstarter.",
"Syncthing is upgrading.": "Syncthing opgraderer.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ud til at være stoppet eller oplever problemer med din internetforbindelse. Prøver igen…",

View File

@@ -34,7 +34,7 @@
"Auto Accept": "Automatische Annahme",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Die automatische Aktualisierung bietet jetzt die Wahl zwischen stabilen Veröffentlichungen und Veröffentlichungskandidaten.",
"Automatic upgrades": "Automatische Aktualisierungen aktivieren",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Automatische Upgrades sind für Veröffentlichungskandidaten immer aktiviert.",
"Automatically create or share folders that this device advertises at the default path.": "Automatisch Ordner erstellen oder freigeben, die dieses Gerät im Standardpfad ankündigt.",
"Available debug logging facilities:": "Verfügbare Debugging-Möglichkeiten:",
"Be careful!": "Vorsicht!",
@@ -56,7 +56,7 @@
"Copied from original": "Vom Original kopiert",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 der folgenden Unterstützer:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 der folgenden Unterstützer:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 folgende Mitwirkende:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Erstelle Ignoriermuster, welche die existierende Datei {{path}} überschreiben.",
"Danger!": "Achtung!",
"Debugging Facilities": "Debugging-Möglichkeiten",
@@ -171,6 +171,7 @@
"Log": "Protokoll",
"Log tailing paused. Click here to continue.": "Protokollaufzeichnungen sind pausiert. Klicken Sie hier um fortzufahren.",
"Log tailing paused. Scroll to bottom continue.": "Protokollierung pausiert. Scrolle nach unten um fortzufahren.",
"Log tailing paused. Scroll to the bottom to continue.": "Protokolländerungsverfolgung angehalten. Zum Ende blättern, um fortzufahren.",
"Logs": "Protokolle",
"Major Upgrade": "Hauptversionsaktualisierung",
"Mass actions": "Massenaktionen",
@@ -295,6 +296,7 @@
"Syncing": "Synchronisiere",
"Syncthing has been shut down.": "Syncthing wurde heruntergefahren.",
"Syncthing includes the following software or portions thereof:": "Syncthing enthält die folgende Software oder Teile von:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing ist freie und quelloffene Software, lizenziert als MPL v2.0.",
"Syncthing is restarting.": "Syncthing wird neu gestartet",
"Syncthing is upgrading.": "Syncthing wird aktualisiert",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing scheint nicht erreichbar zu sein oder es gibt ein Problem mit Deiner Internetverbindung. Versuche erneut...",
@@ -350,9 +352,9 @@
"Uptime": "Betriebszeit",
"Usage reporting is always enabled for candidate releases.": "Nutzungsbericht ist für Veröffentlichungskandidaten immer aktiviert.",
"Use HTTPS for GUI": "HTTPS für Benutzeroberfläche verwenden",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Use notifications from the filesystem to detect changed items.": "Benachrichtigungen des Dateisystems nutzen, um Änderungen zu erkennen.",
"Variable Size Blocks": "Blöcke mit variabler Größe",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Blöcke mit variabler Größe (auch „große Blöcke“) sind für große Dateien effizienter.",
"Version": "Version",
"Versions": "Versionen",
"Versions Path": "Versionierungspfad",
@@ -365,7 +367,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Achtung: Wenn Sie einen externen Beobachter wie {{syncthingInotify}} benutzen, sollten sie sicher sein das dieser deaktiviert ist.",
"Watch for Changes": "Auf Änderungen achten",
"Watching for Changes": "Auf Änderungen achten",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"Watching for changes discovers most changes without periodic scanning.": "Das Überwachen von Änderungen entdeckt die meisten Änderungen ohne regelmäßiges Scannen.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Beachte beim Hinzufügen eines neuen Gerätes, dass dieses Gerät auch auf den anderen Geräten hinzugefügt werden muss.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Beachte bitte beim Hinzufügen eines neuen Ordners, dass die Ordnerkennung dazu verwendet wird, Ordner zwischen Geräten zu verbinden. Die Kennung muss also auf allen Geräten gleich sein, die Groß- und Kleinschreibung muss dabei beachtet werden.",
"Yes": "Ja",

View File

@@ -171,6 +171,7 @@
"Log": "Αρχείο καταγραφής",
"Log tailing paused. Click here to continue.": "Η αυτόματη κύλιση έχει διακοπεί. Πατήστε εδώ για να συνεχιστεί.",
"Log tailing paused. Scroll to bottom continue.": "Η αυτόματη ακολούθηση του αρχείου καταγραφής είναι σε παύση. Κυλίστε στο τέλος της οθόνης για να συνεχίσετε.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Αρχεία καταγραφής",
"Major Upgrade": "Σημαντική αναβάθμιση",
"Mass actions": "Μαζικές ενέργειες",
@@ -295,6 +296,7 @@
"Syncing": "Συγχρονίζω",
"Syncthing has been shut down.": "Το Syncthing έχει απενεργοποιηθεί.",
"Syncthing includes the following software or portions thereof:": "Το Syncthing περιλαμβάνει τα παρακάτω λογισμικά ή μέρη αυτών:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Το Syncthing επανεκκινείται.",
"Syncthing is upgrading.": "Το Syncthing αναβαθμίζεται.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Το Syncthing φαίνεται πως είναι απενεργοποιημένο ή υπάρχει πρόβλημα στη σύνδεσή σου στο διαδίκτυο. Προσπαθώ πάλι…",

View File

@@ -171,6 +171,7 @@
"Log": "Log",
"Log tailing paused. Click here to continue.": "Log tailing paused. Click here to continue.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Logs",
"Major Upgrade": "Major Upgrade",
"Mass actions": "Mass actions",
@@ -295,6 +296,7 @@
"Syncing": "Syncing",
"Syncthing has been shut down.": "Syncthing has been shut down.",
"Syncthing includes the following software or portions thereof:": "Syncthing includes the following software or portions thereof:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing is restarting.",
"Syncthing is upgrading.": "Syncthing is upgrading.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…",

View File

@@ -32,6 +32,7 @@
"Are you sure you want to remove folder {%label%}?": "Are you sure you want to remove folder {{label}}?",
"Are you sure you want to restore {%count%} files?": "Are you sure you want to restore {{count}} files?",
"Auto Accept": "Auto Accept",
"Automatic Crash Reporting": "Automatic Crash Reporting",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Automatic upgrade now offers the choice between stable releases and release candidates.",
"Automatic upgrades": "Automatic upgrades",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
@@ -71,6 +72,7 @@
"Device rate limits": "Device rate limits",
"Device that last modified the item": "Device that last modified the item",
"Devices": "Devices",
"Disable Crash Reporting": "Disable Crash Reporting",
"Disabled": "Disabled",
"Disabled periodic scanning and disabled watching for changes": "Disabled periodic scanning and disabled watching for changes",
"Disabled periodic scanning and enabled watching for changes": "Disabled periodic scanning and enabled watching for changes",
@@ -92,6 +94,7 @@
"Edit Folder": "Edit Folder",
"Editing": "Editing",
"Editing {%path%}.": "Editing {{path}}.",
"Enable Crash Reporting": "Enable Crash Reporting",
"Enable NAT traversal": "Enable NAT traversal",
"Enable Relaying": "Enable Relaying",
"Enabled": "Enabled",
@@ -141,6 +144,7 @@
"Global State": "Global State",
"Help": "Help",
"Home page": "Home page",
"However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.": "However, your current settings indicate you might not want it enabled. We have disabled automatic crash reporting for you.",
"Ignore": "Ignore",
"Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Ignore Permissions",
@@ -171,6 +175,7 @@
"Log": "Log",
"Log tailing paused. Click here to continue.": "Log tailing paused. Click here to continue.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Logs",
"Major Upgrade": "Major Upgrade",
"Mass actions": "Mass actions",
@@ -298,6 +303,7 @@
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing is restarting.",
"Syncthing is upgrading.": "Syncthing is upgrading.",
"Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.": "Syncthing now supports automatically reporting crashes to the developers. This feature is enabled by default.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.",
"Take me back": "Take me back",

View File

@@ -171,6 +171,7 @@
"Log": "Protokolo",
"Log tailing paused. Click here to continue.": "Vostado de protokolo paŭzis. Alklaku ĉi tie por daŭrigi.",
"Log tailing paused. Scroll to bottom continue.": "Vostado de protokolo paŭzis. Rulumu malsupre por daŭrigi.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Protokoloj",
"Major Upgrade": "Ĉefa Ĝisdatigo",
"Mass actions": "Amasa agoj",
@@ -295,6 +296,7 @@
"Syncing": "Sinkronigas",
"Syncthing has been shut down.": "Syncthing estis malŝaltita.",
"Syncthing includes the following software or portions thereof:": "Syncthing inkluzivas la jenajn programarojn aŭ porciojn ĝiajn:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing estas libera kaj malferma fonta programaro licencita kiel MPL v2.0.",
"Syncthing is restarting.": "Syncthing estas restartanta.",
"Syncthing is upgrading.": "Syncthing estas ĝisdatigita.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ŝajnas nefunkcii, aŭ estas problemo kun via retkonekto. Reprovado...",

View File

@@ -34,7 +34,7 @@
"Auto Accept": "Auto aceptar",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Ahora la actualización automática permite elegir entre versiones estables o versiones candidatas.",
"Automatic upgrades": "Actualizaciones automáticas",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Las actualizaciones automáticas siempre están activadas para las versiones candidatas.",
"Automatically create or share folders that this device advertises at the default path.": "Crear o compartir automáticamente las carpetas que este dispositivo anuncia en la ruta por defecto.",
"Available debug logging facilities:": "Ayudas disponibles para la depuración del registro:",
"Be careful!": "¡Ten cuidado!",
@@ -56,13 +56,13 @@
"Copied from original": "Copiado del original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 los siguientes Colaboradores:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 Los siguientes colaboradores:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 los siguientes Colaboradores:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Crear patrones a ignorar, sobreescribiendo un fichero existente en {{path}}.",
"Danger!": "¡Peligro!",
"Debugging Facilities": "Ayudas a la depuración",
"Default Folder Path": "Ruta de la carpeta por defecto",
"Deleted": "Eliminado",
"Deselect All": "Deselect All",
"Deselect All": "Deseleccionar Todo",
"Device": "Dispositivo",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "El dispositivo \"{{name}}\" ({{device}} en la dirección {{address}}) quiere conectarse. Añadir nuevo dispositivo?",
"Device ID": "ID del Dispositivo",
@@ -75,7 +75,7 @@
"Disabled periodic scanning and disabled watching for changes": "Desactivados el escaneo periódico y la vigilancia de cambios",
"Disabled periodic scanning and enabled watching for changes": "Desactivado el escaneo periódico y activada la vigilancia de cambios",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Desactivado el escaneo periódico y falló la activación de la vigilancia de cambios, reintentando cada 1 minuto:",
"Discard": "Discard",
"Discard": "Descartar",
"Disconnected": "Desconectado",
"Discovered": "Descubierto",
"Discovery": "Descubrimiento",
@@ -98,7 +98,7 @@
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Introduce un número no negativo (por ejemplo, \"2.35\") y selecciona una unidad. Los porcentajes son como parte del tamaño total del disco.",
"Enter a non-privileged port number (1024 - 65535).": "Introduce un puerto sin privilegios (1024 - 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduzca las direcciones, separadas por comas (\"tcp://ip:port\", \"tcp://host:port\"), o \"dynamic\" para llevar a cabo el descubrimiento automático de la dirección.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Introducir direcciones separadas por coma (\"tcp://ip:port\", \"tcp://host:port\") o dinámicas para realizar el descubrimiento automático de la dirección.",
"Enter ignore patterns, one per line.": "Introducir patrones a ignorar, uno por línea.",
"Error": "Error",
"External File Versioning": "Versionado externo de fichero",
@@ -144,9 +144,9 @@
"Ignore": "Ignorar",
"Ignore Patterns": "Patrones a ignorar",
"Ignore Permissions": "Permisos a ignorar",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored at": "Ignored at",
"Ignored Devices": "Dispositivos Ignorados",
"Ignored Folders": "Carpetas Ignoradas",
"Ignored at": "Ignorado En",
"Incoming Rate Limit (KiB/s)": "Límite de descarga (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Una configuración incorrecta puede dañar los contenidos de la carpeta y hacer que Syncthing no funcione.",
"Introduced By": "Introducido por",
@@ -160,17 +160,18 @@
"Later": "Más tarde",
"Latest Change": "Último Cambio",
"Learn more": "Saber más",
"Limit": "Limit",
"Limit": "Límite",
"Listeners": "Oyentes",
"Loading data...": "Cargando datos...",
"Loading...": "Cargando...",
"Local Discovery": "Descubrimiento local",
"Local State": "Estado local",
"Local State (Total)": "Estado Local (Total)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "Ítems Cambiados Localmente",
"Log": "Registro",
"Log tailing paused. Click here to continue.": "Pausada la continuación del registro. Pulsar aquí para continuar.",
"Log tailing paused. Scroll to bottom continue.": "Pausada la continuación del registro. Continúa hasta el final.",
"Log tailing paused. Scroll to the bottom to continue.": "Pausada la inscripción en el Registro. Desplázate hasta el final para continuar.",
"Logs": "Registros",
"Major Upgrade": "Actualización importante",
"Mass actions": "Acciones en masa",
@@ -209,7 +210,7 @@
"Pause": "Pausar",
"Pause All": "Pausar todo",
"Paused": "Pausado",
"Pending changes": "Pending changes",
"Pending changes": "Cambios pendientes",
"Periodic scanning at given interval and disabled watching for changes": "Escaneo periódico en un intervalo determinado y desactivada la vigilancia de cambios",
"Periodic scanning at given interval and enabled watching for changes": "Escaneo periódico en un intervalo determinado y activada la vigilancia de cambios",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Escaneo periódico en un intervalo determinado y falló la configuración de la vigilancia de cambios, se reintentará cada 1 minuto:",
@@ -253,7 +254,7 @@
"Scanning": "Analizando",
"See external versioner help for supported templated command line parameters.": "Consultar la ayuda externa del versionador para ver las plantillas de los parámetros de línea de comandos",
"See external versioning help for supported templated command line parameters.": "Consultar la ayuda externa del versionado para ver las plantillas de los parámetros de línea de comandos",
"Select All": "Select All",
"Select All": "Seleccionar Todo",
"Select a version": "Selecciona una versión",
"Select latest version": "Selecciona la última versión",
"Select oldest version": "Selecciona la versión más antigua",
@@ -290,17 +291,18 @@
"Statistics": "Estadísticas",
"Stopped": "Detenido",
"Support": "Forum",
"Support Bundle": "Support Bundle",
"Support Bundle": "Lote de Soporte",
"Sync Protocol Listen Addresses": "Direcciones de escucha del protocolo de sincronización",
"Syncing": "Sincronizando",
"Syncthing has been shut down.": "Syncthing se ha detenido.",
"Syncthing includes the following software or portions thereof:": "Syncthing incluye el siguiente software o partes de él:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing es Software Gratuito y Open Source Software licenciado como MPL v2.0.",
"Syncthing is restarting.": "Syncthing se está reiniciando.",
"Syncthing is upgrading.": "Syncthing se está actualizando.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing parece no estar activo o hay un problema con tu conexión de internet. Reintentando...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing tiene problemas para procesar tu solicitud. Por favor, actualiza la página o reinicia Syncthing si el problema persiste.",
"Take me back": "Take me back",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.",
"Take me back": "Llévame atrás",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "La dirección del GUI es sobreescrita por las opciones de arranque. Los cambios de aquí no tendrán efecto mientras la sobreescritura esté activa.",
"The Syncthing admin interface is configured to allow remote access without a password.": "El panel de administración de Syncthing está configurado para permitir el acceso remoto sin contraseña.",
"The aggregated statistics are publicly available at the URL below.": "Las estadísticas agragadas están disponibles públicamente en la URL de abajo.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuración ha sido grabada pero no activada. Syncthing debe reiniciarse para activar la nueva configuración.",
@@ -314,7 +316,7 @@
"The folder path cannot be blank.": "La ruta de la carpeta no puede estar en blanco.",
"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.": "Se utilizan los siguientes intervalos: para la primera hora se mantiene una versión cada 30 segundos, para el primer día se mantiene una versión cada hora, para los primeros 30 días se mantiene una versión diaria hasta la edad máxima de una semana.",
"The following items could not be synchronized.": "Los siguientes elementos no pueden ser sincronizados.",
"The following items were changed locally.": "The following items were changed locally.",
"The following items were changed locally.": "Los siguientes ítems fueron cambiados localmente.",
"The maximum age must be a number and cannot be blank.": "La edad máxima debe ser un número y no puede estar vacía.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "El tiempo máximo para mantener una versión en días (introducir 0 para mantener las versiones indefinidamente).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "El porcentaje de espacio libre mínimo debe ser un número no negativo entre 0 y 100 (ambos inclusive).",
@@ -337,7 +339,7 @@
"Unavailable": "No disponible",
"Unavailable/Disabled by administrator or maintainer": "No disponible/Desactivado por el administrador o el mantenedor",
"Undecided (will prompt)": "Aún no decidido (se preguntará al usuario)",
"Unignore": "Unignore",
"Unignore": "Designorar",
"Unknown": "Desconocido",
"Unshared": "No compartido",
"Unused": "No usado",
@@ -350,14 +352,14 @@
"Uptime": "Tiempo de funcionamiento",
"Usage reporting is always enabled for candidate releases.": "El informe de uso está siempre habilitado en las versiones candidatas.",
"Use HTTPS for GUI": "Usar HTTPS para la Interfaz Gráfica de Usuario (GUI)",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Use notifications from the filesystem to detect changed items.": "Usar notificaciones del sistema de ficheros para detectar los ítems cambiados.",
"Variable Size Blocks": "Bloques de Tamaño Variable",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Los bloques de tamaño variable (también conocidos como \"bloques grandes\") son más eficientes para ficheros grandes.",
"Version": "Versión",
"Versions": "Versiones",
"Versions Path": "Ruta de las versiones",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Las versiones se borran automáticamente si son más antiguas que la edad máxima o exceden el número de ficheros permitidos en un intervalo.",
"Waiting to scan": "Waiting to scan",
"Waiting to scan": "Esperando para escanear",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "¡Peligro! Esta ruta es un directorio principal de la carpeta ya existente \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "'Peligro! Esta ruta es un subdirectorio de la carpeta ya existente \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Peligro! Esta ruta es un subdirectorio de una carpeta ya existente llamada \"{{otherFolder}}\".",
@@ -365,16 +367,16 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Advertencia: Si estás usando un vigilante externo como {{syncthingInotify}}, deberías asegurarte de que está desactivado.",
"Watch for Changes": "Vigilar los cambios",
"Watching for Changes": "Vigilando los cambios",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"Watching for changes discovers most changes without periodic scanning.": "Vigilar los cambios descubre la mayoría de cambios sin escaneo periódico.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Cuando añada un nuevo dispositivo, tenga en cuenta que este debe añadirse también en el otro lado.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Cuando añada una nueva carpeta, tenga en cuenta que su ID se usa para unir carpetas entre dispositivos. Son sensibles a las mayúsculas y deben coincidir exactamente entre todos los dispositivos.",
"Yes": "Si",
"You can also select one of these nearby devices:": "Puedes seleccionar también uno de estos dispositivos cercanos:",
"You can change your choice at any time in the Settings dialog.": "Puedes cambiar tu elección en cualquier momento en el panel de Ajustes.",
"You can read more about the two release channels at the link below.": "Puedes leer más sobre los dos método de publicación de versiones en el siguiente enlace.",
"You have no ignored devices.": "You have no ignored devices.",
"You have no ignored folders.": "You have no ignored folders.",
"You have unsaved changes. Do you really want to discard them?": "You have unsaved changes. Do you really want to discard them?",
"You have no ignored devices.": "No tienes dispositivos ignorados.",
"You have no ignored folders.": "No tienes carpetas ignoradas.",
"You have unsaved changes. Do you really want to discard them?": "Tienes cambios sin guardar. ¿Quieres descartarlos?",
"You must keep at least one version.": "Debes mantener al menos una versión.",
"days": "días",
"directories": "directorios",

View File

@@ -171,6 +171,7 @@
"Log": "Registro",
"Log tailing paused. Click here to continue.": "Seguimiento del registro pausado. Haga clic aquí para continuar.",
"Log tailing paused. Scroll to bottom continue.": "Registro de cola en pausa. Mueve el cursor hasta la parte inferior para continuar.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Registros",
"Major Upgrade": "Actualización importante",
"Mass actions": "Acción masiva",
@@ -295,6 +296,7 @@
"Syncing": "Sincronizando",
"Syncthing has been shut down.": "Syncthing se ha detenido.",
"Syncthing includes the following software or portions thereof:": "Syncthing incluye el siguiente software o partes de él:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing se está reiniciando.",
"Syncthing is upgrading.": "Syncthing se está actualizando.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing parece no estar activo o hay un problema con tu conexión de internet. Reintentando...",

View File

@@ -171,6 +171,7 @@
"Log": "Loki",
"Log tailing paused. Click here to continue.": "Login seuraaminen pysäytetty. Jatka klikkaamalla tästä.",
"Log tailing paused. Scroll to bottom continue.": "Login seuraaminen pysäytetty. Jatka vierittämällä alas.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Lokit",
"Major Upgrade": "Pääversion päivitys.",
"Mass actions": "Massamuutokset",
@@ -295,6 +296,7 @@
"Syncing": "Synkronoidaan",
"Syncthing has been shut down.": "Syncthing on sammutettu.",
"Syncthing includes the following software or portions thereof:": "Syncthing sisältää seuraavat ohjelmistot tai sen osat:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing käynnistyy uudelleen.",
"Syncthing is upgrading.": "Syncthing päivittyy.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing näyttää olevan alhaalla tai internetyhteydessä on ongelma. Yritetään uudelleen...",

View File

@@ -171,6 +171,7 @@
"Log": "Journal",
"Log tailing paused. Click here to continue.": "La file d'attente du journal est en pause. Cliquer ici pour continuer.",
"Log tailing paused. Scroll to bottom continue.": "Le défilement du journal est en pause. Faites défiler vers le bas pour continuer.",
"Log tailing paused. Scroll to the bottom to continue.": "Le défilement du journal est en pause. Faites défiler jusqu'en bas pour continuer.",
"Logs": "Journaux",
"Major Upgrade": "Mise à jour majeure",
"Mass actions": "Actions multiples",
@@ -295,6 +296,7 @@
"Syncing": "Synchronisation en cours",
"Syncthing has been shut down.": "Syncthing a été arrêté.",
"Syncthing includes the following software or portions thereof:": "Syncthing intègre les logiciels suivants (ou des éléments provenant de ces logiciels) :",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing est un logiciel Libre et Open Source sous licence MPL v2.0.",
"Syncthing is restarting.": "Syncthing redémarre.",
"Syncthing is upgrading.": "Syncthing se met à jour.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing semble être arrêté, ou il y a un problème avec votre connexion Internet. Nouvelle tentative ...",

View File

@@ -34,7 +34,7 @@
"Auto Accept": "Auto-akseptaasje",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Automatyske fernijing biedt no de kar tusken stabyle ferzjes en ferzje kandidaten",
"Automatic upgrades": "Automatyske fernijings",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Automatyske opwurdearrings stean altyd oan foar kandidaat-ferzjes.",
"Automatically create or share folders that this device advertises at the default path.": "Meitsje of diel automatysk mappen dy't dit apparaat advertearret op it standert paad.",
"Available debug logging facilities:": "Beskikbere debug-lochfoarsjennings:",
"Be careful!": "Tink derom!",
@@ -56,7 +56,7 @@
"Copied from original": "Oernommen fan orizjineel",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 de folgende bydragers:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 de folgende Bydragers:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 de folgende Bydragers:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Meitsje negear-patroanen dy in besteande triem oerskriuwe yn {{path}}.",
"Danger!": "Gefaar!",
"Debugging Facilities": "Debug-foarsjennings",
@@ -98,7 +98,7 @@
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Fier in net-negatyf nûmer yn (bygelyks \"2.35\") en selektearje in ienheid. Percentages stean foar it part fan de totale skiifromte.",
"Enter a non-privileged port number (1024 - 65535).": "Fier in net-befoarrjochte poart-nûmer yn (1024 - 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Fier troch komma's skieden (\"tcp://ip:port\", \"tcp://host:port\") adressen yn of \"dynamic\" om automatyske ûntdekking fan it adres út te fieren.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Fier troch komma's skieden (\"tcp://ip:port\", \"tcp://host:port\") adressen yn of \"dynamic\" om automatyske ûntdekking fan it adres út te fieren.",
"Enter ignore patterns, one per line.": "Fier negearpatroanen yn, ien per rigel.",
"Error": "Flater",
"External File Versioning": "Ekstern ferzjebehear foar triemen",
@@ -160,17 +160,18 @@
"Later": "Letter",
"Latest Change": "Meast Resinte Feroarings",
"Learn more": "Mear witte",
"Limit": "Limit",
"Limit": "Limyt",
"Listeners": "Harkers",
"Loading data...": "Data oan it laden...",
"Loading...": "Oan it laden...",
"Local Discovery": "Lokale ûntdekking",
"Local State": "Lokale tastân",
"Local State (Total)": "Lokale tastân (Folledich)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "Lokaal Feroare Items",
"Log": "Loch",
"Log tailing paused. Click here to continue.": "Loch-sturt skofte. Klik hjir om fjirder te gean.",
"Log tailing paused. Scroll to bottom continue.": "Loch-sturt skofte. Rolje helendal nei ûnder om fjirder te gean.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Lochs",
"Major Upgrade": "Wichtige fernijing",
"Mass actions": "Massa-aksjes",
@@ -295,6 +296,7 @@
"Syncing": "Oan it Syncen",
"Syncthing has been shut down.": "Syncthing is útsetten",
"Syncthing includes the following software or portions thereof:": "Syncthing befettet de folgende sêftguod of parten dêrfan:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Fergees en Iepenboarne Programmatuer mei in MPL V2.0 lisinsje.",
"Syncthing is restarting.": "Syncthing oan it werstarten.",
"Syncthing is upgrading.": "Syncthing is oan it fernijen.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "It liket dêrop dat Syncthing op dit stuit net rint, of der is in swierrichheid mei jo ynternetferbining. Wurd no opnij besocht...",
@@ -314,7 +316,7 @@
"The folder path cannot be blank.": "It map-paad mei net leech wêze.",
"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.": "De folgende yntervals wurd brûkt: foar it earste oere wurd eltse 30 sekonden in ferzje bewarre, foar de earste dei wurd eltse oere in ferzje bewarre, foar de earste 30 dagen wurd eltse dei in ferzje bewarre, oant ta de maksimale âldens wurd eltse wike in ferzje bewarre.",
"The following items could not be synchronized.": "De folgende items koene net syngronisearre wurde.",
"The following items were changed locally.": "The following items were changed locally.",
"The following items were changed locally.": "De neikommende items binne lokaal feroare.",
"The maximum age must be a number and cannot be blank.": "De maksimale âldens moat in nûmer en net leech wêze.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "De maksimale tiid dat in ferzje bewarre wurde moat (yn dagen, stel yn op 0 om ferzjes foar immer te bewarjen).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "It maksimale persintaazje frije skiifromte moat in posityf nûmer wêze tusken 0 en 100 (ynklusyf).",
@@ -350,14 +352,14 @@
"Uptime": "Rintiid",
"Usage reporting is always enabled for candidate releases.": "Brûkersrapportaazje stiet altyd oan foar ferzje kandidaten.",
"Use HTTPS for GUI": "Brûk HTTPS foar GUI",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Use notifications from the filesystem to detect changed items.": "Brûk notifikaasjes fan it triemsysteem om feroare items te detektearjen.",
"Variable Size Blocks": "Fariabele Blokgrutte",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Fariabele blokgrutte (ek wol \"grutte blokken\") binne effisjinter foar gruttere triemmen.",
"Version": "Ferzje",
"Versions": "Ferzjes",
"Versions Path": "Ferzjes-paad",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Ferzjes wurde automatysk fuortsmiten wannear't se âlder binne dan de maksimale âldens of wannear it tal fan triemen yn in ynterval grutter is dan tastean.",
"Waiting to scan": "Waiting to scan",
"Waiting to scan": "Wachtet om te skennen",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Warskôging, dit paad is in boppelizzende triemtafel fan in besteande map \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Warskôging, dit paad is in boppelizzende triemtafel fan in besteande map \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Warskôging, dit paad is in ûnderlizzende triemtafel fan in besteande map \"{{otherFolder}}\".",
@@ -365,7 +367,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Warskôging: As jo in eksterne sjogger lykas {{syncthingInotify}} brûke, bin der dan wiis fan dat dizze út stiet.",
"Watch for Changes": "Sjoch foar Feroarings",
"Watching for Changes": "Sjocht foar Feroarings",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"Watching for changes discovers most changes without periodic scanning.": "Sjen foar feroarings ûntdekt de measte feroarings sûnder periodyk skennen.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Hâld by it taheakjen fan in nij apparaat yn de holle dat it apparaat oan de oare kant ek taheakke wurde moat. ",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Hâld by it taheakjen fan in nije map yn de holle dat de map-ID brûkt wurd om de mappen tusken apparaten mei-inoar te ferbinen. Se binne haadlettergefoelich en moatte oer alle apparaten eksakt oerienkomme.",
"Yes": "Ja",

View File

@@ -171,6 +171,7 @@
"Log": "Napló",
"Log tailing paused. Click here to continue.": "Napló utolsó sorainak figyelése leállítva. Ide kattintva lehet folytatni.",
"Log tailing paused. Scroll to bottom continue.": "Napló utolsó sorainak figyelése leállítva. Görgetve lehet folytatni.",
"Log tailing paused. Scroll to the bottom to continue.": "Napló utolsó sorainak figyelése leállítva. Görgetve lehet folytatni.",
"Logs": "Naplófájlok",
"Major Upgrade": "Főverzió-frissítés",
"Mass actions": "Tömeges műveletek",
@@ -295,6 +296,7 @@
"Syncing": "Szinkronizálás",
"Syncthing has been shut down.": "Syncthing leállítva",
"Syncthing includes the following software or portions thereof:": "A Syncthing a következő programokat, vagy komponenseket tartalmazza.",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "A Syncthing szabad és nyílt forráskódú szoftver MPL v2.0 licenccel.",
"Syncthing is restarting.": "Syncthing újraindul",
"Syncthing is upgrading.": "Syncthing frissül",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Úgy tűnik, hogy a Syncthing nem működik, vagy valami probléma van a hálózati kapcsolattal. Újra próbálom...",

View File

@@ -56,7 +56,7 @@
"Copied from original": "Copiato dall'originale",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 i seguenti Collaboratori:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 i seguenti Collaboratori:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 i seguenti Collaboratori:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creazione di schemi di esclusione, sovrascrivendo un file esistente in {{path}}.",
"Danger!": "Pericolo!",
"Debugging Facilities": "Servizi di Debug",
@@ -171,6 +171,7 @@
"Log": "Log",
"Log tailing paused. Click here to continue.": "Visualizzazione log in pausa. Clicca qui per continuare.",
"Log tailing paused. Scroll to bottom continue.": "Visualizzazione log in pausa. Scorri fino in fondo per continuare.",
"Log tailing paused. Scroll to the bottom to continue.": "Visualizzazione log in pausa. Scorri fino in fondo per continuare.",
"Logs": "Log",
"Major Upgrade": "Aggiornamento Principale",
"Mass actions": "Azioni di massa",
@@ -295,6 +296,7 @@
"Syncing": "Sincronizzazione in corso",
"Syncthing has been shut down.": "Syncthing è stato arrestato.",
"Syncthing includes the following software or portions thereof:": "Syncthing utilizza i seguenti software o porzioni di questi:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing è un software Libero e Open Source concesso in licenza MPL v2.0.",
"Syncthing is restarting.": "Riavvio di Syncthing in corso.",
"Syncthing is upgrading.": "Aggiornamento di Syncthing in corso.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing sembra inattivo, oppure c'è un problema con la tua connessione a Internet. Nuovo tentativo…",

View File

@@ -171,6 +171,7 @@
"Log": "ログ",
"Log tailing paused. Click here to continue.": "Log tailing paused. Click here to continue.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "ログ",
"Major Upgrade": "メジャーアップグレード",
"Mass actions": "Mass actions",
@@ -295,6 +296,7 @@
"Syncing": "同期中",
"Syncthing has been shut down.": "Syncthingをシャットダウンしました。",
"Syncthing includes the following software or portions thereof:": "Syncthingは以下のソフトウェアまたはその一部を内包しています:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthingを再起動しています。",
"Syncthing is upgrading.": "Syncthingをアップグレード中です。",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthingが落ちているか、インターネット接続に問題があります。リトライ中です…",
@@ -354,7 +356,7 @@
"Variable Size Blocks": "Variable Size Blocks",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "バージョン",
"Versions": "Versions",
"Versions": "バージョン",
"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 scan": "Waiting to scan",
@@ -365,7 +367,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Warning: If you are using an external watcher like {{syncthingInotify}}, you should make sure it is deactivated.",
"Watch for Changes": "変更の監視",
"Watching for Changes": "変更の監視",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"Watching for changes discovers most changes without periodic scanning.": "変更の監視は、定期スキャンを行わずにほとんどの変更を検出できます。",
"When adding a new device, keep in mind that this device must be added on the other side too.": "新しいデバイスを追加する際は、相手側デバイスにもこのデバイスを追加してください。",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "新しいフォルダーを追加する際、フォルダーIDはデバイス間でフォルダーの対応づけに使われることに注意してください。フォルダーIDは大文字と小文字が区別され、共有するすべてのデバイスの間で完全に一致しなくてはなりません。",
"Yes": "はい",

View File

@@ -171,6 +171,7 @@
"Log": "기록",
"Log tailing paused. Click here to continue.": "기록 출력이 일시정지됨. 계속하려면 여기를 클릭하십시오. ",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "기록",
"Major Upgrade": "메이저 업데이트",
"Mass actions": "Mass actions",
@@ -295,6 +296,7 @@
"Syncing": "동기화 중",
"Syncthing has been shut down.": "Syncthing이 종료되었습니다.",
"Syncthing includes the following software or portions thereof:": "Syncthing은 다음과 같은 소프트웨어나 그 일부를 포함합니다:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing이 재시작 중입니다.",
"Syncthing is upgrading.": "Syncthing이 업데이트 중입니다.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing이 중지되었거나 인터넷 연결에 문제가 있는 것 같습니다. 재시도 중입니다...",

View File

@@ -171,6 +171,7 @@
"Log": "Žurnalas",
"Log tailing paused. Click here to continue.": "Žurnalo galas pristabdytas. Spustelėkite čia, norėdami tęsti.",
"Log tailing paused. Scroll to bottom continue.": "Žurnalo galas pristabdytas. Slinkite į apačią, norėdami tęsti.",
"Log tailing paused. Scroll to the bottom to continue.": "Žurnalo galas pristabdytas. Slinkite į apačią, norėdami tęsti.",
"Logs": "Žurnalai",
"Major Upgrade": "Stambus atnaujinimas",
"Mass actions": "Masiniai veiksmai",
@@ -295,6 +296,7 @@
"Syncing": "Sutapatinama",
"Syncthing has been shut down.": "Syncthing išjungtas",
"Syncthing includes the following software or portions thereof:": "Syncthing naudoja šias programas ar jų dalis:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing yra laisva ir atvirojo kodo programinė įranga, licencijuota pagal MPL v2.0.",
"Syncthing is restarting.": "Syncthing perleidžiamas",
"Syncthing is upgrading.": "Syncthing atsinaujina.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing išjungta arba problemos su Interneto ryšių. Bandoma iš naujo...",

View File

@@ -34,7 +34,7 @@
"Auto Accept": "Godta automatisk",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Automatisk oppgradering lar deg nå få valget mellom ferdige utgaver og utgivelseskandidater.",
"Automatic upgrades": "Automatiske oppdateringer",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatic upgrades are always enabled for candidate releases.": "Automatisk oppgradering er alltid påslått for utgivelseskandidater.",
"Automatically create or share folders that this device advertises at the default path.": "Opprett eller del mapper automatisk i mapper som denne enheten melder som forvalgt mappe.",
"Available debug logging facilities:": "Tilgjengelige funksjoner for logging i feilrettingsøyemed:",
"Be careful!": "Vær forsiktig!",
@@ -56,7 +56,7 @@
"Copied from original": "Kopiert fra original",
"Copyright © 2014-2016 the following Contributors:": "Opphavsrett © 2014-2016 for følgende bidragsytere:",
"Copyright © 2014-2017 the following Contributors:": "Opphavsrett © 2014-2017 for følgende bidragsytere:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Opphavrett © 2014-2019 for følgende bidragsytere:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Oppretter ignoreringsmønster, overskriver eksisterende fil i {{path}}.",
"Danger!": "Fare!",
"Debugging Facilities": "Feilrettingsverktøy",
@@ -75,7 +75,7 @@
"Disabled periodic scanning and disabled watching for changes": "Skrudde av både periodisk skanning og oppsyn med endringer",
"Disabled periodic scanning and enabled watching for changes": "Skrudde av periodisk skanning og skrudde på oppsyn med endringer",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Skrudde av periodisk skanning og mislyktes i oppsett av oppsyn med endringer, prøver igjen hvert minutt:",
"Discard": "Discard",
"Discard": "Kasser",
"Disconnected": "Frakoblet",
"Discovered": "Oppdaget",
"Discovery": "Oppslag",
@@ -145,7 +145,7 @@
"Ignore Patterns": "Utelatelsesmønster",
"Ignore Permissions": "Ignorer rettigheter",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored Folders": "Utelatte mapper",
"Ignored at": "Ignored at",
"Incoming Rate Limit (KiB/s)": "Innkommende hastighetsbegrensning (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Feilaktige innstillinger kan skade innholdet i dine delte mapper og hindre Syncthing i å fungere.",
@@ -171,6 +171,7 @@
"Log": "Logg",
"Log tailing paused. Click here to continue.": "Tail-utdata pauset. Klikk her for å fortsette.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Logger",
"Major Upgrade": "Storoppgradering",
"Mass actions": "Massehandlinger",
@@ -295,6 +296,7 @@
"Syncing": "Synkroniserer",
"Syncthing has been shut down.": "Syncthing har blitt slått av.",
"Syncthing includes the following software or portions thereof:": "Syncthing inkluderer helt eller delvis følgende programvare:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing starter på ny.",
"Syncthing is upgrading.": "Syncthing oppgraderer.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ut til å være nede, eller så er det et problem med nettforbindelsen din. Prøver på ny …",
@@ -357,7 +359,7 @@
"Versions": "Versjoner",
"Versions Path": "Plassering av versjoner",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versjoner blir automatisk slettet når maksimal levetid er nådd eller når antall filer er oversteget.",
"Waiting to scan": "Waiting to scan",
"Waiting to scan": "Venter på å starte gjennomsøkning",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Advarsel, denne stien er en foreldremappe for en eksisterende mappe \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advarsel, denne stien er en foreldremappe for en eksisterende mappe \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Advarsel, denne stien er en undermappe i en eksisterende mappe \"{{otherFolder}}\".",

View File

@@ -169,8 +169,9 @@
"Local State (Total)": "Lokale status (totaal)",
"Locally Changed Items": "Lokaal gewijzigde items",
"Log": "Logboek",
"Log tailing paused. Click here to continue.": "Loggen gepauzeerd. Klik hier om verder te gaan.",
"Log tailing paused. Scroll to bottom continue.": "Loggen gepauzeerd. Naar beneden scrollen om door te gaan.",
"Log tailing paused. Click here to continue.": "Log-tailing gepauzeerd. Klik hier om verder te gaan.",
"Log tailing paused. Scroll to bottom continue.": "Log-tailing gepauzeerd. Naar onderkant scrollen om door te gaan.",
"Log tailing paused. Scroll to the bottom to continue.": "Log-tailing gepauzeerd. Naar de onderkant scrollen om door te gaan.",
"Logs": "Logboeken",
"Major Upgrade": "Grote upgrade",
"Mass actions": "Groepsacties",
@@ -295,6 +296,7 @@
"Syncing": "Synchroniseren",
"Syncthing has been shut down.": "Syncthing werd afgesloten.",
"Syncthing includes the following software or portions thereof:": "Syncthing bevat de volgende software of delen daarvan:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is gratis en opensource software onder licentie van MPL v2.0.",
"Syncthing is restarting.": "Syncthing is aan het herstarten.",
"Syncthing is upgrading.": "Syncthing is aan het bijwerken.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing lijkt gestopt te zijn, of er is een probleem met uw internetverbinding. Opnieuw proberen...",
@@ -372,9 +374,9 @@
"You can also select one of these nearby devices:": "U kunt ook een van deze apparaten in de buurt selecteren:",
"You can change your choice at any time in the Settings dialog.": "U kunt uw keuze op elk moment aanpassen in het instellingen-venster.",
"You can read more about the two release channels at the link below.": "U kunt meer te weten komen over de twee release-kanalen via onderstaande link.",
"You have no ignored devices.": "U heeft geen genegeerde apparaten.",
"You have no ignored folders.": "U heeft geen genegeerde mappen.",
"You have unsaved changes. Do you really want to discard them?": "U heeft niet-opgeslagen wijzigingen. Wilt u ze echt verwerpen?",
"You have no ignored devices.": "U hebt geen genegeerde apparaten.",
"You have no ignored folders.": "U hebt geen genegeerde mappen.",
"You have unsaved changes. Do you really want to discard them?": "U hebt niet-opgeslagen wijzigingen. Wilt u ze echt verwerpen?",
"You must keep at least one version.": "U moet minstens één versie bewaren.",
"days": "dagen",
"directories": "mappen",

View File

@@ -171,6 +171,7 @@
"Log": "Log",
"Log tailing paused. Click here to continue.": "Śledzenie loga wstrzymane. Kliknij tutaj aby wznowić",
"Log tailing paused. Scroll to bottom continue.": "Zatrzymano śledzenie dziennika. Przewiń w dół, aby kontynuować.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Logi",
"Major Upgrade": "Ważna aktualizacja",
"Mass actions": "Działania masowe",
@@ -295,6 +296,7 @@
"Syncing": "Synchronizowanie",
"Syncthing has been shut down.": "Syncthing został wyłączony",
"Syncthing includes the following software or portions thereof:": "Syncthing zawiera następujące oprogramowanie lub ich częśći:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing to wolne oprogramowanie na licencji MPL 2.0",
"Syncthing is restarting.": "Restart Syncthing",
"Syncthing is upgrading.": "Aktualizowanie Syncthing",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing wydaje się być wyłączony lub jest problem z twoim połączeniem internetowym. Próbuje ponownie...",
@@ -351,7 +353,7 @@
"Usage reporting is always enabled for candidate releases.": "Raportowanie użycia dla wydań kandydujących jest zawsze włączone.",
"Use HTTPS for GUI": "Używaj HTTPS",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable Size Blocks": "Bloki różnych wielkości",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "Wersja",
"Versions": "Wersje",

View File

@@ -171,6 +171,7 @@
"Log": "Log",
"Log tailing paused. Click here to continue.": "Observação do log pausada. Clique aqui para continuar.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Logs",
"Major Upgrade": "Atualização \"major\"",
"Mass actions": "Ações em massa",
@@ -295,6 +296,7 @@
"Syncing": "Sincronizando",
"Syncthing has been shut down.": "O Syncthing foi desligado.",
"Syncthing includes the following software or portions thereof:": "O Syncthing inclui os seguintes programas ou partes deles:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "O Syncthing está sendo reiniciado.",
"Syncthing is upgrading.": "O Syncthing está sendo atualizado.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Parece que o Syncthing está desligado ou há um problema com a sua conexão de internet. Tentando novamente...",

View File

@@ -171,6 +171,7 @@
"Log": "Registo",
"Log tailing paused. Click here to continue.": "O acompanhamento do final do registo está em pausa. Clique aqui para continuar.",
"Log tailing paused. Scroll to bottom continue.": "O acompanhamento do final do registo está em pausa. Desloque para o final para continuar.",
"Log tailing paused. Scroll to the bottom to continue.": "O acompanhamento do final do registo está em pausa. Desloque para o final para continuar.",
"Logs": "Registos",
"Major Upgrade": "Actualização importante",
"Mass actions": "Acções em massa",
@@ -295,6 +296,7 @@
"Syncing": "A Sincronizar",
"Syncthing has been shut down.": "O Syncthing foi desligado.",
"Syncthing includes the following software or portions thereof:": "O Syncthing inclui as seguintes aplicações ou partes delas:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing é Software Livre e de Código Aberto licenciado como MPL v2.0.",
"Syncthing is restarting.": "O Syncthing está a reiniciar.",
"Syncthing is upgrading.": "O Syncthing está a actualizar-se.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "O Syncthing parece estar em baixo, ou então existe um problema com a sua ligação à Internet. Tentando novamente...",
@@ -365,7 +367,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Aviso: Se estiver a usar um verificador externo, tal como o {{syncthingInotify}}, deve certificar-se que está desactivado.",
"Watch for Changes": "Vigiar alterações",
"Watching for Changes": "Vigilância de alterações",
"Watching for changes discovers most changes without periodic scanning.": "A vigilância de alterações encontra a maior parte das alterações sem a verificação periódica.",
"Watching for changes discovers most changes without periodic scanning.": "A vigilância de alterações detecta a maior parte das alterações sem a necessidade de fazer uma verificação periódica.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Quando adicionar um novo dispositivo, lembre-se que este dispositivo tem que ser adicionado do outro lado também.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Quando adicionar uma nova pasta, lembre-se que o ID da pasta é utilizado para ligar as pastas entre dispositivos. É sensível às diferenças entre maiúsculas e minúsculas e tem que ter uma correspondência perfeita entre todos os dispositivos.",
"Yes": "Sim",

View File

@@ -171,6 +171,7 @@
"Log": "Журнал",
"Log tailing paused. Click here to continue.": "Вывод журнала приостановлен. Чтобы продолжить, нажмите здесь.",
"Log tailing paused. Scroll to bottom continue.": "Вывод журнала приостановлен. Чтобы продолжить, прокрутите журнал до конца.",
"Log tailing paused. Scroll to the bottom to continue.": "Вывод журнала приостановлен. Чтобы продолжить, прокрутите до журнал конца.",
"Logs": "Журналы",
"Major Upgrade": "Обновление основной версии",
"Mass actions": "Массовые действия",
@@ -295,6 +296,7 @@
"Syncing": "Синхронизация",
"Syncthing has been shut down.": "Syncthing был выключен.",
"Syncthing includes the following software or portions thereof:": "Syncthing включает в себя следующее ПО или его части:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing — свободное программное обеспечение с открытым кодом под лицензией MPL v2.0.",
"Syncthing is restarting.": "Перезапуск Syncthing.",
"Syncthing is upgrading.": "Обновление Syncthing.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Кажется, Syncthing не запущен или есть проблемы с подключением к Интернету. Переподключаюсь...",
@@ -336,7 +338,7 @@
"Type": "Тип",
"Unavailable": "Недоступно",
"Unavailable/Disabled by administrator or maintainer": "Недоступно или отключено администратором",
"Undecided (will prompt)": "Запрос каждый раз",
"Undecided (will prompt)": "Не определено (запрашивать каждый раз)",
"Unignore": "Не игнорировать",
"Unknown": "Неизвестно",
"Unshared": "Необщедоступно",

View File

@@ -12,7 +12,7 @@
"Add Remote Device": "Pridať vzdialené zariadenie",
"Add devices from the introducer to our device list, for mutually shared folders.": "Pre vzájomne zdieľané adresáre pridaj zariadenie od zavádzača do svojho zoznamu zariadení.",
"Add new folder?": "Pridať nový adresár?",
"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.": "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.",
"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.": "Naviac interval plného skenovania bude navýšený (60krát, t.j. nová výchozia hodnota 1h). Môžete to nastaviť aj manuálne pre každý adresár ak zvolíte Nie.",
"Address": "Adresa",
"Addresses": "Adresy",
"Advanced": "Pokročilé",
@@ -56,13 +56,13 @@
"Copied from original": "Skopírované z originálu",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 následujúci prispivatelia:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 následujúci prispivatelia:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 nasledujúci prispievatelia:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Vytváranie vzorov ignorovania, prepísanie existujúceho súboru v {{path}}.",
"Danger!": "Pozor!",
"Debugging Facilities": "Debugging Facilities",
"Default Folder Path": "Predvolená adresárová cesta",
"Deleted": "Zmazané",
"Deselect All": "Deselect All",
"Deselect All": "Odznačiť všetko",
"Device": "Zariadenie",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Zariadenie \"{{name}}\" ({{device}} na {{address}}) sa chce pripojiť. Pridať nové zariadenie?",
"Device ID": "ID zariadenia",
@@ -75,14 +75,14 @@
"Disabled periodic scanning and disabled watching for changes": "Disabled periodic scanning and disabled watching for changes",
"Disabled periodic scanning and enabled watching for changes": "Disabled periodic scanning and enabled watching for changes",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:",
"Discard": "Discard",
"Discard": "Zahodiť",
"Disconnected": "Odpojené",
"Discovered": "Zistené",
"Discovery": "Zisťovanie",
"Discovery Failures": "Zlyhania zisťovania",
"Do not restore": "Neobnovovať",
"Do not restore all": "Neobnovovať všetko",
"Do you want to enable watching for changes for all your folders?": "Do you want to enable watching for changes for all your folders?",
"Do you want to enable watching for changes for all your folders?": "Chcete zapnúť sledovanie zmien vo všetkých priečinkoch?",
"Documentation": "Dokumentácia",
"Download Rate": "Rýchlosť sťahovania",
"Downloaded": "Stiahnuté",
@@ -144,8 +144,8 @@
"Ignore": "Ignorovať",
"Ignore Patterns": "Ignorované vzory",
"Ignore Permissions": "Ignorované práva",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored Devices": "Ignorované zariadenia",
"Ignored Folders": "Ingorované priečinky",
"Ignored at": "Ignored at",
"Incoming Rate Limit (KiB/s)": "Limit pre sťahovanie (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Nesprávna konfigurácia môže poškodiť váš adresár a spôsobiť nefunkčnosť aplikácie Súbory.",
@@ -167,10 +167,11 @@
"Local Discovery": "Lokálne vyhľadávanie",
"Local State": "Lokálny status",
"Local State (Total)": "Lokálny status (celkový)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "Lokálne zmenené položky",
"Log": "Záznam",
"Log tailing paused. Click here to continue.": "Posúvanie záznamu prerušené. Klikni pre pokračovanie.",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Záznamy",
"Major Upgrade": "Hlavná aktualizácia",
"Mass actions": "Hromadná akcia",
@@ -209,11 +210,11 @@
"Pause": "Pozastaviť",
"Pause All": "Pozastaviť všetky",
"Paused": "Pozastavené",
"Pending changes": "Pending changes",
"Periodic scanning at given interval and disabled watching for changes": "Periodic scanning at given interval and disabled watching for changes",
"Periodic scanning at given interval and enabled watching for changes": "Periodic scanning at given interval and enabled watching for changes",
"Pending changes": "Čakajúce zmeny",
"Periodic scanning at given interval and disabled watching for changes": "Periodické skenovanie v zvolenom rozsahu a vypnuté sledovanie zmien.",
"Periodic scanning at given interval and enabled watching for changes": "Periodické skenovanie v zvolenom rozsahu a zapnuté sledovanie zmien.",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:",
"Permissions": "Permissions",
"Permissions": "Prístupové oprávnenia",
"Please consult the release notes before performing a major upgrade.": "Pred spustením hlavnej aktualizácie si prosím prečítajte poznámky k vydaniu.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Zadajte prosím prihlasovanie meno a heslo v dialógovom okne nastavení.",
"Please wait": "Prosím čakajte",
@@ -224,7 +225,7 @@
"Quick guide to supported patterns": "Rýchly sprievodca podporovanými vzormi",
"RAM Utilization": "Využitie RAM",
"Random": "Náhodne",
"Receive Only": "Receive Only",
"Receive Only": "Iba prijímanie",
"Recent Changes": "Nedávne zmeny",
"Reduced by ignore patterns": "Znížené o ignorované vzory",
"Release Notes": "Poznámky k vydaniu",
@@ -237,7 +238,7 @@
"Rescan": "Opakovať skenovanie",
"Rescan All": "Opakovať skenovanie všetkých",
"Rescan Interval": "Interval opakovania skenovania",
"Rescans": "Rescans",
"Rescans": "Opätovné skeny",
"Restart": "Reštart",
"Restart Needed": "Potrebný reštart",
"Restarting": "Reštartovanie",
@@ -246,14 +247,14 @@
"Resume": "Pokračovať",
"Resume All": "Pokračuj so všetkými",
"Reused": "Opakovane použité",
"Revert Local Changes": "Revert Local Changes",
"Running": "Running",
"Revert Local Changes": "Vrátiť lokálne zmeny",
"Running": "Beží",
"Save": "Uložiť",
"Scan Time Remaining": "Zostávajúci čas skenovania",
"Scanning": "Skenovanie",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"See external versioning help for supported templated command line parameters.": "See external versioning help for supported templated command line parameters.",
"Select All": "Select All",
"Select All": "Vybrať všetko",
"Select a version": "Zvoliť verziu",
"Select latest version": "Zvoliť najnovšiu verziu",
"Select oldest version": "Zvoliť najstaršiu verziu",
@@ -268,7 +269,7 @@
"Share With Devices": "Zdieľať so zariadeniami",
"Share this folder?": "Zdieľať tento adresár?",
"Shared With": "Zdieľané s",
"Sharing": "Sharing",
"Sharing": "Zdieľať",
"Show ID": "Zobraziť ID",
"Show QR": "Zobraziť QR",
"Show diff with previous version": "Ukázať rozdiely s predchádzajúcou verziou",
@@ -295,11 +296,12 @@
"Syncing": "Synchronizácia",
"Syncthing has been shut down.": "Syncthing bol vypnutý.",
"Syncthing includes the following software or portions thereof:": "Syncthing obsahuje nasledujúci software nebo jeho časti:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing je otvorený softvér s licenciou MPL v2.0.",
"Syncthing is restarting.": "Syncthing sa reštartuje.",
"Syncthing is upgrading.": "Syncthing sa aktualizuje.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing se zdá byť nefunkčný, alebo je problém s internetovým pripojením. Opakujem...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.",
"Take me back": "Take me back",
"Take me back": "Späť",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.",
"The Syncthing admin interface is configured to allow remote access without a password.": "The Syncthing admin interface is configured to allow remote access without a password.",
"The aggregated statistics are publicly available at the URL below.": "Súhrnné štatistiky sú verejne dostupné na uvedenej URL.",
@@ -314,7 +316,7 @@
"The folder path cannot be blank.": "Cesta k adresáru nemôže byť prázdna.",
"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.": "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.",
"The following items could not be synchronized.": "The following items could not be synchronized.",
"The following items were changed locally.": "The following items were changed locally.",
"The following items were changed locally.": "Tieto položky boli zmenené lokálne",
"The maximum age must be a number and cannot be blank.": "Maximálny vek musí byť číslo a nemôže byť prázdne.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "The maximum time to keep a version (in days, set to 0 to keep versions forever).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Minimálne voľné miesto na disku v percentách musí byť kladné číslo medzi 0 a 100 (vrátane).",
@@ -351,20 +353,20 @@
"Usage reporting is always enabled for candidate releases.": "Hlásenia o používaní sú pri kandidátoch na vydanie vždy povolené.",
"Use HTTPS for GUI": "Použiť HTTPS pre grafické rozhranie",
"Use notifications from the filesystem to detect changed items.": "Use notifications from the filesystem to detect changed items.",
"Variable Size Blocks": "Variable Size Blocks",
"Variable Size Blocks": "Bloky premenlivej veľkosti",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "Verzia",
"Versions": "Verzie",
"Versions Path": "Cesta k verziám",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Verzie sú automaticky zmazané ak sú staršie ako je maximálny časový limit alebo presiahnu počet súborov povolených v danom intervale.",
"Waiting to scan": "Waiting to scan",
"Waiting to scan": "Čaká na sken",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Warning, this path is a parent directory of an existing folder \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Warning, this path is a parent directory of an existing folder \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Warning, this path is a subdirectory of an existing folder \"{{otherFolder}}\".",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Warning, this path is a subdirectory of an existing folder \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Warning: If you are using an external watcher like {{syncthingInotify}}, you should make sure it is deactivated.",
"Watch for Changes": "Watch for Changes",
"Watching for Changes": "Watching for Changes",
"Watch for Changes": "Sleduj zmeny",
"Watching for Changes": "Sledujú sa zmeny",
"Watching for changes discovers most changes without periodic scanning.": "Watching for changes discovers most changes without periodic scanning.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "When adding a new device, keep in mind that this device must be added on the other side too.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.",
@@ -372,9 +374,9 @@
"You can also select one of these nearby devices:": "Môžete tiež vybrať jedno z týchto blízkych zariadení:",
"You can change your choice at any time in the Settings dialog.": "Voľbu môžete kedykoľvek zmeniť v dialógu Nastavenia.",
"You can read more about the two release channels at the link below.": "O dvoch vydávacích kanáloch si môžete viacej prečítať v odkaze nižšie.",
"You have no ignored devices.": "You have no ignored devices.",
"You have no ignored folders.": "You have no ignored folders.",
"You have unsaved changes. Do you really want to discard them?": "You have unsaved changes. Do you really want to discard them?",
"You have no ignored devices.": "Nemáte žiadne ignorované zariadenia.",
"You have no ignored folders.": "Nemáte žiadne ignorované priečinky.",
"You have unsaved changes. Do you really want to discard them?": "Niektoré zmeny ste neuložili. Chcete ich skutočne zahodiť?",
"You must keep at least one version.": "Musíte ponechať aspoň jednu verziu",
"days": "dní",
"directories": "adresáre",

View File

@@ -1,5 +1,5 @@
{
"A device with that ID is already added.": "En enhet med det ID är redan tillagt.",
"A device with that ID is already added.": "En enhet med det ID:t är redan tillagt.",
"A negative number of days doesn't make sense.": "Ett negativt antal dagar är inte rimligt.",
"A new major version may not be compatible with previous versions.": "En ny huvudversion kan eventuellt vara inkompatibel med tidigare versioner.",
"API Key": "API-nyckel",
@@ -55,7 +55,7 @@
"Copied from elsewhere": "Kopierat från annanstans",
"Copied from original": "Kopierat från original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 följande bidragare:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 följande bidragande:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 följande bidragsgivare:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 följande bidragsgivare:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Skapa ignorera mönster, skriver över en existerande fil på {{path}}.",
"Danger!": "Fara!",
@@ -171,6 +171,7 @@
"Log": "Logg",
"Log tailing paused. Click here to continue.": "Loggning pausad. Klicka här för att fortsätta.",
"Log tailing paused. Scroll to bottom continue.": "Loggning pausad. Rulla till botten för att fortsätta.",
"Log tailing paused. Scroll to the bottom to continue.": "Log fortsättning pausad. Bläddra till botten för att fortsätta.",
"Logs": "Loggar",
"Major Upgrade": "Större uppgradering",
"Mass actions": "Massåtgärder",
@@ -295,6 +296,7 @@
"Syncing": "Synkroniserar",
"Syncthing has been shut down.": "Syncthing har stängts.",
"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 restarting.": "Syncthing startar om.",
"Syncthing is upgrading.": "Syncthing uppgraderas.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing verkar avstängd eller så är det problem med din Internetanslutning. Försöker igen...",

View File

@@ -171,6 +171,7 @@
"Log": "Журнал",
"Log tailing paused. Click here to continue.": "Перемотка журналу призупинена. Натиснути для продовження.",
"Log tailing paused. Scroll to bottom continue.": "Висвітлення журналу призупинене. Прокрутіть нижче, щоби продовжити.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "Журнали",
"Major Upgrade": "Мажорне оновлення",
"Mass actions": "Масові операції",
@@ -295,6 +296,7 @@
"Syncing": "Синхронізація",
"Syncthing has been shut down.": "Syncthing вимкнено (закрито).",
"Syncthing includes the following software or portions thereof:": "Syncthing містить наступне програмне забезпечення (або його частини):",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing перезавантажується.",
"Syncthing is upgrading.": "Syncthing оновлюється.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Схоже на те, що Syncthing закритий, або виникла проблема із Інтернет-з’єднанням. Проводиться повторна спроба з’єднання…",

View File

@@ -171,6 +171,7 @@
"Log": "日志",
"Log tailing paused. Click here to continue.": "已暂停日志跟踪。点击此处以继续。",
"Log tailing paused. Scroll to bottom continue.": "已暂停日志跟踪。滚动到底部以继续。",
"Log tailing paused. Scroll to the bottom to continue.": "已暂停日志跟踪。滚动到底部以继续。",
"Logs": "日志",
"Major Upgrade": "重大更新",
"Mass actions": "批量操作",
@@ -295,6 +296,7 @@
"Syncing": "同步中",
"Syncthing has been shut down.": "Syncthing 已关闭。",
"Syncthing includes the following software or portions thereof:": "Syncthing 使用了下列软件或其中的一部分:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing 是个以 MPL v2.0 授权的免费开源软件。",
"Syncthing is restarting.": "Syncthing 正在重启。",
"Syncthing is upgrading.": "Syncthing 正在升级。",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing 似乎关闭了,或者您的网络连接存在故障。重试中…",

View File

@@ -56,13 +56,13 @@
"Copied from original": "從原處複製",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 下列貢獻者:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 下列貢獻者:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 下列貢獻者:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "建立忽略樣式,覆蓋已存在的 {{path}}。",
"Danger!": "危險!",
"Danger!": "危險",
"Debugging Facilities": "除錯工具",
"Default Folder Path": "預設資料夾路徑",
"Deleted": "已刪除",
"Deselect All": "Deselect All",
"Deselect All": "取消選取全部",
"Device": "裝置",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "裝置 \"{{name}}\" ({{device}} 位於 {{address}}) 想要連線。要增加新裝置嗎?",
"Device ID": "裝置識別碼",
@@ -75,7 +75,7 @@
"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 分鐘重試:",
"Discard": "Discard",
"Discard": "忽略",
"Disconnected": "斷線",
"Discovered": "已發現",
"Discovery": "探索",
@@ -116,7 +116,7 @@
"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.": "Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.",
"Filesystem Notifications": "檔案系統通知",
"Filesystem Watcher Errors": "檔案系統監視器錯誤\n",
"Filesystem Watcher Errors": "檔案系統監視器錯誤",
"Filter by date": "以日期篩選",
"Filter by name": "以名稱篩選",
"Folder": "資料夾",
@@ -144,9 +144,9 @@
"Ignore": "忽略",
"Ignore Patterns": "忽略樣式",
"Ignore Permissions": "忽略權限",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored at": "Ignored at",
"Ignored Devices": "已忽略的裝置",
"Ignored Folders": "已忽略的資料夾",
"Ignored at": "忽略時間",
"Incoming Rate Limit (KiB/s)": "傳入速率限制 (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "不正確的設定可能會損壞您的資料夾內容,並導致 Syncthing 不正常運作。",
"Introduced By": "引入自",
@@ -160,17 +160,18 @@
"Later": "稍後",
"Latest Change": "最近變動",
"Learn more": "瞭解更多",
"Limit": "Limit",
"Limit": "限制",
"Listeners": "監聽者",
"Loading data...": "正在載入資料...",
"Loading...": "正在載入...",
"Local Discovery": "本機探索",
"Local State": "本機狀態",
"Local State (Total)": "本機狀態 (總結)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "本地變動項目",
"Log": "日誌",
"Log tailing paused. Click here to continue.": "跟隨日誌暫停。點選這裡以繼續。",
"Log tailing paused. Scroll to bottom continue.": "Log tailing paused. Scroll to bottom continue.",
"Log tailing paused. Scroll to the bottom to continue.": "Log tailing paused. Scroll to the bottom to continue.",
"Logs": "日誌",
"Major Upgrade": "重大更新",
"Mass actions": "大量操作",
@@ -209,7 +210,7 @@
"Pause": "暫停",
"Pause All": "全部暫停",
"Paused": "暫停",
"Pending changes": "Pending changes",
"Pending changes": "等待中的變動",
"Periodic scanning at given interval and disabled watching for changes": "在一定的時間間隔,定期掃描及關閉觀察變動",
"Periodic scanning at given interval and enabled watching for changes": "在一定的時間間隔,定期掃描及啟用觀察變動",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "在一定的時間間隔,定期掃描,無法設定觀察變動,每 1 分鐘重試:",
@@ -224,7 +225,7 @@
"Quick guide to supported patterns": "可支援樣式的快速指南",
"RAM Utilization": "記憶體使用量",
"Random": "隨機",
"Receive Only": "僅接收\n",
"Receive Only": "僅接收",
"Recent Changes": "最近變動",
"Reduced by ignore patterns": "已由忽略樣式縮減",
"Release Notes": "版本資訊",
@@ -295,6 +296,7 @@
"Syncing": "正在同步",
"Syncthing has been shut down.": "Syncthing 已經關閉。",
"Syncthing includes the following software or portions thereof:": "Syncthing 包括以下軟體或其中的一部分:",
"Syncthing is Free and Open Source Software licensed as MPL v2.0.": "Syncthing is Free and Open Source Software licensed as MPL v2.0.",
"Syncthing is restarting.": "Syncthing 正在重新啟動。",
"Syncthing is upgrading.": "Syncthing 正在進行升級。",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing 似乎離線了,或者您的網際網路連線出現問題。正在重試...",

View File

@@ -42,7 +42,7 @@
<p class="navbar-text hidden-xs" ng-class="{'hidden-sm':upgradeInfo && upgradeInfo.newer}">{{thisDeviceName()}}</p>
<ul class="nav navbar-nav navbar-right">
<li ng-if="upgradeInfo && upgradeInfo.newer" class="upgrade-newer">
<button type="button" class="btn navbar-btn btn-primary btn-sm" ng-click="upgrade()">
<button type="button" class="btn navbar-btn btn-primary btn-sm" data-toggle="modal" data-target="#upgrade">
<span class="fas fa-arrow-circle-up"></span>
<span class="hidden-xs" translate translate-value-version="{{upgradeInfo.latest}}">Upgrade To {%version%}</span>
</button>
@@ -323,9 +323,14 @@
<span class="visible-xs" aria-label="{{'Scanning' | translate}}"><i class="fas fa-fw fa-search"></i></span>
</span>
<span ng-switch-when="idle"><span class="hidden-xs" translate>Up to Date</span><span class="visible-xs" aria-label="{{'Up to Date' | translate}}"><i class="fas fa-fw fa-check"></i></span></span>
<span ng-switch-when="localadditions"><span class="hidden-xs" translate>Local Additions</span><span class="visible-xs" aria-label="{{'Local Additions' | translate}}"><i class="fas fa-fw fa-check"></i></span></span>
<span ng-switch-when="sync-preparing">
<span class="hidden-xs" translate>Preparing to Sync</span>
<span class="visible-xs" aria-label="{{'Preparing to Sync' | translate}}"><i class="fas fa-fw fa-hourglass-half"></i></span>
</span>
<span ng-switch-when="syncing">
<span class="hidden-xs" translate>Syncing</span>
<span ng-show="syncRemaining(folder.id)">({{syncPercentage(folder.id) | percent}}, {{syncRemaining(folder.id) | binary}}B)</span>
<span>({{syncPercentage(folder.id) | percent}}, {{model[folder.id].needBytes | binary}}B)</span>
</span>
<span ng-switch-when="outofsync"><span class="hidden-xs" translate>Out of Sync</span><span class="visible-xs" aria-label="{{'Out of Sync' | translate}}"><i class="fas fa-fw fa-exclamation-circle"></i></span></span>
<span ng-switch-when="faileditems"><span class="hidden-xs" translate>Failed Items</span><span class="visible-xs" aria-label="{{'Failed Items' | translate}}"><i class="fas fa-fw fa-exclamation-circle"></i></span></span>
@@ -337,7 +342,7 @@
</button>
<div id="folder-{{$index}}" class="panel-collapse collapse">
<div class="panel-body">
<table class="table table-condensed table-striped">
<table class="table table-condensed table-striped table-auto">
<tbody>
<tr ng-show="folder.label != undefined && folder.label.length > 0">
<th><span class="fas fa-fw fa-info-circle"></span>&nbsp;<span translate>Folder ID</span></th>
@@ -506,7 +511,7 @@
<button type="button" class="btn btn-default btn-sm" ng-click="restoreVersions.show(folder.id)" ng-if="folder.versioning.type">
<span class="fas fa-undo"></span>&nbsp;<span translate>Versions</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="rescanFolder(folder.id)" ng-disabled="['idle', 'stopped', 'unshared', 'outofsync'].indexOf(folderStatus(folder)) < 0">
<button type="button" class="btn btn-sm btn-default" ng-click="rescanFolder(folder.id)" ng-disabled="['idle', 'stopped', 'unshared', 'outofsync', 'faileditems'].indexOf(folderStatus(folder)) < 0">
<span class="fas fa-refresh"></span>&nbsp;<span translate>Rescan</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="editFolder(folder)">
@@ -551,7 +556,7 @@
</button>
<div id="device-this" class="panel-collapse collapse in">
<div class="panel-body">
<table class="table table-condensed table-striped">
<table class="table table-condensed table-striped table-auto">
<tbody>
<tr>
<th><span class="fas fa-fw fa-cloud-download-alt"></span>&nbsp;<span translate>Download Rate</span></th>
@@ -667,7 +672,7 @@
</button>
<div id="device-{{$index}}" class="panel-collapse collapse">
<div class="panel-body">
<table class="table table-condensed table-striped">
<table class="table table-condensed table-striped table-auto">
<tbody>
<tr ng-if="connections[deviceCfg.deviceID].connected">
<th><span class="fas fa-fw fa-cloud-download-alt"></span>&nbsp;<span translate>Download Rate</span></th>
@@ -715,8 +720,14 @@
</span>
</td>
<td ng-if="!connections[deviceCfg.deviceID].connected" class="text-right">
<span ng-repeat="addr in deviceCfg.addresses"><span tooltip data-original-title="{{'Configured' | translate}}">{{addr}}</span><br></span>
<span ng-repeat="addr in discoveryCache[deviceCfg.deviceID].addresses"><span tooltip data-original-title="{{'Discovered' | translate}}">{{addr}}</span><br></span>
<span ng-repeat="addr in deviceCfg.addresses">
<span tooltip data-original-title="{{'Configured' | translate}}">{{addr}}</span><br>
<small ng-if="system.lastDialStatus[addr].error" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
</span>
<span ng-repeat="addr in discoveryCache[deviceCfg.deviceID].addresses">
<span tooltip data-original-title="{{'Discovered' | translate}}">{{addr}}</span><br>
<small ng-if="system.lastDialStatus[addr].error" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
</span>
</td>
</tr>
<tr ng-if="connections[deviceCfg.deviceID].connected && connections[deviceCfg.deviceID].type.indexOf('Relay') > -1" tooltip data-original-title="Connections via relays might be rate limited by the relay">
@@ -830,6 +841,7 @@
<ng-include src="'syncthing/transfer/failedFilesModalView.html'"></ng-include>
<ng-include src="'syncthing/transfer/remoteNeededFilesModalView.html'"></ng-include>
<ng-include src="'syncthing/transfer/localChangedFilesModalView.html'"></ng-include>
<ng-include src="'syncthing/core/upgradeModalView.html'"></ng-include>
<ng-include src="'syncthing/core/majorUpgradeModalView.html'"></ng-include>
<ng-include src="'syncthing/core/aboutModalView.html'"></ng-include>
<ng-include src="'syncthing/core/discoveryFailuresModalView.html'"></ng-include>

View File

@@ -66,6 +66,14 @@ function folderCompare(a, b) {
return labelA > labelB;
}
function deviceMap(l) {
var m = {};
l.forEach(function (r) {
m[r.deviceID] = r;
});
return m;
}
function folderMap(l) {
var m = {};
l.forEach(function (r) {
@@ -179,7 +187,7 @@ function buildTree(children) {
key: keySoFar.join('/'),
folder: true,
children: []
}
};
parent.children.push(child);
parent = child;
}
@@ -209,7 +217,7 @@ function unitPrefixed(input, binary) {
var i = '';
if (binary) {
factor = 1024;
i = 'i'
i = 'i';
}
if (input > factor * factor * factor * factor * 1000) {
// Don't show any decimals for more than 4 digits

View File

@@ -1,7 +1,7 @@
<modal id="about" status="info" icon="far fa-heart" heading="{{'About' | translate}}" large="yes" closeable="yes">
<div class="modal-body">
<h1 class="text-center">
<img alt="Syncthing" src="assets/img/logo-horizontal.svg" style="vertical-align: -16px" height="100" width="366" />
<img alt="Syncthing" src="assets/img/logo-horizontal.svg" style="max-width: 366px; vertical-align: -16px" />
<br />
<small>{{versionString()}}</small>
<br />
@@ -14,7 +14,7 @@
<p translate>Copyright &copy; 2014-2019 the following Contributors:</p>
<div class="row">
<div class="col-md-12" id="contributor-list">
Jakob Borg, Audrius Butkevicius, Simon Frei, Alexander Graf, Alexandre Viau, Anderson Mesquita, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Nate Morrison, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Wulf Weich, Aaron Bieber, Adam Piggott, Adel Qalieh, Alessandro G., Andrew Dunham, Andrew Rabert, Andrey D, Antoine Lamielle, Aranjedeath, Arthur Axel fREW Schmidt, BAHADIR YILMAZ, Bart De Vries, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benno Fünfstück, Benny Ng, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Chris Howie, Chris Joel, Chris Tonkinson, Colin Kennedy, Cromefire_, Dale Visser, Daniel Bergmann, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dmitry Saveliev, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Erik Meitner, Evgeny Kuznetsov, Federico Castagnini, Felix Ableitner, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gilli Sigurdsson, Graham Miln, Han Boetes, Harrison Jones, Heiko Zuerker, Hugo Locurcio, Iain Barnett, Ian Johnson, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jake Peterson, James Patterson, Jaroslav Malec, Jaya Chithra, Jens Diemer, Jerry Jacobs, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan Cross, Jose Manuel Delicado, Jörg Thalheim, Karol Różycki, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin White, Jr., Kurt Fitzner, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Mark Pulford, Mateusz Naściszewski, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max Schulze, MaximAL, Maxime Thirouin, Michael Jephcote, Michael Tilli, Mike Boone, MikeLund, Nicholas Rishel, Nico Stapelbroek, Nicolas Braud-Santoni, Niels Peter Roest, Nils Jakobi, NoLooseEnds, Oyebanji Jacob Mayowa, Pascal Jungblut, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phil Davis, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Richard Hartmann, Robert Carosi, Roman Zaynetdinov, Ross Smith II, Sacheendra Talluri, Scott Klupfel, Sly_tom_cat, Stefan Kuntz, Suhas Gundimeda, Taylor Khan, Thomas Hipp, Tim Abell, Tim Howes, Tobias Nygren, Tobias Tom, Tomas Cerveny, Tommy Thorn, Tully Robinson, Tyler Brazier, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, Vladimir Rusinov, William A. Kennington III, Xavier O., Yannic A., andresvia, andyleap, chucic, derekriemer, desbma, georgespatton, janost, jaseg, klemens, marco-m, otbutz, perewa, rubenbe, wangguoliang, xjtdy888, 佛跳墙
Jakob Borg, Audrius Butkevicius, Simon Frei, Alexander Graf, Alexandre Viau, Anderson Mesquita, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Nate Morrison, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Wulf Weich, Aaron Bieber, Adam Piggott, Adel Qalieh, Alessandro G., Andrew Dunham, Andrew Rabert, Andrey D, André Colomb, Antoine Lamielle, Aranjedeath, Arthur Axel fREW Schmidt, BAHADIR YILMAZ, Bart De Vries, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benedikt Morbach, Benno Fünfstück, Benny Ng, Boris Rybalkin, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Chris Howie, Chris Joel, Chris Tonkinson, Colin Kennedy, Cromefire_, Dale Visser, Daniel Bergmann, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dmitry Saveliev, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Erik Meitner, Evgeny Kuznetsov, Federico Castagnini, Felix Ableitner, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gilli Sigurdsson, Graham Miln, Han Boetes, Harrison Jones, Heiko Zuerker, Hugo Locurcio, Iain Barnett, Ian Johnson, Iskander Sharipov, Jaakko Hannikainen, Jacek Szafarkiewicz, Jake Peterson, James Patterson, Jaroslav Malec, Jaya Chithra, Jens Diemer, Jerry Jacobs, Jochen Voss, Johan Andersson, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan Cross, Jose Manuel Delicado, Jörg Thalheim, Kalle Laine, Karol Różycki, Keith Turner, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin White, Jr., Kurt Fitzner, Laurent Arnoud, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Mark Pulford, Mateusz Naściszewski, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max Schulze, MaximAL, Maxime Thirouin, Michael Jephcote, Michael Tilli, Mike Boone, MikeLund, Mingxuan Lin, Nicholas Rishel, Nico Stapelbroek, Nicolas Braud-Santoni, Niels Peter Roest, Nils Jakobi, Nitroretro, NoLooseEnds, Oyebanji Jacob Mayowa, Pascal Jungblut, Pawel Palenica, Paweł Rozlach, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phil Davis, Phill Luby, Pier Paolo Ramon, Piotr Bejda, Pramodh KP, Richard Hartmann, Robert Carosi, Roman Zaynetdinov, Ross Smith II, Sacheendra Talluri, Scott Klupfel, Sly_tom_cat, Stefan Kuntz, Suhas Gundimeda, Taylor Khan, Thomas Hipp, Tim Abell, Tim Howes, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tomas Cerveny, Tommy Thorn, Tully Robinson, Tyler Brazier, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, Vladimir Rusinov, William A. Kennington III, Xavier O., Yannic A., andresvia, andyleap, chucic, dependabot-preview[bot], dependabot[bot], derekriemer, desbma, georgespatton, janost, jaseg, klemens, marco-m, otbutz, perewa, rubenbe, wangguoliang, xjtdy888, 佛跳墙
</div>
</div>
<hr />

View File

@@ -23,7 +23,6 @@ angular.module('syncthing.core')
svg.appendChild(rect);
};
var rect;
var row;
var col;
var middleCol;

View File

@@ -8,7 +8,6 @@ angular.module('syncthing.core')
var uid = new Date();
var storage = window.localStorage;
storage.setItem(uid, uid);
var success = storage.getItem(uid) == uid;
storage.removeItem(uid);
return storage;
} catch (exception) {

View File

@@ -8,8 +8,8 @@
<div id="log-viewer-log" class="tab-pane in active">
<label translate ng-if="logging.logEntries.length == 0">Loading...</label>
<textarea id="logViewerText" class="form-control" rows="20" ng-if="logging.logEntries.length != 0" readonly style="font-family: Consolas; font-size: 11px; overflow: auto;">{{ logging.content() }}</textarea>
<p translate class="help-block" ng-style="{'visibility': logging.paused ? 'visible' : 'hidden'}">Log tailing paused. Scroll to bottom continue.</p>
<textarea id="logViewerText" class="form-control" rows="20" ng-if="logging.logEntries.length != 0" readonly style="font-family: Consolas, monospace; font-size: 11px; overflow: auto;">{{ logging.content() }}</textarea>
<p translate class="help-block" ng-style="{'visibility': logging.paused ? 'visible' : 'hidden'}">Log tailing paused. Scroll to the bottom to continue.</p>
</div>
<div id="log-viewer-facilities" class="tab-pane">

View File

@@ -6,7 +6,7 @@
<span translate>Please consult the release notes before performing a major upgrade.</span>
</p>
<p>
<a href="https://github.com/syncthing/syncthing/releases/tag/{{upgradeInfo.latest}}" target="_blank" translate>Release Notes</a>
<a ng-href="https://github.com/syncthing/syncthing/releases/tag/{{upgradeInfo.latest}}" target="_blank" translate>Release Notes</a>
</p>
</div>
<div class="modal-footer">

Some files were not shown because too many files have changed in this diff Show More