Compare commits

...

113 Commits

Author SHA1 Message Date
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
a54d7a32d1 etc: Revert systemd After=multi-user.target addition (fixes #5676)
This reverts commit 84fe285659.
2019-04-29 21:48:28 +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
Simon Frei
ca823bd591 lib/fs: When watching remove \\?\ for drive letters (fixes #5578) (#5633) 2019-04-09 09:02:04 +02:00
Jakob Borg
eabd972667 docker: Update build image version 2019-04-07 16:13:55 +02:00
Simon Frei
395e524e2d lib/model: Update db on scan/pull in folder (#5608) 2019-04-07 13:29:17 +02:00
Jakob Borg
48b1a2b264 gui, man, authors: Update docs, translations, and contributors 2019-04-03 07:45:31 +02:00
Evgeny Kuznetsov
58953d799c gui: Add licensing information to aboutModalView (fixes #1223) (#5605) 2019-03-28 07:49:29 +01:00
Jakob Borg
f0f8bf7784 lib/config: Round times stored for pending folders/devices (fixes #5554) 2019-03-27 20:35:42 +01:00
Jakob Borg
bf3834e367 lib/protocol: Use constants instead of init time hashing (fixes #5624) (#5625)
This constructs the map of hashes of zero blocks from constants instead
of calculating it at startup time. A new test verifies that the map is
correct.
2019-03-27 20:20:30 +01:00
Simon Frei
8d1eff7e41 lib/model: Missing queue.Done and reset between pulls (fixes #5332) (#5626) 2019-03-27 20:19:35 +01:00
Simon Frei
0cff66fcbc lib/model: Optimize puller for meta only changes (#5622) 2019-03-27 08:36:58 +00:00
Jakob Borg
d23e8be39f gui, man, authors: Update docs, translations, and contributors 2019-03-27 07:45:25 +01:00
Simon Frei
43a5be1c4b lib/model: Send item finished even after deregistering (fixes #5362) (#5620) 2019-03-26 21:31:33 +01:00
Simon Frei
b50039a920 cmd/syncthing, lib/api: Separate api/gui into own package (ref #4085) (#5529)
* cmd/syncthing, lib/gui: Separate gui into own package (ref #4085)

* fix tests

* Don't use main as interface name (make old go happy)

* gui->api

* don't leak state via locations and use in-tree config

* let api (un-)subscribe to config

* interface naming and exporting

* lib/ur

* fix tests and lib/foldersummary

* shorter URVersion and ur debug fix

* review

* model.JsonCompletion(FolderCompletion) -> FolderCompletion.Map()

* rename debug facility https -> api

* folder summaries in model

* disassociate unrelated constants

* fix merge fail

* missing id assignement
2019-03-26 19:53:58 +00:00
Simon Frei
d4e81fff8a lib/model: Remove unnecessary arguments in pulling functions (#5619) 2019-03-25 12:59:22 +01:00
Jakob Borg
3a557a43cd Merge branch 'release'
* release:
  lib/model: Pass correct file info to deleteItemOnDisk (fixes #5616) (#5617)
  gui: Add missing quote char
2019-03-25 12:58:12 +01:00
Simon Frei
bc53782f88 test: Update conflict integration test (ref #5511) (#5618)
The change in 225c0dda80 (#5511) results in
conflicts being immediately scanned and synced, while the test expects just one
conflict on either side. Change it to expect the same conflict on both sides.
2019-03-25 12:53:06 +01:00
Simon Frei
e4ab9d3312 lib/model: Pass correct file info to deleteItemOnDisk (fixes #5616) (#5617) 2019-03-25 12:43:21 +01:00
Simon Frei
e31a116e6e lib/model: Pass correct file info to deleteItemOnDisk (fixes #5616) (#5617) 2019-03-25 12:42:39 +01:00
Jakob Borg
24f41e169a gui: Add missing quote char 2019-03-25 12:37:10 +01:00
Simon Frei
675f289aef gui: Add new folder state "Failed Items" (fixes #5456) (#5614) 2019-03-22 17:57:53 +00:00
Simon Frei
e7ae851900 lib/model: Debug and test fixes (#5613) 2019-03-22 14:43:47 +01:00
Jakob Borg
73fa7a6e5b go.mod: Update golang.org/x/sys
There was a vulnerability in salsa20, which we don't use, but better
safe than sorry.
2019-03-21 08:08:15 +01:00
Simon Frei
1a6d023ba8 lib/model: Run recvonly tests in temporary dirs (#5587) 2019-03-20 17:38:03 +00:00
Jakob Borg
9207535028 gui: Add missing quote char 2019-03-14 07:37:18 +01:00
Jakob Borg
24967e99a7 gui, man, authors: Update docs, translations, and contributors 2019-03-13 07:45:25 +01:00
Simon Frei
50d8c43e7c lib/config: Set UseLargeBlocks to true by default (fixes #5599) (#5600) 2019-03-12 12:59:26 +00:00
Evgeny Kuznetsov
90d9b2de2b cmd/syncthing: Add a check for particular far-future version of config (fixes #1101) 2019-03-12 08:20:47 +00:00
Evgeny Kuznetsov
04f05f102d cmd: Add check for newer config file and an option to override it (fixes #4921) (#5597)
* Add check for newer config file and override option

* Expanded error message

* Polish previous commits

* Make it newER
2019-03-12 07:12:08 +00:00
Simon Frei
289a02e994 lib/model: Integrate stat refs in folder (#5596) 2019-03-11 16:57:21 +00:00
georgespatton
84fe285659 etc: Systemd unit should declare after=multiuser.target (fixes #5346) (#5593) 2019-03-11 15:50:34 +01:00
Simon Frei
445637ebec lib/model: Pass fset & ignores on folder creation (#5592) 2019-03-11 07:28:54 +01:00
Simon Frei
3f3d2c814b lib/model: Remove unused code (#5591) 2019-03-10 17:05:39 +01:00
Simon Frei
189e44488e lib/model: Introduce must test utility (#5586)
* lib/model: Introduce must test utility

* nice
2019-03-09 18:45:36 +00:00
Simon Frei
27ff20faa3 lib/model: Introduce waitForState test utility (#5585)
* lib/model: Introduce waitForState test utility

* folder id as param to waitForState
2019-03-09 10:36:55 +00:00
Simon Frei
b1564e53e4 lib/model: Improve test utilities (#5584) 2019-03-08 20:29:09 +00:00
Simon Frei
3a75b63776 lib/model: Use temp dir from osutils in tests (#5581) 2019-03-07 16:34:41 +01:00
Simon Frei
8e238c8e48 lib/model: Check before replacing existing file on pull (fixes #5571) (#5567) 2019-03-07 15:15:14 +01:00
Jakob Borg
3d5af675db gui, man, authors: Update docs, translations, and contributors 2019-03-06 07:45:23 +01:00
Jakob Borg
9da3273eb8 lib/model: Clarify fileInfoBatch.flushIfFull criteria 2019-03-05 21:34:04 +01:00
Simon Frei
bd37f6da17 lib/model: Optimize dbUpdaterRoutine (#5576) 2019-03-05 21:32:37 +01:00
Simon Frei
6940d79f5b lib/model: Use errors.Wrap for pull errors (#5563) 2019-03-04 13:01:52 +00:00
Simon Frei
0f80318ef6 lib/scanner: Consistenlty use CreateFileInfo and remove outdated comment (#5574) 2019-03-04 13:27:33 +01:00
Simon Frei
d6622b1f68 lib/model: setUp -> setup (#5573) 2019-03-04 12:27:10 +00:00
Simon Frei
43bcb3d5a5 lib/model: Refactor conflict name handling (#5572) 2019-03-04 12:20:40 +00:00
Evgeny Kuznetsov
e2e8f6e940 gui: Update copyright notices (fixes #5569) (#5570) 2019-03-03 13:15:17 +01:00
Jakob Borg
88b0ce892d gui, man, authors: Update docs, translations, and contributors 2019-02-27 07:45:23 +01:00
otbutz
55cd4b3d9b gui: Use handshake icon for "Introduced by" (fixes #5560) (#5561) 2019-02-26 14:18:35 +01:00
Jakob Borg
f24676ba5a lib/tlsutil: Enable TLS 1.3 when available, on test builds (fixes #5065) (#5558)
* lib/tlsutil: Enable TLS 1.3 when available, on test builds (fixes #5065)

This enables TLS 1.3 negotiation on Go 1.12 by setting the GODEBUG
variable. For now, this just gets enabled on test versions (those with a
dash in the version number).

Users wishing to enable this on production builds can set GODEBUG
manually.

The string representation of connections now includes the TLS version
and cipher suite. This becomes part of the log output on connections.
That is, when talking to an old client:

    Established secure connection .../TLS1.2-TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

and now potentially:

    Established secure connection .../TLS1.3-TLS_AES_128_GCM_SHA256

(The cipher suite was there previously in the log output, but not the
TLS version.)

I also added this info as a new Crypto() method on the connection, and
propagate this out to the API and GUI, where it can be seen in the
connection address hover (although with bad word wrapping sometimes).

* wip

* wip
2019-02-26 11:49:02 +01:00
Simon Frei
722b3fce6a all: Hide implementations behind interfaces for mocked testing (#5548)
* lib/model: Hide implementations behind interfaces for mocked testing

* review
2019-02-26 08:09:25 +00:00
Jonas Thelemann
8a05492622 docs: Correct Docker README (#5480) (#5545)
Plus some formatting.
2019-02-26 00:37:59 +04:00
Jakob Borg
63c4e7f6d0 Merge branch 'release'
* release:
  lib/scanner: Use standard adler32 when we don't need rolling (#5556)
2019-02-25 19:36:41 +01:00
Audrius Butkevicius
fafd30f804 lib/scanner: Use standard adler32 when we don't need rolling (#5556)
* lib/scanner: Use standard adler32 when we don't need rolling

Seems the rolling adler32 implementation is super slow when executed on large blocks, even tho I can't explain why.

BenchmarkFind1MFile-16    				     100	  18991667 ns/op	  55.21 MB/s	  398844 B/op	      20 allocs/op
BenchmarkBlock/adler32-131072/#00-16     		     200	   9726519 ns/op	1078.06 MB/s	 2654936 B/op	     163 allocs/op
BenchmarkBlock/bozo32-131072/#00-16      		      20	  73435540 ns/op	 142.79 MB/s	 2654928 B/op	     163 allocs/op
BenchmarkBlock/buzhash32-131072/#00-16   		      20	  61482005 ns/op	 170.55 MB/s	 2654928 B/op	     163 allocs/op
BenchmarkBlock/buzhash64-131072/#00-16   		      20	  61673660 ns/op	 170.02 MB/s	 2654928 B/op	     163 allocs/op
BenchmarkBlock/vanilla-adler32-131072/#00-16         	     300	   4377307 ns/op	2395.48 MB/s	 2654935 B/op	     163 allocs/op
BenchmarkBlock/adler32-16777216/#00-16               	       2	 544010100 ns/op	  19.27 MB/s	   65624 B/op	       5 allocs/op
BenchmarkBlock/bozo32-16777216/#00-16                	       1	4678108500 ns/op	   2.24 MB/s	51970144 B/op	      24 allocs/op
BenchmarkBlock/buzhash32-16777216/#00-16             	       1	3880370700 ns/op	   2.70 MB/s	51970144 B/op	      24 allocs/op
BenchmarkBlock/buzhash64-16777216/#00-16             	       1	3875911700 ns/op	   2.71 MB/s	51970144 B/op	      24 allocs/op
BenchmarkBlock/vanilla-adler32-16777216/#00-16       	     300	   4010279 ns/op	2614.72 MB/s	   65624 B/op	       5 allocs/op
BenchmarkRoll/adler32-131072/#00-16                  	    2000	    974279 ns/op	 134.53 MB/s	     270 B/op	       0 allocs/op
BenchmarkRoll/bozo32-131072/#00-16                   	    2000	    791770 ns/op	 165.54 MB/s	     270 B/op	       0 allocs/op
BenchmarkRoll/buzhash32-131072/#00-16                	    2000	    917409 ns/op	 142.87 MB/s	     270 B/op	       0 allocs/op
BenchmarkRoll/buzhash64-131072/#00-16                	    2000	    881125 ns/op	 148.76 MB/s	     270 B/op	       0 allocs/op
BenchmarkRoll/adler32-16777216/#00-16                	      10	 124000400 ns/op	 135.30 MB/s	 7548937 B/op	       0 allocs/op
BenchmarkRoll/bozo32-16777216/#00-16                 	      10	 118008080 ns/op	 142.17 MB/s	 7548928 B/op	       0 allocs/op
BenchmarkRoll/buzhash32-16777216/#00-16              	      10	 126794440 ns/op	 132.32 MB/s	 7548928 B/op	       0 allocs/op
BenchmarkRoll/buzhash64-16777216/#00-16              	      10	 126631960 ns/op	 132.49 MB/s	 7548928 B/op	       0 allocs/op

* Update benchmark_test.go

* gofmt

* fixup benchmark
2019-02-25 13:29:31 +04:00
Simon Frei
ad5a046843 lib/fs: Rename fsFile* to basicFile* (#5546) 2019-02-24 18:02:02 +01:00
Jakob Borg
4b8853bfde gui, man, authors: Update docs, translations, and contributors 2019-02-20 07:45:22 +01:00
Evgeny Kuznetsov
648fcf2c45 etc: Remove unnecessary quotes in .desktop (#5540) 2019-02-15 07:35:19 +00:00
Simon Frei
ca3ae64bbf lib/db: Flush batch based on size and refactor (fixes #5531) (#5536)
Flush the batch when exceeding a certain size, instead of when reaching a number
of batched operations.
Move batch to lowlevel to be able to use it in NamespacedKV.
Increase the leveldb memory buffer from 4 to 16 MiB.
2019-02-14 23:15:13 +00:00
Simon Frei
e2204d0071 build: Add option to get test coverage (#5539) 2019-02-14 22:38:47 +00:00
Simon Frei
d5ff2c41dc all: Get rid of fatal logging (#5537)
* cleanup Fatal in lib/config/config.go

* cleanup Fatal in lib/config/folderconfiguration.go

* cleanup Fatal in lib/model/model.go

* cleanup Fatal in cmd/syncthing/monitor.go

* cleanup Fatal in cmd/syncthing/main.go

* cleanup Fatal in lib/api

* remove Fatal methods from logger

* lowercase in errors.Wrap

* one less channel
2019-02-14 20:29:14 +00:00
Simon Frei
7a40c42e8b cmd/syncthing: Introduce exiter to handle termination (#5532) 2019-02-13 23:07:27 +00:00
Simon Frei
905c3594b0 lib/model: Various model test fixes and polish (#5528)
* lib/model: Various model test fixes and polish

Missing calls to m.Stop()
Don't fail test if temporary test dir cleanup fails

* drop lazyness
2019-02-13 18:54:04 +00:00
Jakob Borg
5fd333e4f7 gui, man, authors: Update docs, translations, and contributors 2019-02-13 07:45:23 +01:00
Simon Frei
225c0dda80 lib/model: Scan conflicts after creation (#5511)
Also unflakes and improve TestRequestRemoteRenameChanged.
2019-02-12 16:05:20 +01:00
Simon Frei
5fd2cab102 lib/model: Run more tests in tmp dir (#5527) 2019-02-12 16:04:04 +01:00
175 changed files with 5265 additions and 3325 deletions

5
.codecov.yml Normal file
View File

@@ -0,0 +1,5 @@
coverage:
range: "40...100"
ignore:
- "**.pb.go"

10
AUTHORS
View File

@@ -29,7 +29,7 @@ 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>
@@ -70,11 +70,13 @@ Elias Jarlebring (jarlebring) <jarlebring@gmail.com>
Elliot Huffman <thelich2@gmail.com>
Emil Hessman (ceh) <emil@hessman.se>
Erik Meitner (WSGCSysadmin) <e.meitner@willystreet.coop>
Evgeny Kuznetsov <evgeny@kuznetsov.md>
Federico Castagnini (facastagnini) <federico.castagnini@gmail.com>
Felix Ableitner (Nutomic) <me@nutomic.com>
Felix Unterpaintner (bigbear2nd) <bigbear2nd@gmail.com>
Francois-Xavier Gsell (zukoo) <fxgsell@gmail.com>
Frank Isemann (fti7) <frank@isemann.name>
georgespatton <georgespatton@users.noreply.github.com>
Gilli Sigurdsson (gillisig) <gilli@vx.is>
Graham Miln (grahammiln) <graham.miln@dssw.co.uk> <graham.miln@miln.eu>
Han Boetes <han@boetes.org>
@@ -83,7 +85,7 @@ Heiko Zuerker (Smiley73) <heiko@zuerker.org>
Hugo Locurcio <hugo.locurcio@hugo.pro>
Iain Barnett <iainspeed@gmail.com>
Ian Johnson (anonymouse64) <ian.johnson@canonical.com> <person.uwsome@gmail.com>
Iskander (Alex) Sharipov <quasilyte@gmail.com>
Iskander Sharipov (Alex) <quasilyte@gmail.com>
Jaakko Hannikainen (jgke) <jgke@jgke.fi>
Jacek Szafarkiewicz (hadogenes) <szafar@linux.pl>
Jake Peterson (acogdev) <jake@acogdev.com>
@@ -99,6 +101,7 @@ Jochen Voss (seehuhn) <voss@seehuhn.de>
Johan Andersson <j@i19.se>
Johan Vromans (sciurius) <jvromans@squirrel.nl>
John Rinehart (fuzzybear3965) <johnrichardrinehart@gmail.com>
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>
@@ -126,6 +129,7 @@ Mark Pulford (mpx) <mark@kyne.com.au>
Mateusz Naściszewski (mateon1) <matin1111@wp.pl>
Matic Potočnik <hairyfotr@gmail.com>
Matt Burke (burkemw3) <mburke@amplify.com> <burkemw3@gmail.com>
Matt Robenolt <matt@ydekproductions.com>
Matteo Ruina <matteo.ruina@gmail.com>
Maurizio Tomasi <ziotom78@gmail.com>
Max Schulze (kralo) <max.schulze@online.de> <kralo@users.noreply.github.com>
@@ -142,7 +146,9 @@ 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>
Pascal Jungblut (pascalj) <github@pascalj.com> <mail@pascal-jungblut.com>
Pawel Palenica (qepasa) <pawelpalenica11@gmail.com>

View File

@@ -1,4 +1,4 @@
FROM golang:1.11 AS builder
FROM golang:1.12 AS builder
WORKDIR /src
COPY . .

View File

@@ -1,39 +1,30 @@
# Docker Container for Syncthing
Use the Dockerfile in this repo, or pull the `syncthing/syncthing` image
from Docker Hub. Use volumes to have the synchronized files available on the
host.
from Docker Hub.
The exposed volumes are by default:
/var/syncthing/config - the configuration and index directory into the Container
/var/syncthing - the default sync folder into the Container
You can add more folders and map them as you prefer.
Use the `/var/syncthing` volume to have the synchronized files available on the
host. You can add more folders and map them as you prefer.
Note that Syncthing runs as UID 1000 and GID 1000 by default. These may be
altered with the ``PUID`` and ``PGID`` environment variables.
Example usage:
## Example Usage
```
$ docker pull syncthing/syncthing
$ docker run -p 8384:8384 -p 22000:22000 \
-v /wherever/st-cfg:/var/syncthing/config \
-v /wherever/st-sync:/var/syncthing \
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.
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:
```
$ docker pull syncthing/syncthing
$ docker run --network=host \
-v /wherever/st-cfg:/var/syncthing/config \
-v /wherever/st-sync:/var/syncthing \
syncthing/syncthing:latest
```

View File

@@ -48,6 +48,7 @@ var (
pkgdir string
cc string
debugBinary bool
coverage bool
timeout = "120s"
gogoProtoVersion = "v1.2.0"
)
@@ -330,24 +331,27 @@ func parseFlags() {
flag.StringVar(&pkgdir, "pkgdir", "", "Set -pkgdir parameter for `go build`")
flag.StringVar(&cc, "cc", os.Getenv("CC"), "Set CC environment variable for `go build`")
flag.BoolVar(&debugBinary, "debug-binary", debugBinary, "Create unoptimized binary to use with delve, set -gcflags='-N -l' and omit -ldflags")
flag.BoolVar(&coverage, "coverage", coverage, "Write coverage profile of tests to coverage.txt")
flag.Parse()
}
func test(pkgs ...string) {
lazyRebuildAssets()
useRace := runtime.GOARCH == "amd64"
switch runtime.GOOS {
case "darwin", "linux", "freebsd": // , "windows": # See https://github.com/golang/go/issues/27089
default:
useRace = false
args := []string{"test", "-short", "-timeout", timeout, "-tags", "purego"}
if runtime.GOARCH == "amd64" {
switch runtime.GOOS {
case "darwin", "linux", "freebsd": // , "windows": # See https://github.com/golang/go/issues/27089
args = append(args, "-race")
}
}
if useRace {
runPrint(goCmd, append([]string{"test", "-short", "-race", "-timeout", timeout, "-tags", "purego"}, pkgs...)...)
} else {
runPrint(goCmd, append([]string{"test", "-short", "-timeout", timeout, "-tags", "purego"}, pkgs...)...)
if coverage {
args = append(args, "-covermode", "atomic", "-coverprofile", "coverage.txt")
}
runPrint(goCmd, append(args, pkgs...)...)
}
func bench(pkgs ...string) {

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

@@ -14,15 +14,9 @@ import (
)
var (
l = logger.DefaultLogger.NewFacility("main", "Main package")
httpl = logger.DefaultLogger.NewFacility("http", "REST API")
l = logger.DefaultLogger.NewFacility("main", "Main package")
)
func shouldDebugHTTP() bool {
return l.ShouldDebug("http")
}
func init() {
l.SetDebug("main", strings.Contains(os.Getenv("STTRACE"), "main") || os.Getenv("STTRACE") == "all")
l.SetDebug("http", strings.Contains(os.Getenv("STTRACE"), "http") || os.Getenv("STTRACE") == "all")
}

View File

@@ -9,7 +9,6 @@ package main
import (
"bytes"
"crypto/tls"
"errors"
"flag"
"fmt"
"io"
@@ -30,6 +29,7 @@ import (
"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"
@@ -47,7 +47,9 @@ import (
"github.com/syncthing/syncthing/lib/sha256"
"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"
)
@@ -62,16 +64,12 @@ const (
const (
bepProtocolName = "bep/1.0"
tlsDefaultCommonName = "syncthing"
defaultEventTimeout = time.Minute
maxSystemErrors = 5
initialSystemLog = 10
maxSystemLog = 250
)
var (
myID protocol.DeviceID
stop = make(chan int)
)
var myID protocol.DeviceID
const (
usage = "syncthing [options]"
@@ -166,34 +164,35 @@ var (
)
type RuntimeOptions struct {
confDir string
resetDatabase bool
resetDeltaIdxs bool
showVersion bool
showPaths bool
showDeviceId bool
doUpgrade bool
doUpgradeCheck bool
upgradeTo string
noBrowser bool
browserOnly bool
hideConsole bool
logFile string
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
showHelp bool
confDir string
resetDatabase bool
resetDeltaIdxs bool
showVersion bool
showPaths bool
showDeviceId bool
doUpgrade bool
doUpgradeCheck bool
upgradeTo string
noBrowser bool
browserOnly bool
hideConsole bool
logFile string
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
showHelp bool
allowNewerConfig bool
}
func defaultRuntimeOptions() RuntimeOptions {
@@ -247,6 +246,7 @@ func parseCommandLineOptions() RuntimeOptions {
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.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" {
// Allow user to hide the console window
flag.BoolVar(&options.hideConsole, "no-console", false, "Hide console window")
@@ -264,6 +264,33 @@ 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)
@@ -282,7 +309,8 @@ func main() {
// to complain if they set -logfile explicitly, not if it's set to its
// default location
if options.noRestart && (options.logFile != "" && options.logFile != "-") {
l.Fatalln("-logfile may not be used with -no-restart or STNORESTART")
l.Warnln("-logfile may not be used with -no-restart or STNORESTART")
os.Exit(exitError)
}
if options.hideConsole {
@@ -295,11 +323,13 @@ func main() {
var err error
options.confDir, err = filepath.Abs(options.confDir)
if err != nil {
l.Fatalln(err)
l.Warnln("Failed to make options path absolute:", err)
os.Exit(exitError)
}
}
if err := locations.SetBaseDir(locations.ConfigBaseDir, options.confDir); err != nil {
l.Fatalln(err)
l.Warnln(err)
os.Exit(exitError)
}
}
@@ -336,7 +366,8 @@ func main() {
locations.Get(locations.KeyFile),
)
if err != nil {
l.Fatalln("Error reading device ID:", err)
l.Warnln("Error reading device ID:", err)
os.Exit(exitError)
}
myID = protocol.NewDeviceID(cert.Certificate[0])
@@ -345,22 +376,32 @@ func main() {
}
if options.browserOnly {
openGUI()
if err := openGUI(); err != nil {
l.Warnln("Failed to open web UI:", err)
os.Exit(exitError)
}
return
}
if options.generateDir != "" {
generate(options.generateDir)
if err := generate(options.generateDir); err != nil {
l.Warnln("Failed to generate config and keys:", err)
os.Exit(exitError)
}
return
}
// Ensure that our home directory exists.
ensureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700)
if err := ensureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
l.Warnln("Failure on home directory:", err)
os.Exit(exitError)
}
if options.upgradeTo != "" {
err := upgrade.ToURL(options.upgradeTo)
if err != nil {
l.Fatalln("Upgrade:", err) // exits 1
l.Warnln("Error while Upgrading:", err)
os.Exit(exitError)
}
l.Infoln("Upgraded from", options.upgradeTo)
return
@@ -379,7 +420,8 @@ func main() {
if options.resetDatabase {
if err := resetDB(); err != nil {
l.Fatalln("Resetting database:", err)
l.Warnln("Resetting database:", err)
os.Exit(exitError)
}
return
}
@@ -391,23 +433,30 @@ func main() {
}
}
func openGUI() {
cfg, _ := loadOrDefaultConfig()
func openGUI() error {
cfg, err := loadOrDefaultConfig()
if err != nil {
return err
}
if cfg.GUI().Enabled {
if err := openURL(cfg.GUI().URL()); err != nil {
l.Fatalln("Open URL:", err)
return err
}
} else {
l.Warnln("Browser: GUI is currently disabled")
}
return nil
}
func generate(generateDir string) {
func generate(generateDir string) error {
dir, err := fs.ExpandTilde(generateDir)
if err != nil {
l.Fatalln("generate:", err)
return err
}
if err := ensureDir(dir, 0700); err != nil {
return err
}
ensureDir(dir, 0700)
certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
@@ -417,11 +466,11 @@ func generate(generateDir string) {
} else {
cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName)
if err != nil {
l.Fatalln("Create certificate:", err)
return errors.Wrap(err, "create certificate")
}
myID = protocol.NewDeviceID(cert.Certificate[0])
if err != nil {
l.Fatalln("Load certificate:", err)
return errors.Wrap(err, "load certificate")
}
if err == nil {
l.Infoln("Device ID:", protocol.NewDeviceID(cert.Certificate[0]))
@@ -431,13 +480,17 @@ func generate(generateDir string) {
cfgFile := filepath.Join(dir, "config.xml")
if _, err := os.Stat(cfgFile); err == nil {
l.Warnln("Config exists; will not overwrite.")
return
return nil
}
cfg, err := defaultConfig(cfgFile)
if err != nil {
return err
}
var cfg = defaultConfig(cfgFile)
err = cfg.Save()
if err != nil {
l.Warnln("Failed to save config", err)
return errors.Wrap(err, "save config")
}
return nil
}
func debugFacilities() string {
@@ -467,7 +520,8 @@ func checkUpgrade() upgrade.Release {
opts := cfg.Options()
release, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
if err != nil {
l.Fatalln("Upgrade:", err)
l.Warnln("Upgrade:", err)
os.Exit(exitError)
}
if upgrade.CompareVersions(release.Tag, build.Version) <= 0 {
@@ -486,14 +540,16 @@ func performUpgrade(release upgrade.Release) {
if err == nil {
err = upgrade.To(release)
if err != nil {
l.Fatalln("Upgrade:", err)
l.Warnln("Upgrade:", err)
os.Exit(exitError)
}
l.Infof("Upgraded to %q", release.Tag)
} else {
l.Infoln("Attempting upgrade through running Syncthing...")
err = upgradeViaRest()
if err != nil {
l.Fatalln("Upgrade:", err)
l.Warnln("Upgrade:", err)
os.Exit(exitError)
}
l.Infoln("Syncthing upgrading")
os.Exit(exitUpgrading)
@@ -567,8 +623,8 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
// 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(defaultEventMask), eventSubBufferSize)
diskSub := events.NewBufferedSubscription(events.Default.Subscribe(diskEventMask), eventSubBufferSize)
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())
@@ -592,7 +648,8 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
tlsDefaultCommonName,
)
if err != nil {
l.Fatalln(err)
l.Infoln("Failed to generate certificate:", err)
os.Exit(exitError)
}
}
@@ -614,10 +671,15 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
"myID": myID.String(),
})
cfg := loadConfigAtStartup()
cfg, err := loadConfigAtStartup(runtimeOptions.allowNewerConfig)
if err != nil {
l.Warnln("Failed to initialize config:", err)
os.Exit(exitError)
}
if err := checkShortIDs(cfg); err != nil {
l.Fatalln("Short device IDs are in conflict. Unlucky!\n Regenerate the device ID of one of the following:\n ", err)
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 {
@@ -626,21 +688,24 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
runtime.SetBlockProfileRate(1)
err := http.ListenAndServe(runtimeOptions.profiler, nil)
if err != nil {
l.Fatalln(err)
l.Warnln(err)
os.Exit(exitError)
}
}()
}
perf := cpuBench(3, 150*time.Millisecond, true)
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.Fatalln("Error opening database:", err)
l.Warnln("Error opening database:", err)
os.Exit(exitError)
}
if err := db.UpdateSchema(ldb); err != nil {
l.Fatalln("Database schema:", err)
l.Warnln("Database schema:", err)
os.Exit(exitError)
}
if runtimeOptions.resetDeltaIdxs {
@@ -769,25 +834,15 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
}
}
// GUI
setupGUI(mainService, cfg, m, defaultSub, diskSub, cachedDiscovery, connectionsService, errors, systemLog, runtimeOptions)
if runtimeOptions.cpuProfile {
f, err := os.Create(fmt.Sprintf("cpu-%d.pprof", os.Getpid()))
if err != nil {
l.Fatalln("Creating profile:", err)
l.Warnln("Creating profile:", err)
os.Exit(exitError)
}
if err := pprof.StartCPUProfile(f); err != nil {
l.Fatalln("Starting profile:", err)
}
}
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)
l.Warnln("Starting profile:", err)
os.Exit(exitError)
}
}
@@ -795,8 +850,8 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
if opts := cfg.Options(); build.IsCandidate {
l.Infoln("Anonymous usage reporting is always enabled for candidate releases.")
if opts.URAccepted != usageReportVersion {
opts.URAccepted = usageReportVersion
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.
@@ -810,9 +865,21 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
cfg.Save()
}
usageReportingSvc := newUsageReportingService(cfg, m, connectionsService)
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)
}
}
if opts := cfg.Options(); opts.RestartOnWakeup {
go standbyMonitor()
}
@@ -858,9 +925,10 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
}
}
code := <-stop
code := exit.waitForExit()
mainService.Stop()
ldb.Close()
l.Infoln("Exiting")
@@ -879,7 +947,7 @@ func setupSignalHandling() {
signal.Notify(restartSign, sigHup)
go func() {
<-restartSign
stop <- exitRestarting
exit.Restart()
}()
// Exit with "success" code (no restart) on INT/TERM
@@ -889,45 +957,57 @@ func setupSignalHandling() {
signal.Notify(stopSign, os.Interrupt, sigTerm)
go func() {
<-stopSign
stop <- exitSuccess
exit.Shutdown()
}()
}
func loadOrDefaultConfig() (*config.Wrapper, error) {
func loadOrDefaultConfig() (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, err := config.Load(cfgFile, myID)
if err != nil {
cfg = defaultConfig(cfgFile)
cfg, err = defaultConfig(cfgFile)
}
return cfg, err
}
func loadConfigAtStartup() *config.Wrapper {
func loadConfigAtStartup(allowNewerConfig bool) (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, err := config.Load(cfgFile, myID)
if os.IsNotExist(err) {
cfg = defaultConfig(cfgFile)
cfg.Save()
l.Infof("Default config saved. Edit %s to taste or use the GUI\n", cfg.ConfigPath())
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 {
l.Fatalln("Failed to load config: unexpected end of file. Truncated or empty configuration?")
return nil, errors.New("Failed to load config: unexpected end of file. Truncated or empty configuration?")
} else if err != nil {
l.Fatalln("Failed to load config:", err)
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 {
l.Fatalln("Config archive:", err)
return nil, errors.Wrap(err, "config archive")
}
}
return cfg
return cfg, nil
}
func archiveAndSaveConfig(cfg *config.Wrapper) error {
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)
@@ -976,7 +1056,8 @@ func startAuditing(mainService *suture.Supervisor, auditFile string) {
}
fd, err = os.OpenFile(auditFile, auditFlags, 0600)
if err != nil {
l.Fatalln("Audit:", err)
l.Warnln("Audit:", err)
os.Exit(exitError)
}
auditDest = auditFile
}
@@ -991,7 +1072,7 @@ func startAuditing(mainService *suture.Supervisor, auditFile string) {
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, errors, systemLog logger.Recorder, runtimeOptions RuntimeOptions) {
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 {
@@ -1005,50 +1086,49 @@ func setupGUI(mainService *suture.Supervisor, cfg *config.Wrapper, m *model.Mode
cpu := newCPUService()
mainService.Add(cpu)
api := newAPIService(myID, cfg, locations.Get(locations.HTTPSCertFile), locations.Get(locations.HTTPSKeyFile), runtimeOptions.assetDir, m, defaultSub, diskSub, discoverer, connectionsService, errors, systemLog, cpu)
cfg.Subscribe(api)
mainService.Add(api)
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.
<-api.startedOnce
go func() { _ = openURL(guiCfg.URL()) }()
}
}
func defaultConfig(cfgFile string) *config.Wrapper {
newCfg := config.NewWithFreePorts(myID)
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)
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)
return config.Wrap(cfgFile, newCfg), nil
}
func resetDB() error {
return os.RemoveAll(locations.Get(locations.Database))
}
func restart() {
l.Infoln("Restarting")
stop <- exitRestarting
}
func shutdown() {
l.Infoln("Shutting down")
stop <- exitSuccess
}
func ensureDir(dir string, mode fs.FileMode) {
func ensureDir(dir string, mode fs.FileMode) error {
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
err := fs.MkdirAll(".", mode)
if err != nil {
l.Fatalln(err)
return err
}
if fi, err := fs.Stat("."); err == nil {
@@ -1064,6 +1144,7 @@ func ensureDir(dir string, mode fs.FileMode) {
}
}
}
return nil
}
func standbyMonitor() {
@@ -1079,14 +1160,14 @@ func standbyMonitor() {
// things a moment to stabilize.
time.Sleep(restartDelay)
restart()
exit.Restart()
return
}
now = time.Now()
}
}
func autoUpgrade(cfg *config.Wrapper) {
func autoUpgrade(cfg config.Wrapper) {
timer := time.NewTimer(0)
sub := events.Default.Subscribe(events.DeviceConnected)
for {
@@ -1137,7 +1218,7 @@ func autoUpgrade(cfg *config.Wrapper) {
events.Default.Unsubscribe(sub)
l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
time.Sleep(time.Minute)
stop <- exitUpgrading
exit.ExitUpgrading()
return
}
}
@@ -1188,7 +1269,7 @@ 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 {
func checkShortIDs(cfg config.Wrapper) error {
exists := make(map[protocol.ShortID]protocol.DeviceID)
for deviceID := range cfg.Devices() {
shortID := deviceID.Short()
@@ -1210,7 +1291,7 @@ func showPaths(options RuntimeOptions) {
fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations.Get(locations.DefFolder))
}
func setPauseState(cfg *config.Wrapper, paused bool) {
func setPauseState(cfg config.Wrapper, paused bool) {
raw := cfg.RawCopy()
for i := range raw.Devices {
raw.Devices[i].Paused = paused
@@ -1219,6 +1300,7 @@ func setPauseState(cfg *config.Wrapper, paused bool) {
raw.Folders[i].Paused = paused
}
if _, err := cfg.Replace(raw); err != nil {
l.Fatalln("Cannot adjust paused state:", err)
l.Warnln("Cannot adjust paused state:", err)
os.Exit(exitError)
}
}

View File

@@ -85,18 +85,18 @@ func monitorMain(runtimeOptions RuntimeOptions) {
stderr, err := cmd.StderrPipe()
if err != nil {
l.Fatalln("stderr:", err)
panic(err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
l.Fatalln("stdout:", err)
panic(err)
}
l.Infoln("Starting syncthing")
err = cmd.Start()
if err != nil {
l.Fatalln(err)
panic(err)
}
stdoutMut.Lock()

View File

@@ -1,7 +1,7 @@
[Desktop Entry]
Name=Syncthing Web UI
GenericName=File synchronization UI
Comment="Opens Syncthing's Web UI in the default browser (Syncthing must already be started)."
Comment=Opens Syncthing's Web UI in the default browser (Syncthing must already be started).
Exec=/usr/bin/syncthing -browser-only
Icon=syncthing
Terminal=false

11
go.mod
View File

@@ -11,18 +11,18 @@ require (
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/gogo/protobuf v1.2.1
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/kr/pretty v0.1.0 // indirect
github.com/lib/pq v1.0.0
github.com/mattn/go-isatty v0.0.4
github.com/lib/pq v1.1.1
github.com/mattn/go-isatty v0.0.7
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/geoip2-golang v1.3.0
github.com/oschwald/maxminddb-golang v0.0.0-20170901134056-26fe5ace1c70 // indirect
github.com/petermattis/goid v0.0.0-20170816195418-3db12ebb2a59 // indirect
github.com/pkg/errors v0.8.1
@@ -36,9 +36,8 @@ require (
github.com/thejerf/suture v3.0.2+incompatible
github.com/urfave/cli v1.20.0
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
golang.org/x/crypto v0.0.0-20171231215028-0fcca4842a8d
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06 // indirect
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

17
go.sum
View File

@@ -22,6 +22,8 @@ github.com/gobwas/glob v0.0.0-20170212200151-51eb1ee00b6d h1:IngNQgbqr5ZOU0exk39
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/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
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/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
@@ -32,6 +34,8 @@ github.com/jackpal/gateway v0.0.0-20161225004348-5795ac81146e h1:lS8IitpqG4RkZbE
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/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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=
@@ -39,8 +43,12 @@ 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/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/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/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/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=
@@ -51,6 +59,8 @@ github.com/onsi/gomega v0.0.0-20171227184521-ba3724c94e4d h1:r351oUAFgdsydkt/g+X
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/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 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=
@@ -85,6 +95,8 @@ github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 h1:okhMind4q9H1OxF44gN
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-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/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
@@ -92,10 +104,15 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
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-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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/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=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=

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;

View File

@@ -56,6 +56,7 @@
"Copied from original": "Копиран от оригинала",
"Copyright © 2014-2016 the following Contributors:": "Всички правата запазени © 2014-2016 Сътрудници:",
"Copyright © 2014-2017 the following Contributors:": "Всички правата запазени © 2014-2017. Сътрудници:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Създаване на шаблони за игнориране, презаписване на съществуващ файл в {{path}}.",
"Danger!": "Опасност!",
"Debugging Facilities": "Дебъг функционалност",
@@ -228,7 +229,7 @@
"Reduced by ignore patterns": "Намалено посредством шаблон за игнориране",
"Release Notes": "Бележки по обновяването",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Кандидат версиите съдържат най-новата функционалност и поправки. Те са близки до традиционните дву-седмични Synchthing обновления.",
"Remote Devices": "Чужди устройства",
"Remote Devices": "Устройства",
"Remove": "Премахни",
"Remove Device": "Премахване на устройство",
"Remove Folder": "Премахване на папка",
@@ -294,13 +295,14 @@
"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 не е включен, или има проблем с връзката с Интернет. Повторен опит...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing има проблем при обработването на заявката. Моля, презаредете браузъра или рестартирайте Syncthing ако проблемът продължи.",
"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.",
"The Syncthing admin interface is configured to allow remote access without a password.": "Администраторския панел на Syncthing е разрешава дистанционен достъп без да изисква парола.",
"The Syncthing admin interface is configured to allow remote access without a password.": "Администраторският панел на Syncthing разрешава дистанционен достъп без да изисква парола.",
"The aggregated statistics are publicly available at the URL below.": "Обобщение на събраните статистически ще намерите на долния URL адрес.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Конфигурацията е запазена, но не е активирана. Syncthing трябва да рестартира, за да се активира новата конфигурация.",
"The device ID cannot be blank.": "Полето идентификатор на устройство не може да бъде празно.",
@@ -349,6 +351,9 @@
"Uptime": "Работи от",
"Usage reporting is always enabled for candidate releases.": "Докладът за ползването е винаги включен за кандидат нови версии.",
"Use HTTPS for GUI": "Използвай 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 (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "Версия",
"Versions": "Версии",
"Versions Path": "Път до версиите",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Предупреждение: Ако използвате външна програма за наблюдение като {{syncthingInotify}}, трябва да я деактивирате.",
"Watch for Changes": "Мониторинг за промени",
"Watching for Changes": "Мониторинг за промени",
"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.": "Когато добавяте нов идентификатор на папка имайте предвид, че той се използва за свързване на папките между отделните устройства. Идентификатора разграничава главни/малки букви.",
"Yes": "Да",

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,12 +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 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",
@@ -74,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",
@@ -97,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",
@@ -143,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",
@@ -159,14 +160,14 @@
"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.",
@@ -208,7 +209,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:",
@@ -252,7 +253,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",
@@ -289,17 +290,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ó.",
@@ -313,7 +315,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).",
@@ -336,7 +338,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",
@@ -349,11 +351,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.": "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}}\".",
@@ -361,15 +366,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.": "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

@@ -51,11 +51,12 @@
"Connection Error": "Chyba připojení",
"Connection Type": "Typ připojení",
"Connections": "Připojení",
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Syncthing nyní umožňuje nepřetržité sledování změn. To zachytí změny na disku na spustí sken pouze pro změněné cesty. Výhody jsou rychlejší propagace změn a méně plných skenů.",
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Syncthing nyní umožňuje nepřetržité sledování změn. To zachytí změny na disku a spustí sken pouze pro změněné cesty. Výhody jsou rychlejší propagace změn a méně plných skenů.",
"Copied from elsewhere": "Zkopírováno odjinud",
"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 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í",
@@ -294,6 +295,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 is Free and Open Source Software licensed as 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...",
@@ -349,6 +351,9 @@
"Uptime": "Celkový čas běhu",
"Usage reporting is always enabled for candidate releases.": "Hlášení o používání je pro kandidáty na vydání vždy zapnuto.",
"Use HTTPS for GUI": "Použít HTTPS pro grafické rozhraní",
"Use notifications from the filesystem to detect changed items.": "Použít oznamování soubor. systému pro nalezení změněných položek.",
"Variable Size Blocks": "Bloky variabilní velikosti",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Bloky variabilní velikosti (také \"velké bloky\") jsou účinnější pro velké soubory.",
"Version": "Verze",
"Versions": "Verze",
"Versions Path": "Cesta k verzím",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Pozor: Pokud používáte externí sledování změn jako {{syncthingInotify}}, měly byste se ujistit, že je toto sledování vypnuto.",
"Watch for Changes": "Sledovat změny",
"Watching for Changes": "Sledování změn",
"Watching for changes discovers most changes without periodic scanning.": "Sledování změn odhalí většinu změn bez periodického skenování.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Při přidávání nového zařízení mějte na paměti, že je ho třeba také zadat na druhé straně.",
"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.": "Při přidávání nového adresáře mějte na paměti, že jeho ID je použito ke svázání adresářů napříč zařízeními. Rozlišují se malá a velká písmena a musí přesně souhlasit mezi všemi zařízeními.",
"Yes": "Ano",

View File

@@ -56,12 +56,13 @@
"Copied from original": "Kopieret fra originalen",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 de følgende bidragsydere:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 de følgende bidragsydere:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 de følgende bidragsydere:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Opretter ignoreringsmønstre; overskriver en eksisterende fil på {{path}}.",
"Danger!": "Fare!",
"Debugging Facilities": "Faciliteter til fejlretning",
"Default Folder Path": "Standardmappesti",
"Deleted": "Slettet",
"Deselect All": "Deselect All",
"Deselect All": "Fravælg alle",
"Device": "Enhed",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Enheden “{{name}}” ({{device}} på {{address}}) vil gerne forbinde. Tilføj denne enhed?",
"Device ID": "Enheds-ID",
@@ -74,11 +75,11 @@
"Disabled periodic scanning and disabled watching for changes": "Deaktiverede periodisk skanning og deaktiverede overvågning af ændringer",
"Disabled periodic scanning and enabled watching for changes": "Deaktiverede periodisk skanning og aktiverede overvågning af ændringer",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Deaktiverede periodisk skanning fra og lykkedes ikke med at opsætte overvågning af ændringer; prøver igen hvert minut:",
"Discard": "Discard",
"Discard": "Behold ikke",
"Disconnected": "Ikke tilsluttet",
"Discovered": "Opdaget",
"Discovery": "Opslag",
"Discovery Failures": "Opdagelses Fejl ",
"Discovery Failures": "Fejl ved opdagelse",
"Do not restore": "Genskab ikke",
"Do not restore all": "Genskab ikke alle",
"Do you want to enable watching for changes for all your folders?": "Vil du aktivere løbende overvågning af ændringer for alle dine mapper?",
@@ -97,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.": "Indtast et ikke-negativt tal (fx “2,35”) og vælg en enhed. Procentsatser er ud fra total diskstørrelse.",
"Enter a non-privileged port number (1024 - 65535).": "Indtast et ikke-priviligeret portnummer (102465535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Angiv kommaseparerede adresser (“tcp://ip:port”, “tcp://host:port”) eller “dynamic” for at benytte automatisk opdagelse af adressen.",
"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.": "Angiv en kommaadskilt adresseliste (\"tcp://ip:port\", \"tcp://host:port\")  eller \"dynamic\" for automatisk at opdage adressen.",
"Enter ignore patterns, one per line.": "Indtast ignoreringsmønstre, ét per linje.",
"Error": "Fejl",
"External File Versioning": "Ekstern filversionering",
@@ -143,9 +144,9 @@
"Ignore": "Ignorér",
"Ignore Patterns": "Ignoreringsmønstre",
"Ignore Permissions": "Ignorér rettigheder",
"Ignored Devices": "Ignored Devices",
"Ignored Folders": "Ignored Folders",
"Ignored at": "Ignored at",
"Ignored Devices": "Ignorerede enheder",
"Ignored Folders": "Ignorerede mapper",
"Ignored at": "Ignoreret på",
"Incoming Rate Limit (KiB/s)": "Indgående hastighedsbegrænsning (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Ukorrekt opsætning kan skade dine data og gøre Syncthing ude af stand til at fungere.",
"Introduced By": "Introduceret af",
@@ -159,14 +160,14 @@
"Later": "Senere",
"Latest Change": "Seneste ændring",
"Learn more": "Lær mere",
"Limit": "Limit",
"Limit": "Grænse",
"Listeners": "Lyttere",
"Loading data...": "Indlæser data",
"Loading...": "Indlæser",
"Loading data...": "Indlæser data ...",
"Loading...": "Indlæser ...",
"Local Discovery": "Lokal opslag",
"Local State": "Lokal tilstand",
"Local State (Total)": "Lokal tilstand (total)",
"Locally Changed Items": "Locally Changed Items",
"Locally Changed Items": "Lokalt ændrede filer",
"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.",
@@ -208,7 +209,7 @@
"Pause": "Pause",
"Pause All": "Sæt alt på pause",
"Paused": "På pause",
"Pending changes": "Pending changes",
"Pending changes": "Ventende ændringer",
"Periodic scanning at given interval and disabled watching for changes": "Periodisk skanning med et givent interval og deaktiveret overvågning af ændringer",
"Periodic scanning at given interval and enabled watching for changes": "Periodisk skanning med et givent interval og aktiveret overvågning af ændringer",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodisk skanning med et givent interval og lykkedes ikke med at opsætte overvågning af ændringer; prøver igen hvert minut:",
@@ -252,7 +253,7 @@
"Scanning": "Skanner",
"See external versioner help for supported templated command line parameters.": "Se hjælp til ekstern versionering for understøttede kommandolinjeparametre.",
"See external versioning help for supported templated command line parameters.": "Se hjælp til ekstern versionering for understøttede kommandolinjeparametre.",
"Select All": "Select All",
"Select All": "Vælg alle",
"Select a version": "Vælg en version",
"Select latest version": "Vælg seneste version",
"Select oldest version": "Vælg ældste version",
@@ -289,16 +290,17 @@
"Statistics": "Statistikker",
"Stopped": "Stoppet",
"Support": "Støt",
"Support Bundle": "Support Bundle",
"Support Bundle": "Støttepakke",
"Sync Protocol Listen Addresses": "Lytteadresser for synkroniseringsprotokol",
"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…",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Det ser ud til, at Syncthing har problemer med at udføre opgaven. Prøv at genindlæse siden eller genstarte Synching, hvis problemet vedbliver.",
"Take me back": "Take me back",
"Take me back": "Tag mig tilbage",
"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.": "Syncthing-administationsfladen er sat op til at kunne fjernstyres uden adgangskode.",
"The aggregated statistics are publicly available at the URL below.": "Den indsamlede statistik er offentligt tilgængelig på den nedenstående URL.",
@@ -313,7 +315,7 @@
"The folder path cannot be blank.": "Mappestien må ikke være tom.",
"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 følgende intervaller er brugt: Inden for den første time bliver en version gemt hvert 30. sekund, inden for den første dag bliver en version gemt hver time, inden for de første 30 dage bliver en version gemt hver dag, og indtil den maksimale alder bliver en version gemt hver uge.",
"The following items could not be synchronized.": "Følgende filer kunne ikke synkroniseres.",
"The following items were changed locally.": "The following items were changed locally.",
"The following items were changed locally.": "De følgende filer er ændret lokalt.",
"The maximum age must be a number and cannot be blank.": "Maksimal alder skal være et tal og feltet må ikke være tomt.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Den maksimale tid, en version skal gemmes (i dage; sæt lig med 0 for at beholde gamle versioner for altid).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Procentsatsen for mindst ledig diskplads skal være et ikke-negativt tal mellem 0 og 100 (inklusive).",
@@ -336,40 +338,44 @@
"Unavailable": "Ikke tilgængelig",
"Unavailable/Disabled by administrator or maintainer": "Ikke tilgængelig / deaktiveret af administrator eller vedligeholder",
"Undecided (will prompt)": "Ubestemt (du bliver spurgt)",
"Unignore": "Unignore",
"Unignore": "Fjern ignorering",
"Unknown": "Ukendt",
"Unshared": "Ikke delt",
"Unused": "Ubrugt",
"Up to Date": "Fuldt opdateret",
"Updated": "Opdateret",
"Upgrade": "Upgradér",
"Upgrade": "Opgradér",
"Upgrade To {%version%}": "Opgradér til {{version}}",
"Upgrading": "Opgraderer",
"Upload Rate": "Uploadhastighed",
"Uptime": "Oppetid",
"Usage reporting is always enabled for candidate releases.": "Forbrugsraportering er altid aktiveret for udgivelseskandidater.",
"Use HTTPS for GUI": "Anvend HTTPS til GUI-adgang",
"Use notifications from the filesystem to detect changed items.": "Benyt notifikationer fra filsystemet til at finde filændringer.",
"Variable Size Blocks": "Skiftende blokstørrelse",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Skiftende blokstørrelse (også \"store blokke\") er mere effektivt for større filer.",
"Version": "Version",
"Versions": "Versioner",
"Versions Path": "Versionssti",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versioner slettes automatisk, hvis de er ældre end den givne maksimum alder eller overstiger det tilladte antal filer i et interval.",
"Waiting to scan": "Waiting to scan",
"Waiting to scan": "Venter på at skanne",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Advarsel: Denne sti er en forældermappe til den eksisterende mappe “{{otherFolder}}”.",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advarsel: Denne sti er en forældermappe til den eksisterende mappe “{{otherFolderLabel}}” ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Advarsel: Denne sti er en undermappe til den eksisterende mappe “{{otherFolder}}”.",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advarsel: Denne sti er en undermappe til den eksisterende mappe “{{otherFolderLabel}}” ({{otherFolder}}).",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Advarsel: Hvis du bruger en ekstern overvågning så som {{syncthingInotify}}, bør du være sikker på, at den er deaktiveret.",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Advarsel: Hvis du bruger en ekstern overvågning såsom {{syncthingInotify}}, bør du være sikker på, at den er deaktiveret.",
"Watch for Changes": "Overvåg ændringer",
"Watching for Changes": "Overvågning af ændringer",
"Watching for changes discovers most changes without periodic scanning.": "Overvågning af ændringer finder ændringer uden at skanne fra tid til anden.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Når der tilføjes en ny enhed, vær da opmærksom på, at denne enhed også skal tilføjes i den anden ende.",
"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.": "Når der tilføjes en ny enhed, vær da opmærksom på at samme mappe-ID bruges til at forbinde mapper på de forskellige enheder. Der er forskel på store og små bogstaver, og ID skal være fuldstændig identisk på alle enheder.",
"Yes": "Ja",
"You can also select one of these nearby devices:": "Du kan også vælge en af disse enheder i nærheden:",
"You can change your choice at any time in the Settings dialog.": "Du kan altid ændre dit valg under indstillinger.",
"You can read more about the two release channels at the link below.": "Du kan læse mere om de to udgivelseskanaler på linket herunder.",
"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.": "Du har ingen ignorerede enheder.",
"You have no ignored folders.": "Du har ingen ignorerede mapper.",
"You have unsaved changes. Do you really want to discard them?": "Du har ændringer, som ikke er gemt. Er du sikker på, at du ikke vil beholde dem?",
"You must keep at least one version.": "Du skal beholde mindst én version.",
"days": "dage",
"directories": "mapper",

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,6 +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 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",
@@ -294,6 +295,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...",
@@ -349,6 +351,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.": "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",
@@ -361,6 +366,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.": "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

@@ -56,6 +56,7 @@
"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:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Δημιουργία προτύπων αγνόησης, αντικατάσταση του υπάρχοντος αρχείου στο {{path}}.",
"Danger!": "Προσοχή!",
"Debugging Facilities": "Εργαλεία αποσφαλμάτωσης",
@@ -294,6 +295,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 φαίνεται πως είναι απενεργοποιημένο ή υπάρχει πρόβλημα στη σύνδεσή σου στο διαδίκτυο. Προσπαθώ πάλι…",
@@ -349,6 +351,9 @@
"Uptime": "Χρόνος απρόσκοπτης λειτουργίας",
"Usage reporting is always enabled for candidate releases.": "Η αποστολή αναφορών χρήσης είναι πάντα ενεργοποιημένη στις υποψήφιες εκδόσεις.",
"Use HTTPS for GUI": "Χρήση 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 (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "Έκδοση",
"Versions": "Εκδόσεις",
"Versions Path": "Φάκελος τήρησης εκδόσεων",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Προσοχή: αν χρησιμοποιείτε ένα εξωτερικό εργαλείο επιτήρησης, όπως το {{syncthingInotify}}, σιγουρευτείτε ότι έχει απενεργοποιηθεί.",
"Watch for Changes": "Επιτήρηση αλλαγών",
"Watching for Changes": "Εκτελείται η επιτήρηση αλλαγών",
"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.": "Όταν προσθέτεις έναν νέο φάκελο, θυμήσου πως η ταυτότητα ενός φακέλου χρησιμοποιείται για να να συσχετίσει φακέλους μεταξύ συσκευών. Η ταυτότητα του φακέλου θα πρέπει να είναι η ίδια σε όλες τις συσκευές και έχουν σημασία τα πεζά ή κεφαλαία γράμματα.",
"Yes": "Ναι",

View File

@@ -56,6 +56,7 @@
"Copied from original": "Copied from original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 the following Contributors:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creating ignore patterns, overwriting an existing file at {{path}}.",
"Danger!": "Danger!",
"Debugging Facilities": "Debugging Facilities",
@@ -294,6 +295,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…",
@@ -349,6 +351,9 @@
"Uptime": "Uptime",
"Usage reporting is always enabled for candidate releases.": "Usage reporting is always enabled for candidate releases.",
"Use HTTPS for GUI": "Use HTTPS for 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.",
"Version": "Version",
"Versions": "Versions",
"Versions Path": "Versions Path",
@@ -361,6 +366,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": "Watch for Changes",
"Watching for Changes": "Watching for Changes",
"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.",
"Yes": "Yes",

View File

@@ -56,6 +56,7 @@
"Copied from original": "Copied from original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 the following Contributors:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creating ignore patterns, overwriting an existing file at {{path}}.",
"Danger!": "Danger!",
"Debugging Facilities": "Debugging Facilities",
@@ -170,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",
@@ -294,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

@@ -0,0 +1,387 @@
{
"A device with that ID is already added.": "Aparato kun samtia ID estis jam aldonita.",
"A negative number of days doesn't make sense.": "Negativa numero de tagoj ne havas sencon.",
"A new major version may not be compatible with previous versions.": "Nova ĉefa versio eble ne kongruanta kun antaŭaj versioj.",
"API Key": "API Ŝlosilo",
"About": "Pri",
"Action": "Ago",
"Actions": "Agoj",
"Add": "Aldoni",
"Add Device": "Aldoni Aparaton",
"Add Folder": "Aldoni Dosierujon",
"Add Remote Device": "Aldoni Foran Aparaton",
"Add devices from the introducer to our device list, for mutually shared folders.": "Aldoni aparatojn de la enkondukanto ĝis nia aparatlisto, por reciproke komunigitaj dosierujoj.",
"Add new folder?": "Aldoni novan dosierujon?",
"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.": "Aldone, plena reskana intervalo estos pliigita (60-oble, t.e. nova defaŭlto estas 1h). Vi povas ankaŭ agordi ĝin permane por ĉiu dosierujo poste post elekto de Ne.",
"Address": "Adreso",
"Addresses": "Adresoj",
"Advanced": "Altnivela",
"Advanced Configuration": "Altnivela Agordo",
"Advanced settings": "Altnivelaj agordoj",
"All Data": "Ĉiuj Datumoj",
"Allow Anonymous Usage Reporting?": "Permesi Anoniman Raporton de Uzado?",
"Allowed Networks": "Permesitaj Retoj",
"Alphabetic": "Alfabeta",
"An external command handles the versioning. It has to remove the file from the shared folder.": "Ekstera komando manipulas la version. Ĝi devas forigi la dosieron el la komunigita dosierujo.",
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Ekstera komando manipulas la version. Ĝi devas forigi la dosieron el la komunigita dosierujo. Se la vojo al la apliko elhavas blankoj, ĝi devas esti inter citiloj.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Ekstera komando manipulas la version. Ĝi devas forigi la dosieron el la sinkronigita dosierujo.",
"Anonymous Usage Reporting": "Anonima Raporto de Uzado",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Formato de anonima raporto de uzado ŝanĝis. Ĉu vi ŝatus transiri al la nova formato?",
"Any devices configured on an introducer device will be added to this device as well.": "Ajnaj aparatoj agorditaj sur enkondukanta aparato estos ankaŭ aldonita al ĉi tiu aparato.",
"Are you sure you want to remove device {%name%}?": "Ĉu vi certas, ke vi volas forigi aparaton {{name}}?",
"Are you sure you want to remove folder {%label%}?": "Ĉu vi certas, ke vi volas forigi dosierujon {{label}}?",
"Are you sure you want to restore {%count%} files?": "Ĉu vi certas, ke vi volas restarigi {{count}} dosierojn?",
"Auto Accept": "Akcepti Aŭtomate",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Aŭtomata ĝisdatigo nun proponas la elekton inter stabilaj eldonoj kaj kandidataj eldonoj.",
"Automatic upgrades": "Aŭtomataj ĝisdatigoj",
"Automatic upgrades are always enabled for candidate releases.": "Aŭtomataj ĝisdatigoj ĉiam ŝaltitaj por kandidataj eldonoj.",
"Automatically create or share folders that this device advertises at the default path.": "Aŭtomate krei aŭ komunigi dosierujojn, kiujn ĉi tiu aparato anoncas, ĉe la defaŭlta vojo.",
"Available debug logging facilities:": "Disponeblaj elpurigadaj protokoliloj:",
"Be careful!": "Atentu!",
"Bugs": "Cimoj",
"CPU Utilization": "Ĉefprocesoro Uzo",
"Changelog": "Ŝanĝoprotokolo",
"Clean out after": "Purigi poste",
"Click to see discovery failures": "Alklaku por vidi malsukcesajn malkovrojn",
"Close": "Fermi",
"Command": "Komando",
"Comment, when used at the start of a line": "Komento, kiam uzita ĉe la komenco de lineo",
"Compression": "Densigo",
"Configured": "Agordita",
"Connection Error": "Eraro de Konekto",
"Connection Type": "Tipo de Konekto",
"Connections": "Konektoj",
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Daŭra rigardado je ŝanĝoj estas nun havebla ene Syncthing. Ĉi tio detektos ŝangoj sur disko kaj skanos nur modifitajn vojojn. La avantaĝo estas en pli rapifa propagiĝo de ŝanĝoj kaj bezono je malpli plenaj skanoj.",
"Copied from elsewhere": "Kopiita el aliloke",
"Copied from original": "Kopiita el la originalo",
"Copyright © 2014-2016 the following Contributors:": "Kopirajto © 2014-2016 por la sekvantaj Kontribuantoj:",
"Copyright © 2014-2017 the following Contributors:": "Kopirajto © 2014-2017 por la sekvantaj Kontribuantoj:",
"Copyright © 2014-2019 the following Contributors:": "Kopirajto © 2014-2019 por la sekvantaj Kontribuantoj:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Kreante ignorantajn ŝablonojn, anstataŭige ekzistantan dosieron ĉe {{path}}.",
"Danger!": "Danĝero!",
"Debugging Facilities": "Elpurigadiloj",
"Default Folder Path": "Defaŭlta Dosieruja Vojo",
"Deleted": "Forigita",
"Deselect All": "Malelekti Ĉiujn",
"Device": "Aparato",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Aparato \"{{name}}\" ({{device}} ĉe {{address}}) volas konekti. Aldoni la novan aparaton?",
"Device ID": "Aparato ID",
"Device Identification": "Identigo de Aparato",
"Device Name": "Nomo de Aparato",
"Device rate limits": "Limoj de rapideco de aparato",
"Device that last modified the item": "Aparato kiu laste modifis la eron",
"Devices": "Aparatoj",
"Disabled": "Malebligita",
"Disabled periodic scanning and disabled watching for changes": "Malebligita perioda skanado kaj malebligita rigardado je ŝanĝoj",
"Disabled periodic scanning and enabled watching for changes": "Malebligita perioda skanado kaj ebligita rigardado je ŝanĝoj",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Malebligita perioda skanado kaj malsukcesis agordi rigardadon je ŝanĝoj. Provante denove ĉiuminute:",
"Discard": "Forĵeti",
"Disconnected": "Malkonektita",
"Discovered": "Malkovrita",
"Discovery": "Malkovro",
"Discovery Failures": "Malsukcesoj de Malkovro",
"Do not restore": "Ne restarigu",
"Do not restore all": "Ne restarigu ĉion",
"Do you want to enable watching for changes for all your folders?": "Ĉu vi volas ebligi rigardado je ŝanĝoj por ĉiuj viaj dosierujoj?",
"Documentation": "Dokumentado",
"Download Rate": "Elŝutrapideco",
"Downloaded": "Elŝutita",
"Downloading": "Elŝutado",
"Edit": "Redakti",
"Edit Device": "Redakti Aparaton",
"Edit Folder": "Redakti Dosierujon",
"Editing": "Redaktado",
"Editing {%path%}.": "Redaktado de {{path}}.",
"Enable NAT traversal": "Ŝaltu trairan NAT",
"Enable Relaying": "Ŝaltu Relajsadon",
"Enabled": "Ebligita",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Enigu ne negativan nombron (ekz. \"2.35\") kaj elektu uniton. Procentoj estas kiel parto de tuta grandeco de disko.",
"Enter a non-privileged port number (1024 - 65535).": "Enigu ne privilegiitan numeron de pordo (1024- 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enigu adresojn dividitajn per komoj (\"tcp://ip:port\", \"tcp://host:port\") aŭ \"dynamic\" por elfari aŭtomatan malkovradon de la adreso.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Enigu adresojn dividitajn per komoj (\"tcp://ip:port\", \"tcp://host:port\") aŭ \"dynamic\" por elfari aŭtomatan malkovradon de la adreso.",
"Enter ignore patterns, one per line.": "Enigu ignorantajn ŝablonojn, unu po linio.",
"Error": "Eraro",
"External File Versioning": "Ekstera Versionado de Dosiero",
"Failed Items": "Malsukcesaj Eroj",
"Failed to load ignore patterns": "Malsukcesis ŝarĝi ignorantajn ŝablonojn",
"Failed to setup, retrying": "Malsukcesis agordi, provante denove",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Malsukceso por konekti al IPv6 serviloj atendante se ekzistas neniu IPv6 konektebleco.",
"File Pull Order": "Ordo por Tiri Dosieron",
"File Versioning": "Versionado de Dosieroj",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Permesoj bitaj de dosieroj estas ignorita dum la serĉado por ŝanĝoj. Uzi en FAT dosiersistemoj.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Dosieroj estas movigitaj al .stversions dosierujo kiam anstataŭigitaj aŭ forigitaj en Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Dosieroj estas movigitaj al .stversions dosierujo kiam anstataŭigitaj aŭ forigitaj en Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Dosieroj estas movigitaj al date stampitaj versioj en .stversions dosierujo kiam ili estas anstataŭigitaj aŭ forigitaj en Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Dosieroj estas movigitaj al datostampitaj versioj en .stversions dosierujo kiam ili estas anstataŭigitaj aŭ forigitaj en Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Dosieroj estas protektataj kontraŭ ŝanĝoj faritaj en aliaj aparatoj, sed ŝanĝoj faritaj en ĉi tiu aparato estos senditaj al cetera parto de la grupo.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Dosieroj estas sinkronigitaj de la grupo, sed ajnaj ŝanĝoj faritaj loke ne estis senditaj al aliaj aparatoj.",
"Filesystem Notifications": "Dosiersistemaj Sciigoj",
"Filesystem Watcher Errors": "Eraroj de Rigardanto de Dosiersistemo",
"Filter by date": "Filtri per daton",
"Filter by name": "Filtri per nomon",
"Folder": "Dosierujo",
"Folder ID": "Dosieruja ID",
"Folder Label": "Dosieruja Etikedo",
"Folder Path": "Dosieruja Vojo",
"Folder Type": "Dosieruja Tipo",
"Folders": "Dosierujoj",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "Por la sekvantaj dosierujoj eraro okazis dum komencado de rigardado je ŝanĝoj. Provante denove ĉiuminute, do eraroj eble foriros baldaŭ. Se ili persistas, provu ripari subkuŝantan problemon kaj petu helpon, se vi ne povas.",
"Full Rescan Interval (s)": "Plena Reskana Intervalo (s)",
"GUI": "Grafika Interfaco",
"GUI Authentication Password": "Pasvorta Aŭtentigo en Grafika Interfaco",
"GUI Authentication User": "Uzanta Aŭtentigo en Grafika Interfaco",
"GUI Listen Address": "Adreso de Aŭskultado en Grafika Interfaco",
"GUI Listen Addresses": "Adresoj de Aŭskultado en Grafika Interfaco",
"GUI Theme": "Etoso de Grafika Interfaco",
"General": "Ĝenerala",
"Generate": "Generi",
"Global Changes": "Mallokaj Ŝanĝoj",
"Global Discovery": "Malloka Malkovro",
"Global Discovery Servers": "Serviloj de Malloka Malkovro",
"Global State": "Malloka Stato",
"Help": "Helpo",
"Home page": "Hejma paĝo",
"Ignore": "Ignoru",
"Ignore Patterns": "Ignorantaj Ŝablonoj",
"Ignore Permissions": "Ignori Permesojn",
"Ignored Devices": "Ignoritaj Aparatoj",
"Ignored Folders": "Ignoritaj Dosierujoj",
"Ignored at": "Ignorita ĉe",
"Incoming Rate Limit (KiB/s)": "Alvenanta Rapideco Limo (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Erara agordo povas difekti viajn dosierujajn enhavojn kaj senefikigi Syncthing-n.",
"Introduced By": "Enkondukita Per",
"Introducer": "Enkondukanto",
"Inversion of the given condition (i.e. do not exclude)": "Inversigo de la donita kondiĉo (t.e. ne ekskludi)",
"Keep Versions": "Konservi Versiojn",
"Largest First": "Plej Granda Unue",
"Last File Received": "Lasta Dosiero Ricevita",
"Last Scan": "Lasta Skano",
"Last seen": "Lasta vidita",
"Later": "Poste",
"Latest Change": "Lasta Ŝanĝo",
"Learn more": "Lerni pli",
"Limit": "Limo",
"Listeners": "Aŭskultantoj",
"Loading data...": "Ŝarĝas datumojn...",
"Loading...": "Ŝarĝas...",
"Local Discovery": "Loka Malkovro",
"Local State": "Loka Stato",
"Local State (Total)": "Loka Stato (Tuta)",
"Locally Changed Items": "Loke Ŝanĝitaj Eroj",
"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.",
"Logs": "Protokoloj",
"Major Upgrade": "Ĉefa Ĝisdatigo",
"Mass actions": "Amasa agoj",
"Master": "Ĉefa",
"Maximum Age": "Maksimuma Aĝo",
"Metadata Only": "Nur Metadatumoj",
"Minimum Free Disk Space": "Minimuma Libera Diskospaco",
"Mod. Device": "Mod. Aparato",
"Mod. Time": "Mod. Tempo",
"Move to top of queue": "Movi al la supro de atendovico",
"Multi level wildcard (matches multiple directory levels)": "Multnivela ĵokero (egalas multoblajn dosierujaj niveloj)",
"Never": "Neniam",
"New Device": "Nova Aparato",
"New Folder": "Nova Dosierujo",
"Newest First": "Plejnova Unue",
"No": "Ne",
"No File Versioning": "Sen Dosiera Versionado",
"No files will be deleted as a result of this operation.": "Neniuj dosieroj estos forigitaj rezulte de ĉi tiu ago.",
"No upgrades": "Sen ĝisdatigoj",
"Normal": "Normala",
"Notice": "Avizo",
"OK": "Bone",
"Off": "Malŝata",
"Oldest First": "Malnova Unue",
"Optional descriptive label for the folder. Can be different on each device.": "Laŭvola priskriba etikedo por la dosierujo. Povas esti malsama en ĉiu aparato.",
"Options": "Opcioj",
"Out of Sync": "Elsinkronigita",
"Out of Sync Items": "Elsinkronigitaj Eroj",
"Outgoing Rate Limit (KiB/s)": " Eliranta Rapideco Limo (KiB/s)",
"Override Changes": "Transpasi Ŝanĝojn",
"Path": "Vojo",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Vojo de la dosierujo en la loka komputilo. Kreiĝos se ne ekzistas. La tilda signo (~) povas esti uzata kiel mallongigilo por",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "La vojo, kie novaj aŭtomate akceptitaj dosierujoj estos kreita, kaj ankaŭ la defaŭlta sugestita vojo aldoninte novajn dosierujojn per uzinterfaco. Tildo (~) malvolvas al {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Vojo kies versioj devus esti stokitaj (lasu malplena por la defaŭlta .stversions dosierujo en la komunigita dosierujo).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Vojo kies vesioj estas konservitaj (lasi malplena por la defaŭlta .stversions dosierujo en la dosierujo).",
"Pause": "Paŭzu",
"Pause All": "Paŭzu Ĉion",
"Paused": "Paŭzita",
"Pending changes": "Pritraktataj ŝanĝoj",
"Periodic scanning at given interval and disabled watching for changes": "Perioda skanado ĉe donita intervalo kaj malebligita rigardado je ŝanĝoj",
"Periodic scanning at given interval and enabled watching for changes": "Perioda skanado ĉe donita intervalo kaj ebligita rigardado je ŝanĝoj",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Perioda skanado ĉe donita intervalo kaj malsukcesis agordi rigardadon je ŝanĝoj. Provante denove ĉiuminute:",
"Permissions": "Permesoj",
"Please consult the release notes before performing a major upgrade.": "Bonvolu konsulti la notojn de eldono antaŭ elfari ĉefan ĝisdatigon.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Bonvolu agordi GUI Authentication Uzanto kaj Pasvorto en la agordoj dialogo.",
"Please wait": "Bonvolu atendi",
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefikso indikanta, ke la dosiero povas esti forigita, se ĝi malhelpas forigi dosierujon",
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefikso indikanta, ke la ŝablono devus esti egalita usklecoblinde.",
"Preview": "Antaŭrigardo",
"Preview Usage Report": "Antaŭrigardo Uzada Raporto",
"Quick guide to supported patterns": "Rapida gvidilo pri subtenata ŝablonoj",
"RAM Utilization": "Labormemoro Uzo",
"Random": "Hazarda",
"Receive Only": "Nur Ricevi",
"Recent Changes": "Lastatempaj Ŝanĝoj",
"Reduced by ignore patterns": "Malpliigita per ignorantaj ŝablonoj",
"Release Notes": "Notoj de Eldono",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Kandidataj eldonoj enhavas la lastajn trajtojn kaj korektojn. Ili estas similaj al la tradiciaj dusemajnaj Syncthing eldonoj.",
"Remote Devices": "Foraj Aparatoj",
"Remove": "Forigu",
"Remove Device": "Forigi Aparaton",
"Remove Folder": "Forigi Dosierujon",
"Required identifier for the folder. Must be the same on all cluster devices.": "Nepra identigilo por la dosierujo. Devas esti la sama en ĉiuj aparatoj de la grupo.",
"Rescan": "Reskanu",
"Rescan All": "Reskanu Ĉion",
"Rescan Interval": "Reskana Intervalo",
"Rescans": "Reskanoj",
"Restart": "Restartu",
"Restart Needed": "Restarto Bezonata",
"Restarting": "Restartado",
"Restore": "Restarigi",
"Restore Versions": "Restarigi Versiojn",
"Resume": "Daŭrigu",
"Resume All": "Daŭrigu Ĉion",
"Reused": "Reuzita",
"Revert Local Changes": "Reverti Lokajn Ŝangojn",
"Running": "Kurante",
"Save": "Konservu",
"Scan Time Remaining": "Restanta Tempo de Skano",
"Scanning": "Skanado",
"See external versioner help for supported templated command line parameters.": "Vidu informlibron de ekstera versionilo por subtenata ŝablona parametroj de komandlinio.",
"See external versioning help for supported templated command line parameters.": "Vidu informlibron de ekstera versionado por subtenata ŝablona parametroj de komandlinio.",
"Select All": "Elekti Ĉiujn",
"Select a version": "Elekti version",
"Select latest version": "Elekti plej novan version",
"Select oldest version": "Elekti plej malnovan version",
"Select the devices to share this folder with.": "Elekti la aparatojn por komunigi ĉi tiun dosierujon.",
"Select the folders to share with this device.": "Elekti la dosierujojn por komunigi kun ĉi tiu aparato.",
"Send & Receive": "Sendi kaj Ricevi",
"Send Only": "Nur Sendi",
"Settings": "Agordoj",
"Share": "Komunigi",
"Share Folder": "Komunigu Dosierujon",
"Share Folders With Device": "Dosierujoj Komunigitaj Kun Aparato",
"Share With Devices": "Komunigu Kun Aparatoj",
"Share this folder?": "Komunigi ĉi tiun dosierujon?",
"Shared With": "Komunigita Kun",
"Sharing": "Komunigo",
"Show ID": "Montru ID",
"Show QR": "Montru QR",
"Show diff with previous version": "Montri diferenco kun antaŭa versio",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Montrita anstataŭ ID de Aparato en la statuso de la grupo. Estos anoncita al aliaj aparatoj kiel laŭvola defaŭlta nomo.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Montri anstataŭ ID de Aparato en la statuso de la grupo. Estos ĝisdatigita al la nomo de la aparato sciigante se ĝi estas lasita malplena.",
"Shutdown": "Sistemfermo",
"Shutdown Complete": "Sistemfermo Tuta",
"Simple File Versioning": "Simpla Versionado de Dosieroj",
"Single level wildcard (matches within a directory only)": "Ununivela ĵokero (egalas nur ene de dosierujo)",
"Size": "Grandeco",
"Smallest First": "Plej Malgranda Unue",
"Some items could not be restored:": "Iuj eroj ne povis esti restarigitaj:",
"Source Code": "Fontkodo",
"Stable releases and release candidates": "Stabilaj eldonoj kaj kandidataj eldonoj",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Stabilaj eldonoj prokrastas je ĉirkaŭ du semjanoj. Dum tiu tempo ili estos testataj kiel kandidataj eldonoj.",
"Stable releases only": "Nur stabilaj eldonoj",
"Staggered File Versioning": "Gradigita Dosiera Versionado",
"Start Browser": "Startu Retumilon",
"Statistics": "Statistikoj",
"Stopped": "Haltita",
"Support": "Subteno",
"Support Bundle": "Pakaĵo por subteno",
"Sync Protocol Listen Addresses": "Aŭskultado Adresoj de Sinkprotokolo",
"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...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing ŝajnas renkonti problemon kun la traktado de via peto. Bonvolu refreŝigi la paĝon aŭ restarti Syncthing se la problemo daŭras.",
"Take me back": "Prenu min reen",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "La adreso de grafika interfaco estas superregita per startigaj agordoj. Ŝanĝoj ĉi tie ne efektiviĝas dum la superrego estas aktuala.",
"The Syncthing admin interface is configured to allow remote access without a password.": "La administra interfaco de Syncthing estas agordita por permesi foran atingon sen pasvorto.",
"The aggregated statistics are publicly available at the URL below.": "La agregita statistikoj estas publike disponebla ĉe la URL malsupre.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La agordo estis registrita sed ne aktivigita. Syncthing devas restarti por aktivigi la novan agordon.",
"The device ID cannot be blank.": "La aparato ID ne povas esti malplena.",
"The device ID to enter here can be found in the \"Actions > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "La aparato ID por eniri ĉi tie estas trovebla per \"Agoj > Montru ID\" dialogo en la alia aparato. Interspacoj kaj streketoj estas opcio (ignorigita).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "La ĉifrita raporto de uzado estas sendata ĉiutage. Ĝi estas uzata por sekvi komunajn platformojn, dosierujajn grandojn kaj aplikaĵajn versiojn. Se la raporto datumaro ŝanĝis, vi estos avertata per ĉi tiu dialogo denove.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "La enigita aparato ID ne ŝajnas valida. Ĝi devas esti signoĉeno el 52 aŭ 56 karaktroj longa enhavanta leterojn kaj nombrojn, kun interspacoj kaj streketoj opciaj.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "La unua komandlinia parametro estas la vojo de la dosierujo kaj la dua parametro estas la relativa vojo en la dosierujo.",
"The folder ID cannot be blank.": "La dosierujo ID ne povas esti malplena.",
"The folder ID must be unique.": "La dosierujo ID devas esti unika.",
"The folder path cannot be blank.": "La vojo de dosierujo ne povas esti malplena.",
"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.": "La jenaj intervaloj estas uzataj: dum la unua horo version restas dum ĉiuj 30 sekundoj, dum la unua tago versio restas konservita dum ĉiu horo, dum la unuaj 30 tagoj versio estas konservita dum ĉiu tago, ĝis la maksimume aĝa versio restas konservita dum ĉiu semajno.",
"The following items could not be synchronized.": "La sekvantaj eroj ne povas esti sinkronigitaj.",
"The following items were changed locally.": "La sekvantaj eroj estis ŝanĝitaj loke.",
"The maximum age must be a number and cannot be blank.": "La maksimuma aĝo devas esti nombro kaj ne povas esti malplena.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "La maksimuma tempo por konservi version (en tagoj, agordi je 0 por konservi versiojn eterne).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "La minimuma procento de libera diskospaco devas esti pozitiva nombro inter 0 kaj 100 (inkluziva).",
"The number of days must be a number and cannot be blank.": "La nombro da tagoj devas esti nombro kaj ne povas esti malplena.",
"The number of days to keep files in the trash can. Zero means forever.": "La nombro da tagoj por konservi dosierojn en la rubujo. Nulo signifas eterne.",
"The number of old versions to keep, per file.": "La nombro da malnovaj versioj por konservi, po ĉiu dosiero.",
"The number of versions must be a number and cannot be blank.": "La nombro da versioj devas esti nombro kaj ne povas esti malplena.",
"The path cannot be blank.": "La vojo ne povas esti malplena.",
"The rate limit must be a non-negative number (0: no limit)": "La rapideca limo devas esti pozitiva nombro (0: senlimo)",
"The rescan interval must be a non-negative number of seconds.": "La intervalo de reskano devas esti pozitiva nombro da sekundoj.",
"They are retried automatically and will be synced when the error is resolved.": "Ili estas reprovitaj aŭtomate kaj estos sinkronigitaj kiam la eraro estas solvita.",
"This Device": "Ĉi Tiu Aparato",
"This can easily give hackers access to read and change any files on your computer.": "Ĉi tio povas facile doni al kodumuloj atingon por legi kaj ŝanĝi ajnajn dosierojn en via komputilo.",
"This is a major version upgrade.": "Ĉi tio estas ĉefversio ĝisdatigita.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Ĉi tiu agordo regas la libera spaco postulita sur la hejma (t.e. indeksa datumbaza) disko.",
"Time": "Tempo",
"Time the item was last modified": "Tempo de lasta modifo de la ero",
"Trash Can File Versioning": "Rubuja Dosiera Versionado",
"Type": "Tipo",
"Unavailable": "Ne disponebla",
"Unavailable/Disabled by administrator or maintainer": "Ne disponebla/Malebligita de administranto aŭ subtenanto",
"Undecided (will prompt)": "Hezitema (demandos)",
"Unignore": "Malignoru",
"Unknown": "Nekonata",
"Unshared": "Nekomunigita",
"Unused": "Neuzita",
"Up to Date": "Ĝisdata",
"Updated": "Ĝisdatigita",
"Upgrade": "Altgradigo",
"Upgrade To {%version%}": "Altgradigi Al {{version}}",
"Upgrading": "Altgradigata",
"Upload Rate": "Alŝutrapideco",
"Uptime": "Daŭro de funkciado",
"Usage reporting is always enabled for candidate releases.": "Uzada raportado ĉiam ŝaltita por kandidataj eldonoj.",
"Use HTTPS for GUI": "Uzi HTTPS por grafika interfaco.",
"Use notifications from the filesystem to detect changed items.": "Uzi sciigoj de la dosiersistemo por detekti ŝanĝitajn erojn.",
"Variable Size Blocks": "Blokoj de Variaj Grandecoj",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Blokoj de Variaj Grandecoj (ankaŭ \"grandaj blokoj\") estas pli efika por grandaj dosieroj.",
"Version": "Versio",
"Versions": "Versioj",
"Versions Path": "Vojo de Versioj",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versioj estas aŭtomate forigita se ili estas pli malnovaj ol la maksimuma aĝo aŭ superas la nombron da dosieroj permesita en intervalo.",
"Waiting to scan": "Atendante scanadon",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Averto, ĉi tiu vojo estas parenta dosierujo de ekzistanta dosierujo \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Averto, ĉi tiu vojo estas parenta dosierujo de ekzistanta dosierujo \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Averto, ĉi tiu vojo estas subdosierujo de ekzistanta dosierujo \"{{otherFolder}}\".",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Averto, ĉi tiu vojo estas subdosierujo de ekzistanta dosierujo \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Averto: se vi uzas ekstera rigardanto simila al {{syncthingInotify}}, vi devas certiĝi ĝi estas senaktivita.",
"Watch for Changes": "Rigardi Ŝanĝojn",
"Watching for Changes": "Rigardado je Ŝanĝoj",
"Watching for changes discovers most changes without periodic scanning.": "Rigardado je ŝanĝoj malkovras plejparton de la ŝanĝoj sen perioda skanado.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Dum la aldonado de nova aparato, memoru ke ĉi tiu aparato devas esti aldonita en la alia flanko ankaŭ.",
"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.": "Dum la aldonado de nova dosierujo, memoru ke la Dosieruja ID estas uzita por ligi la dosierujojn kune inter aparatoj. Ili estas literfakodistingaj kaj devas kongrui precize inter ĉiuj aparatoj.",
"Yes": "Jes",
"You can also select one of these nearby devices:": "Vi povas ankaŭ elekti unu el ĉi tiuj proksimaj aparatoj:",
"You can change your choice at any time in the Settings dialog.": "Vi povas ŝanĝi vian elekton iam ajn en la Agorda dialogo.",
"You can read more about the two release channels at the link below.": "Vi povas legi plu pri la du eldonkanaloj per la malsupra ligilo.",
"You have no ignored devices.": "Vi havas neniujn ignoritajn aparatojn.",
"You have no ignored folders.": "Vi havas neniujn ignoritajn dosierujojn.",
"You have unsaved changes. Do you really want to discard them?": "Vi havas ne konservitaj ŝanĝoj. Ĉu vi vere volas forĵeti ilin?",
"You must keep at least one version.": "Vi devas konservi almenaŭ unu version.",
"days": "tagoj",
"directories": "dosierujoj",
"files": "dosieroj",
"full documentation": "tuta dokumentado",
"items": "eroj",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} volas komunigi dosierujon \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} volas komunigi dosierujon \"{{folderlabel}}\" ({{folder}})."
}

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,12 +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 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",
@@ -74,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",
@@ -97,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",
@@ -143,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",
@@ -159,14 +160,14 @@
"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.",
@@ -208,7 +209,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:",
@@ -252,7 +253,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",
@@ -289,17 +290,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.",
@@ -313,7 +315,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).",
@@ -336,7 +338,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",
@@ -349,11 +351,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.": "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}}\".",
@@ -361,15 +366,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.": "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

@@ -56,6 +56,7 @@
"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:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Crear patrones a ignorar, sobreescribiendo un fichero existente en {{path}}.",
"Danger!": "¡Peligro!",
"Debugging Facilities": "Servicios de depuración",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"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.",
"Version": "Versión",
"Versions": "Versiones",
"Versions Path": "Ruta de las versiones",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Advertencia: Si estás utilizando un observador externo como {{syncthingInotify}}, debes asegurarte de que está desactivado.",
"Watch for Changes": "Vigila 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.",
"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",

View File

@@ -56,6 +56,7 @@
"Copied from original": "Kopioitu alkuperäisestä lähteestä",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 seuraavat avustajat",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 seuraavat avustajat:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Luodaan ohituslausekkeet. Ylikirjoitetaan tiedosto: {{path}}.",
"Danger!": "Vaara!",
"Debugging Facilities": "Debug -luokat",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"Uptime": "Päälläoloaika",
"Usage reporting is always enabled for candidate releases.": "Käytön raportointi on aina käytössä testiversioissa.",
"Use HTTPS for GUI": "Käytä HTTPS:ää GUI:n kanssa",
"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.",
"Version": "Versio",
"Versions": "Versiot",
"Versions Path": "Versioiden polku",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Varoitus: jos käytät ulkopuolista tiedostojärjestelmän muutosten valvojaa, kuten {{syncthingInotify}} varmista, että se ei ole aktiivinen.",
"Watch for Changes": "Seuraa muutoksia",
"Watching for Changes": "Seuraa muutoksia",
"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.": "Lisättäessä laitetta, muista että tämä laite tulee myös lisätä toiseen laitteeseen.",
"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.": "Lisättäessä uutta kansiota, muista että kansion ID:tä käytetään solmimaan kansiot yhteen laitteiden välillä. Ne ovat riippuvaisia kirjankoosta ja niiden tulee täsmätä kaikkien laitteiden välillä.",
"Yes": "Kyllä",

View File

@@ -56,6 +56,7 @@
"Copied from original": "Copié depuis l'original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016, les contributeurs sont:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017, les contributeurs sont:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 les Contributeurs suivants :",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Création de masques d'exclusion, remplacement du fichier existant : {{path}}.",
"Danger!": "Attention !",
"Debugging Facilities": "Outils de débogage",
@@ -138,7 +139,7 @@
"Global Discovery": "Découverte globale",
"Global Discovery Servers": "Serveurs de découverte globale",
"Global State": "État global",
"Help": "Aide",
"Help": "Aide (anglais)",
"Home page": "Page d'accueil",
"Ignore": "Refuser",
"Ignore Patterns": "Exclusions...",
@@ -294,11 +295,12 @@
"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 ...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing semble avoir un problème pour traiter votre demande. Rafraîchissez la page (F5 sur PC) ou redémarrez Syncthing si le problème persiste.",
"Take me back": "Reprends moi",
"Take me back": "Vérifier ...",
"The GUI address is overridden by startup options. Changes here will not take effect while the override is in place.": "L'adresse de l'interface graphique est remplacée par une ou des options de lancement. Les modifications apportées ici ne seront pas effectives tant que ces options seront utilisées.",
"The Syncthing admin interface is configured to allow remote access without a password.": "L'interface d'administration de Syncthing est paramétrée pour autoriser les accès à distance sans mot de passe !!!",
"The aggregated statistics are publicly available at the URL below.": "Les statistiques agrégées sont disponibles publiquement à l'adresse ci-dessous.",
@@ -349,6 +351,9 @@
"Uptime": "Durée de fonctionnement",
"Usage reporting is always enabled for candidate releases.": "L'envoi des statistiques d'utilisation est obligatoirement actif pour les versions préliminaires.",
"Use HTTPS for GUI": "Utiliser l'HTTPS pour le GUI",
"Use notifications from the filesystem to detect changed items.": "Utiliser les notifications du système de fichiers pour détecter les éléments modifiés.",
"Variable Size Blocks": "Blocs de taille variable",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Les blocs de taille variable (dont les \"gros blocs\") sont plus efficaces pour les gros fichiers.",
"Version": "Version",
"Versions": "Restauration...",
"Versions Path": "Emplacement des versions",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Attention : si vous utilisez un système externe de surveillance tel que {{syncthingInotify}}, vous devez vous assurer qu'il est désactivé.",
"Watch for Changes": "Écouter les changements",
"Watching for Changes": "Surveillance des changements",
"Watching for changes discovers most changes without periodic scanning.": "La surveillance des changements découvre la plupart des changements sans réanalyses périodiques.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Lorsque vous ajoutez un appareil, gardez à l'esprit que le votre doit aussi être ajouté de l'autre coté.",
"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.": "Lorsqu'un nouveau partage est ajouté, gardez à l'esprit que son ID est utilisée pour lier les répertoires à travers les appareils. L'ID est sensible à la casse et sera forcément la même sur tous les appareils participant à ce partage.",
"Yes": "Oui",
@@ -369,7 +375,7 @@
"You can read more about the two release channels at the link below.": "Vous pouvez en savoir plus sur les deux canaux de distribution via le lien ci-dessous.",
"You have no ignored devices.": "Aucun appareil refusé.",
"You have no ignored folders.": "Aucun partage refusé.",
"You have unsaved changes. Do you really want to discard them?": "Vous avez des réglages non enregistrés. Voulez-vous vraiment les ignorer ?",
"You have unsaved changes. Do you really want to discard them?": "Vous avez des réglages non enregistrés. Voulez-vous vraiment les rejeter ?",
"You must keep at least one version.": "Vous devez garder au minimum une version.",
"days": "Jours",
"directories": "répertoires",

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,6 +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 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",
@@ -97,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",
@@ -159,14 +160,14 @@
"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.",
@@ -294,6 +295,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...",
@@ -313,7 +315,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).",
@@ -349,11 +351,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.": "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}}\".",
@@ -361,6 +366,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.": "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

@@ -56,6 +56,7 @@
"Copied from original": "Eredetiről másolva",
"Copyright © 2014-2016 the following Contributors:": "Szerzői jog © 2014-2016 az alábbi közreműködők:",
"Copyright © 2014-2017 the following Contributors:": "Szerzői jog © 2014-2017 az alábbi közreműködők:",
"Copyright © 2014-2019 the following Contributors:": "Szerzői jog © 2014-2019 az alábbi közreműködők:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Mellőzési minták létrehozása, egy létező fájl felülírása itt: {{path}}.",
"Danger!": "Veszély!",
"Debugging Facilities": "Hibakeresési képességek",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"Uptime": "Üzemidő",
"Usage reporting is always enabled for candidate releases.": "Az előzetes kiadásokban a használati jelentés mindig engedélyezett.",
"Use HTTPS for GUI": "HTTPS használata a grafikus felülethez",
"Use notifications from the filesystem to detect changed items.": "A fájlrendszer által szolgáltatott értesítések alkalmazása a megváltozott elemek keresésére.",
"Variable Size Blocks": "Változó méretű blokkok",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "A változó mérető blokkok (ún. „nagy blokkok”) sokkal hatékonyabbak nagy fájloknál.",
"Version": "Verzió",
"Versions": "Verziók",
"Versions Path": "Verziók útvonala",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Figyelem: Ha eddig külső megfigyelő volt erre a célra alkalmazva, mint pl. a(z) {{syncthingInotify}}, akkor előbb meg kell győződni arról, hogy az ki lett kapcsolva.",
"Watch for Changes": "Változásfigyelés",
"Watching for Changes": "Változások figyelése",
"Watching for changes discovers most changes without periodic scanning.": "A változások keresése felfedezi a legtöbb változást periodikus átnézés nélkül.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Új eszköz hozzáadásakor nem szabad elfeledkezni arról, hogy a másik oldalon ezt az eszközt is hozzá kell adni.",
"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.": "Új eszköz hozzáadásakor észben kell tartani, hogy a mappaazonosító arra való, hogy összekösse a mappákat az eszközökön. Az azonosító kisbetű-nagybetű érzékeny és pontosan egyeznie kell az eszközökön.",
"Yes": "Igen",

View File

@@ -56,6 +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 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",
@@ -294,6 +295,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…",
@@ -349,6 +351,9 @@
"Uptime": "Tempo di Funzionamento",
"Usage reporting is always enabled for candidate releases.": "Le segnalazioni di utilizzo sono sempre abilitate le versioni candidate al rilascio.",
"Use HTTPS for GUI": "Utilizza HTTPS per l'interfaccia grafica",
"Use notifications from the filesystem to detect changed items.": "Usa le notifiche dal filesystem per rilevare gli elementi modificati.",
"Variable Size Blocks": "Blocchi di dimensioni variabile",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "I blocchi di dimensioni variabile (anche \"blocchi di grandi dimensioni\") sono più efficienti per file di grandi dimensioni.",
"Version": "Versione",
"Versions": "Versioni",
"Versions Path": "Percorso Cartella Versioni",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Attenzione: se stai usando uno strumento esterno di monitoraggio come {{syncthingInotify}}, dovresti assicurarti che sia disattivato.",
"Watch for Changes": "Monitorare i cambiamenti",
"Watching for Changes": "Monitoraggio dei cambiamenti",
"Watching for changes discovers most changes without periodic scanning.": "Guardando le modifiche si scopre la maggior parte delle modifiche senza scansione periodica.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Quando si aggiunge un nuovo dispositivo, tenere presente che il dispositivo deve essere aggiunto anche dall'altra parte.",
"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 aggiungi una nuova cartella, ricordati che gli ID vengono utilizzati per collegare le cartelle nei dispositivi. Distinguono maiuscole e minuscole e devono corrispondere esattamente su tutti i dispositivi.",
"Yes": "Sì",

View File

@@ -56,10 +56,11 @@
"Copied from original": "元ファイルからコピー済",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 the following Contributors:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "無視パターンを作成中。既存のファイルが {{path}} にある場合は上書きされます。",
"Danger!": "危険!",
"Debugging Facilities": "Debugging Facilities",
"Default Folder Path": "Default Folder Path",
"Debugging Facilities": "デバッグ機能",
"Default Folder Path": "デフォルトのフォルダーパス",
"Deleted": "削除",
"Deselect All": "すべて選択解除",
"Device": "デバイス",
@@ -202,7 +203,7 @@
"Override Changes": "他のデバイスの変更を上書きする",
"Path": "パス",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "ローカルコンピュータ上のフォルダーパス。フォルダーが存在しない場合は作成されます。チルダ (~) で以下のフォルダーを短縮入力できます:",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {{tilde}}.",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "新しい自動承諾フォルダーが作成されるパス、およびUIを使用して新しいフォルダーを追加するときにデフォルトでサジェストされるパスです。チルダ文字(~)の場合は {{tilde}} に展開されます。",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "古いバージョンを保存するパス (空欄の場合、デフォルトで共有フォルダー内の .stversions ディレクトリ)",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "古いバージョンを保存するパス (空欄の場合、デフォルトでフォルダー内の .stversions フォルダー)",
"Pause": "一時停止",
@@ -294,6 +295,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が落ちているか、インターネット接続に問題があります。リトライ中です…",
@@ -349,6 +351,9 @@
"Uptime": "稼働時間",
"Usage reporting is always enabled for candidate releases.": "リリース候補版では常に使用状況レポートが送信されます。",
"Use HTTPS for GUI": "GUIに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 (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 Path": "古いバージョンを保存するパス",
@@ -361,6 +366,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.",
"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

@@ -56,6 +56,7 @@
"Copied from original": "원본에서 복사됨",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 the following Contributors:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 the following Contributors:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "무시 패턴 만들기, {{path}}에 존재하는 파일을 덮어쓰기 합니다",
"Danger!": "경고!",
"Debugging Facilities": "디버깅 기능",
@@ -294,6 +295,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이 중지되었거나 인터넷 연결에 문제가 있는 것 같습니다. 재시도 중입니다...",
@@ -349,6 +351,9 @@
"Uptime": "가동 시간",
"Usage reporting is always enabled for candidate releases.": "출시 후보 버전에서는 사용 보고서가 항상 활성화 됩니다.",
"Use HTTPS for GUI": "GUI에서 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 (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "버전",
"Versions": "버전",
"Versions Path": "버전 저장 경로",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "경고 : {{syncthingInotify}} 와 같은 외부 감시 도구를 사용하는 경우 비활성화되어 있는지 확인해야 합니다.",
"Watch for Changes": "변경 사항 감시",
"Watching for Changes": "변경 사항 감시",
"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

@@ -56,6 +56,7 @@
"Copied from original": "Nukopijuota iš originalo",
"Copyright © 2014-2016 the following Contributors:": "Autorių teisės © 2014-2016 šių bendraautorių:",
"Copyright © 2014-2017 the following Contributors:": "Autorių teisės © 2014-2017 šių bendraautorių:",
"Copyright © 2014-2019 the following Contributors:": "Autorių teisės © 2014-2019 šių bendraautorių:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Kuriami nepaisomi šablonai, perrašomas esamas failas, esantis {{path}}.",
"Danger!": "Pavojus!",
"Debugging Facilities": "Derinimo priemonės",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"Uptime": "Veiksnumo laikas",
"Usage reporting is always enabled for candidate releases.": "Naudojimo ataskaita kandidatinėms versijoms visada yra įjungta.",
"Use HTTPS for GUI": "Valdymo skydeliui naudoti saugų ryšį ",
"Use notifications from the filesystem to detect changed items.": "Naudoti pranešimus iš failų sistemos, norint aptikti pakeistus elementus.",
"Variable Size Blocks": "Kintamųjų dydžių blokai",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Kintamųjų dydžių blokai (taip pat \"dideli blokai\") yra efektyvesni dideliems failams.",
"Version": "Versija",
"Versions": "Versijos",
"Versions Path": "Kelias iki versijos",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Įspėjimas: Jeigu naudojate išorinį stebėtoją, tokį kaip {{syncthingInotify}}, tuomet turite įsitikinti, kad jis yra išjungtas.",
"Watch for Changes": "Stebėti pakeitimus",
"Watching for Changes": "Stebimi pakeitimai",
"Watching for changes discovers most changes without periodic scanning.": "Pakeitimų stebėjimas aptinka daugumą pakeitimų be periodinio nuskaitymo.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Pridėdami įrenginį, turėkite omeny, kad šis įrenginys taip pat turi būti pridėtas kitoje pusėje.",
"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.": "Kai įvedate naują aplanką neužmirškite, kad jis bus naudojamas visuose įrenginiuose. Svarbu visur įvesti visiškai tokį pat aplanko vardą neužmirštant apie didžiąsias ir mažąsias raides.",
"Yes": "Taip",

View File

@@ -56,6 +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:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Oppretter ignoreringsmønster, overskriver eksisterende fil i {{path}}.",
"Danger!": "Fare!",
"Debugging Facilities": "Feilrettingsverktøy",
@@ -294,6 +295,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 …",
@@ -349,6 +351,9 @@
"Uptime": "Oppetid",
"Usage reporting is always enabled for candidate releases.": "Bruksrapportering er alltid påslått for utgivelseskandidater",
"Use HTTPS for GUI": "Bruk HTTPS for 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.",
"Version": "Versjon",
"Versions": "Versjoner",
"Versions Path": "Plassering av versjoner",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Advarsel: Hvis du bruker en ekstern viser, som {{syncthingInotify}}, burde du forsikre deg om at den avslått.",
"Watch for Changes": "Hold oppsyn med endringer",
"Watching for Changes": "Holder oppsyn med endringer",
"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.": "Når du legger til en ny enhet, husk at enheten må legges til på andre siden også.",
"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.": "Når en ny mappe blir lagt til, husk at Mappe-ID blir brukt til å binde sammen mapper mellom enheter. Det er forskjell på store og små bokstaver, så IDene må være identiske på alle enhetene.",
"Yes": "Ja",

View File

@@ -52,10 +52,11 @@
"Connection Type": "Soort verbinding",
"Connections": "Verbindingen",
"Continuously watching for changes is now available within Syncthing. This will detect changes on disk and issue a scan on only the modified paths. The benefits are that changes are propagated quicker and that less full scans are required.": "Continu opvolgen van wijzigingen is nu beschikbaar in Syncthing. Dit zal wijzigingen op een schijf detecteren en alleen een scan uitvoeren op de gewijzigde paden. De voordelen zijn dat wijzigingen sneller doorgevoerd worden en dat minder volledige scans nodig zijn.",
"Copied from elsewhere": "Gekopieerd van ergens anders",
"Copied from original": "Gekopieerd van het origineel",
"Copied from elsewhere": "Gekopieerd van elders",
"Copied from original": "Gekopieerd van origineel",
"Copyright © 2014-2016 the following Contributors:": "Auteursrecht © 2014-2016 voor de volgende bijdragers:",
"Copyright © 2014-2017 the following Contributors:": "Auteursrecht © 2014-2017 voor de volgende bijdragers:",
"Copyright © 2014-2019 the following Contributors:": "Auteursrecht © 2014-2019 voor de volgende bijdragers:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Negeerpatronen worden aangemaakt, bestaand bestand wordt overschreven op {{path}}.",
"Danger!": "Let op!",
"Debugging Facilities": "Debugmogelijkheden",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"Uptime": "Bedrijfstijd",
"Usage reporting is always enabled for candidate releases.": "Gebruiksrapportering is altijd ingeschakeld voor de kandidaat-releases.",
"Use HTTPS for GUI": "HTTPS gebruiken voor GUI",
"Use notifications from the filesystem to detect changed items.": "Meldingen van het bestandssysteem gebruiken om gewijzigde items te detecteren.",
"Variable Size Blocks": "Blokken met variabele grootte",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Blokken met variabele grootte (ook \"grote blokken\") zijn efficiënter voor grote bestanden.",
"Version": "Versie",
"Versions": "Versies",
"Versions Path": "Pad voor versies",
@@ -361,15 +366,16 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Waarschuwing: als u een externe opvolger gebruikt zoals {{syncthingInotify}}, moet u zich ervan verzekeren dat die uitgeschakeld is.",
"Watch for Changes": "Wijzigingen opvolgen",
"Watching for Changes": "Wijzigingen opvolgen",
"Watching for changes discovers most changes without periodic scanning.": "Opvolgen van wijzigingen ontdekt de meeste wijzigingen zonder periodiek scannen.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Houd er bij het toevoegen van een nieuw apparaat rekening mee dat dit apparaat ook aan de andere kant moet toegevoegd worden.",
"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.": "Houd er bij het toevoegen van een nieuwe map rekening mee dat de map-ID gebruikt wordt om mappen aan elkaar te koppelen tussen apparaten. Ze zijn hoofdlettergevoelig en moeten exact overeenkomen op alle apparaten.",
"Yes": "Ja",
"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

@@ -56,6 +56,7 @@
"Copied from original": "Skopiowane z oryginału",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016: ",
"Copyright © 2014-2017 the following Contributors:": "Prawa autorskie © 2014-2017 dla następujących autorów:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Ustawienie wzorów ignorowania, nadpisze istniejący plik w {{path}}.",
"Danger!": "Niebezpieczne!",
"Debugging Facilities": "Odpluskwianie",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"Uptime": "Czas działania",
"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": "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",
"Versions Path": "Ścieżka wersji",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Uwaga: Jeśli korzystasz z zewnętrznego obserwatora takiego jak {{syncthingInotify}}, upewnij się, że jest on dezaktywowany.",
"Watch for Changes": "Obserwuj zmiany",
"Watching for Changes": "Obserwowanie zmian",
"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.": "Gdy dodajesz nowe urządzenie, pamiętaj że urządzenie musi zostać dodane także po drugiej stronie.",
"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.": "Przy dodawaniu nowego folderu, pamiętaj, że ID użyte jest do łączenia folderów pomiędzy urządzeniami. Wielkość liter ciągu ma znaczenie musi zgadzać się na wszystkich urządzeniach.",
"Yes": "Tak",

View File

@@ -56,6 +56,7 @@
"Copied from original": "Copiado do original",
"Copyright © 2014-2016 the following Contributors:": "Direitos reservados © 2014-2016 aos seguintes colaboradores:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 dos seguintes Colaboradores:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Criando filtros, sobrescrevendo o arquivo {{path}}.",
"Danger!": "Perigo!",
"Debugging Facilities": "Facilidades de depuração",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"Uptime": "Tempo ligado",
"Usage reporting is always enabled for candidate releases.": "O relatório de uso está sempre habilitado em versões candidatas ao lançamento",
"Use HTTPS for GUI": "Usar HTTPS para a interface web",
"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.",
"Version": "Versão",
"Versions": "Versões",
"Versions Path": "Caminho do versionamento",
@@ -361,6 +366,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": "Observar alterações",
"Watching for Changes": "Observando alterações",
"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.": "Quando estiver adicionando um dispositivo, lembre-se de que este dispositivo deve 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 pastas entre dispositivos. Ele é sensível às diferenças entre maiúsculas e minúsculas e deve ser o mesmo em todos os dispositivos.",
"Yes": "Sim",

View File

@@ -56,6 +56,7 @@
"Copied from original": "Copiado do original",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 os seguintes contribuidores:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 dos seguintes contribuidores:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 dos seguintes contribuidores:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Criando padrões de exclusão, sobrescrevendo um ficheiro existente em {{path}}.",
"Danger!": "Perigo!",
"Debugging Facilities": "Recursos de depuração",
@@ -249,7 +250,7 @@
"Running": "Em execução",
"Save": "Gravar",
"Scan Time Remaining": "Tempo restante da verificação",
"Scanning": "Verificando",
"Scanning": "Verificação de alterações",
"See external versioner help for supported templated command line parameters.": "Veja a ajuda do gestor de versões externo para saber que parâmetros da linha de comandos são suportados.",
"See external versioning help for supported templated command line parameters.": "Veja a ajuda externa sobre gestão de versões para ver os modelos suportados de parâmetros para a linha de comandos.",
"Select All": "Seleccionar tudo",
@@ -294,6 +295,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...",
@@ -349,6 +351,9 @@
"Uptime": "Tempo em actividade",
"Usage reporting is always enabled for candidate releases.": "O relatório de utilização está sempre activado nas versões candidatas a lançamento.",
"Use HTTPS for GUI": "Utilizar HTTPS na interface gráfica",
"Use notifications from the filesystem to detect changed items.": "Use notificações do sistema de ficheiros para detectar itens alterados.",
"Variable Size Blocks": "Blocos de tamanho variável",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Blocos de tamanho variável (também designados por \"blocos grandes\") são mais eficientes para ficheiros grandes.",
"Version": "Versão",
"Versions": "Versões",
"Versions Path": "Caminho das versões",
@@ -361,6 +366,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 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

@@ -10,7 +10,7 @@
"Add Device": "Добавить устройство",
"Add Folder": "Добавить папку",
"Add Remote Device": "Добавить удалённое устройство",
"Add devices from the introducer to our device list, for mutually shared folders.": "Add devices from the introducer to our device list, for mutually shared folders.",
"Add devices from the introducer to our device list, for mutually shared folders.": "Добавлять устройства, известные рекомендателю, в список устройств, если есть общие с ними папки.",
"Add new folder?": "Добавить новую папку?",
"Additionally the full rescan interval will be increased (times 60, i.e. new default of 1h). You can also configure it manually for every folder later after choosing No.": "Также будет увеличен интервал полного сканирования (в 60 раз, т.е. новое значение по умолчанию 1 час). Вы можете вручную настроить интервал для каждой папки, выбрав \"Нет\".",
"Address": "Адрес",
@@ -23,7 +23,7 @@
"Allowed Networks": "Разрешённые сети",
"Alphabetic": "По алфавиту",
"An external command handles the versioning. It has to remove the file from the shared folder.": "Для версионирования используется внешняя программа. Ей нужно удалить файл из общей папки.",
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.",
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Для версионирования используется внешняя программа. Ей нужно удалить файл из общей папки. Если путь к приложению содержит пробелы, его нужно взять в кавычки.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Внешний процесс управляет версиями файлов. Процесс удалит файл из синхронизируемой папки.",
"Anonymous Usage Reporting": "Анонимный отчет об использовании",
"Anonymous usage report format has changed. Would you like to move to the new format?": "Формат анонимных отчётов изменился. Вы хотите переключиться на новый формат?",
@@ -34,8 +34,8 @@
"Auto Accept": "Автопринятие",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Автоматическое обновление теперь предлагает выбор между стабильными выпусками и кандидатами в релизы.",
"Automatic upgrades": "Автообновление",
"Automatic upgrades are always enabled for candidate releases.": "Automatic upgrades are always enabled for candidate releases.",
"Automatically create or share folders that this device advertises at the default path.": "Automatically create or share folders that this device advertises at the default path.",
"Automatic upgrades are always enabled for candidate releases.": "Автоматическое обновление всегда включено для кандидатов в релизы.",
"Automatically create or share folders that this device advertises at the default path.": "Автоматически создавать, используя путь по умолчанию, или делиться папками, о которых сообщает это устройство.",
"Available debug logging facilities:": "Доступные средства отладочного журнала:",
"Be careful!": "Будьте осторожны!",
"Bugs": "Ошибки",
@@ -56,12 +56,13 @@
"Copied from original": "Скопировано с оригинала",
"Copyright © 2014-2016 the following Contributors:": "Авторские права © 20142016 принадлежат:",
"Copyright © 2014-2017 the following Contributors:": "Авторские права © 2014—2017 следующие участники:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creating ignore patterns, overwriting an existing file at {{path}}.",
"Copyright © 2014-2019 the following Contributors:": "Авторские права © 20142019 принадлежат:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Создание шаблонов игнорирования, существующий файл {{path}} будет перезаписан.",
"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": "ID устройства",
@@ -73,8 +74,8 @@
"Disabled": "Отключено",
"Disabled periodic scanning and disabled watching for changes": "Периодическое сканирование и отслеживание изменений отключено",
"Disabled periodic scanning and enabled watching for changes": "Периодическое сканирование отключено, отслеживание изменений включено",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:",
"Discard": "Discard",
"Disabled periodic scanning and failed setting up watching for changes, retrying every 1m:": "Периодическое сканирование отключено, не удалось включить отслеживание изменений, повторная попытка каждую минуту.",
"Discard": "Отменить",
"Disconnected": "Нет соединения",
"Discovered": "Обнаружено",
"Discovery": "Обнаружение",
@@ -97,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.": "Введите положительное значение (например, \"2.35\") и выберите единицу измерения, либо процент от общей ёмкости диска.",
"Enter a non-privileged port number (1024 - 65535).": "Введите непривилегированный порт (1024—65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Введите через запятую («tcp://ip:port», «tcp://host:port») адреса, либо «dynamic», чтобы выполнить автоматическое обнаружение адреса.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "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.": "Введите через запятую («tcp://ip:port», «tcp://host:port») адреса, либо «dynamic», чтобы выполнить автоматическое обнаружение адреса.",
"Enter ignore patterns, one per line.": "Введите шаблоны игнорирования, по одному на строку.",
"Error": "Ошибка",
"External File Versioning": "Внешний контроль версий файлов",
@@ -115,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.": "Файлы синхронизируются из группы, но изменения, сделанные на этом устройстве, не будут отправлены на другие устройства группы.",
"Filesystem Notifications": "Уведомления файловой системы",
"Filesystem Watcher Errors": "Filesystem Watcher Errors",
"Filesystem Watcher Errors": "Ошибки отслеживания файловой системы",
"Filter by date": "Отфильтровать по дате",
"Filter by name": "Отфильтровать по имени",
"Folder": "Папка",
@@ -124,7 +125,7 @@
"Folder Path": "Путь к папке",
"Folder Type": "Тип папки",
"Folders": "Папки",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.",
"For the following folders an error occurred while starting to watch for changes. It will be retried every minute, so the errors might go away soon. If they persist, try to fix the underlying issue and ask for help if you can't.": "Для следующих папок произошла ошибка при запуске отслеживания изменений. Попытки будут повторяться раз в минуту, и ошибки скоро могут быть устранены. Если этого не произойдёт, попробуйте разобраться в причинах и попросите поддержки, если у вас не получится.",
"Full Rescan Interval (s)": "Интервал полного сканирования (в секундах)",
"GUI": "Интерфейс",
"GUI Authentication Password": "Пароль для доступа к панели управления",
@@ -159,14 +160,14 @@
"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.": "Вывод журнала приостановлен. Чтобы продолжить, прокрутите журнал до конца.",
@@ -177,8 +178,8 @@
"Maximum Age": "Максимальный срок",
"Metadata Only": "Только метаданные",
"Minimum Free Disk Space": "Минимальное свободное место на диске",
"Mod. Device": "Mod. Device",
"Mod. Time": "Mod. Time",
"Mod. Device": "Изм. устройство",
"Mod. Time": "Посл. изм.",
"Move to top of queue": "Поместить в начало очереди",
"Multi level wildcard (matches multiple directory levels)": "Многоуровневая маска (поиск совпадений во всех подпапках)",
"Never": "Никогда",
@@ -208,16 +209,16 @@
"Pause": "Пауза",
"Pause All": "Приостановить все",
"Paused": "Приостановлено",
"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",
"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:",
"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:": "Периодическое сканирование с заданным интервалом, не удалось включить отслеживание изменений, повторная попытка каждую минуту.",
"Permissions": "Разрешения",
"Please consult the release notes before performing a major upgrade.": "Перед проведением обновления основной версии ознакомтесь, пожалуйста, с Замечаниями к версии",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Установите имя пользователя и пароль для интерфейса в настройках",
"Please wait": "Пожалуйста, подождите",
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefix indicating that the file can be deleted if preventing directory removal",
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefix indicating that the pattern should be matched without case sensitivity",
"Prefix indicating that the file can be deleted if preventing directory removal": "Префикс указывает, что файл может быть удалён, если он мешает удалить папку",
"Prefix indicating that the pattern should be matched without case sensitivity": "Префикс указывает, что регистр букв (заглавные/строчные) игнорируется",
"Preview": "Предварительный просмотр",
"Preview Usage Report": "Посмотреть отчёт об использовании",
"Quick guide to supported patterns": "Краткое руководство по поддерживаемым шаблонам",
@@ -245,14 +246,14 @@
"Resume": "Возобновить",
"Resume All": "Возобновить все",
"Reused": "Повторно использовано",
"Revert Local Changes": "Revert Local Changes",
"Revert Local Changes": "Отменить изменения на этом компьютере",
"Running": "Запущено",
"Save": "Сохранить",
"Scan Time Remaining": "Оставшееся время сканирования",
"Scanning": "Сканирование",
"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",
"See external versioner help for supported templated command line parameters.": "Поддерживаемые шаблонные параметры командной строки см. в документации сторонней программы контроля версий",
"See external versioning help for supported templated command line parameters.": "Поддерживаемые шаблонные параметры командной строки см. в документации сторонней программы контроля версий",
"Select All": "Выбрать все",
"Select a version": "Выберите версию",
"Select latest version": "Выбрать последнюю версию",
"Select oldest version": "Выбрать самую старую версию",
@@ -267,7 +268,7 @@
"Share With Devices": "Предоставить доступ устройствам",
"Share this folder?": "Предоставить доступ к этой папке?",
"Shared With": "Доступ предоставлен",
"Sharing": "Sharing",
"Sharing": "Предоставление доступа",
"Show ID": "Показать ID",
"Show QR": "Показать QR-код",
"Show diff with previous version": "Показать различия с предыдущей версией",
@@ -289,16 +290,17 @@
"Statistics": "Статистика",
"Stopped": "Остановлено",
"Support": "Поддержка",
"Support Bundle": "Support Bundle",
"Support Bundle": "Данные для поддержки",
"Sync Protocol Listen Addresses": "Адрес протокола синхронизации",
"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 не запущен или есть проблемы с подключением к Интернету. Переподключаюсь...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing столкнулся с проблемой при обработке Вашего запроса. Пожалуйста, обновите страницу или перезапустите Syncthing если проблема повторится.",
"Take me back": "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 Syncthing admin interface is configured to allow remote access without a password.": "Административный интерфейс Syncthing настроен для предоставления удаленного доступа без пароля.",
"The aggregated statistics are publicly available at the URL below.": "Агрегированные статистические данные общедоступны по ссылке ниже.",
@@ -313,7 +315,7 @@
"The folder path cannot be blank.": "Путь к папке не должен быть пустым.",
"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.": "Используются следующие интервалы: в первый час версия меняется каждые 30 секунд, в первый день - каждый час, первые 30 дней - каждый день, после, до максимального срока - каждую неделю.",
"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.": "Следующие объекты были изменены локально",
"The maximum age must be a number and cannot be blank.": "Максимальный срок должен быть числом и не может быть пустым.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Максимальный срок хранения версии (в днях, 0 значит вечное хранение).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Минимальное свободное место на диске должно быть в процентах между 0 и 100 включительно.",
@@ -334,8 +336,8 @@
"Trash Can File Versioning": "Использовать версионность для файлов в Корзине",
"Type": "Тип",
"Unavailable": "Недоступно",
"Unavailable/Disabled by administrator or maintainer": "Unavailable/Disabled by administrator or maintainer",
"Undecided (will prompt)": "Undecided (will prompt)",
"Unavailable/Disabled by administrator or maintainer": "Недоступно или отключено администратором",
"Undecided (will prompt)": "Запрос каждый раз",
"Unignore": "Не игнорировать",
"Unknown": "Неизвестно",
"Unshared": "Необщедоступно",
@@ -349,18 +351,22 @@
"Uptime": "Время работы",
"Usage reporting is always enabled for candidate releases.": "Отправка отчётов об использовании всегда включена для кандидатов в релизы.",
"Use HTTPS for GUI": "Использовать HTTPS для панели управления",
"Use notifications from the filesystem to detect changed items.": "Использовать уведомления от файловой системы для обнаружения изменённых объектов.",
"Variable Size Blocks": "Блоки переменного размера",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "Блоки переменного размера (или \"большие блоки\") более эффективны для файлов большого размера.",
"Version": "Версия",
"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",
"Waiting to scan": "Ожидание сканирования",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Внимание! Этот путь — родительская директория уже существующей папки «{{otherFolder}}».",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Внимание! Этот путь — родительская директория уже существующей папки «{{otherFolderLabel}}» ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Осторожно, этот путь является подкаталогом существующей папки «{{otherFolder}}».",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Внимание! Этот путь — поддиректория уже существующей папки «{{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.",
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Внимание! Если вы используете внешнюю программу для отслеживания изменений, например, {{syncthingInotify}}, убедитесь, что она отключена.",
"Watch for Changes": "Следить за изменениями",
"Watching for Changes": "Слежение за изменениями",
"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 папок используются для того, чтобы связывать папки между всеми устройствами. Они чувствительны к регистру и должны совпадать на всех используемых устройствах.",
"Yes": "Да",

View File

@@ -56,12 +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 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",
@@ -74,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é",
@@ -143,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.",
@@ -166,7 +167,7 @@
"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.",
@@ -208,11 +209,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",
@@ -223,7 +224,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",
@@ -236,7 +237,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",
@@ -245,14 +246,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",
@@ -267,7 +268,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",
@@ -294,11 +295,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.",
@@ -313,7 +315,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).",
@@ -349,27 +351,31 @@
"Uptime": "Doba prevádzky",
"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": "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.",
"Yes": "Áno",
"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,12 +55,13 @@
"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!",
"Debugging Facilities": "Felsökningsanläggningar",
"Default Folder Path": "Standard mappsökväg",
"Deleted": "Tog bort",
"Deleted": "Raderade",
"Deselect All": "Avmarkera alla",
"Device": "Enhet",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Enhet \"{{name}}\" ({{device}} på {{address}}) vill ansluta. Lägg till ny enhet?",
@@ -108,10 +109,10 @@
"File Pull Order": "Filhämtningsprioritering",
"File Versioning": "Filversionshantering",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Filrättigheter ignoreras under sökning efter förändringar. Används på FAT-filsystem.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Filer flyttas till .stversions-mappen vid byte eller tas bort av Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Filer flyttas till .stversions-mappen när de ersätts eller tas bort av Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Filer flyttas till datumstämplade versioner i en .stversions-mapp när de ersätts eller tas bort av Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Filer flyttas till datummärkta versioner i en .stversions mapp när de ersätts eller tas bort av Syncthing.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Filer flyttas till .stversions-mappen vid byte eller raderas av Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Filer flyttas till .stversions-mappen när de ersätts eller raderas av Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Filer flyttas till datumstämplade versioner i en .stversions-mapp när de ersätts eller raderas av Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Filer flyttas till datummärkta versioner i en .stversions-mapp när de ersätts eller raderas av Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Filer skyddas från ändringar gjorda på andra enheter, men ändringar som görs på den här noden skickas till de andra klustermedlemmarna.",
"Files are synchronized from the cluster, but any changes made locally will not be sent to other devices.": "Filer synkroniseras från klustret, men alla ändringar som görs lokalt skickas inte till andra enheter.",
"Filesystem Notifications": "filsystemsnotifieringar",
@@ -187,7 +188,7 @@
"Newest First": "Nyast först",
"No": "Nej",
"No File Versioning": "Ingen filversionshantering",
"No files will be deleted as a result of this operation.": "Inga filer kommer att tas bort till följd av denna operation.",
"No files will be deleted as a result of this operation.": "Inga filer kommer att raderas till följd av denna operation.",
"No upgrades": "Inga uppgraderingar",
"Normal": "Normal",
"Notice": "Observera",
@@ -203,7 +204,7 @@
"Path": "Sökväg",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Sökväg till mappen på din dator. Kommer att skapas om det inte finns. Tecknet tilde (~) kan användas som en genväg för",
"Path where new auto accepted folders will be created, as well as the default suggested path when adding new folders via the UI. Tilde character (~) expands to {%tilde%}.": "Sökvägen där nya automatiskt accepterade mappar kommer att skapas, liksom den föreslagna sökvägen när du lägger till nya mappar via gränssnittet. Tecknet tilde (~) expanderar till {{tilde}}.",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Sökväg där versioner ska lagras (lämna tomt för standard .stversions-katalogen i den delade katalogen).",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Sökväg där versioner ska lagras (lämna tomt för standard .stversions-mappen i den delade katalogen).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Sökväg där versioner sparas (lämna tomt för att använda standard .stversions-mappen i mappen).",
"Pause": "Paus",
"Pause All": "Pausa alla",
@@ -211,12 +212,12 @@
"Pending changes": "Väntar på ändringar",
"Periodic scanning at given interval and disabled watching for changes": "Periodisk uppdatering i givet intervall och inaktiverad spaning efter ändringar",
"Periodic scanning at given interval and enabled watching for changes": "Periodisk uppdatering i givet intervall och aktiverad spaning efter ändringar",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodisk uppdatering i givet intervall och misslyckades med att ställa in spaning efter ändringar, försök igen var 1m:",
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodisk uppdatering i givet intervall och misslyckades med att ställa in utkik efter ändringar, försök igen var 1m:",
"Permissions": "Behörigheter",
"Please consult the release notes before performing a major upgrade.": "Läs igenom versionsnyheterna innan den stora uppgraderingen.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Ställ in ett grafiska gränssnittets användarautentisering och lösenord i inställningsdialogrutan.",
"Please wait": "Var god vänta",
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefix som indikerar att filen kan raderas om det förhindrar borttagning av katalog",
"Prefix indicating that the file can be deleted if preventing directory removal": "Prefix som indikerar att filen kan raderas om det förhindrar radering av katalog",
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefix som indikerar att mönstret ska matchas utan skiftlägeskänslighet",
"Preview": "Förhandsgranska",
"Preview Usage Report": "Förhandsgranska statistik",
@@ -294,6 +295,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...",
@@ -349,10 +351,13 @@
"Uptime": "Drifttid",
"Usage reporting is always enabled for candidate releases.": "Användningsrapportering är alltid aktiverad för kandidatutgåvor.",
"Use HTTPS for GUI": "Använd HTTPS för gränssnittet",
"Use notifications from the filesystem to detect changed items.": "Använd aviseringar från filsystemet för att upptäcka ändrade objekt.",
"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": "Version",
"Versions": "Versioner",
"Versions Path": "Sökväg för versioner",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versioner tas bort automatiskt när de är äldre än den maximala åldersgränsen eller överstiger frekvensen i intervallet.",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versioner raderas automatiskt när de är äldre än den maximala åldersgränsen eller överstiger frekvensen i intervallet.",
"Waiting to scan": "Väntar på uppdatering",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Varning, denna sökväg är en överordnad mapp av en befintlig mapp \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Varning, denna sökväg är en överordnad mapp av en befintlig mapp \"{{otherFolderLabel}}\" ({{otherFolder}}).",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "Varning: Om du använder en extern bevakare som {{syncthingInotify}}, bör du se till att den är inaktiverad.",
"Watch for Changes": "Håll utkik efter ändringar",
"Watching for Changes": "Håller utkik efter ändringar",
"Watching for changes discovers most changes without periodic scanning.": "Hålla utkik efter ändringar upptäcker de flesta förändringar utan periodisk uppdatering.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "När du lägger till en ny enhet, kom ihåg att den här enheten måste läggas till på den andra enheten också.",
"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.": "När du lägger till ny mapp, tänk på att mapp-ID knyter ihop mappar mellan olika enheter. De skiftlägeskänsliga och måste matcha precis mellan alla enheter.",
"Yes": "Ja",

View File

@@ -56,6 +56,7 @@
"Copied from original": "Скопійовано з оригіналу",
"Copyright © 2014-2016 the following Contributors:": "© 2014-2016 Всі права застережено, вклад внесли:",
"Copyright © 2014-2017 the following Contributors:": "© 2014-2017 Всі права застережено, вклад внесли:",
"Copyright © 2014-2019 the following Contributors:": "Copyright © 2014-2019 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Створення шаблонів винятків з перезаписом існуючого файлу {{path}}.",
"Danger!": "Небезпечно!",
"Debugging Facilities": "Засоби відладки",
@@ -294,6 +295,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 закритий, або виникла проблема із Інтернет-з’єднанням. Проводиться повторна спроба з’єднання…",
@@ -349,6 +351,9 @@
"Uptime": "Тривалість роботи",
"Usage reporting is always enabled for candidate releases.": "Звіти про користування завжди увімкнені для реліз-кандидатів.",
"Use HTTPS for GUI": "Використовувати 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 (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "Версія",
"Versions": "Версії",
"Versions Path": "Шлях до версій",
@@ -361,6 +366,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.",
"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 цієї директорії використовується для того, щоб зв’язувати директорії разом між пристроями. Назви повинні точно співпадати між усіма пристроями, регістр символів має значення.",
"Yes": "Так",

View File

@@ -56,6 +56,7 @@
"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:": "版权所有 © 2014-2019 以下贡献者:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "正在创建忽略模式,覆盖位于 {{path}} 的已有文件。",
"Danger!": "危险!",
"Debugging Facilities": "调试功能",
@@ -289,11 +290,12 @@
"Statistics": "统计",
"Stopped": "已停止",
"Support": "支持",
"Support Bundle": "Support Bundle",
"Support Bundle": "支持捆绑包",
"Sync Protocol Listen Addresses": "协议监听地址",
"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 @@
"Unavailable": "无效",
"Unavailable/Disabled by administrator or maintainer": "无效/禁用(由管理员或维护者)",
"Undecided (will prompt)": "待定(将提示)",
"Unignore": "屏蔽",
"Unignore": "解除忽略",
"Unknown": "未知",
"Unshared": "未共享",
"Unused": "未使用",
@@ -349,6 +351,9 @@
"Uptime": "已启动",
"Usage reporting is always enabled for candidate releases.": "发布候选版总是会启用使用报告。",
"Use HTTPS for GUI": "使用加密连接到图形管理页面",
"Use notifications from the filesystem to detect changed items.": "使用文件系统的通知来检测更改的项目。",
"Variable Size Blocks": "可变大小块",
"Variable size blocks (also \"large blocks\") are more efficient for large files.": "可变大小块(既“较大块”)对于大文件更有效率。",
"Version": "版本",
"Versions": "历史版本",
"Versions Path": "历史版本路径",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "警告:如果你在使用外部的监视器如 {{syncthingInotify}},你应该确保它已经取消激活。",
"Watch for Changes": "监视更改",
"Watching for Changes": "正在监视更改",
"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 的文件夹将会被同步。且文件夹 ID 区分大小写。",
"Yes": "是",

View File

@@ -56,6 +56,7 @@
"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:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "建立忽略樣式,覆蓋已存在的 {{path}}。",
"Danger!": "危險!",
"Debugging Facilities": "除錯工具",
@@ -294,6 +295,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 似乎離線了,或者您的網際網路連線出現問題。正在重試...",
@@ -349,6 +351,9 @@
"Uptime": "上線時間",
"Usage reporting is always enabled for candidate releases.": "發行候選版永遠啟用使用數據回報。",
"Use HTTPS for GUI": "為 GUI 使用 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 (also \"large blocks\") are more efficient for large files.": "Variable size blocks (also \"large blocks\") are more efficient for large files.",
"Version": "版本",
"Versions": "版本",
"Versions Path": "歷史版本路徑",
@@ -361,6 +366,7 @@
"Warning: If you are using an external watcher like {%syncthingInotify%}, you should make sure it is deactivated.": "警告:如果您正在使用外部監視工具,如 {{syncthingInotify}},您應該確認已經將其關閉。",
"Watch for Changes": "監視變動",
"Watching for Changes": "正在監視變動",
"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.": "當新增一個資料夾時,請記住,資料夾識別碼是用來將裝置之間的資料夾綁定在一起的。它們有區分大小寫,且必須在所有裝置之間完全相同。",
"Yes": "是",

View File

@@ -1 +1 @@
var langPrettyprint = {"bg":"Bulgarian","ca@valencia":"Catalan (Valencian)","cs":"Czech","da":"Danish","de":"German","el":"Greek","en":"English","en-GB":"English (United Kingdom)","es":"Spanish","es-ES":"Spanish (Spain)","fi":"Finnish","fr":"French","fy":"Western Frisian","hu":"Hungarian","it":"Italian","ja":"Japanese","ko-KR":"Korean (Korea)","lt":"Lithuanian","nb":"Norwegian Bokmål","nl":"Dutch","pl":"Polish","pt-BR":"Portuguese (Brazil)","pt-PT":"Portuguese (Portugal)","ru":"Russian","sk":"Slovak","sv":"Swedish","uk":"Ukrainian","zh-CN":"Chinese (China)","zh-TW":"Chinese (Taiwan)"}
var langPrettyprint = {"bg":"Bulgarian","ca@valencia":"Catalan (Valencian)","cs":"Czech","da":"Danish","de":"German","el":"Greek","en":"English","en-GB":"English (United Kingdom)","eo":"Esperanto","es":"Spanish","es-ES":"Spanish (Spain)","fi":"Finnish","fr":"French","fy":"Western Frisian","hu":"Hungarian","it":"Italian","ja":"Japanese","ko-KR":"Korean (Korea)","lt":"Lithuanian","nb":"Norwegian Bokmål","nl":"Dutch","pl":"Polish","pt-BR":"Portuguese (Brazil)","pt-PT":"Portuguese (Portugal)","ru":"Russian","sk":"Slovak","sv":"Swedish","uk":"Ukrainian","zh-CN":"Chinese (China)","zh-TW":"Chinese (Taiwan)"}

View File

@@ -1 +1 @@
var validLangs = ["bg","ca@valencia","cs","da","de","el","en","en-GB","es","es-ES","fi","fr","fy","hu","it","ja","ko-KR","lt","nb","nl","pl","pt-BR","pt-PT","ru","sk","sv","uk","zh-CN","zh-TW"]
var validLangs = ["bg","ca@valencia","cs","da","de","el","en","en-GB","eo","es","es-ES","fi","fr","fy","hu","it","ja","ko-KR","lt","nb","nl","pl","pt-BR","pt-PT","ru","sk","sv","uk","zh-CN","zh-TW"]

View File

@@ -328,6 +328,7 @@
<span ng-show="syncRemaining(folder.id)">({{syncPercentage(folder.id) | percent}}, {{syncRemaining(folder.id) | 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>
</div>
<div class="panel-title-text">
<span tooltip data-original-title="{{folder.label.length != 0 ? folder.id : ''}}">{{folder.label.length != 0 ? folder.label : folder.id}}</span>
@@ -336,7 +337,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>
@@ -550,7 +551,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>
@@ -666,7 +667,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>
@@ -709,7 +710,7 @@
<tr>
<th><span class="fas fa-fw fa-link"></span>&nbsp<span translate>Address</span></th>
<td ng-if="connections[deviceCfg.deviceID].connected" class="text-right">
<span tooltip data-original-title="{{ connections[deviceCfg.deviceID].type.indexOf('Relay') > -1 ? '' : connections[deviceCfg.deviceID].type }}">
<span tooltip data-original-title="{{ connections[deviceCfg.deviceID].type.indexOf('Relay') > -1 ? '' : connections[deviceCfg.deviceID].type }} {{ connections[deviceCfg.deviceID].crypto }}">
{{deviceAddr(deviceCfg)}}
</span>
</td>
@@ -740,7 +741,7 @@
<td translate class="text-right">Yes</td>
</tr>
<tr ng-if="deviceCfg.introducedBy">
<th><span class="far fa-fw fa-meh"></span>&nbsp;<span translate>Introduced By</span></th>
<th><span class="far fa-fw fa-handshake-o"></span>&nbsp;<span translate>Introduced By</span></th>
<td class="text-right">{{ deviceName(findDevice(deviceCfg.introducedBy)) || deviceCfg.introducedBy.substring(0, 5) }}</td>
</tr>
<tr ng-if="connections[deviceCfg.deviceID].clientVersion">

View File

@@ -179,7 +179,7 @@ function buildTree(children) {
key: keySoFar.join('/'),
folder: true,
children: []
}
};
parent.children.push(child);
parent = child;
}
@@ -209,7 +209,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

@@ -9,10 +9,12 @@
</h1>
<hr />
<p translate>Copyright &copy; 2014-2017 the following Contributors:</p>
<p translate>Syncthing is Free and Open Source Software licensed as MPL v2.0.</p>
<hr />
<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, 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 (Alex) 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, 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, 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, janost, jaseg, klemens, marco-m, 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, 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, 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, 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, 佛跳墙
</div>
</div>
<hr />
@@ -20,21 +22,47 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Alexander Graf, Alexandre Viau, And
<p translate>Syncthing includes the following software or portions thereof:</p>
<ul class="list-unstyled two-columns" id="copyright-notices">
<li><a href="http://getbootstrap.com/">Bootstrap</a>, Copyright &copy; 2011-2016 Twitter, Inc.</li>
<li><a href="https://angularjs.org/">AngularJS</a>, Copyright &copy; 2010-2016 Google, Inc.</li>
<li><a href="https://angularjs.org/">AngularJS</a>, Copyright &copy; 2010-2014, 2016 Google, Inc.</li>
<li><a href="http://www.daterangepicker.com/">Date Range Picker</a>, Copyright &copy; 2012-2018 Dan Grossman.</li>
<li><a href="https://github.com/mar10/fancytree">JQuery Fancytree Plugin</a>, Copyright &copy; 2008-2018 Martin Wendt.</li>
<li><a href="https://forkaweso.me/Fork-Awesome/">Fork Awesome</a>, Copyright &copy; 2018 Dave Gandy &amp; Fork Awesome.</li>
<li><a href="http://jquery.com/">jQuery JavaScript Library</a>, Copyright &copy; jQuery Foundation and other contributors.</li>
<li><a href="http://momentjs.com/">moment.js</a>, Copyright &copy; JS Foundation and other contributors.</li>
<li><a href="https://prometheus.io/">Prometheus</a>, Copyright &copy; 2012-2015 The Prometheus Authors.</li>
<li><a href="https://github.com/AudriusButkevicius/go-nat-pmp">AudriusButkevicius/go-nat-pmp</a>, Copyright &copy; 2013 John Howard Palevich.</li>
<li><a href="https://github.com/AudriusButkevicius/recli">AudriusButkevicius/recli</a>, Copyright &copy; 2019 Audrius Butkevicius.</li>
<li><a href="https://github.com/beorn7/perks">beorn7/perks</a>, Copyright &copy; 2013 Blake Mizerany.</li>
<li><a href="https://github.com/bkaradzic/go-lz4">bkaradzic/go-lz4</a>, Copyright &copy; 2011-2012 Branimir Karadzic, 2013 Damian Gryski.</li>
<li><a href="https://github.com/chmduquesne/rollinghash">chmduquesne/rollinghash</a>, Copyright &copy; 2015 Christophe-Marie Duquesne</li>
<li><a href="https://github.com/calmh/du">calmh/du</a>, Public domain.</li>
<li><a href="https://github.com/calmh/xdr">calmh/xdr</a>, Copyright &copy; 2014 Jakob Borg.</li>
<li><a href="https://github.com/chmduquesne/rollinghash">chmduquesne/rollinghash</a>, Copyright &copy; 2015 Christophe-Marie Duquesne.</li>
<li><a href="https://github.com/d4l3k/messagediff">d4l3k/messagediff</a>, Copyright &copy; 2015 Tristan Rice.</li>
<li><a href="https://github.com/flynn-archive/go-shlex">flynn-archive/go-shlex</a>, Copyright &copy; 2012 Google Inc.</li>
<li><a href="https://github.com/gobwas/glob">gobwas/glob</a>, Copyright &copy; 2016 Sergey Kamardin.</li>
<li><a href="https://github.com/gogo/protobuf">gogo/protobuf</a>, Copyright &copy; 2013 The GoGo Authors.</li>
<li><a href="https://github.com/golang/groupcache">golang/groupcache</a>, Copyright &copy; 2013 Google Inc.</li>
<li><a href="https://github.com/golang/protobuf">golang/protobuf</a>, Copyright &copy; 2010 The Go Authors.</li>
<li><a href="https://github.com/golang/snappy">golang/snappy</a>, Copyright &copy; 2011 The Snappy-Go Authors.</li>
<li><a href="https://github.com/jackpal/gateway">jackpal/gateway</a>, Copyright &copy; 2010 Jack Palevich.</li>
<li><a href="https://github.com/minio/sha256-simd">minio/sha256-simd</a>, Copyright &copy; 2016 Minio, Inc.</li>
<li><a href="https://github.com/kballard/go-shellquote">kballard/go-shellquote</a>, Copyright &copy; 2014 Kevin Ballard.</li>
<li><a href="https://github.com/lib/pq">lib/pq</a>, Copyright &copy; 2011-2013, 'pq' Contributors, portions Copyright &copy; 2011 Blake Mizerany.</li>
<li><a href="https://github.com/mattn/go-isatty">mattn/go-isatty</a>, Copyright &copy; Yasuhiro MATSUMOTO.</li>
<li><a href="https://github.com/matttproud/golang_protobuf_extensions">matttproud/golang_protobuf_extensions</a>, Copyright &copy; 2012 Matt T. Proud.</li>
<li><a href="https://github.com/minio/sha256-simd">minio/sha256-simd</a>, Copyright &copy; 2016-2017 Minio, Inc.</li>
<li><a href="https://github.com/oschwald/geoip2-golang">oschwald/geoip2-golang</a>, Copyright &copy; 2015, Gregory J. Oschwald.</li>
<li><a href="https://github.com/oschwald/maxminddb-golang">oschwald/maxminddb-golang</a>, Copyright &copy; 2015, Gregory J. Oschwald.</li>
<li><a href="https://github.com/petermattis/goid">petermattis/goid</a>, Copyright &copy; 2015-2016 Peter Mattis.</li>
<li><a href="https://github.com/pkg/errors">pkg/errors</a>, Copyright &copy; 2015, Dave Cheney.</li>
<li><a href="https://github.com/rcrowley/go-metrics">rcrowley/go-metrics</a>, Copyright &copy; 2012 Richard Crowley.</li>
<li><a href="https://github.com/sasha-s/go-deadlock">sasha-s/go-deadlock</a>, Copyright &copy; 2016 sasha-s</li>
<li><a href="https://github.com/sasha-s/go-deadlock">sasha-s/go-deadlock</a>, Copyright &copy; 2016 sasha-s.</li>
<li><a href="https://github.com/syncthing/notify">syncthing/notify</a>, Copyright &copy; 2014-2015 The Notify Authors.</li>
<li><a href="https://github.com/syndtr/goleveldb">syndtr/goleveldb</a>, Copyright &copy; 2012 Suryandaru Triandana.</li>
<li><a href="https://github.com/thejerf/suture">thejerf/suture</a>, Copyright &copy; 2014-2015 Barracuda Networks, Inc.</li>
<li><a href="https://github.com/vitrun/qart">vitrun/qart</a>, Copyright &copy; The Go Authors.</li>
<li><a href="https://golang.org">The Go Programming Language</a>, Copyright &copy; 2012 The Go Authors.</li>
<li><a href="https://github.com/urfave/cli">urfave/cli</a>, Copyright &copy; 2016 Jeremy Saenz &amp; Contributors.</li>
<li><a href="https://github.com/vitrun/qart">vitrun/qart</a>, Copyright &copy; 2010-2011 The Go Authors.</li>
<li><a href="https://gopkg.in/asn1-ber.v1">gopkg.in/asn1-ber.v1</a>, Copyright &copy; 2011-2015 Michael Mitton, portions Copyright &copy; 2015-2016 go-asn1-ber Authors.</li>
<li><a href="https://gopkg.in/ldap.v2">gopkg.in/ldap.v2</a>, Copyright &copy; 2011-2015 Michael Mitton, portions Copyright &copy; 2015-2016 go-ldap Authors.</li>
<li><a href="https://golang.org">The Go Programming Language</a>, Copyright &copy; 2009 The Go Authors.</li>
<li>Font Awesome by Dave Gandy - <a href="http://fontawesome.io/">http://fontawesome.io</a></li>
</ul>
</div>

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

@@ -9,7 +9,7 @@
<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>
<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">

View File

@@ -329,7 +329,7 @@ angular.module('syncthing.core')
});
$scope.$on(Events.FOLDER_ERRORS, function (event, arg) {
$scope.model[arg.data.folder].pullErrors = arg.data.errors.length;
$scope.model[arg.data.folder].errors = arg.data.errors.length;
});
$scope.$on(Events.FOLDER_SCAN_PROGRESS, function (event, arg) {
@@ -357,7 +357,7 @@ angular.module('syncthing.core')
recalcLocalStateTotal();
console.log("refreshFolder", folder, data);
}).error($scope.emitHTTPError);
}, 1000, true);
}, 1000);
}
debouncedFuncs[key]();
}
@@ -479,7 +479,7 @@ angular.module('syncthing.core')
$scope.completion[device]._needItems = 0;
} else {
$scope.completion[device]._total = Math.floor(100 * (1 - needed / total));
$scope.completion[device]._needBytes = needed
$scope.completion[device]._needBytes = needed;
$scope.completion[device]._needItems = items + deletes;
}
@@ -653,7 +653,7 @@ angular.module('syncthing.core')
};
$scope.refreshFailed = function (page, perpage) {
var url = urlbase + '/folder/pullerrors?folder=' + encodeURIComponent($scope.failed.folder);
var url = urlbase + '/folder/errors?folder=' + encodeURIComponent($scope.failed.folder);
url += "&page=" + page + "&perpage=" + perpage;
$http.get(url).success(function (data) {
$scope.failed = data;
@@ -676,7 +676,7 @@ angular.module('syncthing.core')
$scope.refreshLocalChanged = function (page, perpage) {
var url = urlbase + '/db/localchanged?folder=';
url += encodeURIComponent($scope.localChanged.folder);
url += encodeURIComponent($scope.localChangedFolder);
url += "&page=" + page + "&perpage=" + perpage;
$http.get(url).success(function (data) {
$scope.localChanged = data;
@@ -751,6 +751,9 @@ angular.module('syncthing.core')
if (state === 'idle' && $scope.model[folderCfg.id].needTotalItems > 0) {
return 'outofsync';
}
if ($scope.hasFailedFiles(folderCfg.id)) {
return 'faileditems';
}
if (state === 'scanning') {
return state;
}
@@ -777,7 +780,7 @@ angular.module('syncthing.core')
if (status === 'unknown') {
return 'info';
}
if (status === 'stopped' || status === 'outofsync' || status === 'error') {
if (status === 'stopped' || status === 'outofsync' || status === 'error' || status === 'faileditems') {
return 'danger';
}
if (status === 'unshared' || status === 'scan-waiting') {
@@ -1169,7 +1172,7 @@ angular.module('syncthing.core')
}
});
}
}
};
$scope.editSettings = function () {
// Make a working copy
@@ -1250,7 +1253,7 @@ angular.module('syncthing.core')
var ignoredFoldersEquals = angular.equals($scope.config.devices, $scope.tmpDevices);
console.log("settings equals - options: " + optionsEqual + " gui: " + guiEquals + " ignDev: " + ignoredDevicesEquals + " ignFol: " + ignoredFoldersEquals);
return !optionsEqual || !guiEquals || !ignoredDevicesEquals || !ignoredFoldersEquals;
}
};
$scope.saveSettings = function () {
// Make sure something changed
@@ -1531,7 +1534,7 @@ angular.module('syncthing.core')
$scope.thisDevice = function () {
return $scope.thisDeviceIn($scope.devices);
}
};
$scope.thisDeviceIn = function (l) {
for (var i = 0; i < l.length; i++) {
@@ -1570,7 +1573,7 @@ angular.module('syncthing.core')
}
});
return errs;
}
};
$scope.friendlyDevices = function (str) {
for (var i = 0; i < $scope.devices.length; i++) {
@@ -1885,7 +1888,7 @@ angular.module('syncthing.core')
}
var label = $scope.folders[folderID].label;
return label && label.length > 0 ? label : folderID;
}
};
$scope.deleteFolder = function (id) {
$('#editFolder').modal('hide');
@@ -2190,7 +2193,7 @@ angular.module('syncthing.core')
if (!$scope.model[folder]) {
return false;
}
return $scope.model[folder].pullErrors !== 0;
return $scope.model[folder].errors !== 0;
};
$scope.override = function (folder) {
@@ -2198,7 +2201,7 @@ angular.module('syncthing.core')
};
$scope.showLocalChanged = function (folder) {
$scope.localChanged.folder = folder;
$scope.localChangedFolder = folder;
$scope.localChanged = $scope.refreshLocalChanged(1, 10);
$('#localChanged').modal().one('hidden.bs.modal', function () {
$scope.localChanged = {};

View File

@@ -12,7 +12,7 @@
</table>
<dir-pagination-controls on-page-change="refreshFailed(newPageNumber, failed.perpage)" pagination-id="failed"></dir-pagination-controls>
<ul class="pagination pull-right">
<li ng-repeat="option in [10, 25, 50]" ng-class="{ active: failed.page == option }">
<li ng-repeat="option in [10, 25, 50]" ng-class="{ active: failed.perpage == option }">
<a href="#" ng-click="refreshFailed(failed.page, option)">{{option}}</a>
</li>
</ul>

View File

@@ -10,14 +10,14 @@
<th translate>Size</th>
</tr>
</thead>
<tr dir-paginate="file in localChanged.files | itemsPerPage: localChanged.perpage" current-page="localChanged.page" total-items="model[localChanged.folder].receiveOnlyTotalItems" pagination-id="localChanged">
<tr dir-paginate="file in localChanged.files | itemsPerPage: localChanged.perpage" current-page="localChanged.page" total-items="model[localChangedFolder].receiveOnlyTotalItems" pagination-id="localChanged">
<td>{{file.name}}</td>
<td><span ng-hide="file.type == 'DIRECTORY'">{{file.size | binary}}B</span></td>
</tr>
</table>
<dir-pagination-controls on-page-change="refreshLocalChanged(newPageNumber, localChanged.perpage)" pagination-id="localChanged"></dir-pagination-controls>
<ul class="pagination pull-right">
<li ng-repeat="option in [10, 25, 50]" ng-class="{ active: localChanged.page == option }">
<li ng-repeat="option in [10, 25, 50]" ng-class="{ active: localChanged.perpage == option }">
<a href="#" ng-click="refreshLocalChanged(localChanged.page, option)">{{option}}</a>
</li>
</ul>

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"bytes"
@@ -40,142 +40,104 @@ import (
"github.com/syncthing/syncthing/lib/model"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/stats"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/versioner"
"github.com/syncthing/syncthing/lib/ur"
"github.com/thejerf/suture"
"github.com/vitrun/qart/qr"
"golang.org/x/crypto/bcrypt"
)
var (
startTime = time.Now()
// matches a bcrypt hash and not too much else
bcryptExpr = regexp.MustCompile(`^\$2[aby]\$\d+\$.{50,}`)
)
// matches a bcrypt hash and not too much else
var bcryptExpr = regexp.MustCompile(`^\$2[aby]\$\d+\$.{50,}`)
const (
defaultEventMask = events.AllEvents &^ events.LocalChangeDetected &^ events.RemoteChangeDetected
diskEventMask = events.LocalChangeDetected | events.RemoteChangeDetected
eventSubBufferSize = 1000
DefaultEventMask = events.AllEvents &^ events.LocalChangeDetected &^ events.RemoteChangeDetected
DiskEventMask = events.LocalChangeDetected | events.RemoteChangeDetected
EventSubBufferSize = 1000
defaultEventTimeout = time.Minute
)
type apiService struct {
id protocol.DeviceID
cfg configIntf
httpsCertFile string
httpsKeyFile string
statics *staticsServer
model modelIntf
eventSubs map[events.EventType]events.BufferedSubscription
eventSubsMut sync.Mutex
discoverer discover.CachingMux
connectionsService connectionsIntf
fss *folderSummaryService
systemConfigMut sync.Mutex // serializes posts to /rest/system/config
stop chan struct{} // signals intentional stop
configChanged chan struct{} // signals intentional listener close due to config change
started chan string // signals startup complete by sending the listener address, for testing only
startedOnce chan struct{} // the service has started successfully at least once
cpu rater
type service struct {
id protocol.DeviceID
cfg config.Wrapper
statics *staticsServer
model model.Model
eventSubs map[events.EventType]events.BufferedSubscription
eventSubsMut sync.Mutex
discoverer discover.CachingMux
connectionsService connections.Service
fss model.FolderSummaryService
urService *ur.Service
systemConfigMut sync.Mutex // serializes posts to /rest/system/config
cpu Rater
contr Controller
noUpgrade bool
tlsDefaultCommonName string
stop chan struct{} // signals intentional stop
configChanged chan struct{} // signals intentional listener close due to config change
started chan string // signals startup complete by sending the listener address, for testing only
startedOnce chan struct{} // the service has started successfully at least once
startupErr error
guiErrors logger.Recorder
systemLog logger.Recorder
}
type modelIntf interface {
GlobalDirectoryTree(folder, prefix string, levels int, dirsonly bool) map[string]interface{}
Completion(device protocol.DeviceID, folder string) model.FolderCompletion
Override(folder string)
Revert(folder string)
NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated)
RemoteNeedFolderFiles(device protocol.DeviceID, folder string, page, perpage int) ([]db.FileInfoTruncated, error)
LocalChangedFiles(folder string, page, perpage int) []db.FileInfoTruncated
NeedSize(folder string) db.Counts
ConnectionStats() map[string]interface{}
DeviceStatistics() map[string]stats.DeviceStatistics
FolderStatistics() map[string]stats.FolderStatistics
CurrentFolderFile(folder string, file string) (protocol.FileInfo, bool)
CurrentGlobalFile(folder string, file string) (protocol.FileInfo, bool)
ResetFolder(folder string)
Availability(folder string, file protocol.FileInfo, block protocol.BlockInfo) []model.Availability
GetIgnores(folder string) ([]string, []string, error)
GetFolderVersions(folder string) (map[string][]versioner.FileVersion, error)
RestoreFolderVersions(folder string, versions map[string]time.Time) (map[string]string, error)
SetIgnores(folder string, content []string) error
DelayScan(folder string, next time.Duration)
ScanFolder(folder string) error
ScanFolders() map[string]error
ScanFolderSubdirs(folder string, subs []string) error
BringToFront(folder, file string)
Connection(deviceID protocol.DeviceID) (connections.Connection, bool)
GlobalSize(folder string) db.Counts
LocalSize(folder string) db.Counts
ReceiveOnlyChangedSize(folder string) db.Counts
CurrentSequence(folder string) (int64, bool)
RemoteSequence(folder string) (int64, bool)
State(folder string) (string, time.Time, error)
UsageReportingStats(version int, preview bool) map[string]interface{}
FolderErrors(folder string) ([]model.FileError, error)
WatchError(folder string) error
}
type configIntf interface {
GUI() config.GUIConfiguration
LDAP() config.LDAPConfiguration
RawCopy() config.Configuration
Options() config.OptionsConfiguration
Replace(cfg config.Configuration) (config.Waiter, error)
Subscribe(c config.Committer)
Folders() map[string]config.FolderConfiguration
Devices() map[protocol.DeviceID]config.DeviceConfiguration
SetDevice(config.DeviceConfiguration) (config.Waiter, error)
SetDevices([]config.DeviceConfiguration) (config.Waiter, error)
Save() error
ListenAddresses() []string
RequiresRestart() bool
}
type connectionsIntf interface {
Status() map[string]interface{}
NATType() string
}
type rater interface {
type Rater interface {
Rate() float64
}
func newAPIService(id protocol.DeviceID, cfg configIntf, httpsCertFile, httpsKeyFile, assetDir string, m modelIntf, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connectionsIntf, errors, systemLog logger.Recorder, cpu rater) *apiService {
service := &apiService{
id: id,
cfg: cfg,
httpsCertFile: httpsCertFile,
httpsKeyFile: httpsKeyFile,
statics: newStaticsServer(cfg.GUI().Theme, assetDir),
model: m,
eventSubs: map[events.EventType]events.BufferedSubscription{
defaultEventMask: defaultSub,
diskEventMask: diskSub,
},
eventSubsMut: sync.NewMutex(),
discoverer: discoverer,
connectionsService: connectionsService,
systemConfigMut: sync.NewMutex(),
stop: make(chan struct{}),
configChanged: make(chan struct{}),
startedOnce: make(chan struct{}),
guiErrors: errors,
systemLog: systemLog,
cpu: cpu,
}
return service
type Controller interface {
ExitUpgrading()
Restart()
Shutdown()
}
func (s *apiService) getListener(guiCfg config.GUIConfiguration) (net.Listener, error) {
cert, err := tls.LoadX509KeyPair(s.httpsCertFile, s.httpsKeyFile)
type Service interface {
suture.Service
config.Committer
WaitForStart() error
}
func New(id protocol.DeviceID, cfg config.Wrapper, assetDir, tlsDefaultCommonName string, m model.Model, defaultSub, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connections.Service, urService *ur.Service, fss model.FolderSummaryService, errors, systemLog logger.Recorder, cpu Rater, contr Controller, noUpgrade bool) Service {
return &service{
id: id,
cfg: cfg,
statics: newStaticsServer(cfg.GUI().Theme, assetDir),
model: m,
eventSubs: map[events.EventType]events.BufferedSubscription{
DefaultEventMask: defaultSub,
DiskEventMask: diskSub,
},
eventSubsMut: sync.NewMutex(),
discoverer: discoverer,
connectionsService: connectionsService,
fss: fss,
urService: urService,
systemConfigMut: sync.NewMutex(),
guiErrors: errors,
systemLog: systemLog,
cpu: cpu,
contr: contr,
noUpgrade: noUpgrade,
tlsDefaultCommonName: tlsDefaultCommonName,
stop: make(chan struct{}),
configChanged: make(chan struct{}),
startedOnce: make(chan struct{}),
}
}
func (s *service) WaitForStart() error {
<-s.startedOnce
return s.startupErr
}
func (s *service) getListener(guiCfg config.GUIConfiguration) (net.Listener, error) {
httpsCertFile := locations.Get(locations.HTTPSCertFile)
httpsKeyFile := locations.Get(locations.HTTPSKeyFile)
cert, err := tls.LoadX509KeyPair(httpsCertFile, httpsKeyFile)
if err != nil {
l.Infoln("Loading HTTPS certificate:", err)
l.Infoln("Creating new HTTPS certificate")
@@ -185,10 +147,10 @@ func (s *apiService) getListener(guiCfg config.GUIConfiguration) (net.Listener,
var name string
name, err = os.Hostname()
if err != nil {
name = tlsDefaultCommonName
name = s.tlsDefaultCommonName
}
cert, err = tlsutil.NewCertificate(s.httpsCertFile, s.httpsKeyFile, name)
cert, err = tlsutil.NewCertificate(httpsCertFile, httpsKeyFile, name)
}
if err != nil {
return nil, err
@@ -228,7 +190,7 @@ func sendJSON(w http.ResponseWriter, jsonObject interface{}) {
fmt.Fprintf(w, "%s\n", bs)
}
func (s *apiService) Serve() {
func (s *service) Serve() {
listener, err := s.getListener(s.cfg.GUI())
if err != nil {
select {
@@ -236,14 +198,15 @@ func (s *apiService) Serve() {
// We let this be a loud user-visible warning as it may be the only
// indication they get that the GUI won't be available.
l.Warnln("Starting API/GUI:", err)
return
default:
// This is during initialization. A failure here should be fatal
// as there will be no way for the user to communicate with us
// otherwise anyway.
l.Fatalln("Starting API/GUI:", err)
s.startupErr = err
close(s.startedOnce)
}
return
}
if listener == nil {
@@ -254,6 +217,9 @@ func (s *apiService) Serve() {
defer listener.Close()
s.cfg.Subscribe(s)
defer s.cfg.Unsubscribe(s)
// The GET handlers
getRestMux := http.NewServeMux()
getRestMux.HandleFunc("/rest/db/completion", s.getDBCompletion) // device folder
@@ -369,10 +335,6 @@ func (s *apiService) Serve() {
ReadTimeout: 15 * time.Second,
}
s.fss = newFolderSummaryService(s.cfg, s.model)
defer s.fss.Stop()
s.fss.ServeBackground()
l.Infoln("GUI and API listening on", listener.Addr())
l.Infoln("Access the GUI via the following URL:", guiCfg.URL())
if s.started != nil {
@@ -410,15 +372,28 @@ func (s *apiService) Serve() {
}
}
func (s *apiService) Stop() {
// Complete implements suture.IsCompletable, which signifies to the supervisor
// whether to stop restarting the service.
func (s *service) Complete() bool {
select {
case <-s.startedOnce:
return s.startupErr != nil
case <-s.stop:
return true
default:
}
return false
}
func (s *service) Stop() {
close(s.stop)
}
func (s *apiService) String() string {
return fmt.Sprintf("apiService@%p", s)
func (s *service) String() string {
return fmt.Sprintf("api.service@%p", s)
}
func (s *apiService) VerifyConfiguration(from, to config.Configuration) error {
func (s *service) VerifyConfiguration(from, to config.Configuration) error {
if to.GUI.Network() != "tcp" {
return nil
}
@@ -426,7 +401,7 @@ func (s *apiService) VerifyConfiguration(from, to config.Configuration) error {
return err
}
func (s *apiService) CommitConfiguration(from, to config.Configuration) bool {
func (s *service) CommitConfiguration(from, to config.Configuration) bool {
// No action required when this changes, so mask the fact that it changed at all.
from.GUI.Debugging = to.GUI.Debugging
@@ -478,7 +453,7 @@ func debugMiddleware(h http.Handler) http.Handler {
written = rf.Int()
}
}
httpl.Debugf("http: %s %q: status %d, %d bytes in %.02f ms", r.Method, r.URL.String(), status, written, ms)
l.Debugf("http: %s %q: status %d, %d bytes in %.02f ms", r.Method, r.URL.String(), status, written, ms)
}
})
}
@@ -586,7 +561,7 @@ func localhostMiddleware(h http.Handler) http.Handler {
})
}
func (s *apiService) whenDebugging(h http.Handler) http.Handler {
func (s *service) whenDebugging(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if s.cfg.GUI().Debugging {
h.ServeHTTP(w, r)
@@ -597,11 +572,11 @@ func (s *apiService) whenDebugging(h http.Handler) http.Handler {
})
}
func (s *apiService) restPing(w http.ResponseWriter, r *http.Request) {
func (s *service) restPing(w http.ResponseWriter, r *http.Request) {
sendJSON(w, map[string]string{"ping": "pong"})
}
func (s *apiService) getJSMetadata(w http.ResponseWriter, r *http.Request) {
func (s *service) getJSMetadata(w http.ResponseWriter, r *http.Request) {
meta, _ := json.Marshal(map[string]string{
"deviceID": s.id.String(),
})
@@ -609,7 +584,7 @@ func (s *apiService) getJSMetadata(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "var metadata = %s;\n", meta)
}
func (s *apiService) getSystemVersion(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemVersion(w http.ResponseWriter, r *http.Request) {
sendJSON(w, map[string]interface{}{
"version": build.Version,
"codename": build.Codename,
@@ -622,7 +597,7 @@ func (s *apiService) getSystemVersion(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) getSystemDebug(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemDebug(w http.ResponseWriter, r *http.Request) {
names := l.Facilities()
enabled := l.FacilityDebugging()
sort.Strings(enabled)
@@ -632,7 +607,7 @@ func (s *apiService) getSystemDebug(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) postSystemDebug(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemDebug(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
q := r.URL.Query()
for _, f := range strings.Split(q.Get("enable"), ",") {
@@ -651,7 +626,7 @@ func (s *apiService) postSystemDebug(w http.ResponseWriter, r *http.Request) {
}
}
func (s *apiService) getDBBrowse(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBBrowse(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
prefix := qs.Get("prefix")
@@ -665,7 +640,7 @@ func (s *apiService) getDBBrowse(w http.ResponseWriter, r *http.Request) {
sendJSON(w, s.model.GlobalDirectoryTree(folder, prefix, levels, dirsonly))
}
func (s *apiService) getDBCompletion(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBCompletion(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var folder = qs.Get("folder")
var deviceStr = qs.Get("device")
@@ -676,100 +651,26 @@ func (s *apiService) getDBCompletion(w http.ResponseWriter, r *http.Request) {
return
}
sendJSON(w, jsonCompletion(s.model.Completion(device, folder)))
sendJSON(w, s.model.Completion(device, folder).Map())
}
func jsonCompletion(comp model.FolderCompletion) map[string]interface{} {
return map[string]interface{}{
"completion": comp.CompletionPct,
"needBytes": comp.NeedBytes,
"needItems": comp.NeedItems,
"globalBytes": comp.GlobalBytes,
"needDeletes": comp.NeedDeletes,
}
}
func (s *apiService) getDBStatus(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBStatus(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
if sum, err := folderSummary(s.cfg, s.model, folder); err != nil {
if sum, err := s.fss.Summary(folder); err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
} else {
sendJSON(w, sum)
}
}
func folderSummary(cfg configIntf, m modelIntf, folder string) (map[string]interface{}, error) {
var res = make(map[string]interface{})
errors, err := m.FolderErrors(folder)
if err != nil && err != model.ErrFolderPaused {
// Stats from the db can still be obtained if the folder is just paused
return nil, err
}
res["errors"] = len(errors)
res["pullErrors"] = len(errors) // deprecated
res["invalid"] = "" // Deprecated, retains external API for now
global := m.GlobalSize(folder)
res["globalFiles"], res["globalDirectories"], res["globalSymlinks"], res["globalDeleted"], res["globalBytes"], res["globalTotalItems"] = global.Files, global.Directories, global.Symlinks, global.Deleted, global.Bytes, global.TotalItems()
local := m.LocalSize(folder)
res["localFiles"], res["localDirectories"], res["localSymlinks"], res["localDeleted"], res["localBytes"], res["localTotalItems"] = local.Files, local.Directories, local.Symlinks, local.Deleted, local.Bytes, local.TotalItems()
need := m.NeedSize(folder)
res["needFiles"], res["needDirectories"], res["needSymlinks"], res["needDeletes"], res["needBytes"], res["needTotalItems"] = need.Files, need.Directories, need.Symlinks, need.Deleted, need.Bytes, need.TotalItems()
if cfg.Folders()[folder].Type == config.FolderTypeReceiveOnly {
// Add statistics for things that have changed locally in a receive
// only folder.
ro := m.ReceiveOnlyChangedSize(folder)
res["receiveOnlyChangedFiles"] = ro.Files
res["receiveOnlyChangedDirectories"] = ro.Directories
res["receiveOnlyChangedSymlinks"] = ro.Symlinks
res["receiveOnlyChangedDeletes"] = ro.Deleted
res["receiveOnlyChangedBytes"] = ro.Bytes
res["receiveOnlyTotalItems"] = ro.TotalItems()
}
res["inSyncFiles"], res["inSyncBytes"] = global.Files-need.Files, global.Bytes-need.Bytes
res["state"], res["stateChanged"], err = m.State(folder)
if err != nil {
res["error"] = err.Error()
}
ourSeq, _ := m.CurrentSequence(folder)
remoteSeq, _ := m.RemoteSequence(folder)
res["version"] = ourSeq + remoteSeq // legacy
res["sequence"] = ourSeq + remoteSeq // new name
ignorePatterns, _, _ := m.GetIgnores(folder)
res["ignorePatterns"] = false
for _, line := range ignorePatterns {
if len(line) > 0 && !strings.HasPrefix(line, "//") {
res["ignorePatterns"] = true
break
}
}
err = m.WatchError(folder)
if err != nil {
res["watchError"] = err.Error()
}
return res, nil
}
func (s *apiService) postDBOverride(w http.ResponseWriter, r *http.Request) {
func (s *service) postDBOverride(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var folder = qs.Get("folder")
go s.model.Override(folder)
}
func (s *apiService) postDBRevert(w http.ResponseWriter, r *http.Request) {
func (s *service) postDBRevert(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var folder = qs.Get("folder")
go s.model.Revert(folder)
@@ -787,7 +688,7 @@ func getPagingParams(qs url.Values) (int, int) {
return page, perpage
}
func (s *apiService) getDBNeed(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBNeed(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
@@ -806,7 +707,7 @@ func (s *apiService) getDBNeed(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) getDBRemoteNeed(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBRemoteNeed(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
@@ -830,7 +731,7 @@ func (s *apiService) getDBRemoteNeed(w http.ResponseWriter, r *http.Request) {
}
}
func (s *apiService) getDBLocalChanged(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBLocalChanged(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
@@ -846,19 +747,19 @@ func (s *apiService) getDBLocalChanged(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) getSystemConnections(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemConnections(w http.ResponseWriter, r *http.Request) {
sendJSON(w, s.model.ConnectionStats())
}
func (s *apiService) getDeviceStats(w http.ResponseWriter, r *http.Request) {
func (s *service) getDeviceStats(w http.ResponseWriter, r *http.Request) {
sendJSON(w, s.model.DeviceStatistics())
}
func (s *apiService) getFolderStats(w http.ResponseWriter, r *http.Request) {
func (s *service) getFolderStats(w http.ResponseWriter, r *http.Request) {
sendJSON(w, s.model.FolderStatistics())
}
func (s *apiService) getDBFile(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBFile(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
file := qs.Get("file")
@@ -879,15 +780,15 @@ func (s *apiService) getDBFile(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) getSystemConfig(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemConfig(w http.ResponseWriter, r *http.Request) {
sendJSON(w, s.cfg.RawCopy())
}
func (s *apiService) postSystemConfig(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemConfig(w http.ResponseWriter, r *http.Request) {
s.systemConfigMut.Lock()
defer s.systemConfigMut.Unlock()
to, err := config.ReadJSON(r.Body, myID)
to, err := config.ReadJSON(r.Body, s.id)
r.Body.Close()
if err != nil {
l.Warnln("Decoding posted config:", err)
@@ -926,16 +827,16 @@ func (s *apiService) postSystemConfig(w http.ResponseWriter, r *http.Request) {
}
}
func (s *apiService) getSystemConfigInsync(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemConfigInsync(w http.ResponseWriter, r *http.Request) {
sendJSON(w, map[string]bool{"configInSync": !s.cfg.RequiresRestart()})
}
func (s *apiService) postSystemRestart(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemRestart(w http.ResponseWriter, r *http.Request) {
s.flushResponse(`{"ok": "restarting"}`, w)
go restart()
go s.contr.Restart()
}
func (s *apiService) postSystemReset(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemReset(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
folder := qs.Get("folder")
@@ -958,27 +859,27 @@ func (s *apiService) postSystemReset(w http.ResponseWriter, r *http.Request) {
s.flushResponse(`{"ok": "resetting folder `+folder+`"}`, w)
}
go restart()
go s.contr.Restart()
}
func (s *apiService) postSystemShutdown(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemShutdown(w http.ResponseWriter, r *http.Request) {
s.flushResponse(`{"ok": "shutting down"}`, w)
go shutdown()
go s.contr.Shutdown()
}
func (s *apiService) flushResponse(resp string, w http.ResponseWriter) {
func (s *service) flushResponse(resp string, w http.ResponseWriter) {
w.Write([]byte(resp + "\n"))
f := w.(http.Flusher)
f.Flush()
}
func (s *apiService) getSystemStatus(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemStatus(w http.ResponseWriter, r *http.Request) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
tilde, _ := fs.ExpandTilde("~")
res := make(map[string]interface{})
res["myID"] = myID.String()
res["myID"] = s.id.String()
res["goroutines"] = runtime.NumGoroutine()
res["alloc"] = m.Alloc
res["sys"] = m.Sys - m.HeapReleased
@@ -1002,31 +903,31 @@ func (s *apiService) getSystemStatus(w http.ResponseWriter, r *http.Request) {
// gives us percent
res["cpuPercent"] = s.cpu.Rate() / 10 / float64(runtime.NumCPU())
res["pathSeparator"] = string(filepath.Separator)
res["urVersionMax"] = usageReportVersion
res["uptime"] = int(time.Since(startTime).Seconds())
res["startTime"] = startTime
res["urVersionMax"] = ur.Version
res["uptime"] = s.urService.UptimeS()
res["startTime"] = ur.StartTime
res["guiAddressOverridden"] = s.cfg.GUI().IsOverridden()
sendJSON(w, res)
}
func (s *apiService) getSystemError(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemError(w http.ResponseWriter, r *http.Request) {
sendJSON(w, map[string][]logger.Line{
"errors": s.guiErrors.Since(time.Time{}),
})
}
func (s *apiService) postSystemError(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemError(w http.ResponseWriter, r *http.Request) {
bs, _ := ioutil.ReadAll(r.Body)
r.Body.Close()
l.Warnln(string(bs))
}
func (s *apiService) postSystemErrorClear(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemErrorClear(w http.ResponseWriter, r *http.Request) {
s.guiErrors.Clear()
}
func (s *apiService) getSystemLog(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemLog(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
since, err := time.Parse(time.RFC3339, q.Get("since"))
if err != nil {
@@ -1037,7 +938,7 @@ func (s *apiService) getSystemLog(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) getSystemLogTxt(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemLogTxt(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
since, err := time.Parse(time.RFC3339, q.Get("since"))
if err != nil {
@@ -1055,7 +956,7 @@ type fileEntry struct {
data []byte
}
func (s *apiService) getSupportBundle(w http.ResponseWriter, r *http.Request) {
func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
var files []fileEntry
// Redacted configuration as a JSON
@@ -1112,7 +1013,7 @@ func (s *apiService) getSupportBundle(w http.ResponseWriter, r *http.Request) {
}
// Report Data as a JSON
if usageReportingData, err := json.MarshalIndent(reportData(s.cfg, s.model, s.connectionsService, usageReportVersion, true), "", " "); err != nil {
if usageReportingData, err := json.MarshalIndent(s.urService.ReportData(), "", " "); err != nil {
l.Warnln("Support bundle: failed to create versionPlatform.json:", err)
} else {
files = append(files, fileEntry{name: "usage-reporting.json.txt", data: usageReportingData})
@@ -1157,7 +1058,7 @@ func (s *apiService) getSupportBundle(w http.ResponseWriter, r *http.Request) {
io.Copy(w, &zipFilesBuffer)
}
func (s *apiService) getSystemHTTPMetrics(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemHTTPMetrics(w http.ResponseWriter, r *http.Request) {
stats := make(map[string]interface{})
metrics.Each(func(name string, intf interface{}) {
if m, ok := intf.(*metrics.StandardTimer); ok {
@@ -1177,7 +1078,7 @@ func (s *apiService) getSystemHTTPMetrics(w http.ResponseWriter, r *http.Request
w.Write(bs)
}
func (s *apiService) getSystemDiscovery(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemDiscovery(w http.ResponseWriter, r *http.Request) {
devices := make(map[string]discover.CacheEntry)
if s.discoverer != nil {
@@ -1192,15 +1093,15 @@ func (s *apiService) getSystemDiscovery(w http.ResponseWriter, r *http.Request)
sendJSON(w, devices)
}
func (s *apiService) getReport(w http.ResponseWriter, r *http.Request) {
version := usageReportVersion
func (s *service) getReport(w http.ResponseWriter, r *http.Request) {
version := ur.Version
if val, _ := strconv.Atoi(r.URL.Query().Get("version")); val > 0 {
version = val
}
sendJSON(w, reportData(s.cfg, s.model, s.connectionsService, version, true))
sendJSON(w, s.urService.ReportDataPreview(version))
}
func (s *apiService) getRandomString(w http.ResponseWriter, r *http.Request) {
func (s *service) getRandomString(w http.ResponseWriter, r *http.Request) {
length := 32
if val, _ := strconv.Atoi(r.URL.Query().Get("length")); val > 0 {
length = val
@@ -1210,7 +1111,7 @@ func (s *apiService) getRandomString(w http.ResponseWriter, r *http.Request) {
sendJSON(w, map[string]string{"random": str})
}
func (s *apiService) getDBIgnores(w http.ResponseWriter, r *http.Request) {
func (s *service) getDBIgnores(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
@@ -1227,7 +1128,7 @@ func (s *apiService) getDBIgnores(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) postDBIgnores(w http.ResponseWriter, r *http.Request) {
func (s *service) postDBIgnores(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
bs, err := ioutil.ReadAll(r.Body)
@@ -1253,19 +1154,19 @@ func (s *apiService) postDBIgnores(w http.ResponseWriter, r *http.Request) {
s.getDBIgnores(w, r)
}
func (s *apiService) getIndexEvents(w http.ResponseWriter, r *http.Request) {
s.fss.gotEventRequest()
func (s *service) getIndexEvents(w http.ResponseWriter, r *http.Request) {
s.fss.OnEventRequest()
mask := s.getEventMask(r.URL.Query().Get("events"))
sub := s.getEventSub(mask)
s.getEvents(w, r, sub)
}
func (s *apiService) getDiskEvents(w http.ResponseWriter, r *http.Request) {
sub := s.getEventSub(diskEventMask)
func (s *service) getDiskEvents(w http.ResponseWriter, r *http.Request) {
sub := s.getEventSub(DiskEventMask)
s.getEvents(w, r, sub)
}
func (s *apiService) getEvents(w http.ResponseWriter, r *http.Request, eventSub events.BufferedSubscription) {
func (s *service) getEvents(w http.ResponseWriter, r *http.Request, eventSub events.BufferedSubscription) {
qs := r.URL.Query()
sinceStr := qs.Get("since")
limitStr := qs.Get("limit")
@@ -1294,8 +1195,8 @@ func (s *apiService) getEvents(w http.ResponseWriter, r *http.Request, eventSub
sendJSON(w, evs)
}
func (s *apiService) getEventMask(evs string) events.EventType {
eventMask := defaultEventMask
func (s *service) getEventMask(evs string) events.EventType {
eventMask := DefaultEventMask
if evs != "" {
eventList := strings.Split(evs, ",")
eventMask = 0
@@ -1306,12 +1207,12 @@ func (s *apiService) getEventMask(evs string) events.EventType {
return eventMask
}
func (s *apiService) getEventSub(mask events.EventType) events.BufferedSubscription {
func (s *service) getEventSub(mask events.EventType) events.BufferedSubscription {
s.eventSubsMut.Lock()
bufsub, ok := s.eventSubs[mask]
if !ok {
evsub := events.Default.Subscribe(mask)
bufsub = events.NewBufferedSubscription(evsub, eventSubBufferSize)
bufsub = events.NewBufferedSubscription(evsub, EventSubBufferSize)
s.eventSubs[mask] = bufsub
}
s.eventSubsMut.Unlock()
@@ -1319,8 +1220,8 @@ func (s *apiService) getEventSub(mask events.EventType) events.BufferedSubscript
return bufsub
}
func (s *apiService) getSystemUpgrade(w http.ResponseWriter, r *http.Request) {
if noUpgradeFromEnv {
func (s *service) getSystemUpgrade(w http.ResponseWriter, r *http.Request) {
if s.noUpgrade {
http.Error(w, upgrade.ErrUpgradeUnsupported.Error(), 500)
return
}
@@ -1339,7 +1240,7 @@ func (s *apiService) getSystemUpgrade(w http.ResponseWriter, r *http.Request) {
sendJSON(w, res)
}
func (s *apiService) getDeviceID(w http.ResponseWriter, r *http.Request) {
func (s *service) getDeviceID(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
idStr := qs.Get("id")
id, err := protocol.DeviceIDFromString(idStr)
@@ -1355,7 +1256,7 @@ func (s *apiService) getDeviceID(w http.ResponseWriter, r *http.Request) {
}
}
func (s *apiService) getLang(w http.ResponseWriter, r *http.Request) {
func (s *service) getLang(w http.ResponseWriter, r *http.Request) {
lang := r.Header.Get("Accept-Language")
var langs []string
for _, l := range strings.Split(lang, ",") {
@@ -1365,7 +1266,7 @@ func (s *apiService) getLang(w http.ResponseWriter, r *http.Request) {
sendJSON(w, langs)
}
func (s *apiService) postSystemUpgrade(w http.ResponseWriter, r *http.Request) {
func (s *service) postSystemUpgrade(w http.ResponseWriter, r *http.Request) {
opts := s.cfg.Options()
rel, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
if err != nil {
@@ -1383,12 +1284,11 @@ func (s *apiService) postSystemUpgrade(w http.ResponseWriter, r *http.Request) {
}
s.flushResponse(`{"ok": "restarting"}`, w)
l.Infoln("Upgrading")
stop <- exitUpgrading
s.contr.ExitUpgrading()
}
}
func (s *apiService) makeDevicePauseHandler(paused bool) http.HandlerFunc {
func (s *service) makeDevicePauseHandler(paused bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var deviceStr = qs.Get("device")
@@ -1423,7 +1323,7 @@ func (s *apiService) makeDevicePauseHandler(paused bool) http.HandlerFunc {
}
}
func (s *apiService) postDBScan(w http.ResponseWriter, r *http.Request) {
func (s *service) postDBScan(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
if folder != "" {
@@ -1448,7 +1348,7 @@ func (s *apiService) postDBScan(w http.ResponseWriter, r *http.Request) {
}
}
func (s *apiService) postDBPrio(w http.ResponseWriter, r *http.Request) {
func (s *service) postDBPrio(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
file := qs.Get("file")
@@ -1456,7 +1356,7 @@ func (s *apiService) postDBPrio(w http.ResponseWriter, r *http.Request) {
s.getDBNeed(w, r)
}
func (s *apiService) getQR(w http.ResponseWriter, r *http.Request) {
func (s *service) getQR(w http.ResponseWriter, r *http.Request) {
var qs = r.URL.Query()
var text = qs.Get("text")
code, err := qr.Encode(text, qr.M)
@@ -1469,7 +1369,7 @@ func (s *apiService) getQR(w http.ResponseWriter, r *http.Request) {
w.Write(code.PNG())
}
func (s *apiService) getPeerCompletion(w http.ResponseWriter, r *http.Request) {
func (s *service) getPeerCompletion(w http.ResponseWriter, r *http.Request) {
tot := map[string]float64{}
count := map[string]float64{}
@@ -1493,7 +1393,7 @@ func (s *apiService) getPeerCompletion(w http.ResponseWriter, r *http.Request) {
sendJSON(w, comp)
}
func (s *apiService) getFolderVersions(w http.ResponseWriter, r *http.Request) {
func (s *service) getFolderVersions(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
versions, err := s.model.GetFolderVersions(qs.Get("folder"))
if err != nil {
@@ -1503,7 +1403,7 @@ func (s *apiService) getFolderVersions(w http.ResponseWriter, r *http.Request) {
sendJSON(w, versions)
}
func (s *apiService) postFolderVersionsRestore(w http.ResponseWriter, r *http.Request) {
func (s *service) postFolderVersionsRestore(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
bs, err := ioutil.ReadAll(r.Body)
@@ -1528,7 +1428,7 @@ func (s *apiService) postFolderVersionsRestore(w http.ResponseWriter, r *http.Re
sendJSON(w, ferr)
}
func (s *apiService) getFolderErrors(w http.ResponseWriter, r *http.Request) {
func (s *service) getFolderErrors(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
folder := qs.Get("folder")
page, perpage := getPagingParams(qs)
@@ -1558,7 +1458,7 @@ func (s *apiService) getFolderErrors(w http.ResponseWriter, r *http.Request) {
})
}
func (s *apiService) getSystemBrowse(w http.ResponseWriter, r *http.Request) {
func (s *service) getSystemBrowse(w http.ResponseWriter, r *http.Request) {
qs := r.URL.Query()
current := qs.Get("current")
@@ -1637,7 +1537,7 @@ func browseFiles(current string, fsType fs.FilesystemType) []string {
return append(exactMatches, caseInsMatches...)
}
func (s *apiService) getCPUProf(w http.ResponseWriter, r *http.Request) {
func (s *service) getCPUProf(w http.ResponseWriter, r *http.Request) {
duration, err := time.ParseDuration(r.FormValue("duration"))
if err != nil {
duration = 30 * time.Second
@@ -1654,7 +1554,7 @@ func (s *apiService) getCPUProf(w http.ResponseWriter, r *http.Request) {
}
}
func (s *apiService) getHeapProf(w http.ResponseWriter, r *http.Request) {
func (s *service) getHeapProf(w http.ResponseWriter, r *http.Request) {
filename := fmt.Sprintf("syncthing-heap-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
w.Header().Set("Content-Type", "application/octet-stream")

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"bytes"
@@ -53,7 +53,7 @@ func basicAuthAndSessionMiddleware(cookieName string, guiCfg config.GUIConfigura
}
}
httpl.Debugln("Sessionless HTTP request with authentication; this is expensive.")
l.Debugln("Sessionless HTTP request with authentication; this is expensive.")
error := func() {
time.Sleep(time.Duration(rand.Intn(100)+100) * time.Millisecond)

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"testing"

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"bufio"
@@ -57,7 +57,7 @@ func csrfMiddleware(unique string, prefix string, cfg config.GUIConfiguration, n
if !strings.HasPrefix(r.URL.Path, prefix) {
cookie, err := r.Cookie("CSRF-Token-" + unique)
if err != nil || !validCsrfToken(cookie.Value) {
httpl.Debugln("new CSRF cookie in response to request for", r.URL)
l.Debugln("new CSRF cookie in response to request for", r.URL)
cookie = &http.Cookie{
Name: "CSRF-Token-" + unique,
Value: newCsrfToken(),

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"bytes"

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"bytes"
@@ -27,12 +27,40 @@ import (
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/model"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/ur"
"github.com/thejerf/suture"
)
var (
confDir = filepath.Join("testdata", "config")
token = filepath.Join(confDir, "csrftokens.txt")
)
func TestMain(m *testing.M) {
orig := locations.GetBaseDir(locations.ConfigBaseDir)
locations.SetBaseDir(locations.ConfigBaseDir, confDir)
exitCode := m.Run()
locations.SetBaseDir(locations.ConfigBaseDir, orig)
os.Exit(exitCode)
}
func TestCSRFToken(t *testing.T) {
defer os.Remove(token)
max := 250
int := 5
if testing.Short() {
max = 20
int = 2
}
t1 := newCsrfToken()
t2 := newCsrfToken()
@@ -41,8 +69,8 @@ func TestCSRFToken(t *testing.T) {
t.Fatal("t3 should be valid")
}
for i := 0; i < 250; i++ {
if i%5 == 0 {
for i := 0; i < max; i++ {
if i%int == 0 {
// t1 and t2 should remain valid by virtue of us checking them now
// and then.
if !validCsrfToken(t1) {
@@ -74,7 +102,8 @@ func TestStopAfterBrokenConfig(t *testing.T) {
}
w := config.Wrap("/dev/null", cfg)
srv := newAPIService(protocol.LocalDeviceID, w, "../../test/h1/https-cert.pem", "../../test/h1/https-key.pem", "", nil, nil, nil, nil, nil, nil, nil, nil)
srv := New(protocol.LocalDeviceID, w, "", "syncthing", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false).(*service)
defer os.Remove(token)
srv.started = make(chan string)
sup := suture.New("test", suture.Spec{
@@ -180,7 +209,7 @@ func expectURLToContain(t *testing.T, url, exp string) {
func TestDirNames(t *testing.T) {
names := dirNames("testdata")
expected := []string{"default", "foo", "testfolder"}
expected := []string{"config", "default", "foo", "testfolder"}
if diff, equal := messagediff.PrettyDiff(expected, names); !equal {
t.Errorf("Unexpected dirNames return: %#v\n%s", names, diff)
}
@@ -470,9 +499,7 @@ func TestHTTPLogin(t *testing.T) {
}
func startHTTP(cfg *mockedConfig) (string, error) {
model := new(mockedModel)
httpsCertFile := "../../test/h1/https-cert.pem"
httpsKeyFile := "../../test/h1/https-key.pem"
m := new(mockedModel)
assetDir := "../../gui"
eventSub := new(mockedEventSub)
diskEventSub := new(mockedEventSub)
@@ -484,8 +511,10 @@ func startHTTP(cfg *mockedConfig) (string, error) {
addrChan := make(chan string)
// Instantiate the API service
svc := newAPIService(protocol.LocalDeviceID, cfg, httpsCertFile, httpsKeyFile, assetDir, model,
eventSub, diskEventSub, discoverer, connections, errorLog, systemLog, cpu)
urService := ur.New(cfg, m, connections, false)
summaryService := model.NewFolderSummaryService(cfg, m, protocol.LocalDeviceID)
svc := New(protocol.LocalDeviceID, cfg, assetDir, "syncthing", m, eventSub, diskEventSub, discoverer, connections, urService, summaryService, errorLog, systemLog, cpu, nil, false).(*service)
defer os.Remove(token)
svc.started = addrChan
// Actually start the API service
@@ -946,10 +975,11 @@ func TestEventMasks(t *testing.T) {
cfg := new(mockedConfig)
defSub := new(mockedEventSub)
diskSub := new(mockedEventSub)
svc := newAPIService(protocol.LocalDeviceID, cfg, "", "", "", nil, defSub, diskSub, nil, nil, nil, nil, nil)
svc := New(protocol.LocalDeviceID, cfg, "", "syncthing", nil, defSub, diskSub, nil, nil, nil, nil, nil, nil, nil, nil, false).(*service)
defer os.Remove(token)
if mask := svc.getEventMask(""); mask != defaultEventMask {
t.Errorf("incorrect default mask %x != %x", int64(mask), int64(defaultEventMask))
if mask := svc.getEventMask(""); mask != DefaultEventMask {
t.Errorf("incorrect default mask %x != %x", int64(mask), int64(DefaultEventMask))
}
expected := events.FolderSummary | events.LocalChangeDetected
@@ -962,10 +992,10 @@ func TestEventMasks(t *testing.T) {
t.Errorf("incorrect parsed mask %x != %x", int64(mask), int64(expected))
}
if res := svc.getEventSub(defaultEventMask); res != defSub {
if res := svc.getEventSub(DefaultEventMask); res != defSub {
t.Errorf("should have returned the given default event sub")
}
if res := svc.getEventSub(diskEventMask); res != diskSub {
if res := svc.getEventSub(DiskEventMask); res != diskSub {
t.Errorf("should have returned the given disk event sub")
}
if res := svc.getEventSub(events.LocalIndexUpdated); res == nil || res == defSub || res == diskSub {

28
lib/api/debug.go Normal file
View File

@@ -0,0 +1,28 @@
// 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 api
import (
"os"
"strings"
"github.com/syncthing/syncthing/lib/logger"
)
var (
l = logger.DefaultLogger.NewFacility("api", "REST API")
)
func shouldDebugHTTP() bool {
return l.ShouldDebug("api")
}
func init() {
// The debug facility was originally named "http", changed in:
// https://github.com/syncthing/syncthing/pull/5548
l.SetDebug("api", strings.Contains(os.Getenv("STTRACE"), "api") || strings.Contains(os.Getenv("STTRACE"), "http") || os.Getenv("STTRACE") == "all")
}

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"github.com/syncthing/syncthing/lib/config"
@@ -44,6 +44,8 @@ func (c *mockedConfig) Replace(cfg config.Configuration) (config.Waiter, error)
func (c *mockedConfig) Subscribe(cm config.Committer) {}
func (c *mockedConfig) Unsubscribe(cm config.Committer) {}
func (c *mockedConfig) Folders() map[string]config.FolderConfiguration {
return nil
}
@@ -68,6 +70,58 @@ func (c *mockedConfig) RequiresRestart() bool {
return false
}
func (c *mockedConfig) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) {}
func (c *mockedConfig) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID) {}
func (m *mockedConfig) MyName() string {
return ""
}
func (m *mockedConfig) ConfigPath() string {
return ""
}
func (m *mockedConfig) SetGUI(gui config.GUIConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) SetOptions(opts config.OptionsConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) Folder(id string) (config.FolderConfiguration, bool) {
return config.FolderConfiguration{}, false
}
func (m *mockedConfig) FolderList() []config.FolderConfiguration {
return nil
}
func (m *mockedConfig) SetFolder(fld config.FolderConfiguration) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) Device(id protocol.DeviceID) (config.DeviceConfiguration, bool) {
return config.DeviceConfiguration{}, false
}
func (m *mockedConfig) RemoveDevice(id protocol.DeviceID) (config.Waiter, error) {
return noopWaiter{}, nil
}
func (m *mockedConfig) IgnoredDevice(id protocol.DeviceID) bool {
return false
}
func (m *mockedConfig) IgnoredFolder(device protocol.DeviceID, folder string) bool {
return false
}
func (m *mockedConfig) GlobalDiscoveryServers() []string {
return nil
}
type noopWaiter struct{}
func (noopWaiter) Wait() {}

View File

@@ -4,7 +4,7 @@
// 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
package api
type mockedConnections struct{}
@@ -15,3 +15,7 @@ func (m *mockedConnections) Status() map[string]interface{} {
func (m *mockedConnections) NATType() string {
return ""
}
func (m *mockedConnections) Serve() {}
func (m *mockedConnections) Stop() {}

View File

@@ -4,7 +4,7 @@
// 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
package api
type mockedCPUService struct{}

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"time"

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"time"

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"time"

View File

@@ -4,11 +4,13 @@
// 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
package api
import (
"net"
"time"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/connections"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/model"
@@ -150,3 +152,38 @@ func (m *mockedModel) WatchError(folder string) error {
func (m *mockedModel) LocalChangedFiles(folder string, page, perpage int) []db.FileInfoTruncated {
return nil
}
func (m *mockedModel) Serve() {}
func (m *mockedModel) Stop() {}
func (m *mockedModel) Index(deviceID protocol.DeviceID, folder string, files []protocol.FileInfo) {}
func (m *mockedModel) IndexUpdate(deviceID protocol.DeviceID, folder string, files []protocol.FileInfo) {
}
func (m *mockedModel) Request(deviceID protocol.DeviceID, folder, name string, size int32, offset int64, hash []byte, weakHash uint32, fromTemporary bool) (protocol.RequestResponse, error) {
return nil, nil
}
func (m *mockedModel) ClusterConfig(deviceID protocol.DeviceID, config protocol.ClusterConfig) {}
func (m *mockedModel) Closed(conn protocol.Connection, err error) {}
func (m *mockedModel) DownloadProgress(deviceID protocol.DeviceID, folder string, updates []protocol.FileDownloadProgressUpdate) {
}
func (m *mockedModel) AddConnection(conn connections.Connection, hello protocol.HelloResult) {}
func (m *mockedModel) OnHello(protocol.DeviceID, net.Addr, protocol.HelloResult) error {
return nil
}
func (m *mockedModel) GetHello(protocol.DeviceID) protocol.HelloIntf {
return nil
}
func (m *mockedModel) AddFolder(cfg config.FolderConfiguration) {}
func (m *mockedModel) RestartFolder(from, to config.FolderConfiguration) {}
func (m *mockedModel) StartFolder(folder string) {}
func (m *mockedModel) StartDeadlockDetector(timeout time.Duration) {}

View File

@@ -4,7 +4,7 @@
// 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
package api
import (
"archive/zip"
@@ -14,7 +14,7 @@ import (
)
// getRedactedConfig redacting some parts of config
func getRedactedConfig(s *apiService) config.Configuration {
func getRedactedConfig(s *service) config.Configuration {
rawConf := s.cfg.RawCopy()
rawConf.GUI.APIKey = "REDACTED"
if rawConf.GUI.Password != "" {

23
lib/api/testdata/config/cert.pem vendored Normal file
View File

@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID3jCCAkigAwIBAgIBADALBgkqhkiG9w0BAQUwFDESMBAGA1UEAxMJc3luY3Ro
aW5nMB4XDTE0MDMxNDA3MDA1M1oXDTQ5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJ
c3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEArDOcd5ft
R7SnalxF1ckU3lDQpgfMIPhFDU//4dvdSSFevrMuVDTbUYhyCfGtg/g+F5TmKhZg
E2peYhllITupz5MP7OHGaO2GHf2XnUDD4QUO3E+KVAUw7dyFSwy09esqApVLzH3+
ov+QXyyzmRWPsJe9u18BHU1Hob/RmBhS9m2CAJgzN6EJ8KGjApiW3iR8lD/hjVyi
IVde8IRD6qYHEJYiPJuziTVcQpCblVYxTz3ScmmT190/O9UvViIpcOPQdwgOdewP
NNMK35c9Edt0AH5flYp6jgrja9NkLQJ3+KOiro6yl9IUS5w87GMxI8qzI8SgCAZZ
pYSoLbu1FJPvxV4p5eHwuprBCwmFYZWw6Y7rqH0sN52C+3TeObJCMNP9ilPadqRI
+G0Q99TCaloeR022x33r/8D8SIn3FP35zrlFM+DvqlxoS6glbNb/Bj3p9vN0XONO
RCuynOGe9F/4h/DaNnrbrRWqJOxBsZTsbbcJaKATfWU/Z9GcC+pUpPRhAgMBAAGj
PzA9MA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
AwIwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQUDggGBAFF8dklGoC43fMrUZfb4
6areRWG8quO6cSX6ATzRQVJ8WJ5VcC7OJk8/FeiYA+wcvUJ/1Zm/VHMYugtOz5M8
CrWAF1r9D3Xfe5D8qfrEOYG2XjxD2nFHCnkbY4fP+SMSuXaDs7ixQnzw0UFh1wsV
9Jy/QrgXFAIFZtu1Nz+rrvoAgw24gkDhY3557MbmYfmfPsJ8cw+WJ845sxGMPFF2
c+5EN0jiSm0AwZK11BMJda36ke829UZctDkopbGEg1peydDR5LiyhiTAPtWn7uT/
PkzHYLuaECAkVbWC3bZLocMGOP6F1pG+BMr00NJgVy05ASQzi4FPjcZQNNY8s69R
ZgoCIBaJZq3ti1EsZQ1H0Ynm2c2NMVKdj4czoy8a9ZC+DCuhG7EV5Foh20VhCWgA
RfPhlHVJthuimsWBx39X85gjSBR017uk0AxOJa6pzh/b/RPCRtUfX8EArInS3XCf
RvRtdrnBZNI3tiREopZGt0SzgDZUs4uDVBUX8HnHzyFJrg==
-----END CERTIFICATE-----

134
lib/api/testdata/config/config.xml vendored Normal file
View File

@@ -0,0 +1,134 @@
<configuration version="28">
<folder id="default" label="" path="s1/" type="sendreceive" rescanIntervalS="10" fsWatcherEnabled="false" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true">
<filesystemType>basic</filesystemType>
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" introducedBy=""></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC" introducedBy=""></device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" introducedBy=""></device>
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT" introducedBy=""></device>
<minDiskFree unit="%">1</minDiskFree>
<versioning></versioning>
<copiers>1</copiers>
<pullerMaxPendingKiB>0</pullerMaxPendingKiB>
<hashers>0</hashers>
<order>random</order>
<ignoreDelete>false</ignoreDelete>
<scanProgressIntervalS>0</scanProgressIntervalS>
<pullerPauseS>0</pullerPauseS>
<maxConflicts>-1</maxConflicts>
<disableSparseFiles>false</disableSparseFiles>
<disableTempIndexes>false</disableTempIndexes>
<paused>false</paused>
<weakHashThresholdPct>25</weakHashThresholdPct>
<markerName>.stfolder</markerName>
<useLargeBlocks>true</useLargeBlocks>
</folder>
<folder id="¯\_(ツ)_/¯ Räksmörgås 动作 Адрес" label="" path="s12-1/" type="sendreceive" rescanIntervalS="10" fsWatcherEnabled="false" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true">
<filesystemType>basic</filesystemType>
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" introducedBy=""></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC" introducedBy=""></device>
<minDiskFree unit="%">1</minDiskFree>
<versioning></versioning>
<copiers>1</copiers>
<pullerMaxPendingKiB>0</pullerMaxPendingKiB>
<hashers>0</hashers>
<order>random</order>
<ignoreDelete>false</ignoreDelete>
<scanProgressIntervalS>0</scanProgressIntervalS>
<pullerPauseS>0</pullerPauseS>
<maxConflicts>-1</maxConflicts>
<disableSparseFiles>false</disableSparseFiles>
<disableTempIndexes>false</disableTempIndexes>
<paused>false</paused>
<weakHashThresholdPct>25</weakHashThresholdPct>
<markerName>.stfolder</markerName>
<useLargeBlocks>true</useLargeBlocks>
</folder>
<device id="EJHMPAQ-OGCVORE-ISB4IS3-SYYVJXF-TKJGLTU-66DIQPF-GJ5D2GX-GQ3OWQK" name="s4" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
<address>tcp://127.0.0.1:22004</address>
<paused>false</paused>
<autoAcceptFolders>false</autoAcceptFolders>
<maxSendKbps>0</maxSendKbps>
<maxRecvKbps>0</maxRecvKbps>
<maxRequestKiB>0</maxRequestKiB>
</device>
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" name="s1" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
<address>tcp://127.0.0.1:22001</address>
<paused>false</paused>
<autoAcceptFolders>false</autoAcceptFolders>
<maxSendKbps>0</maxSendKbps>
<maxRecvKbps>0</maxRecvKbps>
<maxRequestKiB>0</maxRequestKiB>
</device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC" name="s2" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
<address>tcp://127.0.0.1:22002</address>
<paused>false</paused>
<autoAcceptFolders>false</autoAcceptFolders>
<maxSendKbps>0</maxSendKbps>
<maxRecvKbps>0</maxRecvKbps>
<maxRequestKiB>0</maxRequestKiB>
</device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" name="s3" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
<address>tcp://127.0.0.1:22003</address>
<paused>false</paused>
<autoAcceptFolders>false</autoAcceptFolders>
<maxSendKbps>0</maxSendKbps>
<maxRecvKbps>0</maxRecvKbps>
<maxRequestKiB>0</maxRequestKiB>
</device>
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT" name="s4" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
<address>tcp://127.0.0.1:22004</address>
<paused>false</paused>
<autoAcceptFolders>false</autoAcceptFolders>
<maxSendKbps>0</maxSendKbps>
<maxRecvKbps>0</maxRecvKbps>
<maxRequestKiB>0</maxRequestKiB>
</device>
<gui enabled="true" tls="false" debugging="true">
<address>127.0.0.1:8081</address>
<user>testuser</user>
<password>$2a$10$7tKL5uvLDGn5s2VLPM2yWOK/II45az0mTel8hxAUJDRQN1Tk2QYwu</password>
<apikey>abc123</apikey>
<theme>default</theme>
</gui>
<ldap></ldap>
<options>
<listenAddress>tcp://127.0.0.1:22001</listenAddress>
<globalAnnounceServer>default</globalAnnounceServer>
<globalAnnounceEnabled>false</globalAnnounceEnabled>
<localAnnounceEnabled>true</localAnnounceEnabled>
<localAnnouncePort>21027</localAnnouncePort>
<localAnnounceMCAddr>[ff12::8384]:21027</localAnnounceMCAddr>
<maxSendKbps>0</maxSendKbps>
<maxRecvKbps>0</maxRecvKbps>
<reconnectionIntervalS>5</reconnectionIntervalS>
<relaysEnabled>false</relaysEnabled>
<relayReconnectIntervalM>10</relayReconnectIntervalM>
<startBrowser>false</startBrowser>
<natEnabled>true</natEnabled>
<natLeaseMinutes>0</natLeaseMinutes>
<natRenewalMinutes>30</natRenewalMinutes>
<natTimeoutSeconds>10</natTimeoutSeconds>
<urAccepted>3</urAccepted>
<urSeen>2</urSeen>
<urUniqueID>tmwxxCqi</urUniqueID>
<urURL>https://data.syncthing.net/newdata</urURL>
<urPostInsecurely>false</urPostInsecurely>
<urInitialDelayS>1800</urInitialDelayS>
<restartOnWakeup>true</restartOnWakeup>
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
<upgradeToPreReleases>false</upgradeToPreReleases>
<keepTemporariesH>24</keepTemporariesH>
<cacheIgnoredFiles>false</cacheIgnoredFiles>
<progressUpdateIntervalS>5</progressUpdateIntervalS>
<limitBandwidthInLan>false</limitBandwidthInLan>
<minHomeDiskFree unit="%">1</minHomeDiskFree>
<releasesURL>https://upgrades.syncthing.net/meta.json</releasesURL>
<overwriteRemoteDeviceNamesOnConnect>false</overwriteRemoteDeviceNamesOnConnect>
<tempIndexMinBlocks>10</tempIndexMinBlocks>
<trafficClass>0</trafficClass>
<defaultFolderPath>~</defaultFolderPath>
<setLowPriority>true</setLowPriority>
<maxConcurrentScans>0</maxConcurrentScans>
<minHomeDiskFreePct>0</minHomeDiskFreePct>
</options>
</configuration>

23
lib/api/testdata/config/https-cert.pem vendored Normal file
View File

@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID5TCCAk+gAwIBAgIIBYqoKiSgB+owCwYJKoZIhvcNAQELMBQxEjAQBgNVBAMT
CXN5bmN0aGluZzAeFw0xNDA5MTQyMjIzMzVaFw00OTEyMzEyMzU5NTlaMBQxEjAQ
BgNVBAMTCXN5bmN0aGluZzCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGB
AKZK/sjb6ZuVVHPvo77Cp5E8LfiznfoIWJRoX/MczE99iDyFZm1Wf9GFT8WhXICM
C2kgGbr/gAxhkeEcZ500vhA2C+aois1DGcb+vNY53I0qp3vSUl4ow55R0xJ4UjpJ
nJWF8p9iPDMwMP6WQ/E/ekKRKCOt0TFj4xqtiSt0pxPLeHfKVpWXxqIVDhnsoGQ+
NWuUjM3FkmEmhp5DdRtwskiZZYz1zCgoHkFzKt/+IxjCuzbO0+Ti8R3b/d0A+WLN
LHr0SjatajLbHebA+9c3ts6t3V5YzcMqDJ4MyxFtRoXFJjEbcM9IqKQE8t8TIhv8
a302yRikJ2uPx+fXJGospnmWCbaK2rViPbvICSgvSBA3As0f3yPzXsEt+aW5NmDV
fLBX1DU7Ow6oBqZTlI+STrzZR1qfvIuweIWoPqnPNd4sxuoxAK50ViUKdOtSYL/a
F0eM3bqbp2ozhct+Bfmqu2oI/RHXe+RUfAXrlFQ8p6jcISW2ip+oiBtR4GZkncI9
YQIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCAKAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCwYJKoZIhvcNAQELA4IBgQBsYc5XVQy5
aJVdwx+mAKiuCs5ZCvV4H4VWY9XUwEJuUUD3yXw2xyzuQl5+lOxfiQcaudhVwARC
Dao75MUctXmx1YU+J5G31cGdC9kbxWuo1xypkK+2Zl+Kwh65aod3OkHVz9oNkKpf
JnXbdph4UiFJzijSruXDDaerrQdABUvlusPozZn8vMwZ21Ls/eNIOJvA0S2d2jep
fvmu7yQPejDp7zcgPdmneuZqmUyXLxxFopYqHqFQVM8f+Y8iZ8HnMiAJgLKQcmro
pp1z/NY0Xr0pLyBY5d/sO+tZmQkyUEWegHtEtQQOO+x8BWinDEAurej/YvZTWTmN
+YoUvGdKyV6XfC6WPFcUDFHY4KPSqS3xoLmoVV4xNjJU3aG/xL4uDencNZR/UFNw
wKsdvm9SX4TpSLlQa0wu1iNv7QyeR4ZKgaBNSwp2rxpatOi7TTs9KRPfjLFLpYAg
bIons/a890SIxpuneuhQZkH63t930EXIZ+9GkU0aUs7MFg5cCmwmlvE=
-----END CERTIFICATE-----

39
lib/api/testdata/config/https-key.pem vendored Normal file
View File

@@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG5AIBAAKCAYEApkr+yNvpm5VUc++jvsKnkTwt+LOd+ghYlGhf8xzMT32IPIVm
bVZ/0YVPxaFcgIwLaSAZuv+ADGGR4RxnnTS+EDYL5qiKzUMZxv681jncjSqne9JS
XijDnlHTEnhSOkmclYXyn2I8MzAw/pZD8T96QpEoI63RMWPjGq2JK3SnE8t4d8pW
lZfGohUOGeygZD41a5SMzcWSYSaGnkN1G3CySJlljPXMKCgeQXMq3/4jGMK7Ns7T
5OLxHdv93QD5Ys0sevRKNq1qMtsd5sD71ze2zq3dXljNwyoMngzLEW1GhcUmMRtw
z0iopATy3xMiG/xrfTbJGKQna4/H59ckaiymeZYJtoratWI9u8gJKC9IEDcCzR/f
I/NewS35pbk2YNV8sFfUNTs7DqgGplOUj5JOvNlHWp+8i7B4hag+qc813izG6jEA
rnRWJQp061Jgv9oXR4zdupunajOFy34F+aq7agj9Edd75FR8BeuUVDynqNwhJbaK
n6iIG1HgZmSdwj1hAgMBAAECggGAQkd334TPSmStgXwNLrYU5a0vwYWNvJ9g9t3X
CGX9BN3K1BxzY7brQQ46alHTNaUb0y2pM8AsQEMPSsLwhVcFPh7chXW9xOwutQLJ
LzVms5lBofeFPuROe6avUxhD5dl7IJl/x4j254wYqxAnSlt7llaWwgnAbEgct4Bd
QMXA5gHeJRivg/Y3hFiSA0Et+GZXEmbl7AoIOtKJK0FFxscXOBpzwEgjtAmxbXLC
rv5y7KaIyeKL0Bmn8rfBKjn+LCQMJt4wZCrNtFLg3aSpkmqZl6r8Q84OwHMp2x8l
SFNVi7j1Cv8DC/yhyEOCbHIRZrK/vzt6Cqe+yjr1UG9niwhQJbEvaV26odzvMSNZ
1VodN+ltCZRFFEBc+z3CR7SKDZayT93dLxolzQ4DuSfDnk0fBLtOfeISxS/Wg7Yv
5q0XF6cTmQEsDbuDswvlHo3k8w3cjz9SmxMasxgHx6jHkSBbkw0iFLT3KdqA8PrG
D3uo67fIQEkcncmRLP3I1qUiWX21AoHBAMVQLLgOd3bOrByyVeugA+5dhef0uopJ
GadzBlAT4EY7Vuxu1Qu/m876FnhQc3tGTLfZhcnL9VXV+3DSTosfRz+YDm+K5lOh
ZRtswuZscm+l26X+2j1h+AGW8SIz5f9M0CnFpqjC8KkopPk/ZKTcDvrNRRxI5EPx
TPZaiPhztlcsc7K5jkLJRL0GiadUniOFY7kUA18hs3MEyzkdYbz8WolUyHeSJT2H
hmpdsA5tzUKB1NVdsIsjWESQF3Hd2FFHMwKBwQDXwOCUq5KSBKa1BSO1oQxhyHy3
ZQ86d5weLNxovwrHd4ivaVPJ46YLjNk+/q685XPUfoDxO1fnyIYIy4ChtkhXmyli
LOPfNt0iSW2M1/L1wb6ZwMz+RWpb3zqPgjMlDCEtD5hQ8Cl5do2tyh3sIrLgamVG
sY1hx+VD0BmXUUTGjl8nJqQSMYl6IXTKzrFrx+QWdzA0yWN753XiAF5cLkxNahes
SKb/ibrMtO/JKt3RBlZPS3wiFRkxtNcS1HrVWRsCgcBaFir0thYxNlc6munDtMFW
uXiD2Sa6MHn4C/pb4VdKeZlMRaYbwRYAQAq2T/UJ2aT5Y+VDp02SLSqp7jtSJavA
C0q7/qz+jfe9t8Cct/LfqthIR72YvPwgravWs99U2ttH1ygqcSaz9QytiBYJdzeX
ptTg/x7JLoi3CcrztNERqAgDF9kuAPrTWwLKVUYGbcaEH/ESJC7sWsn2f8W6JXWo
sf79KMq79v6V3cSeMd+/d8uWxzntrOuGEkvB/0negiUCgcEAp0YwGLQJGFKo2XIZ
pIkva2SgZSPiMadoj/CiFkf/2HRxseYMg1uPcicKjA+zdFrFejt2RxGGbvsGCC2X
FkmYPuvaovZA2d/UhO+/EtKe2TEUUGqtxHoXIxGoenkspA2Kb0BHDIGW9kgXQmWQ
23JvkxSKXsvr3KK5uuDN5oaotvTNCzKnRD/J4bmsrkygO/sneM+BvXtiOT9UIxu8
DOYMXHzjy7wsVbT38hxaSHKGtbefFS1mGZqYBPS7Rysb7Ot/AoHBAL0SAbt1a2Ol
ObrK8vjTHcQHJH74n+6PWRfsBO+UJ1vtOYFzW85BiVZmi8tC4bJ0Hd89TT7AibzP
L1Ftrn0XmBfniwV1SsrjVaRy/KbBeUhjruqyQ2oDLEU7DAm5Z2jG4aG2rLbXYAS9
yOQITLN5AVraI4Pr1IWjZTzd/zaaWA5nFNthyXSww1II0f1BgX1S/49k4aWjXeMn
FrKN5T7BqIh9W6d7YTrzXoH9lEsUPQHV/ci+YRP4mrfrcC9hJZ3O9g==
-----END RSA PRIVATE KEY-----

39
lib/api/testdata/config/key.pem vendored Normal file
View File

@@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG5AIBAAKCAYEArDOcd5ftR7SnalxF1ckU3lDQpgfMIPhFDU//4dvdSSFevrMu
VDTbUYhyCfGtg/g+F5TmKhZgE2peYhllITupz5MP7OHGaO2GHf2XnUDD4QUO3E+K
VAUw7dyFSwy09esqApVLzH3+ov+QXyyzmRWPsJe9u18BHU1Hob/RmBhS9m2CAJgz
N6EJ8KGjApiW3iR8lD/hjVyiIVde8IRD6qYHEJYiPJuziTVcQpCblVYxTz3ScmmT
190/O9UvViIpcOPQdwgOdewPNNMK35c9Edt0AH5flYp6jgrja9NkLQJ3+KOiro6y
l9IUS5w87GMxI8qzI8SgCAZZpYSoLbu1FJPvxV4p5eHwuprBCwmFYZWw6Y7rqH0s
N52C+3TeObJCMNP9ilPadqRI+G0Q99TCaloeR022x33r/8D8SIn3FP35zrlFM+Dv
qlxoS6glbNb/Bj3p9vN0XONORCuynOGe9F/4h/DaNnrbrRWqJOxBsZTsbbcJaKAT
fWU/Z9GcC+pUpPRhAgMBAAECggGAL8+Unc/c3Y/W+7zq1tShqqgdhjub/XtxEKUp
kngNFITjXWc6cb7LNfQAVap4Vq/R7ZI15XGY80sRMYODhJqgJzXZshdtkyx/lEwY
kFyvBgb1fU3IRlO6phAYIiJBDBZi75ysEvbYgEEcwJAUvWgzIQDAeQmDsbMHNG2h
r+zw++Kjua6IaeWYcOsv60Safsr6m96wrSMPENrFTVor0TaPt5c3okRIsMvT9ddY
mzn3Lt0nVQTjO4f+SoqCPhP2FZXqksfKlZlKlr6BLxXGt6b49OrLSXM5eQXIcIZn
ZDRsO24X5z8156qPgM9cA8oNEjuSdnArUTreBOsTwNoSpf24Qadsv/uTZlaHM19V
q6zQvkjH3ERcOpixmg48TKdIj8cPYxezvcbNqSbZmdyQuaVlgDbUxwYI8A4IhhWl
6xhwpX3qPDgw/QHIEngFIWfiIfCk11EPY0SN4cGO6f1rLYug8kqxMPuIQ5Jz9Hhx
eFSRnr/fWoJcVYG6bMDKn9YWObQBAoHBAM8NahsLbjl8mdT43LH1Od1tDmDch+0Y
JM7TgiIN/GM3piZSpGMOFqToLAqvY+Gf3l4sPgNs10cqdPAEpMk8MJ/IXGmbKq38
iVmMaqHTQorCxyUbc54q9AbFU4HKv//F6ZN6K1wSaJt2RBeZpYI+MyBXr5baFiBZ
ddXtXlqoEcCFyNR0DhlXrlZPs+cnyM2ZDp++lpn9Wfy+zkv36+NWpAkXVnARjxdF
l6M+L7OlurYAWiyJE4uHUjawAM82i5+w8QKBwQDU6RCN6/AMmVrYqPy+7QcnAq67
tPDv25gzVExeMKLBAMoz1TkMS+jIF1NMp3cYg5GbLqvx8Qd27fjFbWe/GPeZvlgL
qdQI/T8J60dHAySMeOFOB2QWXhI1kwh0b2X0SDkTgfdJBKGdrKVcLTuLyVE24exu
yRc8cXpYwBtVkXNBYFd7XEM+tC4b1khO23OJXHJUen9+hgsmn8/zUjASAoq3+Zly
J+OHwwXcDcTFLeok3kX3A9NuqIV/Fa9DOGYlenECgcEAvO1onDTZ5uqjE4nhFyDE
JB+WtxuDi/wz2eV1IM3SNlZY7S8LgLciQmb3iOhxIzdVGGkWTNnLtcwv17LlCho5
5BJXAKXtU8TTLzrJMdArL6J7RIi//tsCwAreH9h5SVG1yDP5zJGfkftgNoikVSuc
Sy63sdZdyjbXJtTo+5/QUvPARNuA4e73zRn89jd/Kts2VNz7XpemvND+PKOEQnSU
SRdab/gVsQ53RyU/MZVPwTKhFXIeu3pGsk/27RzAWn6BAoHBAMIRYwaKDffd/SHJ
/v+lHEThvBXa21c26ae36hhc6q1UI/tVGrfrpVZldIdFilgs7RbvVsmksvIj/gMv
M0bL4j0gdC7FcUF0XPaUoBbJdZIZSP0P3ZpJyv1MdYN0WxFsl6IBcD79WrdXPC8m
B8XmDgIhsppU77onkaa+DOxVNSJdR8BpG95W7ERxcN14SPrm6ku4kOfqFNXzC+C1
hJ2V9Y22lLiqRUplaLzpS/eTX36VoF6E/T87mtt5D5UNHoaA8QKBwH5sRqZXoatU
X+vw1MHU5eptMwG7LXR0gw2xmvG3cCN4hbnnBp5YaXlWPiIMmaWhpvschgBIo1TP
qGWUpMEETGES18NenLBym+tWIXlfuyZH3B4NUi4kItiZaKb09LzmTjFvzdfQzun4
HzIeigTNBDHdS0rdicNIn83QLZ4pJaOZJHq79+mFYkp+9It7UUoWsws6DGl/qX8o
0cj4NmJB6QiJa1QCzrGkaajbtThbFoQal9Twk2h3jHgJzX3FbwCpLw==
-----END RSA PRIVATE KEY-----

View File

View File

@@ -84,18 +84,18 @@ func New(myID protocol.DeviceID) Configuration {
return cfg
}
func NewWithFreePorts(myID protocol.DeviceID) Configuration {
func NewWithFreePorts(myID protocol.DeviceID) (Configuration, error) {
cfg := New(myID)
port, err := getFreePort("127.0.0.1", DefaultGUIPort)
if err != nil {
l.Fatalln("get free port (GUI):", err)
return Configuration{}, fmt.Errorf("get free port (GUI): %v", err)
}
cfg.GUI.RawAddress = fmt.Sprintf("127.0.0.1:%d", port)
port, err = getFreePort("0.0.0.0", DefaultTCPPort)
if err != nil {
l.Fatalln("get free port (BEP):", err)
return Configuration{}, fmt.Errorf("get free port (BEP): %v", err)
}
if port == DefaultTCPPort {
cfg.Options.ListenAddresses = []string{"default"}
@@ -106,7 +106,7 @@ func NewWithFreePorts(myID protocol.DeviceID) Configuration {
}
}
return cfg
return cfg, nil
}
func ReadXML(r io.Reader, myID protocol.DeviceID) (Configuration, error) {

View File

@@ -93,7 +93,7 @@ func TestDeviceConfig(t *testing.T) {
t.Fatal("Unexpected file")
}
cfg := wr.cfg
cfg := wr.(*wrapper).cfg
expectedFolders := []FolderConfiguration{
{
@@ -515,7 +515,7 @@ func TestNewSaveLoad(t *testing.T) {
cfg := Wrap(path, intCfg)
// To make the equality pass later
cfg.cfg.XMLName.Local = "configuration"
cfg.(*wrapper).cfg.XMLName.Local = "configuration"
if exists(path) {
t.Error(path, "exists")
@@ -827,7 +827,7 @@ func TestIgnoredFolders(t *testing.T) {
// 2 for folder2, 1 for folder1, as non-existing device and device the folder is shared with is removed.
expectedIgnoredFolders := 3
for _, dev := range wrapper.cfg.Devices {
for _, dev := range wrapper.Devices() {
expectedIgnoredFolders -= len(dev.IgnoredFolders)
}
if expectedIgnoredFolders != 0 {

View File

@@ -52,7 +52,7 @@ type FolderConfiguration struct {
Paused bool `xml:"paused" json:"paused"`
WeakHashThresholdPct int `xml:"weakHashThresholdPct" json:"weakHashThresholdPct"` // Use weak hash if more than X percent of the file has changed. Set to -1 to always use weak hash.
MarkerName string `xml:"markerName" json:"markerName"`
UseLargeBlocks bool `xml:"useLargeBlocks" json:"useLargeBlocks"`
UseLargeBlocks bool `xml:"useLargeBlocks" json:"useLargeBlocks" default:"true"`
CopyOwnershipFromParent bool `xml:"copyOwnershipFromParent" json:"copyOwnershipFromParent"`
cachedFilesystem fs.Filesystem
@@ -106,7 +106,7 @@ func (f FolderConfiguration) Versioner() versioner.Versioner {
}
versionerFactory, ok := versioner.Factories[f.Versioning.Type]
if !ok {
l.Fatalf("Requested versioning type %q that does not exist", f.Versioning.Type)
panic(fmt.Sprintf("Requested versioning type %q that does not exist", f.Versioning.Type))
}
return versionerFactory(f.ID, f.Filesystem(), f.Versioning.Params)

View File

@@ -52,10 +52,48 @@ type noopWaiter struct{}
func (noopWaiter) Wait() {}
// A wrapper around a Configuration that manages loads, saves and published
// A Wrapper around a Configuration that manages loads, saves and published
// notifications of changes to registered Handlers
type Wrapper interface {
MyName() string
ConfigPath() string
type Wrapper struct {
RawCopy() Configuration
Replace(cfg Configuration) (Waiter, error)
RequiresRestart() bool
Save() error
GUI() GUIConfiguration
SetGUI(gui GUIConfiguration) (Waiter, error)
LDAP() LDAPConfiguration
Options() OptionsConfiguration
SetOptions(opts OptionsConfiguration) (Waiter, error)
Folder(id string) (FolderConfiguration, bool)
Folders() map[string]FolderConfiguration
FolderList() []FolderConfiguration
SetFolder(fld FolderConfiguration) (Waiter, error)
Device(id protocol.DeviceID) (DeviceConfiguration, bool)
Devices() map[protocol.DeviceID]DeviceConfiguration
RemoveDevice(id protocol.DeviceID) (Waiter, error)
SetDevice(DeviceConfiguration) (Waiter, error)
SetDevices([]DeviceConfiguration) (Waiter, error)
AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string)
AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID)
IgnoredDevice(id protocol.DeviceID) bool
IgnoredFolder(device protocol.DeviceID, folder string) bool
ListenAddresses() []string
GlobalDiscoveryServers() []string
Subscribe(c Committer)
Unsubscribe(c Committer)
}
type wrapper struct {
cfg Configuration
path string
@@ -69,8 +107,8 @@ type Wrapper struct {
// Wrap wraps an existing Configuration structure and ties it to a file on
// disk.
func Wrap(path string, cfg Configuration) *Wrapper {
w := &Wrapper{
func Wrap(path string, cfg Configuration) Wrapper {
w := &wrapper{
cfg: cfg,
path: path,
mut: sync.NewMutex(),
@@ -80,7 +118,7 @@ func Wrap(path string, cfg Configuration) *Wrapper {
// Load loads an existing file on disk and returns a new configuration
// wrapper.
func Load(path string, myID protocol.DeviceID) (*Wrapper, error) {
func Load(path string, myID protocol.DeviceID) (Wrapper, error) {
fd, err := os.Open(path)
if err != nil {
return nil, err
@@ -95,13 +133,13 @@ func Load(path string, myID protocol.DeviceID) (*Wrapper, error) {
return Wrap(path, cfg), nil
}
func (w *Wrapper) ConfigPath() string {
func (w *wrapper) ConfigPath() string {
return w.path
}
// Subscribe registers the given handler to be called on any future
// configuration changes.
func (w *Wrapper) Subscribe(c Committer) {
func (w *wrapper) Subscribe(c Committer) {
w.mut.Lock()
w.subs = append(w.subs, c)
w.mut.Unlock()
@@ -109,7 +147,7 @@ func (w *Wrapper) Subscribe(c Committer) {
// Unsubscribe de-registers the given handler from any future calls to
// configuration changes
func (w *Wrapper) Unsubscribe(c Committer) {
func (w *wrapper) Unsubscribe(c Committer) {
w.mut.Lock()
for i := range w.subs {
if w.subs[i] == c {
@@ -123,20 +161,20 @@ func (w *Wrapper) Unsubscribe(c Committer) {
}
// RawCopy returns a copy of the currently wrapped Configuration object.
func (w *Wrapper) RawCopy() Configuration {
func (w *wrapper) RawCopy() Configuration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Copy()
}
// Replace swaps the current configuration object for the given one.
func (w *Wrapper) Replace(cfg Configuration) (Waiter, error) {
func (w *wrapper) Replace(cfg Configuration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
return w.replaceLocked(cfg.Copy())
}
func (w *Wrapper) replaceLocked(to Configuration) (Waiter, error) {
func (w *wrapper) replaceLocked(to Configuration) (Waiter, error) {
from := w.cfg
if err := to.clean(); err != nil {
@@ -158,7 +196,7 @@ func (w *Wrapper) replaceLocked(to Configuration) (Waiter, error) {
return w.notifyListeners(from.Copy(), to.Copy()), nil
}
func (w *Wrapper) notifyListeners(from, to Configuration) Waiter {
func (w *wrapper) notifyListeners(from, to Configuration) Waiter {
wg := sync.NewWaitGroup()
wg.Add(len(w.subs))
for _, sub := range w.subs {
@@ -170,7 +208,7 @@ func (w *Wrapper) notifyListeners(from, to Configuration) Waiter {
return wg
}
func (w *Wrapper) notifyListener(sub Committer, from, to Configuration) {
func (w *wrapper) notifyListener(sub Committer, from, to Configuration) {
l.Debugln(sub, "committing configuration")
if !sub.CommitConfiguration(from, to) {
l.Debugln(sub, "requires restart")
@@ -179,7 +217,7 @@ func (w *Wrapper) notifyListener(sub Committer, from, to Configuration) {
}
// Devices returns a map of devices.
func (w *Wrapper) Devices() map[protocol.DeviceID]DeviceConfiguration {
func (w *wrapper) Devices() map[protocol.DeviceID]DeviceConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
if w.deviceMap == nil {
@@ -193,7 +231,7 @@ func (w *Wrapper) Devices() map[protocol.DeviceID]DeviceConfiguration {
// SetDevices adds new devices to the configuration, or overwrites existing
// devices with the same ID.
func (w *Wrapper) SetDevices(devs []DeviceConfiguration) (Waiter, error) {
func (w *wrapper) SetDevices(devs []DeviceConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
@@ -218,12 +256,12 @@ func (w *Wrapper) SetDevices(devs []DeviceConfiguration) (Waiter, error) {
// SetDevice adds a new device to the configuration, or overwrites an existing
// device with the same ID.
func (w *Wrapper) SetDevice(dev DeviceConfiguration) (Waiter, error) {
func (w *wrapper) SetDevice(dev DeviceConfiguration) (Waiter, error) {
return w.SetDevices([]DeviceConfiguration{dev})
}
// RemoveDevice removes the device from the configuration
func (w *Wrapper) RemoveDevice(id protocol.DeviceID) (Waiter, error) {
func (w *wrapper) RemoveDevice(id protocol.DeviceID) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
@@ -240,7 +278,7 @@ func (w *Wrapper) RemoveDevice(id protocol.DeviceID) (Waiter, error) {
// Folders returns a map of folders. Folder structures should not be changed,
// other than for the purpose of updating via SetFolder().
func (w *Wrapper) Folders() map[string]FolderConfiguration {
func (w *wrapper) Folders() map[string]FolderConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
if w.folderMap == nil {
@@ -253,7 +291,7 @@ func (w *Wrapper) Folders() map[string]FolderConfiguration {
}
// FolderList returns a slice of folders.
func (w *Wrapper) FolderList() []FolderConfiguration {
func (w *wrapper) FolderList() []FolderConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Copy().Folders
@@ -261,7 +299,7 @@ func (w *Wrapper) FolderList() []FolderConfiguration {
// SetFolder adds a new folder to the configuration, or overwrites an existing
// folder with the same ID.
func (w *Wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) {
func (w *wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
@@ -280,14 +318,14 @@ func (w *Wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) {
}
// Options returns the current options configuration object.
func (w *Wrapper) Options() OptionsConfiguration {
func (w *wrapper) Options() OptionsConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.Options.Copy()
}
// SetOptions replaces the current options configuration object.
func (w *Wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
func (w *wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
newCfg := w.cfg.Copy()
@@ -295,21 +333,21 @@ func (w *Wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
return w.replaceLocked(newCfg)
}
func (w *Wrapper) LDAP() LDAPConfiguration {
func (w *wrapper) LDAP() LDAPConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.LDAP.Copy()
}
// GUI returns the current GUI configuration object.
func (w *Wrapper) GUI() GUIConfiguration {
func (w *wrapper) GUI() GUIConfiguration {
w.mut.Lock()
defer w.mut.Unlock()
return w.cfg.GUI.Copy()
}
// SetGUI replaces the current GUI configuration object.
func (w *Wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
func (w *wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
w.mut.Lock()
defer w.mut.Unlock()
newCfg := w.cfg.Copy()
@@ -319,7 +357,7 @@ func (w *Wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
// IgnoredDevice returns whether or not connection attempts from the given
// device should be silently ignored.
func (w *Wrapper) IgnoredDevice(id protocol.DeviceID) bool {
func (w *wrapper) IgnoredDevice(id protocol.DeviceID) bool {
w.mut.Lock()
defer w.mut.Unlock()
for _, device := range w.cfg.IgnoredDevices {
@@ -332,7 +370,7 @@ func (w *Wrapper) IgnoredDevice(id protocol.DeviceID) bool {
// IgnoredFolder returns whether or not share attempts for the given
// folder should be silently ignored.
func (w *Wrapper) IgnoredFolder(device protocol.DeviceID, folder string) bool {
func (w *wrapper) IgnoredFolder(device protocol.DeviceID, folder string) bool {
dev, ok := w.Device(device)
if !ok {
return false
@@ -341,7 +379,7 @@ func (w *Wrapper) IgnoredFolder(device protocol.DeviceID, folder string) bool {
}
// Device returns the configuration for the given device and an "ok" bool.
func (w *Wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
func (w *wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
w.mut.Lock()
defer w.mut.Unlock()
for _, device := range w.cfg.Devices {
@@ -353,7 +391,7 @@ func (w *Wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
}
// Folder returns the configuration for the given folder and an "ok" bool.
func (w *Wrapper) Folder(id string) (FolderConfiguration, bool) {
func (w *wrapper) Folder(id string) (FolderConfiguration, bool) {
w.mut.Lock()
defer w.mut.Unlock()
for _, folder := range w.cfg.Folders {
@@ -365,7 +403,7 @@ func (w *Wrapper) Folder(id string) (FolderConfiguration, bool) {
}
// Save writes the configuration to disk, and generates a ConfigSaved event.
func (w *Wrapper) Save() error {
func (w *wrapper) Save() error {
w.mut.Lock()
defer w.mut.Unlock()
@@ -390,7 +428,7 @@ func (w *Wrapper) Save() error {
return nil
}
func (w *Wrapper) GlobalDiscoveryServers() []string {
func (w *wrapper) GlobalDiscoveryServers() []string {
var servers []string
for _, srv := range w.Options().GlobalAnnServers {
switch srv {
@@ -407,7 +445,7 @@ func (w *Wrapper) GlobalDiscoveryServers() []string {
return util.UniqueStrings(servers)
}
func (w *Wrapper) ListenAddresses() []string {
func (w *wrapper) ListenAddresses() []string {
var addresses []string
for _, addr := range w.Options().ListenAddresses {
switch addr {
@@ -420,15 +458,15 @@ func (w *Wrapper) ListenAddresses() []string {
return util.UniqueStrings(addresses)
}
func (w *Wrapper) RequiresRestart() bool {
func (w *wrapper) RequiresRestart() bool {
return atomic.LoadUint32(&w.requiresRestart) != 0
}
func (w *Wrapper) setRequiresRestart() {
func (w *wrapper) setRequiresRestart() {
atomic.StoreUint32(&w.requiresRestart, 1)
}
func (w *Wrapper) MyName() string {
func (w *wrapper) MyName() string {
w.mut.Lock()
myID := w.cfg.MyID
w.mut.Unlock()
@@ -436,7 +474,7 @@ func (w *Wrapper) MyName() string {
return cfg.Name
}
func (w *Wrapper) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) {
func (w *wrapper) AddOrUpdatePendingDevice(device protocol.DeviceID, name, address string) {
defer w.Save()
w.mut.Lock()
@@ -444,7 +482,7 @@ func (w *Wrapper) AddOrUpdatePendingDevice(device protocol.DeviceID, name, addre
for i := range w.cfg.PendingDevices {
if w.cfg.PendingDevices[i].ID == device {
w.cfg.PendingDevices[i].Time = time.Now()
w.cfg.PendingDevices[i].Time = time.Now().Round(time.Second)
w.cfg.PendingDevices[i].Name = name
w.cfg.PendingDevices[i].Address = address
return
@@ -452,14 +490,14 @@ func (w *Wrapper) AddOrUpdatePendingDevice(device protocol.DeviceID, name, addre
}
w.cfg.PendingDevices = append(w.cfg.PendingDevices, ObservedDevice{
Time: time.Now(),
Time: time.Now().Round(time.Second),
ID: device,
Name: name,
Address: address,
})
}
func (w *Wrapper) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID) {
func (w *wrapper) AddOrUpdatePendingFolder(id, label string, device protocol.DeviceID) {
defer w.Save()
w.mut.Lock()
@@ -470,12 +508,12 @@ func (w *Wrapper) AddOrUpdatePendingFolder(id, label string, device protocol.Dev
for j := range w.cfg.Devices[i].PendingFolders {
if w.cfg.Devices[i].PendingFolders[j].ID == id {
w.cfg.Devices[i].PendingFolders[j].Label = label
w.cfg.Devices[i].PendingFolders[j].Time = time.Now()
w.cfg.Devices[i].PendingFolders[j].Time = time.Now().Round(time.Second)
return
}
}
w.cfg.Devices[i].PendingFolders = append(w.cfg.Devices[i].PendingFolders, ObservedFolder{
Time: time.Now(),
Time: time.Now().Round(time.Second),
ID: id,
Label: label,
})

View File

@@ -36,7 +36,7 @@ func TestIsLANHost(t *testing.T) {
AlwaysLocalNets: []string{"10.20.30.0/24"},
},
})
s := &Service{cfg: cfg}
s := &service{cfg: cfg}
for _, tc := range cases {
res := s.isLANHost(tc.addr)

View File

@@ -36,7 +36,7 @@ type waiter interface {
const limiterBurstSize = 4 * 128 << 10
func newLimiter(cfg *config.Wrapper) *limiter {
func newLimiter(cfg config.Wrapper) *limiter {
l := &limiter{
write: rate.NewLimiter(rate.Inf, limiterBurstSize),
read: rate.NewLimiter(rate.Inf, limiterBurstSize),

View File

@@ -24,7 +24,7 @@ func init() {
device4, _ = protocol.DeviceIDFromString("P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2")
}
func initConfig() *config.Wrapper {
func initConfig() config.Wrapper {
cfg := config.Wrap("/dev/null", config.New(device1))
dev1Conf = config.NewDeviceConfiguration(device1, "device1")
dev2Conf = config.NewDeviceConfiguration(device2, "device2")

View File

@@ -22,7 +22,7 @@ func init() {
}
type relayDialer struct {
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
}
@@ -70,7 +70,7 @@ func (d *relayDialer) RedialFrequency() time.Duration {
type relayDialerFactory struct{}
func (relayDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDialer {
func (relayDialerFactory) New(cfg config.Wrapper, tlsCfg *tls.Config) genericDialer {
return &relayDialer{
cfg: cfg,
tlsCfg: tlsCfg,

View File

@@ -29,7 +29,7 @@ type relayListener struct {
onAddressesChangedNotifier
uri *url.URL
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
conns chan internalConn
factory listenerFactory
@@ -180,7 +180,7 @@ func (t *relayListener) NATType() string {
type relayListenerFactory struct{}
func (f *relayListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
func (f *relayListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
return &relayListener{
uri: uri,
cfg: cfg,

View File

@@ -51,6 +51,7 @@ const (
// From go/src/crypto/tls/cipher_suites.go
var tlsCipherSuiteNames = map[uint16]string{
// TLS 1.2
0x0005: "TLS_RSA_WITH_RC4_128_SHA",
0x000a: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
0x002f: "TLS_RSA_WITH_AES_128_CBC_SHA",
@@ -73,13 +74,29 @@ var tlsCipherSuiteNames = map[uint16]string{
0xc02c: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
0xcca8: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
0xcca9: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
// TLS 1.3
0x1301: "TLS_AES_128_GCM_SHA256",
0x1302: "TLS_AES_256_GCM_SHA384",
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
}
var tlsVersionNames = map[uint16]string{
tls.VersionTLS12: "TLS1.2",
772: "TLS1.3", // tls.VersionTLS13 constant available in Go 1.12+
}
// Service listens and dials all configured unconnected devices, via supported
// dialers. Successful connections are handed to the model.
type Service struct {
type Service interface {
suture.Service
Status() map[string]interface{}
NATType() string
}
type service struct {
*suture.Supervisor
cfg *config.Wrapper
cfg config.Wrapper
myID protocol.DeviceID
model Model
tlsCfg *tls.Config
@@ -97,10 +114,10 @@ type Service struct {
listenerSupervisor *suture.Supervisor
}
func NewService(cfg *config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder,
bepProtocolName string, tlsDefaultCommonName string) *Service {
func NewService(cfg config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *tls.Config, discoverer discover.Finder,
bepProtocolName string, tlsDefaultCommonName string) *service {
service := &Service{
service := &service{
Supervisor: suture.New("connections.Service", suture.Spec{
Log: func(line string) {
l.Infoln(line)
@@ -156,7 +173,7 @@ func NewService(cfg *config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *
return service
}
func (s *Service) handle() {
func (s *service) handle() {
next:
for c := range s.conns {
cs := c.ConnectionState()
@@ -275,14 +292,14 @@ next:
protoConn := protocol.NewConnection(remoteID, rd, wr, s.model, c.String(), deviceCfg.Compression)
modelConn := completeConn{c, protoConn}
l.Infof("Established secure connection to %s at %s (%s)", remoteID, c, tlsCipherSuiteNames[c.ConnectionState().CipherSuite])
l.Infof("Established secure connection to %s at %s", remoteID, c)
s.model.AddConnection(modelConn, hello)
continue next
}
}
func (s *Service) connect() {
func (s *service) connect() {
nextDial := make(map[string]time.Time)
// Used as delay for the first few connection attempts, increases
@@ -433,7 +450,7 @@ func (s *Service) connect() {
}
}
func (s *Service) isLANHost(host string) bool {
func (s *service) isLANHost(host string) bool {
// Probably we are called with an ip:port combo which we can resolve as
// a TCP address.
if addr, err := net.ResolveTCPAddr("tcp", host); err == nil {
@@ -447,7 +464,7 @@ func (s *Service) isLANHost(host string) bool {
return false
}
func (s *Service) isLAN(addr net.Addr) bool {
func (s *service) isLAN(addr net.Addr) bool {
var ip net.IP
switch addr := addr.(type) {
@@ -488,7 +505,7 @@ func (s *Service) isLAN(addr net.Addr) bool {
return false
}
func (s *Service) createListener(factory listenerFactory, uri *url.URL) bool {
func (s *service) createListener(factory listenerFactory, uri *url.URL) bool {
// must be called with listenerMut held
l.Debugln("Starting listener", uri)
@@ -500,7 +517,7 @@ func (s *Service) createListener(factory listenerFactory, uri *url.URL) bool {
return true
}
func (s *Service) logListenAddressesChangedEvent(l genericListener) {
func (s *service) logListenAddressesChangedEvent(l genericListener) {
events.Default.Log(events.ListenAddressesChanged, map[string]interface{}{
"address": l.URI(),
"lan": l.LANAddresses(),
@@ -508,11 +525,11 @@ func (s *Service) logListenAddressesChangedEvent(l genericListener) {
})
}
func (s *Service) VerifyConfiguration(from, to config.Configuration) error {
func (s *service) VerifyConfiguration(from, to config.Configuration) error {
return nil
}
func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
func (s *service) CommitConfiguration(from, to config.Configuration) bool {
newDevices := make(map[protocol.DeviceID]bool, len(to.Devices))
for _, dev := range to.Devices {
newDevices[dev.DeviceID] = true
@@ -589,7 +606,7 @@ func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
return true
}
func (s *Service) AllAddresses() []string {
func (s *service) AllAddresses() []string {
s.listenersMut.RLock()
var addrs []string
for _, listener := range s.listeners {
@@ -604,7 +621,7 @@ func (s *Service) AllAddresses() []string {
return util.UniqueStrings(addrs)
}
func (s *Service) ExternalAddresses() []string {
func (s *service) ExternalAddresses() []string {
s.listenersMut.RLock()
var addrs []string
for _, listener := range s.listeners {
@@ -616,7 +633,7 @@ func (s *Service) ExternalAddresses() []string {
return util.UniqueStrings(addrs)
}
func (s *Service) Status() map[string]interface{} {
func (s *service) Status() map[string]interface{} {
s.listenersMut.RLock()
result := make(map[string]interface{})
for addr, listener := range s.listeners {
@@ -636,7 +653,7 @@ func (s *Service) Status() map[string]interface{} {
return result
}
func (s *Service) NATType() string {
func (s *service) NATType() string {
s.listenersMut.RLock()
defer s.listenersMut.RUnlock()
for _, listener := range s.listeners {

View File

@@ -27,6 +27,7 @@ type Connection interface {
RemoteAddr() net.Addr
Priority() int
String() string
Crypto() string
}
// completeConn is the aggregation of an internalConn and the
@@ -101,6 +102,11 @@ func (c internalConn) Priority() int {
return c.priority
}
func (c internalConn) Crypto() string {
cs := c.ConnectionState()
return fmt.Sprintf("%s-%s", tlsVersionNames[cs.Version], tlsCipherSuiteNames[cs.CipherSuite])
}
func (c internalConn) Transport() string {
transport := c.connType.Transport()
host, _, err := net.SplitHostPort(c.LocalAddr().String())
@@ -118,11 +124,11 @@ func (c internalConn) Transport() string {
}
func (c internalConn) String() string {
return fmt.Sprintf("%s-%s/%s", c.LocalAddr(), c.RemoteAddr(), c.Type())
return fmt.Sprintf("%s-%s/%s/%s", c.LocalAddr(), c.RemoteAddr(), c.Type(), c.Crypto())
}
type dialerFactory interface {
New(*config.Wrapper, *tls.Config) genericDialer
New(config.Wrapper, *tls.Config) genericDialer
Priority() int
AlwaysWAN() bool
Valid(config.Configuration) error
@@ -135,7 +141,7 @@ type genericDialer interface {
}
type listenerFactory interface {
New(*url.URL, *config.Wrapper, *tls.Config, chan internalConn, *nat.Service) genericListener
New(*url.URL, config.Wrapper, *tls.Config, chan internalConn, *nat.Service) genericListener
Valid(config.Configuration) error
}

View File

@@ -24,7 +24,7 @@ func init() {
}
type tcpDialer struct {
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
}
@@ -62,7 +62,7 @@ func (d *tcpDialer) RedialFrequency() time.Duration {
type tcpDialerFactory struct{}
func (tcpDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDialer {
func (tcpDialerFactory) New(cfg config.Wrapper, tlsCfg *tls.Config) genericDialer {
return &tcpDialer{
cfg: cfg,
tlsCfg: tlsCfg,

View File

@@ -29,7 +29,7 @@ type tcpListener struct {
onAddressesChangedNotifier
uri *url.URL
cfg *config.Wrapper
cfg config.Wrapper
tlsCfg *tls.Config
stop chan struct{}
conns chan internalConn
@@ -195,7 +195,7 @@ func (t *tcpListener) NATType() string {
type tcpListenerFactory struct{}
func (f *tcpListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
func (f *tcpListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
return &tcpListener{
uri: fixupPort(uri, config.DefaultTCPPort),
cfg: cfg,

View File

@@ -73,7 +73,7 @@ func addToBlockMap(db *instance, folder []byte, fs []protocol.FileInfo) {
name := []byte(f.Name)
for i, block := range f.Blocks {
binary.BigEndian.PutUint32(blockBuf, uint32(i))
keyBuf = t.db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
keyBuf = t.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
t.Put(keyBuf, blockBuf)
}
}
@@ -89,7 +89,7 @@ func discardFromBlockMap(db *instance, folder []byte, fs []protocol.FileInfo) {
if !ef.IsDirectory() && !ef.IsDeleted() && !ef.IsInvalid() {
name := []byte(ef.Name)
for _, block := range ef.Blocks {
keyBuf = t.db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
keyBuf = t.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
t.Delete(keyBuf)
}
}

View File

@@ -80,7 +80,7 @@ func (db *instance) updateLocalFiles(folder []byte, fs []protocol.FileInfo, meta
if ok {
if !ef.IsDirectory() && !ef.IsDeleted() && !ef.IsInvalid() {
for _, block := range ef.Blocks {
keyBuf = t.db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
keyBuf = db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
t.Delete(keyBuf)
}
}
@@ -100,7 +100,7 @@ func (db *instance) updateLocalFiles(folder []byte, fs []protocol.FileInfo, meta
l.Debugf("insert (local); folder=%q %v", folder, f)
t.Put(dk, mustMarshal(&f))
gk = t.db.keyer.GenerateGlobalVersionKey(gk, folder, []byte(f.Name))
gk = db.keyer.GenerateGlobalVersionKey(gk, folder, []byte(f.Name))
keyBuf, _ = t.updateGlobal(gk, keyBuf, folder, protocol.LocalDeviceID[:], f, meta)
keyBuf = db.keyer.GenerateSequenceKey(keyBuf, folder, f.Sequence)
@@ -110,7 +110,7 @@ func (db *instance) updateLocalFiles(folder []byte, fs []protocol.FileInfo, meta
if !f.IsDirectory() && !f.IsDeleted() && !f.IsInvalid() {
for i, block := range f.Blocks {
binary.BigEndian.PutUint32(blockBuf, uint32(i))
keyBuf = t.db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
keyBuf = db.keyer.GenerateBlockMapKey(keyBuf, folder, block.Hash, name)
t.Put(keyBuf, blockBuf)
}
}
@@ -505,7 +505,7 @@ func (db *instance) getIndexID(device, folder []byte) protocol.IndexID {
func (db *instance) setIndexID(device, folder []byte, id protocol.IndexID) {
bs, _ := id.Marshal() // marshalling can't fail
if err := db.Put(db.keyer.GenerateIndexIDKey(nil, device, folder), bs, nil); err != nil {
if err := db.Put(db.keyer.GenerateIndexIDKey(nil, device, folder), bs, nil); err != nil && err != leveldb.ErrClosed {
panic("storing index ID: " + err.Error())
}
}

View File

@@ -9,17 +9,21 @@ package db
import (
"os"
"strings"
"sync"
"sync/atomic"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
"github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
)
const (
dbMaxOpenFiles = 100
dbWriteBuffer = 4 << 20
dbWriteBuffer = 16 << 20
dbFlushBatch = dbWriteBuffer / 4 // Some leeway for any leveldb in-memory optimizations
)
// Lowlevel is the lowest level database interface. It has a very simple
@@ -33,6 +37,8 @@ type Lowlevel struct {
location string
folderIdx *smallIndex
deviceIdx *smallIndex
closed bool
closeMut *sync.RWMutex
}
// Open attempts to open the database at the given location, and runs
@@ -102,6 +108,36 @@ func (db *Lowlevel) Delete(key []byte, wo *opt.WriteOptions) error {
return db.DB.Delete(key, wo)
}
func (db *Lowlevel) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
db.closeMut.RLock()
defer db.closeMut.RUnlock()
if db.closed {
return &closedIter{}
}
return db.DB.NewIterator(slice, ro)
}
func (db *Lowlevel) GetSnapshot() snapshot {
snap, err := db.DB.GetSnapshot()
if err != nil {
if err == leveldb.ErrClosed {
return &closedSnap{}
}
panic(err)
}
return snap
}
func (db *Lowlevel) Close() {
db.closeMut.Lock()
defer db.closeMut.Unlock()
if db.closed {
return
}
db.closed = true
db.DB.Close()
}
// NewLowlevel wraps the given *leveldb.DB into a *lowlevel
func NewLowlevel(db *leveldb.DB, location string) *Lowlevel {
return &Lowlevel{
@@ -109,6 +145,7 @@ func NewLowlevel(db *leveldb.DB, location string) *Lowlevel {
location: location,
folderIdx: newSmallIndex(db, []byte{KeyTypeFolderIdx}),
deviceIdx: newSmallIndex(db, []byte{KeyTypeDeviceIdx}),
closeMut: &sync.RWMutex{},
}
}
@@ -127,3 +164,59 @@ func leveldbIsCorrupted(err error) bool {
return false
}
type batch struct {
*leveldb.Batch
db *Lowlevel
}
func (db *Lowlevel) newBatch() *batch {
return &batch{
Batch: new(leveldb.Batch),
db: db,
}
}
// checkFlush flushes and resets the batch if its size exceeds dbFlushBatch.
func (b *batch) checkFlush() {
if len(b.Dump()) > dbFlushBatch {
b.flush()
b.Reset()
}
}
func (b *batch) flush() {
if err := b.db.Write(b.Batch, nil); err != nil && err != leveldb.ErrClosed {
panic(err)
}
}
type closedIter struct{}
func (it *closedIter) Release() {}
func (it *closedIter) Key() []byte { return nil }
func (it *closedIter) Value() []byte { return nil }
func (it *closedIter) Next() bool { return false }
func (it *closedIter) Prev() bool { return false }
func (it *closedIter) First() bool { return false }
func (it *closedIter) Last() bool { return false }
func (it *closedIter) Seek(key []byte) bool { return false }
func (it *closedIter) Valid() bool { return false }
func (it *closedIter) Error() error { return leveldb.ErrClosed }
func (it *closedIter) SetReleaser(releaser util.Releaser) {}
type snapshot interface {
Get([]byte, *opt.ReadOptions) ([]byte, error)
Has([]byte, *opt.ReadOptions) (bool, error)
NewIterator(*util.Range, *opt.ReadOptions) iterator.Iterator
Release()
}
type closedSnap struct{}
func (s *closedSnap) Get([]byte, *opt.ReadOptions) ([]byte, error) { return nil, leveldb.ErrClosed }
func (s *closedSnap) Has([]byte, *opt.ReadOptions) (bool, error) { return false, leveldb.ErrClosed }
func (s *closedSnap) NewIterator(*util.Range, *opt.ReadOptions) iterator.Iterator {
return &closedIter{}
}
func (s *closedSnap) Release() {}

View File

@@ -10,7 +10,6 @@ import (
"encoding/binary"
"time"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
)
@@ -39,21 +38,12 @@ func NewNamespacedKV(db *Lowlevel, prefix string) *NamespacedKV {
func (n *NamespacedKV) Reset() {
it := n.db.NewIterator(util.BytesPrefix(n.prefix), nil)
defer it.Release()
batch := new(leveldb.Batch)
batch := n.db.newBatch()
for it.Next() {
batch.Delete(it.Key())
if batch.Len() > batchFlushSize {
if err := n.db.Write(batch, nil); err != nil {
panic(err)
}
batch.Reset()
}
}
if batch.Len() > 0 {
if err := n.db.Write(batch, nil); err != nil {
panic(err)
}
batch.checkFlush()
}
batch.flush()
}
// PutInt64 stores a new int64. Any existing value (even if of another type)

View File

@@ -104,18 +104,18 @@ func (db *schemaUpdater) updateSchema0to1() {
var gk, buf []byte
for dbi.Next() {
t.checkFlush()
folder, ok := db.keyer.FolderFromDeviceFileKey(dbi.Key())
if !ok {
// not having the folder in the index is bad; delete and continue
t.Delete(dbi.Key())
t.checkFlush()
continue
}
device, ok := db.keyer.DeviceFromDeviceFileKey(dbi.Key())
if !ok {
// not having the device in the index is bad; delete and continue
t.Delete(dbi.Key())
t.checkFlush()
continue
}
name := db.keyer.NameFromDeviceFileKey(dbi.Key())
@@ -128,7 +128,6 @@ func (db *schemaUpdater) updateSchema0to1() {
gk = db.keyer.GenerateGlobalVersionKey(gk, folder, name)
buf = t.removeFromGlobal(gk, buf, folder, device, nil, nil)
t.Delete(dbi.Key())
t.checkFlush()
continue
}
@@ -149,7 +148,6 @@ func (db *schemaUpdater) updateSchema0to1() {
panic("can't happen: " + err.Error())
}
t.Put(dbi.Key(), bs)
t.checkFlush()
symlinkConv++
}
@@ -210,7 +208,7 @@ func (db *schemaUpdater) updateSchema2to3() {
if !need(f, ok, v) {
return true
}
nk = t.db.keyer.GenerateNeedFileKey(nk, folder, []byte(f.FileName()))
nk = t.keyer.GenerateNeedFileKey(nk, folder, []byte(f.FileName()))
t.Put(nk, nil)
t.checkFlush()
return true
@@ -282,7 +280,7 @@ func (db *schemaUpdater) updateSchema6to7() {
svl, err := t.Get(gk, nil)
if err != nil {
// If there is no global list, we hardly need it.
t.Delete(t.db.keyer.GenerateNeedFileKey(nk, folder, name))
t.Delete(t.keyer.GenerateNeedFileKey(nk, folder, name))
return true
}
var fl VersionList
@@ -293,7 +291,7 @@ func (db *schemaUpdater) updateSchema6to7() {
return true
}
if localFV, haveLocalFV := fl.Get(protocol.LocalDeviceID[:]); !need(global, haveLocalFV, localFV.Version) {
t.Delete(t.db.keyer.GenerateNeedFileKey(nk, folder, name))
t.Delete(t.keyer.GenerateNeedFileKey(nk, folder, name))
}
return true
})

View File

@@ -12,23 +12,16 @@ import (
"github.com/syndtr/goleveldb/leveldb/util"
)
// Flush batches to disk when they contain this many records.
const batchFlushSize = 64
// A readOnlyTransaction represents a database snapshot.
type readOnlyTransaction struct {
*leveldb.Snapshot
db *instance
snapshot
keyer keyer
}
func (db *instance) newReadOnlyTransaction() readOnlyTransaction {
snap, err := db.GetSnapshot()
if err != nil {
panic(err)
}
return readOnlyTransaction{
Snapshot: snap,
db: db,
snapshot: db.GetSnapshot(),
keyer: db.keyer,
}
}
@@ -37,7 +30,7 @@ func (t readOnlyTransaction) close() {
}
func (t readOnlyTransaction) getFile(folder, device, file []byte) (protocol.FileInfo, bool) {
return t.getFileByKey(t.db.keyer.GenerateDeviceFileKey(nil, folder, device, file))
return t.getFileByKey(t.keyer.GenerateDeviceFileKey(nil, folder, device, file))
}
func (t readOnlyTransaction) getFileByKey(key []byte) (protocol.FileInfo, bool) {
@@ -65,7 +58,7 @@ func (t readOnlyTransaction) getFileTrunc(key []byte, trunc bool) (FileIntf, boo
}
func (t readOnlyTransaction) getGlobal(keyBuf, folder, file []byte, truncate bool) ([]byte, FileIntf, bool) {
keyBuf = t.db.keyer.GenerateGlobalVersionKey(keyBuf, folder, file)
keyBuf = t.keyer.GenerateGlobalVersionKey(keyBuf, folder, file)
bs, err := t.Get(keyBuf, nil)
if err != nil {
@@ -77,7 +70,7 @@ func (t readOnlyTransaction) getGlobal(keyBuf, folder, file []byte, truncate boo
return keyBuf, nil, false
}
keyBuf = t.db.keyer.GenerateDeviceFileKey(keyBuf, folder, vl.Versions[0].Device, file)
keyBuf = t.keyer.GenerateDeviceFileKey(keyBuf, folder, vl.Versions[0].Device, file)
if fi, ok := t.getFileTrunc(keyBuf, truncate); ok {
return keyBuf, fi, true
}
@@ -90,14 +83,13 @@ func (t readOnlyTransaction) getGlobal(keyBuf, folder, file []byte, truncate boo
// batch size.
type readWriteTransaction struct {
readOnlyTransaction
*leveldb.Batch
*batch
}
func (db *instance) newReadWriteTransaction() readWriteTransaction {
t := db.newReadOnlyTransaction()
return readWriteTransaction{
readOnlyTransaction: t,
Batch: new(leveldb.Batch),
readOnlyTransaction: db.newReadOnlyTransaction(),
batch: db.newBatch(),
}
}
@@ -106,19 +98,6 @@ func (t readWriteTransaction) close() {
t.readOnlyTransaction.close()
}
func (t readWriteTransaction) checkFlush() {
if t.Batch.Len() > batchFlushSize {
t.flush()
t.Batch.Reset()
}
}
func (t readWriteTransaction) flush() {
if err := t.db.Write(t.Batch, nil); err != nil {
panic(err)
}
}
// updateGlobal adds this device+version to the version list for the given
// file. If the device is already present in the list, the version is updated.
// If the file does not have an entry in the global list, it is created.
@@ -142,11 +121,14 @@ func (t readWriteTransaction) updateGlobal(gk, keyBuf, folder, device []byte, fi
// Inserted a new newest version
global = file
} else {
keyBuf = t.db.keyer.GenerateDeviceFileKey(keyBuf, folder, fl.Versions[0].Device, name)
keyBuf = t.keyer.GenerateDeviceFileKey(keyBuf, folder, fl.Versions[0].Device, name)
if new, ok := t.getFileByKey(keyBuf); ok {
global = new
} else {
panic("This file must exist in the db")
// This file must exist in the db, so this must be caused
// by the db being closed - bail out.
l.Debugln("File should exist:", name)
return keyBuf, false
}
}
@@ -167,7 +149,7 @@ func (t readWriteTransaction) updateGlobal(gk, keyBuf, folder, device []byte, fi
// The previous newest version is now at index 1
oldGlobalFV = fl.Versions[1]
}
keyBuf = t.db.keyer.GenerateDeviceFileKey(keyBuf, folder, oldGlobalFV.Device, name)
keyBuf = t.keyer.GenerateDeviceFileKey(keyBuf, folder, oldGlobalFV.Device, name)
if oldFile, ok := t.getFileByKey(keyBuf); ok {
// A failure to get the file here is surprising and our
// global size data will be incorrect until a restart...
@@ -187,7 +169,7 @@ func (t readWriteTransaction) updateGlobal(gk, keyBuf, folder, device []byte, fi
// device according to the version list and global FileInfo given and updates
// the db accordingly.
func (t readWriteTransaction) updateLocalNeed(keyBuf, folder, name []byte, fl VersionList, global protocol.FileInfo) []byte {
keyBuf = t.db.keyer.GenerateNeedFileKey(keyBuf, folder, name)
keyBuf = t.keyer.GenerateNeedFileKey(keyBuf, folder, name)
hasNeeded, _ := t.Has(keyBuf, nil)
if localFV, haveLocalFV := fl.Get(protocol.LocalDeviceID[:]); need(global, haveLocalFV, localFV.Version) {
if !hasNeeded {
@@ -246,24 +228,27 @@ func (t readWriteTransaction) removeFromGlobal(gk, keyBuf, folder, device []byte
if removedAt == 0 {
// A failure to get the file here is surprising and our
// global size data will be incorrect until a restart...
keyBuf = t.db.keyer.GenerateDeviceFileKey(keyBuf, folder, device, file)
keyBuf = t.keyer.GenerateDeviceFileKey(keyBuf, folder, device, file)
if f, ok := t.getFileByKey(keyBuf); ok {
meta.removeFile(protocol.GlobalDeviceID, f)
}
}
if len(fl.Versions) == 0 {
keyBuf = t.db.keyer.GenerateNeedFileKey(keyBuf, folder, file)
keyBuf = t.keyer.GenerateNeedFileKey(keyBuf, folder, file)
t.Delete(keyBuf)
t.Delete(gk)
return keyBuf
}
if removedAt == 0 {
keyBuf = t.db.keyer.GenerateDeviceFileKey(keyBuf, folder, fl.Versions[0].Device, file)
keyBuf = t.keyer.GenerateDeviceFileKey(keyBuf, folder, fl.Versions[0].Device, file)
global, ok := t.getFileByKey(keyBuf)
if !ok {
panic("This file must exist in the db")
// This file must exist in the db, so this must be caused
// by the db being closed - bail out.
l.Debugln("File should exist:", file)
return keyBuf
}
keyBuf = t.updateLocalNeed(keyBuf, folder, file, fl, global)
meta.addFile(protocol.GlobalDeviceID, global)

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