Compare commits

...

36 Commits

Author SHA1 Message Date
Tobias Tom
5aade9a4a5 Add -device-id command line option (fixes #4387)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4390
2017-09-25 06:05:21 +00:00
Jakob Borg
9717c3d292 authors: Add tobiastom 2017-09-25 07:51:21 +02:00
Jakob Borg
a365ae51c4 lib/model: Hide temporary files on Windows while they are in use (fixes #4382)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4394
2017-09-23 13:47:51 +00:00
Jakob Borg
97222797a0 lib/config: Make folder marker change non fatal 2017-09-23 15:29:55 +02:00
Simon Frei
e588bb29b9 lib/model: remove unused folderFs member from Model
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4389
2017-09-21 09:03:36 +00:00
Jakob Borg
2dd9450793 lib/protocol, vendor: Import luhn code directly
I've changed it incompatibly to fix a correctness bug. Nonetheless, we
should remain incorrect indefinitely.
2017-09-20 21:34:32 +02:00
Jakob Borg
3ee12464b4 lib/config, lib/model: Make sure to hide our special files (fixes #4382)
The folder marker conversion forgot to hide the .stfolder. This adds
that, for those who have not yet been converted.

Also adds Hide() calls to the folder start, to mend historical
unhidedness. (I'm sure this will upset someone who is manually managing
their .stignores in the other direction...)

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4384
2017-09-20 06:49:04 +00:00
Jakob Borg
59ebcea356 gui, man: Update docs & translations 2017-09-20 07:45:17 +02:00
Sly_tom_cat
27d4896a13 gui: Fix title attribute for popups on shared folders / devices (fixes #4377)
Skip-check: authors

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4378
2017-09-19 15:37:26 +00:00
Simon Frei
1088eb12ea lib/model: Fix logging inconsistencies (fixes #4375)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4376
2017-09-18 11:56:19 +00:00
Jakob Borg
f40d219370 gui, man: Update docs & translations 2017-09-13 07:45:17 +02:00
Jakob Borg
429cc20eb7 cmd/syncthing: Add some common security releated HTTP headers (fixes #4360)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4361
2017-09-10 08:28:12 +00:00
Audrius Butkevicius
e85ce7c94e lib/model: Support removing paused folders (fixes #4357)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4358
LGTM: imsodin, calmh
2017-09-09 15:08:59 +00:00
Jakob Borg
283c8d95e2 lib/protocol: Comment typo 2017-09-08 15:25:14 +02:00
wangguoliang
a9aa375109 lib/fs: Comment typo
Skip-check: authors

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4354
2017-09-07 09:40:46 +00:00
Simon Frei
f7d2c58783 lib/model: Deduplicate folder loops
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4352
LGTM: AudriusButkevicius, calmh
2017-09-07 06:17:47 +00:00
Jakob Borg
4d3e0de4ba cmd/syncthing, lib/sha256: Skip CPU benchmarks when user decided (fixes #4348)
When STHASHING is set, don't benchmark as it's already decided. If weak
hashing isn't set to "auto", don't benchmark that either.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4349
2017-09-06 06:55:47 +00:00
Simon Frei
9dbc509996 lib/ignore: Consistent behaviour for nil *Matcher
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4310
2017-09-06 06:39:18 +00:00
Jakob Borg
baec3f909c gui, man: Update docs & translations 2017-09-06 07:45:19 +02:00
Simon Frei
c41aaad3bb lib/ignore: Ignore duplicate lines in .stignore
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4350
LGTM: AudriusButkevicius, calmh
2017-09-04 12:46:19 +00:00
Jakob Borg
9682bbfbda lib/protocol: Optimize luhn and chunk functions
These functions were very naive and slow. We haven't done much about
them because they pretty much don't matter at all for Syncthing
performance. They are however called very often in the discovery server
and these optimizations have a huge effect on the CPU load on the
public discovery servers.

The code isn't exactly obvious, but we have good test coverage on all
these functions.

benchmark                 old ns/op     new ns/op     delta
BenchmarkLuhnify-8        12458         1045          -91.61%
BenchmarkUnluhnify-8      12598         1074          -91.47%
BenchmarkChunkify-8       10792         104           -99.04%

benchmark                 old allocs     new allocs     delta
BenchmarkLuhnify-8        18             1              -94.44%
BenchmarkUnluhnify-8      18             1              -94.44%
BenchmarkChunkify-8       44             2              -95.45%

benchmark                 old bytes     new bytes     delta
BenchmarkLuhnify-8        1278          64            -94.99%
BenchmarkUnluhnify-8      1278          64            -94.99%
BenchmarkChunkify-8       42552         128           -99.70%

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4346
2017-09-03 10:26:12 +00:00
Audrius Butkevicius
9e6a1fdcd4 vendor: Update kcp, removes closeConn (fixes #4343) 2017-09-02 16:11:48 +02:00
Jakob Borg
49bddfbe53 cmd/syncthing: Add test for truncate behavior of log file (ref #4255)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4342
2017-09-02 06:56:35 +00:00
Simon Frei
55e0ac3e24 lib/model: Make puller retrying and logging less aggressive
Currently all errors during pulling and the first of these errors again on
finishing are logged to info. Besides that the errors logged when finishing
are stored in f.errors. This PR moves all logging during pulling to the debug
channel (they might still be relevant in some obscure debugging case) and
uses the stored errors to log the main error per fail when all pulling
iterations are done and failed.

Additional instead of trying 11 times it now only tries 3 times.

This is the first part of what is discussed here:
https://forum.syncthing.net/t/reduce-verboseness-of-puller/10261

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4338
2017-09-02 06:05:55 +00:00
Audrius Butkevicius
cbcc3ea132 lib/connections: Use our own fork of kcp (fixes #4063)
This updates kcp and uses our own fork which:

1. Keys sessions not just by remote address, but by remote address +
conversation id 2. Allows not to close connections that were passed directly
to the library. 3. Resets cache key if the session gets terminated.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4339
LGTM: calmh
2017-09-02 06:04:35 +00:00
Audrius Butkevicius
ab132ff6fe lib: Folder marker is now a folder
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4341
LGTM: calmh
2017-09-02 05:52:38 +00:00
Jakob Borg
19e52a10df readme: Update badges for new build server 2017-09-01 14:23:17 +02:00
Jakob Borg
a8145e187f lib/model: Fixup because I suck and shouldn't commit directly to master 2017-08-31 10:49:17 +02:00
Jakob Borg
e33fa10115 lib/model: Use same batch size constants in db updater as for protocol 2017-08-31 10:47:39 +02:00
Jakob Borg
4b6e7e7867 lib/tlsutil: Remove undesired bufio from UnionedConnection (ref #4245)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4335
2017-08-31 07:34:48 +00:00
Jakob Borg
70d121a94b cmd/strelaysrv: Smaller, adjustable network buffer 2017-08-30 18:52:28 +02:00
Jakob Borg
33ffb07d31 cmd/strelaysrv: Don't leak tickers 2017-08-30 18:46:50 +02:00
Jakob Borg
7aaa92ac47 cmd/strelaysrv: Add profiling support, default disabled 2017-08-30 16:07:15 +02:00
Jakob Borg
5883eb9a25 gui, man: Update docs & translations 2017-08-30 10:50:19 +02:00
MaximAL
e60efa2b3d gui: Correct quotes in title attribute
Skip-check: authors

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4332
2017-08-30 06:02:46 +00:00
Simon Frei
ddf6d64faa lib/model: Create folders via newFolder
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4329
2017-08-25 19:47:01 +00:00
118 changed files with 2453 additions and 899 deletions

View File

@@ -107,6 +107,7 @@ Suhas Gundimeda (snugghash) <suhas.gundimeda@gmail.com> <snugghash@gmail.com>
Tim Abell (timabell) <tim@timwise.co.uk>
Tim Howes (timhowes) <timhowes@berkeley.edu>
Tobias Nygren (tnn2) <tnn@nygren.pp.se>
Tobias Tom (tobiastom) <t.tom@succont.de>
Tomas Cerveny (kozec) <kozec@kozec.com>
Tully Robinson (tojrobinson) <tully@tojr.org>
Tyler Brazier (tylerbrazier) <tyler@tylerbrazier.com>

1
NICKS
View File

@@ -129,6 +129,7 @@ Stefan-Code <Stefan.github@gmail.com>
timabell <tim@timwise.co.uk>
timhowes <timhowes@berkeley.edu>
tnn2 <tnn@nygren.pp.se>
tobiastom <t.tom@succont.de>
tojrobinson <tully@tojr.org>
tpng <benny.tpng@gmail.com>
tylerbrazier <tyler@tylerbrazier.com>

View File

@@ -2,11 +2,10 @@
---
[![Latest Linux & Cross Build](https://img.shields.io/jenkins/s/http/build.syncthing.net/syncthing.svg?style=flat-square&label=linux+%26+cross)](https://build.syncthing.net/job/syncthing/lastBuild/)
[![Latest Windows Build](https://img.shields.io/jenkins/s/http/build.syncthing.net/syncthing-windows.svg?style=flat-square&label=windows)](https://build.syncthing.net/job/syncthing/lastBuild/)
[![Latest Mac Build](https://img.shields.io/jenkins/s/http/build.syncthing.net/syncthing-mac.svg?style=flat-square&label=mac)](https://build.syncthing.net/job/syncthing/lastBuild/)
[![Latest Solaris Build](https://img.shields.io/jenkins/s/http/build.syncthing.net/syncthing-solaris.svg?style=flat-square&label=solaris)](https://build.syncthing.net/job/syncthing/lastBuild/)
[![API Documentation](https://img.shields.io/badge/api-Godoc-blue.svg?style=flat-square)](https://godoc.org/github.com/syncthing/syncthing)
[![Latest Downloads](https://img.shields.io/badge/latest-downloads-brightgreen.svg?style=flat-square)](https://build.syncthing.net/latest/)
[![Latest Linux & Cross Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildLinuxCross.svg?style=flat-square&label=linux+%26+cross+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildLinuxCross&guest=1)
[![Latest Windows Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildWindows.svg?style=flat-square&label=windows+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildWindows&guest=1)
[![Latest Mac Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildMac.svg?style=flat-square&label=mac+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildMac&guest=1)
[![MPLv2 License](https://img.shields.io/badge/license-MPLv2-blue.svg?style=flat-square)](https://www.mozilla.org/MPL/2.0/)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/88/badge)](https://bestpractices.coreinfrastructure.org/projects/88)
[![Go Report Card](https://goreportcard.com/badge/github.com/syncthing/syncthing)](https://goreportcard.com/report/github.com/syncthing/syncthing)
@@ -111,4 +110,4 @@ All code is licensed under the [MPLv2 License][7].
[12]: https://www.bountysource.com/teams/syncthing/issues
[13]: https://github.com/syncthing/syncthing/blob/master/GOALS.md
[14]: assets/logo-text-128.png
[15]: https://syncthing.net/
[15]: https://syncthing.net/

View File

@@ -88,10 +88,10 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
}
rn, _ := filepath.Rel(dir, path)
if rn == "." || rn == ".stfolder" {
if rn == "." {
return nil
}
if rn == ".stversions" {
if rn == ".stversions" || rn == ".stfolder" {
return filepath.SkipDir
}

View File

@@ -104,7 +104,9 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
go messageReader(conn, messages, errors)
pingTicker := time.NewTicker(pingInterval)
defer pingTicker.Stop()
timeoutTicker := time.NewTimer(networkTimeout)
defer timeoutTicker.Stop()
joined := false
for {

View File

@@ -64,12 +64,13 @@ var (
limitCheckTimer *time.Timer
sessionLimitBps int
globalLimitBps int
overLimit int32
descriptorLimit int64
sessionLimiter *rate.Limiter
globalLimiter *rate.Limiter
sessionLimitBps int
globalLimitBps int
overLimit int32
descriptorLimit int64
sessionLimiter *rate.Limiter
globalLimiter *rate.Limiter
networkBufferSize int
statusAddr string
poolAddrs string
@@ -81,6 +82,8 @@ var (
natLease int
natRenewal int
natTimeout int
pprofEnabled bool
)
func main() {
@@ -105,6 +108,8 @@ func main() {
flag.IntVar(&natLease, "nat-lease", 60, "NAT lease length in minutes")
flag.IntVar(&natRenewal, "nat-renewal", 30, "NAT renewal frequency in minutes")
flag.IntVar(&natTimeout, "nat-timeout", 10, "NAT discovery timeout in seconds")
flag.BoolVar(&pprofEnabled, "pprof", false, "Enable the built in profiling on the status server")
flag.IntVar(&networkBufferSize, "network-buffer", 2048, "Network buffer size (two of these per proxied connection)")
flag.Parse()
if extAddress == "" {

View File

@@ -254,7 +254,7 @@ func (s *session) proxy(c1, c2 net.Conn) error {
atomic.AddInt64(&numProxies, 1)
defer atomic.AddInt64(&numProxies, -1)
buf := make([]byte, 65536)
buf := make([]byte, networkBufferSize)
for {
c1.SetReadDeadline(time.Now().Add(networkTimeout))
n, err := c1.Read(buf)

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"log"
"net/http"
"net/http/pprof"
"runtime"
"sync/atomic"
"time"
@@ -18,6 +19,9 @@ func statusService(addr string) {
handler := http.NewServeMux()
handler.HandleFunc("/status", getStatus)
if pprofEnabled {
handler.HandleFunc("/debug/pprof/", pprof.Index)
}
srv := http.Server{
Addr: addr,

View File

@@ -332,7 +332,7 @@ func (s *apiService) Serve() {
}
// Add the CORS handling
handler = corsMiddleware(handler)
handler = corsMiddleware(handler, guiCfg.InsecureAllowFrameLoading)
if addressIsLocalhost(guiCfg.Address()) && !guiCfg.InsecureSkipHostCheck {
// Verify source host
@@ -459,7 +459,7 @@ func debugMiddleware(h http.Handler) http.Handler {
})
}
func corsMiddleware(next http.Handler) http.Handler {
func corsMiddleware(next http.Handler, allowFrameLoading bool) http.Handler {
// Handle CORS headers and CORS OPTIONS request.
// CORS OPTIONS request are typically sent by browser during AJAX preflight
// when the browser initiate a POST request.
@@ -486,6 +486,27 @@ func corsMiddleware(next http.Handler) http.Handler {
return
}
// Other security related headers that should be present.
// https://www.owasp.org/index.php/Security_Headers
if !allowFrameLoading {
// We don't want to be rendered in an <iframe>,
// <frame> or <object>. (Unless we do it ourselves.
// This is also an escape hatch for people who serve
// Syncthing GUI as part of their own website
// through a proxy, so they don't need to set the
// allowFrameLoading bool.)
w.Header().Set("X-Frame-Options", "SAMEORIGIN")
}
// If the browser senses an XSS attack it's allowed to take
// action. (How this would not always be the default I
// don't fully understand.)
w.Header().Set("X-XSS-Protection", "1; mode=block")
// Our content type headers are correct. Don't guess.
w.Header().Set("X-Content-Type-Options", "nosniff")
// For everything else, pass to the next handler
next.ServeHTTP(w, r)
return

View File

@@ -141,17 +141,17 @@ func (s *staticsServer) serveThemes(w http.ResponseWriter, r *http.Request) {
func (s *staticsServer) mimeTypeForFile(file string) string {
// We use a built in table of the common types since the system
// TypeByExtension might be unreliable. But if we don't know, we delegate
// to the system.
// to the system. All our files are UTF-8.
ext := filepath.Ext(file)
switch ext {
case ".htm", ".html":
return "text/html"
return "text/html; charset=utf-8"
case ".css":
return "text/css"
return "text/css; charset=utf-8"
case ".js":
return "application/javascript"
return "application/javascript; charset=utf-8"
case ".json":
return "application/json"
return "application/json; charset=utf-8"
case ".png":
return "image/png"
case ".ttf":
@@ -159,7 +159,7 @@ func (s *staticsServer) mimeTypeForFile(file string) string {
case ".woff":
return "application/x-font-woff"
case ".svg":
return "image/svg+xml"
return "image/svg+xml; charset=utf-8"
default:
return mime.TypeByExtension(ext)
}

View File

@@ -236,6 +236,7 @@ type RuntimeOptions struct {
resetDeltaIdxs bool
showVersion bool
showPaths bool
showDeviceId bool
doUpgrade bool
doUpgradeCheck bool
upgradeTo string
@@ -301,6 +302,7 @@ func parseCommandLineOptions() RuntimeOptions {
flag.BoolVar(&options.doUpgradeCheck, "upgrade-check", false, "Check for available upgrade")
flag.BoolVar(&options.showVersion, "version", false, "Show version")
flag.BoolVar(&options.showPaths, "paths", false, "Show configuration paths")
flag.BoolVar(&options.showDeviceId, "device-id", false, "Show the device ID")
flag.StringVar(&options.upgradeTo, "upgrade-to", options.upgradeTo, "Force upgrade directly from specified URL")
flag.BoolVar(&options.auditEnabled, "audit", false, "Write events to audit file")
flag.BoolVar(&options.verbose, "verbose", false, "Print verbose log output")
@@ -390,6 +392,17 @@ func main() {
return
}
if options.showDeviceId {
cert, err := tls.LoadX509KeyPair(locations[locCertFile], locations[locKeyFile])
if err != nil {
l.Fatalln("Error reading device ID:", err)
}
myID = protocol.NewDeviceID(cert.Certificate[0])
fmt.Println(myID)
return
}
if options.browserOnly {
openGUI()
return
@@ -638,12 +651,10 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
l.Infoln(LongVersion)
l.Infoln("My ID:", myID)
// Select SHA256 implementation and report. Affected by the
// STHASHING environment variable.
sha256.SelectAlgo()
sha256.Report()
perfWithWeakHash := cpuBench(3, 150*time.Millisecond, true)
l.Infof("Hashing performance with weak hash is %.02f MB/s", perfWithWeakHash)
perfWithoutWeakHash := cpuBench(3, 150*time.Millisecond, false)
l.Infof("Hashing performance without weak hash is %.02f MB/s", perfWithoutWeakHash)
// Emit the Starting event, now that we know who we are.
@@ -696,6 +707,11 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
opts := cfg.Options()
if opts.WeakHashSelectionMethod == config.WeakHashAuto {
perfWithWeakHash := cpuBench(3, 150*time.Millisecond, true)
l.Infof("Hashing performance with weak hash is %.02f MB/s", perfWithWeakHash)
perfWithoutWeakHash := cpuBench(3, 150*time.Millisecond, false)
l.Infof("Hashing performance without weak hash is %.02f MB/s", perfWithoutWeakHash)
if perfWithoutWeakHash*0.8 > perfWithWeakHash {
l.Infof("Weak hash disabled, as it has an unacceptable performance impact.")
weakhash.Enabled = false

View File

@@ -0,0 +1,88 @@
// Copyright (C) 2017 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package main
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
)
func TestAutoClosedFile(t *testing.T) {
os.RemoveAll("_autoclose")
defer os.RemoveAll("_autoclose")
os.Mkdir("_autoclose", 0755)
file := filepath.FromSlash("_autoclose/tmp")
data := []byte("hello, world\n")
// An autoclosed file that closes very quickly
ac := newAutoclosedFile(file, time.Millisecond, time.Millisecond)
// Write some data.
if _, err := ac.Write(data); err != nil {
t.Fatal(err)
}
// Wait for it to close
start := time.Now()
for {
time.Sleep(time.Millisecond)
ac.mut.Lock()
fd := ac.fd
ac.mut.Unlock()
if fd == nil {
break
}
if time.Since(start) > time.Second {
t.Fatal("File should have been closed after first write")
}
}
// Write more data, which should be an append.
if _, err := ac.Write(data); err != nil {
t.Fatal(err)
}
// Close.
if err := ac.Close(); err != nil {
t.Fatal(err)
}
// The file should have both writes in it.
bs, err := ioutil.ReadFile(file)
if err != nil {
t.Fatal(err)
}
if len(bs) != 2*len(data) {
t.Fatalf("Writes failed, expected %d bytes, not %d", 2*len(data), len(bs))
}
// Open the file again.
ac = newAutoclosedFile(file, time.Second, time.Second)
// Write something
if _, err := ac.Write(data); err != nil {
t.Fatal(err)
}
// It should now contain only one write, because the first open
// should be a truncate.
bs, err = ioutil.ReadFile(file)
if err != nil {
t.Fatal(err)
}
if len(bs) != len(data) {
t.Fatalf("Write failed, expected %d bytes, not %d", len(data), len(bs))
}
// Close.
if err := ac.Close(); err != nil {
t.Fatal(err)
}
}

View File

@@ -183,6 +183,7 @@
"Save": "Запази",
"Scan Time Remaining": "Оставащо време за сканиране",
"Scanning": "Сканиране",
"See external versioner help for supported templated command line parameters.": "Прегледайте документацията на външното приложение за версии и поддържаните от него командни параметри. ",
"Select the devices to share this folder with.": "Изберете устройствата, с които да споделите папката.",
"Select the folders to share with this device.": "Изберете папките за споделяне с това устройство.",
"Send & Receive": "Изпращане & получаване",

View File

@@ -183,6 +183,7 @@
"Save": "Gravar",
"Scan Time Remaining": "Temps d'escaneig restant",
"Scanning": "Rastrejant",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Selecciona els dispositius amb els que compartir aquesta carpeta.",
"Select the folders to share with this device.": "Selecciona les carpetes per a compartir amb aquest dispositiu.",
"Send & Receive": "Enviar i Rebre",

View File

@@ -69,7 +69,7 @@
"Enable NAT traversal": "Povolit NAT přenos",
"Enable Relaying": "Povolit přenašeče",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Zadajte kladné číslo (např. \"2.35\") a zvolte jednotku. Percenta znamenají část celkové velikosti disku.",
"Enter a non-privileged port number (1024 - 65535).": "Enter a non-privileged port number (1024 - 65535).",
"Enter a non-privileged port number (1024 - 65535).": "Zadejte číslo neprivilegovaného portu (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Zadejte adresy oddělené čárkou (\"tcp://ip:port\", \"tcp://host:port\") nebo \"dynamic\" pro automatické zjišťování adres.",
"Enter ignore patterns, one per line.": "Vložit ignorované vzory, jeden na řádek.",
"Error": "Chyba",
@@ -183,6 +183,7 @@
"Save": "Uložit",
"Scan Time Remaining": "Zbývající čas skenování",
"Scanning": "Skenování",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Vybrat přístroje, se kterými sdílet tento adresář.",
"Select the folders to share with this device.": "Vybrat adresáře sdílené s tímto přístrojem.",
"Send & Receive": "Odeslat a přijmout",
@@ -273,7 +274,7 @@
"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 přístroje 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říč přístoji. Rozlišují se malá a velká písmena a musí přesně souhlasit mezi všemi přístroji.",
"Yes": "Ano",
"You can also select one of these nearby devices:": "You can also select one of these nearby devices:",
"You can also select one of these nearby devices:": "Také můžete vybrat jedno z těchto okolních zařízení:",
"You can change your choice at any time in the Settings dialog.": "Vaši volbu můžete kdykoliv změnit v dialogu nastavení.",
"You can read more about the two release channels at the link below.": "O kandidátech na vydání si můžete přečíst více v odkazu níže.",
"You must keep at least one version.": "Je třeba ponechat alespoň jednu verzi.",

View File

@@ -183,6 +183,7 @@
"Save": "Gem",
"Scan Time Remaining": "Tid tilbage af skanningen",
"Scanning": "Opdaterer",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Vælg hvilke enheder du vil dele denne mappe med",
"Select the folders to share with this device.": "Vælg hvilke mapper du vil dele med denne enhed.",
"Send & Receive": "Send & Modtag",

View File

@@ -183,6 +183,7 @@
"Save": "Speichern",
"Scan Time Remaining": "Zeit für Scan verbleibend",
"Scanning": "Scannen",
"See external versioner help for supported templated command line parameters.": "Siehe externe Versionshilfe für unterstützte Befehlszeilenparameter.",
"Select the devices to share this folder with.": "Wähle die Geräte aus, mit denen Du diesen Ordner teilen willst.",
"Select the folders to share with this device.": "Wähle die Ordner aus, die Du mit diesem Gerät teilen möchtest",
"Send & Receive": "Senden & empfangen",

View File

@@ -183,6 +183,7 @@
"Save": "Αποθήκευση",
"Scan Time Remaining": "Εναπομείναντας χρόνος για τον έλεγχο ",
"Scanning": "Έλεγχος για αλλαγές",
"See external versioner help for supported templated command line parameters.": "Ανατρέξτε στην τεκμηρίωση της εξωτερικής τήρησης εκδόσεων για πληροφορίες σχετικά με τις υποστηριζόμενες παραμέτρους της γραμμής εντολών.",
"Select the devices to share this folder with.": "Διάλεξε τις συσκευές προς τις οποίες θα διαμοιράζεται αυτός ο φάκελος.",
"Select the folders to share with this device.": "Διάλεξε ποιοι φάκελοι θα διαμοιράζονται προς αυτή τη συσκευή.",
"Send & Receive": "Αποστολή και λήψη",

View File

@@ -183,6 +183,7 @@
"Save": "Save",
"Scan Time Remaining": "Scan Time Remaining",
"Scanning": "Scanning",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
"Select the folders to share with this device.": "Select the folders to share with this device.",
"Send & Receive": "Send & Receive",

View File

@@ -183,6 +183,7 @@
"Save": "Save",
"Scan Time Remaining": "Scan Time Remaining",
"Scanning": "Scanning",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
"Select the folders to share with this device.": "Select the folders to share with this device.",
"Send \u0026 Receive": "Send \u0026 Receive",

View File

@@ -183,6 +183,7 @@
"Save": "Konservu",
"Scan Time Remaining": "Skanada Restanta Tempo",
"Scanning": "Skanado",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"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",

View File

@@ -183,6 +183,7 @@
"Save": "Guardar",
"Scan Time Remaining": "Tiempo Restante de Escaneo",
"Scanning": "Analizando",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Selecciona los dispositivos con los que compartir esta carpeta.",
"Select the folders to share with this device.": "Selecciona las carpetas para compartir con este dispositivo.",
"Send & Receive": "Enviar y Recibir",

View File

@@ -183,6 +183,7 @@
"Save": "Guardar",
"Scan Time Remaining": "Tiempo Restante de Escaneo",
"Scanning": "Analizando",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Selecciona los dispositivos con los que compartir esta carpeta.",
"Select the folders to share with this device.": "Selecciona las carpetas para compartir con este dispositivo.",
"Send & Receive": "Enviar y Recibir",

View File

@@ -183,6 +183,7 @@
"Save": "Grabatu",
"Scan Time Remaining": "Gelditzen den azterketa denbora",
"Scanning": "Azterketa martxan",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": " Tresnak hauta itzazu partekatze honekin sinkronizatzeko ",
"Select the folders to share with this device.": "Tresna honek erabiltzen dituen partekatzeak hauta itzazu",
"Send & Receive": "Igorri eta errezibitu",

View File

@@ -183,6 +183,7 @@
"Save": "Tallenna",
"Scan Time Remaining": "Skannausaikaa jäljellä",
"Scanning": "Skannataan",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Valitse laitteet, joiden kanssa tämä kansio jaetaan.",
"Select the folders to share with this device.": "Valitse kansiot jaettavaksi tämän laitteen kanssa.",
"Send & Receive": "Lähetä & vastaanota",

View File

@@ -183,6 +183,7 @@
"Save": "Enregistrer",
"Scan Time Remaining": "Temps d'analyse restant",
"Scanning": "Analyse en cours",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Synchroniser avec :",
"Select the folders to share with this device.": "Sélectionner les partages auxquels participe cet appareil.",
"Send & Receive": "Envoi & réception",

View File

@@ -51,7 +51,7 @@
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "\"{{name}}\" ({{device}}), appareil actuellement à {{address}}, demande à se connecter.\nAcceptez-vous de l'ajouter à votre liste d'appareils connus ?",
"Device ID": "ID de l'appareil",
"Device Identification": "Identifiant de l'appareil",
"Device Name": "Nom de l'appareil",
"Device Name": "Nom convivial local de l'appareil",
"Devices": "Appareils",
"Disconnected": "Déconnecté",
"Discovered": "Découvert",
@@ -61,9 +61,9 @@
"Download Rate": "Débit de réception",
"Downloaded": "Reçu",
"Downloading": "Réception",
"Edit": "Modifier",
"Edit Device": "Modifier l'appareil",
"Edit Folder": "Modifier le partage",
"Edit": "Gérer",
"Edit Device": "Gérer l'appareil",
"Edit Folder": "Gérer le partage",
"Editing": "Modifications",
"Editing {%path%}.": "Modification de {{path}}.",
"Enable NAT traversal": "Activer la translation d'adresses (NAT)",
@@ -142,7 +142,7 @@
"OK": "OK",
"Off": "Désactivé(e)",
"Oldest First": "Les plus anciens en premier",
"Optional descriptive label for the folder. Can be different on each device.": "Nom convivial et optionnel du partage, à votre guise. il peut être différent sur chaque appareil.",
"Optional descriptive label for the folder. Can be different on each device.": "Nom local, convivial et optionnel du partage, à votre guise. il peut être différent sur chaque appareil. Par notification initiale, il sera proposé tel quel aux nouveaux participants.\nAstuce : comme il est modifiable ultérieurement, pensez à indiquer un nom parlant pour les invités, puis renommez-le quand ils l'auront accepté (exemple d'un partage à deux membres où l'initiateur commence par donner son propre nom au partage, puis le renomme plus tard au nom du partenaire quand celui-ci l'a enregistré). Évitez les erreurs d'orthographe car ce nom servira aussi de base au chemin proposé en création (local et distant) et ce chemin est difficilement modifiable.",
"Options": "Options",
"Out of Sync": "Désynchronisé",
"Out of Sync Items": "Éléments non synchronisés",
@@ -169,8 +169,8 @@
"Release Notes": "Notes de version",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Les versions préliminaires contiennent les dernières fonctionnalités et derniers correctifs. Elles sont identiques aux traditionnelles mises à jour bimensuelles.",
"Remote Devices": "Autres appareils",
"Remove": "Enlever",
"Required identifier for the folder. Must be the same on all cluster devices.": "Identifiant du partage. Doit être le même sur tous les appareils concernés.",
"Remove": "Supprimer",
"Required identifier for the folder. Must be the same on all cluster devices.": "Identifiant du partage. Doit être le même sur tous les appareils concernés (généré aléatoirement, mais modifiable à la création).",
"Rescan": "Réanalyser",
"Rescan All": "Tout réanalyser",
"Rescan Interval": "Intervalle d'analyse",
@@ -183,6 +183,7 @@
"Save": "Enregistrer",
"Scan Time Remaining": "Temps d'analyse restant",
"Scanning": "Analyse en cours",
"See external versioner help for supported templated command line parameters.": "Voir l'aide sur la préservation externe des fichiers pour les paramètres supportés en lignes de commande dans les modèles.",
"Select the devices to share this folder with.": "Synchroniser avec :",
"Select the folders to share with this device.": "Sélectionner les partages auxquels cet appareil doit participer :",
"Send & Receive": "Envoi & réception",
@@ -197,7 +198,7 @@
"Show ID": "Afficher mon ID",
"Show QR": "Afficher le QR",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Sera diffusé aux autres appareils comme nom convivial optionnel par défaut.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Si laissé vide, il sera renseigné par le nom convivial proposé par l'appareil distant.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Nom convivial local affiché à la place de l'ID de l'appareil dans la plupart des écrans. Si laissé vide, c'est le nom convivial local de l'appareil distant qui sera utilisé. (Modifiable ultérieurement).",
"Shutdown": "Arrêter",
"Shutdown Complete": "Arrêté !",
"Simple File Versioning": "Suivi simplifié des versions",

View File

@@ -58,9 +58,9 @@
"Discovery": "Untdekking",
"Discovery Failures": "Untdekkingsflaters",
"Documentation": "Dokumintaasje",
"Download Rate": "Ynlaadfluggens",
"Downloaded": "Ynladen",
"Downloading": "Oan it ynladen",
"Download Rate": "Downloadfluggens",
"Downloaded": "Downloaded",
"Downloading": "Oan it downloaden",
"Edit": "Bewurkje",
"Edit Device": "Apparaat Bewurkje",
"Edit Folder": "Map Bewurkje",
@@ -183,6 +183,7 @@
"Save": "Bewarje",
"Scan Time Remaining": "Oerbleaune skentiid",
"Scanning": "Oan it skennen",
"See external versioner help for supported templated command line parameters.": "Sjoch de eksterne help fan fersjebehearder foar stipe foarbylden fan kommando-rige-parameters.",
"Select the devices to share this folder with.": "Sykje de apparaten út om dizze map mei te dielen.",
"Select the folders to share with this device.": "Sykje de mappen út om mei dit apparaat te dielen.",
"Send & Receive": "Stjoere & Untfange",
@@ -211,7 +212,7 @@
"Start Browser": "Browser iepenje wannear't Syncthing start",
"Statistics": "Statistiken",
"Stopped": "Stoppe",
"Support": "Understeuning",
"Support": "Help (Forum)",
"Sync Protocol Listen Addresses": "Sync-protokolharkadressen",
"Syncing": "Oan it Syncen",
"Syncthing has been shut down.": "Syncthing is útsetten",
@@ -259,7 +260,7 @@
"Upgrade": "Fernije",
"Upgrade To {%version%}": "Fernije nei {{version}}",
"Upgrading": "Oan it fernijen",
"Upload Rate": "Oplaadfluggens",
"Upload Rate": "Uploadfluggens",
"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",

View File

@@ -183,6 +183,7 @@
"Save": "Mentés",
"Scan Time Remaining": "Fennmaradó átnézési idő",
"Scanning": "Átnézés",
"See external versioner help for supported templated command line parameters.": "A támogatott parancssori paraméter sablonokat a külső verziókezelő súgójában találod.",
"Select the devices to share this folder with.": "Eszközök, amelyekkel megosztandó a mappa",
"Select the folders to share with this device.": "Mappák, amelyek megosztandók ezzel az eszközzel.",
"Send & Receive": "Küldés és fogadás",

View File

@@ -1,287 +0,0 @@
{
"A device with that ID is already added.": "Perangkat dengan ID tersebut sudah ada.",
"A negative number of days doesn't make sense.": "Tidak mungkin jumlah hari dalam nilai negatif.",
"A new major version may not be compatible with previous versions.": "Versi penting yang baru mungkin tidak kompatibel dengan versi sebelumnya.",
"API Key": "API Key",
"About": "Tentang",
"Action": "Action",
"Actions": "Aksi",
"Add": "Tambah",
"Add Device": "Tambah Perangkat",
"Add Folder": "Tambah Folder",
"Add Remote Device": "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 new folder?": "Tambah folder baru",
"Address": "Alamat",
"Addresses": "Alamat",
"Advanced": "Tingkat Lanjut",
"Advanced Configuration": "Konfigurasi Tingkat Lanjut",
"Advanced settings": "Advanced settings",
"All Data": "Semua Data",
"Allow Anonymous Usage Reporting?": "Aktifkan Laporan Penggunaan Anonim?",
"Allowed Networks": "Allowed Networks",
"Alphabetic": "Alfabet",
"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.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Perintah eksternal mengatur pemversian. Dia harus menghapus berkas dari folder yang tersinkronisasi.",
"Anonymous Usage Reporting": "Pelaporan Penggunaan Anonim",
"Any devices configured on an introducer device will be added to this device as well.": "Semua perangkat yang dikonfigurasi di perangkat pengenal akan ditambahkan di perangkat ini juga.",
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Automatic upgrade now offers the choice between stable releases and release candidates.",
"Automatic upgrades": "Ugrade Otomatis",
"Be careful!": "Harap hati-hati!",
"Bugs": "Bugs",
"CPU Utilization": "Penggunaan CPU",
"Changelog": "Log perubahan",
"Clean out after": "Bersihkan setelah",
"Click to see discovery failures": "Click to see discovery failures",
"Close": "Tutup",
"Command": "Perintah",
"Comment, when used at the start of a line": "Komentar, digunakan saat awal baris",
"Compression": "Kompresi",
"Configured": "Configured",
"Connection Error": "Koneksi Galat",
"Connection Type": "Connection Type",
"Copied from elsewhere": "Tersalin dari tempat lain",
"Copied from original": "Tersalin dari asal",
"Copyright © 2014-2016 the following Contributors:": "Copyright © 2014-2016 the following Contributors:",
"Copyright © 2014-2017 the following Contributors:": "Copyright © 2014-2017 the following Contributors:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creating ignore patterns, overwriting an existing file at {{path}}.",
"Danger!": "Bahaya!",
"Deleted": "Terhapus",
"Device": "Device",
"Device \"{%name%}\" ({%device%} at {%address%}) wants to connect. Add new device?": "Device \"{{name}}\" ({{device}} at {{address}}) wants to connect. Add new device?",
"Device ID": "ID Perangkat",
"Device Identification": "Identifikasi Perangkat",
"Device Name": "Nama Perangkat",
"Devices": "Perangkat",
"Disconnected": "Terputus",
"Discovered": "Discovered",
"Discovery": "Discovery",
"Discovery Failures": "Discovery Failures",
"Documentation": "Dokumentasi",
"Download Rate": "Download Rate",
"Downloaded": "Terunduh",
"Downloading": "Mengunduh",
"Edit": "Sunting",
"Edit Device": "Edit Device",
"Edit Folder": "Edit Folder",
"Editing": "Menyunting",
"Editing {%path%}.": "Editing {{path}}.",
"Enable NAT traversal": "Enable NAT traversal",
"Enable Relaying": "Aktifkan Relay",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.",
"Enter a non-privileged port number (1024 - 65535).": "Enter a non-privileged port number (1024 - 65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Masukkan alamat, pisahkan dengan koma (\"tcp://ip:port\", \"tcp://host:port\") atau \"dynamic\" untuk menjalankan penemuan otomatis alamat tersebut.",
"Enter ignore patterns, one per line.": "Masukkan pola pengabaian, satu per baris.",
"Error": "Galat",
"External File Versioning": "Berkas pemversian eksternal",
"Failed Items": "Materi yang gagal",
"Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.": "Failure to connect to IPv6 servers is expected if there is no IPv6 connectivity.",
"File Pull Order": "Urutan Penarikan Berkas",
"File Versioning": "Versi Berkas",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Bit hak akses berkas diabaikan saat mencari perubahan. Digunakan pada sistem berkas FAT.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Files are moved to .stversions directory when replaced or deleted by Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Berkas dipindahkan ke folder .stversions jika digantikan atau dihapus oleh Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Berkas dipindahkan ke versi bertanggal dalam folder .stversions jika digantikan atau dihapus oleh 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.": "Berkas diproteksi dari perubahan oleh perangkat lain, tetapi perubahan yang dikirim dari perangkat ini akan dikirim ke perangkat lain dalam klaster.",
"Folder": "Folder",
"Folder ID": "ID Folder",
"Folder Label": "Folder Label",
"Folder Path": "Path Folder",
"Folder Type": "Folder Type",
"Folders": "Folder",
"GUI": "GUI",
"GUI Authentication Password": "Sandi Otentikasi GUI",
"GUI Authentication User": "Pengguna Otentikasi GUI",
"GUI Listen Address": "GUI Listen Address",
"GUI Listen Addresses": "Alamat Listen GUI",
"GUI Theme": "GUI Theme",
"Generate": "Buat Baru",
"Global Changes": "Global Changes",
"Global Discovery": "Discovery Global",
"Global Discovery Servers": "Global Discovery Servers",
"Global State": "Status Global",
"Help": "Panduan",
"Home page": "Situs",
"Ignore": "Abaikan",
"Ignore Patterns": "Pola Pengabaian",
"Ignore Permissions": "Hak Akses Pengabaian",
"Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Konfigurasi salah bisa merusak isi folder dan membuat Syncthing tidak bisa dijalankan.",
"Introduced By": "Introduced By",
"Introducer": "Pengenal",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Keep Versions": "Keep Versions",
"Largest First": "Largest First",
"Last File Received": "Last File Received",
"Last Scan": "Last Scan",
"Last seen": "Last seen",
"Later": "Later",
"Latest Change": "Latest Change",
"Learn more": "Learn more",
"Listeners": "Listeners",
"Local Discovery": "Local Discovery",
"Local State": "Local State",
"Local State (Total)": "Local State (Total)",
"Major Upgrade": "Major Upgrade",
"Master": "Master",
"Maximum Age": "Maximum Age",
"Metadata Only": "Metadata Only",
"Minimum Free Disk Space": "Minimum Free Disk Space",
"Move to top of queue": "Move to top of queue",
"Multi level wildcard (matches multiple directory levels)": "Multi level wildcard (matches multiple directory levels)",
"Never": "Never",
"New Device": "New Device",
"New Folder": "New Folder",
"Newest First": "Newest First",
"No": "No",
"No File Versioning": "No File Versioning",
"No upgrades": "No upgrades",
"Normal": "Normal",
"Notice": "Notice",
"OK": "OK",
"Off": "Off",
"Oldest First": "Oldest First",
"Optional descriptive label for the folder. Can be different on each device.": "Optional descriptive label for the folder. Can be different on each device.",
"Options": "Options",
"Out of Sync": "Out of Sync",
"Out of Sync Items": "Out of Sync Items",
"Outgoing Rate Limit (KiB/s)": "Outgoing Rate Limit (KiB/s)",
"Override Changes": "Override Changes",
"Path": "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 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 versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Path where versions should be stored (leave empty for the default .stversions folder in the folder).",
"Pause": "Pause",
"Pause All": "Pause All",
"Paused": "Paused",
"Please consult the release notes before performing a major upgrade.": "Please consult the release notes before performing a major upgrade.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Please set a GUI Authentication User and Password in the Settings dialog.",
"Please wait": "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",
"Preview": "Preview",
"Preview Usage Report": "Preview Usage Report",
"Quick guide to supported patterns": "Quick guide to supported patterns",
"RAM Utilization": "RAM Utilization",
"Random": "Random",
"Reduced by ignore patterns": "Reduced by ignore patterns",
"Release Notes": "Release Notes",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.",
"Remote Devices": "Remote Devices",
"Remove": "Remove",
"Required identifier for the folder. Must be the same on all cluster devices.": "Required identifier for the folder. Must be the same on all cluster devices.",
"Rescan": "Rescan",
"Rescan All": "Rescan All",
"Rescan Interval": "Rescan Interval",
"Restart": "Restart",
"Restart Needed": "Restart Needed",
"Restarting": "Restarting",
"Resume": "Resume",
"Resume All": "Resume All",
"Reused": "Reused",
"Save": "Save",
"Scan Time Remaining": "Scan Time Remaining",
"Scanning": "Scanning",
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
"Select the folders to share with this device.": "Select the folders to share with this device.",
"Send & Receive": "Send & Receive",
"Send Only": "Send Only",
"Settings": "Settings",
"Share": "Share",
"Share Folder": "Share Folder",
"Share Folders With Device": "Share Folders With Device",
"Share With Devices": "Share With Devices",
"Share this folder?": "Share this folder?",
"Shared With": "Shared With",
"Show ID": "Show ID",
"Show QR": "Show QR",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
"Shutdown": "Shutdown",
"Shutdown Complete": "Shutdown Complete",
"Simple File Versioning": "Simple File Versioning",
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
"Smallest First": "Smallest First",
"Source Code": "Source Code",
"Stable releases and release candidates": "Stable releases and release candidates",
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.",
"Stable releases only": "Stable releases only",
"Staggered File Versioning": "Staggered File Versioning",
"Start Browser": "Start Browser",
"Statistics": "Statistics",
"Stopped": "Stopped",
"Support": "Support",
"Sync Protocol Listen Addresses": "Sync Protocol Listen Addresses",
"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 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…",
"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.",
"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.": "The aggregated statistics are publicly available at the URL below.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.",
"The device ID cannot be blank.": "The device ID cannot be blank.",
"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).": "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).",
"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.": "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.",
"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.": "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.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "The first command line parameter is the folder path and the second parameter is the relative path in the folder.",
"The folder ID cannot be blank.": "The folder ID cannot be blank.",
"The folder ID must be unique.": "The folder ID must be unique.",
"The folder path cannot be blank.": "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.": "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 maximum age must be a number and cannot be blank.": "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).": "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).": "The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).",
"The number of days must be a number and cannot be blank.": "The number of days must be a number and cannot be blank.",
"The number of days to keep files in the trash can. Zero means forever.": "The number of days to keep files in the trash can. Zero means forever.",
"The number of old versions to keep, per file.": "The number of old versions to keep, per file.",
"The number of versions must be a number and cannot be blank.": "The number of versions must be a number and cannot be blank.",
"The path cannot be blank.": "The path cannot be blank.",
"The rate limit must be a non-negative number (0: no limit)": "The rate limit must be a non-negative number (0: no limit)",
"The rescan interval must be a non-negative number of seconds.": "The rescan interval must be a non-negative number of seconds.",
"They are retried automatically and will be synced when the error is resolved.": "They are retried automatically and will be synced when the error is resolved.",
"This Device": "This Device",
"This can easily give hackers access to read and change any files on your computer.": "This can easily give hackers access to read and change any files on your computer.",
"This is a major version upgrade.": "This is a major version upgrade.",
"This setting controls the free space required on the home (i.e., index database) disk.": "This setting controls the free space required on the home (i.e., index database) disk.",
"Time": "Time",
"Trash Can File Versioning": "Trash Can File Versioning",
"Type": "Type",
"Unknown": "Unknown",
"Unshared": "Unshared",
"Unused": "Unused",
"Up to Date": "Up to Date",
"Updated": "Updated",
"Upgrade": "Upgrade",
"Upgrade To {%version%}": "Upgrade To {{version}}",
"Upgrading": "Upgrading",
"Upload Rate": "Upload Rate",
"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",
"Version": "Version",
"Versions Path": "Versions Path",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.",
"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}}).",
"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",
"You can also select one of these nearby devices:": "You can also select one of these nearby devices:",
"You can change your choice at any time in the Settings dialog.": "You can change your choice at any time in the Settings dialog.",
"You can read more about the two release channels at the link below.": "You can read more about the two release channels at the link below.",
"You must keep at least one version.": "You must keep at least one version.",
"days": "days",
"directories": "directories",
"files": "files",
"full documentation": "full documentation",
"items": "items",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} wants to share folder \"{{folder}}\".",
"{%device%} wants to share folder \"{%folderlabel%}\" ({%folder%}).": "{{device}} wants to share folder \"{{folderlabel}}\" ({{folder}})."
}

View File

@@ -183,6 +183,7 @@
"Save": "Salva",
"Scan Time Remaining": "Tempo di Scansione Rimanente",
"Scanning": "Scansione in corso",
"See external versioner help for supported templated command line parameters.": "Consultare la guida al controllo di versione per i modelli dei parametri di riga di comando supportati.",
"Select the devices to share this folder with.": "Seleziona i dispositivi con i quali condividere questa cartella.",
"Select the folders to share with this device.": "Seleziona le cartelle da condividere con questo dispositivo.",
"Send & Receive": "Invia & Ricevi",

View File

@@ -183,6 +183,7 @@
"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.",
"Select the devices to share this folder with.": "このフォルダーを共有するデバイスを選択してください。",
"Select the folders to share with this device.": "このデバイスと共有するフォルダーを選択してください。",
"Send & Receive": "送受信",

View File

@@ -183,6 +183,7 @@
"Save": "저장",
"Scan Time Remaining": "탐색 남은 시간",
"Scanning": "탐색중",
"See external versioner help for supported templated command line parameters.": "지원되는 템플릿 명령 행 매개 변수에 대해서는 외부 버전 도움말을 참조하십시오.",
"Select the devices to share this folder with.": "이 폴더를 공유할 장치를 선택합니다.",
"Select the folders to share with this device.": "이 장치와 공유할 폴더를 선택합니다.",
"Send & Receive": "송신 & 수신",

View File

@@ -183,6 +183,7 @@
"Save": "Išsaugoti",
"Scan Time Remaining": "Likęs nuskaitymo laikas",
"Scanning": "Skenuojama",
"See external versioner help for supported templated command line parameters.": "Palaikomiems šabloniniams komandų eilutės parametrams, žiūrėkite išorinį versijų valdymo žinyną.",
"Select the devices to share this folder with.": "Pasirinkite įrenginius, su kuriais dalinsitės šį aplanką.",
"Select the folders to share with this device.": "Pasirinkite aplankus kuriais norite dalintis su šiuo įrenginiu.",
"Send & Receive": "Siųsti ir gauti",

View File

@@ -10,7 +10,7 @@
"Add Device": "Legg til enhet",
"Add Folder": "Legg til mappe",
"Add Remote Device": "Legg til ekstern enhet",
"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.": "Legg til enheter fra introdusøren til vår enhetsliste, for innbyrdes delte mapper.",
"Add new folder?": "Legg til ny mappe?",
"Address": "Adresse",
"Addresses": "Adresser",
@@ -19,7 +19,7 @@
"Advanced settings": "Avanserte innstillinger ",
"All Data": "Alle data",
"Allow Anonymous Usage Reporting?": "Tillat anonym innsamling av brukerdata?",
"Allowed Networks": "Allowed Networks",
"Allowed Networks": "Tillatte nettverk",
"Alphabetic": "Alfabetisk",
"An external command handles the versioning. It has to remove the file from the shared folder.": "En ekstern kommando håndterer versjonkontrollen. Den må fjerne filen fra den delte mappa.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "En ekstern kommando håndterer versjonkontrollen. Den må fjerne filen fra den synkroniserte mappa.",
@@ -44,7 +44,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:",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Creating ignore patterns, overwriting an existing file at {{path}}.",
"Creating ignore patterns, overwriting an existing file at {%path%}.": "Oppretter ignoreringsmønster, overskriver eksisterende fil i {{path}}.",
"Danger!": "Fare!",
"Deleted": "Slettet",
"Device": "Enhet",
@@ -65,11 +65,11 @@
"Edit Device": "Rediger enhet",
"Edit Folder": "Rediger mappe",
"Editing": "Redigerer",
"Editing {%path%}.": "Editing {{path}}.",
"Editing {%path%}.": "Redigerer {{path}}.",
"Enable NAT traversal": "Slå på NAT-traversering",
"Enable Relaying": "Aktiver reléforsendelse",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.",
"Enter a non-privileged port number (1024 - 65535).": "Enter a non-privileged port number (1024 - 65535).",
"Enter a non-negative number (e.g., \"2.35\") and select a unit. Percentages are as part of the total disk size.": "Skriv inn et ikke-negativt nummer (f.eks. \"2.35\") og velg en enhet. Prosenter er deler av total diskstørrelse.",
"Enter a non-privileged port number (1024 - 65535).": "Skriv inn et ikke-priviligert portnummer (1024-65535).",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Skriv inn kommaseparerte (\"tcp://ip:port\", \"tcp://host:port\") adresser, eller ordet \"dynamic\" for å gjøre automatisk oppslag i adressen.",
"Enter ignore patterns, one per line.": "Skriv inn mønster som skal utelates, ett per linje.",
"Error": "Feilmelding",
@@ -93,7 +93,7 @@
"GUI": "grafisk brukergrensesnitt",
"GUI Authentication Password": "Passord for GUI-autenisering",
"GUI Authentication User": "Bruker for GUI-autenisering",
"GUI Listen Address": "GUI Listen Address",
"GUI Listen Address": "Lytteadresse for grafisk brukergrensesnitt",
"GUI Listen Addresses": "GUI-lytteadresse",
"GUI Theme": "GUI-tema",
"Generate": "Generer",
@@ -158,8 +158,8 @@
"Please consult the release notes before performing a major upgrade.": "Sjekk utgivelsesnotatene før en storoppgradering utføres.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Vennligst angi bruker og passord for GUI-autentisering i innstillingsvinduet.",
"Please wait": "Vent",
"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": "Prefiks som indikerer at fila kan slettes hvis den forhindrer fjerning av mappe",
"Prefix indicating that the pattern should be matched without case sensitivity": "Prefiks som indikerer at mønsteret skal samsvare uten versalsensitivitet",
"Preview": "Forhåndsvisning",
"Preview Usage Report": "Forhåndsvisning av datainnsamling",
"Quick guide to supported patterns": "Kjapp innføring i godkjente mønster",
@@ -183,6 +183,7 @@
"Save": "Lagre",
"Scan Time Remaining": "Gjenstående tid for gjennomsøking",
"Scanning": "Gjennomsøker",
"See external versioner help for supported templated command line parameters.": "Se ekstern versjoneringshjelp for støttede mal-baserte kommandolinjeparameter.",
"Select the devices to share this folder with.": "Velg enhetene du vil dele denne mappen med.",
"Select the folders to share with this device.": "Velg hvilke mapper som skal deles med denne enheten.",
"Send & Receive": "Sende og motta",
@@ -247,7 +248,7 @@
"This Device": "Denne enheten",
"This can easily give hackers access to read and change any files on your computer.": "Dette kan lett gi hackere tilgang til å lese og endre alle filer på datamaskinen din.",
"This is a major version upgrade.": "Dette er en storoppgradering",
"This setting controls the free space required on the home (i.e., index database) disk.": "This setting controls the free space required on the home (i.e., index database) disk.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Denne innstillingen kontrollerer ledig diskplass krevd på hjemme- (f.eks. indekseringsdatabase-) disken.",
"Time": "Klokkeslett",
"Trash Can File Versioning": "Papirkurv versjonskontroll",
"Type": "Type",
@@ -270,10 +271,10 @@
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advarsel, denne stien er en foreldremappe for en eksisterende mappe \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolder%}\".": "Advarsel, denne stien er en undermappe i en eksisterende mappe \"{{otherFolder}}\".",
"Warning, this path is a subdirectory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Advarsel, denne stien er en undermappe for en eksisterende mappe \"{{otherFolderLabel}}\" ({{otherFolder}}).",
"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 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",
"You can also select one of these nearby devices:": "You can also select one of these nearby devices:",
"You can also select one of these nearby devices:": "Du kan også velge en av disse enhetene i nærheten:",
"You can change your choice at any time in the Settings dialog.": "Du kan endre ditt valg når som helst i innstillingene.",
"You can read more about the two release channels at the link below.": "Du kan lese mer om de to nye utgivelseskanalene i lenken nedenfor.",
"You must keep at least one version.": "Du må beholde minst én versjon",

View File

@@ -183,6 +183,7 @@
"Save": "Bewaar",
"Scan Time Remaining": "Resterende scantijd",
"Scanning": "Aan het zoeken",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Selecteer de apparaten om deze map mee te delen.",
"Select the folders to share with this device.": "Selecteer de mappen om met dit apparaat te delen.",
"Send & Receive": "Verzenden & Ontvangen",

View File

@@ -183,6 +183,7 @@
"Save": "Lagre",
"Scan Time Remaining": "Gjenståande skannetid",
"Scanning": "Skannar",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Vel einingane du vil dela denne mappa med.",
"Select the folders to share with this device.": "Vel mappene du vil dela med denne eininga.",
"Send & Receive": "Sende og motta",

View File

@@ -183,6 +183,7 @@
"Save": "Zapisz",
"Scan Time Remaining": "Pozostały czas skanowania",
"Scanning": "Skanowanie",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Wybierz urządzenie, któremu udostępnić folder.",
"Select the folders to share with this device.": "Wybierz foldery do współdzielenia z tym urządzeniem.",
"Send & Receive": "Wyślij i odbierz",

View File

@@ -79,10 +79,10 @@
"File Pull Order": "Ordem de retirada do arquivo",
"File Versioning": "Versionamento de arquivos",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Os bits de permissão de um arquivo são ignorados durante as verificações. Use em sistemas de arquivo FAT.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Os arquivos são movidos para o diretório .stversions quando são substituídos ou apagados pelo Syncthing.",
"Files are moved to .stversions directory when replaced or deleted by Syncthing.": "Os arquivos são movidos para o diretório .stversions quando substituídos ou apagados pelo Syncthing.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Os arquivos são movidos para a pasta .stversions quando substituídos ou apagados pelo Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Os arquivos são renomeados com datas e movidos para o diretório .stversions quando são substituídos ou apagados pelo Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Os arquivos são renomeados com suas datas na pasta .stversions após serem substituídos ou removidos pelo Syncthing.",
"Files are moved to date stamped versions in a .stversions directory when replaced or deleted by Syncthing.": "Os arquivos são renomeados com suas datas e movidos para o diretório .stversions quando substituídos ou apagados pelo Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Os arquivos são renomeados com suas datas na pasta .stversions quando substituídos ou removidos pelo 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.": "Os arquivos estão protegidos contra alterações feitas em outros dispositivos, mas alterações feitas neste dispositivo serão enviadas ao resto dos dispositivos.",
"Folder": "Pasta",
"Folder ID": "ID da pasta",
@@ -150,7 +150,7 @@
"Override Changes": "Sobrescrever alterações",
"Path": "Caminho",
"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": "Caminho para a pasta na máquina local. Será criado caso não exista. O caractere til (~) pode ser usado como um atalho para",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Caminho do diretório onde as versões são salvas (deixe em branco para o diretório padrão .stversions dentro da pasta compartilhada). ",
"Path where versions should be stored (leave empty for the default .stversions directory in the shared folder).": "Caminho do diretório onde as versões são salvas (deixe em branco para que seja o diretório padrão .stversions dentro da pasta compartilhada). ",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "O caminho onde as versões serão salvas (deixe vazio para usar a pasta padrão .stversions dentro desta pasta).",
"Pause": "Pausar",
"Pause All": "Pausar Todas",
@@ -183,6 +183,7 @@
"Save": "Salvar",
"Scan Time Remaining": "Tempo de verificação restante",
"Scanning": "Verificando",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Selecione os dispositivos com os quais esta pasta será compartilhada.",
"Select the folders to share with this device.": "Selecione as pastas a serem compartilhadas com este dispositivo.",
"Send & Receive": "Envia e recebe",
@@ -264,7 +265,7 @@
"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",
"Version": "Versão",
"Versions Path": "Caminho das versões",
"Versions Path": "Caminho do versionamento",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "As versões são automaticamente apagadas se elas são mais antigas do que a idade máxima ou excederem o número de arquivos permitido em um intervalo.",
"Warning, this path is a parent directory of an existing folder \"{%otherFolder%}\".": "Aviso: este caminho é o diretório pai da pasta \"{{otherFolder}}\".",
"Warning, this path is a parent directory of an existing folder \"{%otherFolderLabel%}\" ({%otherFolder%}).": "Aviso: este caminho é o diretório pai da pasta \"{{otherFolderLabel}}\" ({{otherFolder}}).",
@@ -273,7 +274,7 @@
"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",
"You can also select one of these nearby devices:": "You can also select one of these nearby devices:",
"You can also select one of these nearby devices:": "Vocẽ também pode selecionar um destes dispositivos próximos:",
"You can change your choice at any time in the Settings dialog.": "Você pode mudar de ideia a qualquer momento na tela de configurações.",
"You can read more about the two release channels at the link below.": "Você pode se informar melhor sobre os dois canais de lançamento no link abaixo.",
"You must keep at least one version.": "Você deve manter pelo menos uma versão.",

View File

@@ -183,6 +183,7 @@
"Save": "Gravar",
"Scan Time Remaining": "Tempo restante da verificação",
"Scanning": "Verificando",
"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.",
"Select the devices to share this folder with.": "Seleccione os dispositivos com os quais vai partilhar esta pasta.",
"Select the folders to share with this device.": "Seleccione as pastas a partilhar com este dispositivo.",
"Send & Receive": "Envia e recebe",

View File

@@ -183,6 +183,7 @@
"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.",
"Select the devices to share this folder with.": "Выберите устройства, для которых будет доступна эта папка.",
"Select the folders to share with this device.": "Выберите папки, которые будут доступны этому устройству.",
"Send & Receive": "Отправить и получить",

View File

@@ -183,6 +183,7 @@
"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.",
"Select the devices to share this folder with.": "Vyberte zariadenia s ktorými chcete zdieľať tento adresár.",
"Select the folders to share with this device.": "Vyberte adresáre ktoré chcete zdieľať s týmto zariadením.",
"Send & Receive": "Prijímať a odosielať",
@@ -273,7 +274,7 @@
"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:": "You can also select one of these nearby devices:",
"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 must keep at least one version.": "Musíte ponechať aspoň jednu verziu",

View File

@@ -183,6 +183,7 @@
"Save": "Spara",
"Scan Time Remaining": "Återstående skanningstid",
"Scanning": "Skannar",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Ange enheterna som den här mappen ska delas med.",
"Select the folders to share with this device.": "Välj mapparna som ska delas med den här enheten.",
"Send & Receive": "Skicka & ta emot",

View File

@@ -183,6 +183,7 @@
"Save": "Kaydet",
"Scan Time Remaining": "Kalan Tarama Zamanı",
"Scanning": "Taranıyor",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Bu klasörü paylaşacağın aygıtları seç.",
"Select the folders to share with this device.": "Bu aygıtla paylaşılacak klasörleri seç.",
"Send & Receive": "Gönder & Al",

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?": "Додати нову директорію?",
"Address": "Адреса",
"Addresses": "Адреси",
@@ -32,7 +32,7 @@
"CPU Utilization": "Навантаження CPU",
"Changelog": "Перелік змін",
"Clean out after": "Очистити після",
"Click to see discovery failures": "Click to see discovery failures",
"Click to see discovery failures": "Клікніть, щоб переглянути помилки виявлення",
"Close": "Закрити",
"Command": "Команда",
"Comment, when used at the start of a line": "Коментар, якщо використовується на початку рядка",
@@ -183,6 +183,7 @@
"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.",
"Select the devices to share this folder with.": "Оберіть пристрої, які матимуть доступ до цієї директорії.",
"Select the folders to share with this device.": "Оберіть директорії до яких матиме доступ цей пристрій.",
"Send & Receive": "Відправити та отримати",
@@ -247,7 +248,7 @@
"This Device": "Локальний пристрій",
"This can easily give hackers access to read and change any files on your computer.": "Це легко може дати хакерам доступ до читання та зміни будь-яких файлів на вашому комп'ютері.",
"This is a major version upgrade.": "Це оновлення мажорної версії",
"This setting controls the free space required on the home (i.e., index database) disk.": "This setting controls the free space required on the home (i.e., index database) disk.",
"This setting controls the free space required on the home (i.e., index database) disk.": "Це налаштування визначає необхідний вільний простір на домашньому (тобто той, що містить базу даних) диску.",
"Time": "Час",
"Trash Can File Versioning": "Версіонування файлів у кошику ",
"Type": "Тип",
@@ -273,7 +274,7 @@
"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": "Так",
"You can also select one of these nearby devices:": "You can also select one of these nearby devices:",
"You can also select one of these nearby devices:": "Ви також можете обрати один із сусідніх пристроїв:",
"You can change your choice at any time in the Settings dialog.": "Ви завжди можете змінити свій вибір у Налаштуваннях.",
"You can read more about the two release channels at the link below.": "Ви можете прочитати більше про два канали випусків за посиланням нижче.",
"You must keep at least one version.": "Ви повинні зберігати щонайменше одну версію.",

View File

@@ -183,6 +183,7 @@
"Save": "Lưu",
"Scan Time Remaining": "Thời gian quét còn lại",
"Scanning": "Đang quét",
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
"Select the devices to share this folder with.": "Chọn các thiết bị để chia sẻ thư mục này.",
"Select the folders to share with this device.": "Chọn các thư mục để chia sẻ với thiết bị này.",
"Send & Receive": "Send & Receive",

View File

@@ -183,6 +183,7 @@
"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.",
"Select the devices to share this folder with.": "选择将本文件夹共享给哪些设备。",
"Select the folders to share with this device.": "选择与该设备共享的文件夹。",
"Send & Receive": "发送与接收",

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)","eo":"Esperanto","es":"Spanish","es-ES":"Spanish (Spain)","eu":"Basque","fi":"Finnish","fr":"French","fr-CA":"French (Canada)","fy":"Western Frisian","hu":"Hungarian","id":"Indonesian","it":"Italian","ja":"Japanese","ko-KR":"Korean (Korea)","lt":"Lithuanian","nb":"Norwegian Bokmål","nl":"Dutch","nn":"Norwegian Nynorsk","pl":"Polish","pt-BR":"Portuguese (Brazil)","pt-PT":"Portuguese (Portugal)","ru":"Russian","sk":"Slovak","sv":"Swedish","tr":"Turkish","uk":"Ukrainian","vi":"Vietnamese","zh-CN":"Chinese (China)"}
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)","eu":"Basque","fi":"Finnish","fr":"French","fr-CA":"French (Canada)","fy":"Western Frisian","hu":"Hungarian","it":"Italian","ja":"Japanese","ko-KR":"Korean (Korea)","lt":"Lithuanian","nb":"Norwegian Bokmål","nl":"Dutch","nn":"Norwegian Nynorsk","pl":"Polish","pt-BR":"Portuguese (Brazil)","pt-PT":"Portuguese (Portugal)","ru":"Russian","sk":"Slovak","sv":"Swedish","tr":"Turkish","uk":"Ukrainian","vi":"Vietnamese","zh-CN":"Chinese (China)"}

View File

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

View File

@@ -394,7 +394,7 @@
</tr>
<tr>
<th><span class="fa fa-fw fa-share-alt"></span>&nbsp;<span translate>Shared With</span></th>
<td class="text-right" title="{{sharesFolder(folder)}}">{{sharesFolder(folder)}}</td>
<td class="text-right" ng-attr-title="{{sharesFolder(folder)}}">{{sharesFolder(folder)}}</td>
</tr>
<tr>
<th><span class="fa fa-fw fa-clock-o"></span>&nbsp;<span translate>Last Scan</span></th>
@@ -645,7 +645,7 @@
</tr>
<tr ng-if="deviceFolders(deviceCfg).length > 0">
<th><span class="fa fa-fw fa-folder"></span>&nbsp;<span translate>Folders</span></th>
<td class="text-right" title="{{deviceFolders(deviceCfg).map(folderLabel).join(", ")}}">{{deviceFolders(deviceCfg).map(folderLabel).join(", ")}}</td>
<td class="text-right" ng-attr-title="{{deviceFolders(deviceCfg).map(folderLabel).join(', ')}}">{{deviceFolders(deviceCfg).map(folderLabel).join(", ")}}</td>
</tr>
</tbody>
</table>

View File

@@ -12,7 +12,7 @@
<p translate>Copyright &copy; 2014-2017 the following Contributors:</p>
<div class="row">
<div class="col-md-12" id="contributor-list">
Jakob Borg, Audrius Butkevicius, Alexander Graf, 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, Simon Frei, Stefan Tatschner, Aaron Bieber, Adam Piggott, Adel Qalieh, Alessandro G., Alexandre Viau, Andrew Dunham, Andrey D, Antoine Lamielle, Arthur Axel fREW Schmidt, Bart De Vries, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benny Ng, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Chris Howie, Chris Joel, Colin Kennedy, Daniel Bergmann, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dominik Heidler, Elias Jarlebring, Emil Hessman, Erik Meitner, Federico Castagnini, Felix Ableitner, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gilli Sigurdsson, Heiko Zuerker, Jaakko Hannikainen, Jacek Szafarkiewicz, Jake Peterson, James Patterson, Jaroslav Malec, Jaya Chithra, Jens Diemer, Jochen Voss, Johan Vromans, Jose Manuel Delicado, Karol Różycki, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin White, Jr., Kurt Fitzner, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Mark Pulford, Mateusz Naściszewski, Matt Burke, Max Schulze, Michael Jephcote, Michael Tilli, Niels Peter Roest, Pascal Jungblut, Peter Hoeg, Phill Luby, Piotr Bejda, Robert Carosi, Roman Zaynetdinov, Ross Smith II, Sacheendra Talluri, Scott Klupfel, Stefan Kuntz, Suhas Gundimeda, Tim Abell, Tim Howes, Tobias Nygren, Tomas Cerveny, Tully Robinson, Tyler Brazier, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, William A. Kennington III, Wulf Weich, Xavier O., Yannic A.
Jakob Borg, Audrius Butkevicius, Alexander Graf, 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, Simon Frei, Stefan Tatschner, Aaron Bieber, Adam Piggott, Adel Qalieh, Alessandro G., Alexandre Viau, Andrew Dunham, Andrey D, Antoine Lamielle, Arthur Axel fREW Schmidt, Bart De Vries, Ben Curthoys, Ben Shepherd, Ben Sidhom, Benny Ng, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Cedric Staniewski, Chris Howie, Chris Joel, Colin Kennedy, Daniel Bergmann, Daniel Martí, Darshil Chanpura, David Rimmer, Denis A., Dennis Wilson, Dominik Heidler, Elias Jarlebring, Emil Hessman, Erik Meitner, Federico Castagnini, Felix Ableitner, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gilli Sigurdsson, Heiko Zuerker, Jaakko Hannikainen, Jacek Szafarkiewicz, Jake Peterson, James Patterson, Jaroslav Malec, Jaya Chithra, Jens Diemer, Jochen Voss, Johan Vromans, Jose Manuel Delicado, Karol Różycki, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin White, Jr., Kurt Fitzner, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Mark Pulford, Mateusz Naściszewski, Matt Burke, Max Schulze, Michael Jephcote, Michael Tilli, Niels Peter Roest, Pascal Jungblut, Peter Hoeg, Phill Luby, Piotr Bejda, Robert Carosi, Roman Zaynetdinov, Ross Smith II, Sacheendra Talluri, Scott Klupfel, Stefan Kuntz, Suhas Gundimeda, Tim Abell, Tim Howes, Tobias Nygren, Tobias Tom, Tomas Cerveny, Tully Robinson, Tyler Brazier, Unrud, Veeti Paananen, Victor Buinsky, Vil Brekin, William A. Kennington III, Wulf Weich, Xavier O., Yannic A.
</div>
</div>
<hr/>

View File

@@ -32,7 +32,7 @@ import (
const (
OldestHandledVersion = 10
CurrentVersion = 22
CurrentVersion = 23
MaxRescanIntervalS = 365 * 24 * 60 * 60
)
@@ -323,6 +323,9 @@ func (cfg *Configuration) clean() error {
if cfg.Version == 21 {
convertV21V22(cfg)
}
if cfg.Version == 22 {
convertV22V23(cfg)
}
// Build a list of available devices
existingDevices := make(map[protocol.DeviceID]bool)
@@ -372,6 +375,34 @@ func (cfg *Configuration) clean() error {
return nil
}
func convertV22V23(cfg *Configuration) {
permBits := fs.FileMode(0777)
if runtime.GOOS == "windows" {
// Windows has no umask so we must chose a safer set of bits to
// begin with.
permBits = 0700
}
for i := range cfg.Folders {
fs := cfg.Folders[i].Filesystem()
// Invalid config posted, or tests.
if fs == nil {
continue
}
if stat, err := fs.Stat(".stfolder"); err == nil && !stat.IsDir() {
err = fs.Remove(".stfolder")
if err == nil {
err = fs.Mkdir(".stfolder", permBits)
fs.Hide(".stfolder") // ignore error
}
if err != nil {
l.Infoln("Failed to upgrade folder marker:", err)
}
}
}
cfg.Version = 23
}
func convertV21V22(cfg *Configuration) {
for i := range cfg.Folders {
cfg.Folders[i].FilesystemType = fs.FilesystemTypeBasic

View File

@@ -86,7 +86,7 @@ func TestDefaultValues(t *testing.T) {
func TestDeviceConfig(t *testing.T) {
for i := OldestHandledVersion; i <= CurrentVersion; i++ {
os.Remove("testdata/.stfolder")
os.RemoveAll("testdata/.stfolder")
wr, err := Load(fmt.Sprintf("testdata/v%d.xml", i), device1)
if err != nil {
t.Fatal(err)

View File

@@ -81,12 +81,17 @@ func (f FolderConfiguration) Filesystem() fs.Filesystem {
func (f *FolderConfiguration) CreateMarker() error {
if !f.HasMarker() {
permBits := fs.FileMode(0777)
if runtime.GOOS == "windows" {
// Windows has no umask so we must chose a safer set of bits to
// begin with.
permBits = 0700
}
fs := f.Filesystem()
fd, err := fs.Create(".stfolder")
err := fs.Mkdir(".stfolder", permBits)
if err != nil {
return err
}
fd.Close()
if dir, err := fs.Open("."); err == nil {
if serr := dir.Sync(); err != nil {
l.Infof("fsync %q failed: %v", ".", serr)

View File

@@ -13,16 +13,17 @@ import (
)
type GUIConfiguration struct {
Enabled bool `xml:"enabled,attr" json:"enabled" default:"true"`
RawAddress string `xml:"address" json:"address" default:"127.0.0.1:8384"`
User string `xml:"user,omitempty" json:"user"`
Password string `xml:"password,omitempty" json:"password"`
RawUseTLS bool `xml:"tls,attr" json:"useTLS"`
APIKey string `xml:"apikey,omitempty" json:"apiKey"`
InsecureAdminAccess bool `xml:"insecureAdminAccess,omitempty" json:"insecureAdminAccess"`
Theme string `xml:"theme" json:"theme" default:"default"`
Debugging bool `xml:"debugging,attr" json:"debugging"`
InsecureSkipHostCheck bool `xml:"insecureSkipHostcheck,omitempty" json:"insecureSkipHostcheck"`
Enabled bool `xml:"enabled,attr" json:"enabled" default:"true"`
RawAddress string `xml:"address" json:"address" default:"127.0.0.1:8384"`
User string `xml:"user,omitempty" json:"user"`
Password string `xml:"password,omitempty" json:"password"`
RawUseTLS bool `xml:"tls,attr" json:"useTLS"`
APIKey string `xml:"apikey,omitempty" json:"apiKey"`
InsecureAdminAccess bool `xml:"insecureAdminAccess,omitempty" json:"insecureAdminAccess"`
Theme string `xml:"theme" json:"theme" default:"default"`
Debugging bool `xml:"debugging,attr" json:"debugging"`
InsecureSkipHostCheck bool `xml:"insecureSkipHostcheck,omitempty" json:"insecureSkipHostcheck"`
InsecureAllowFrameLoading bool `xml:"insecureAllowFrameLoading,omitempty" json:"insecureAllowFrameLoading"`
}
func (c GUIConfiguration) Address() string {

16
lib/config/testdata/v23.xml vendored Normal file
View File

@@ -0,0 +1,16 @@
<configuration version="22">
<folder id="test" path="testdata" type="readonly" ignorePerms="false" rescanIntervalS="600" autoNormalize="true">
<filesystemType>basic</filesystemType>
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
<minDiskFree unit="%">1</minDiskFree>
<maxConflicts>-1</maxConflicts>
<fsync>true</fsync>
</folder>
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="metadata">
<address>tcp://a</address>
</device>
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2" name="node two" compression="metadata">
<address>tcp://b</address>
</device>
</configuration>

View File

@@ -11,9 +11,9 @@ import (
"net/url"
"time"
"github.com/AudriusButkevicius/kcp-go"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/xtaci/kcp-go"
"github.com/xtaci/smux"
)

View File

@@ -14,11 +14,11 @@ import (
"sync"
"time"
"github.com/AudriusButkevicius/kcp-go"
"github.com/AudriusButkevicius/pfilter"
"github.com/ccding/go-stun/stun"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/nat"
"github.com/xtaci/kcp-go"
"github.com/xtaci/smux"
)

View File

@@ -71,7 +71,7 @@ func newBasicFilesystem(root string) *BasicFilesystem {
// rooted expands the relative path to the full path that is then used with os
// package. If the relative path somehow causes the final path to escape the root
// directoy, this returns an error, to prevent accessing files that are not in the
// directory, this returns an error, to prevent accessing files that are not in the
// shared directory.
func (f *BasicFilesystem) rooted(rel string) (string, error) {
// The root must not be empty.

View File

@@ -11,6 +11,7 @@ import (
"io"
"os"
"path/filepath"
"strings"
"time"
)
@@ -133,3 +134,20 @@ func NewFilesystem(fsType FilesystemType, uri string) Filesystem {
}
return fs
}
// IsInternal returns true if the file, as a path relative to the folder
// root, represents an internal file that should always be ignored. The file
// path must be clean (i.e., in canonical shortest form).
func IsInternal(file string) bool {
internals := []string{".stfolder", ".stignore", ".stversions"}
pathSep := string(PathSeparator)
for _, internal := range internals {
if file == internal {
return true
}
if strings.HasPrefix(file, internal+pathSep) {
return true
}
}
return false
}

43
lib/fs/filesystem_test.go Normal file
View File

@@ -0,0 +1,43 @@
// Copyright (C) 2017 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 fs
import (
"path/filepath"
"testing"
)
func TestIsInternal(t *testing.T) {
cases := []struct {
file string
internal bool
}{
{".stfolder", true},
{".stignore", true},
{".stversions", true},
{".stfolder/foo", true},
{".stignore/foo", true},
{".stversions/foo", true},
{".stfolderfoo", false},
{".stignorefoo", false},
{".stversionsfoo", false},
{"foo.stfolder", false},
{"foo.stignore", false},
{"foo.stversions", false},
{"foo/.stfolder", false},
{"foo/.stignore", false},
{"foo/.stversions", false},
}
for _, tc := range cases {
res := IsInternal(filepath.FromSlash(tc.file))
if res != tc.internal {
t.Errorf("Unexpected result: IsInteral(%q): %v should be %v", tc.file, res, tc.internal)
}
}
}

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 ignore
package fs
import (
"crypto/md5"

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 ignore
package fs
import (
"strings"

View File

@@ -132,19 +132,13 @@ func (m *Matcher) Load(file string) error {
return nil
}
fd, err := m.fs.Open(file)
fd, info, err := loadIgnoreFile(m.fs, file, m.changeDetector)
if err != nil {
m.parseLocked(&bytes.Buffer{}, file)
return err
}
defer fd.Close()
info, err := fd.Stat()
if err != nil {
m.parseLocked(&bytes.Buffer{}, file)
return err
}
m.changeDetector.Reset()
m.changeDetector.Remember(m.fs, file, info.ModTime())
@@ -158,7 +152,7 @@ func (m *Matcher) Parse(r io.Reader, file string) error {
}
func (m *Matcher) parseLocked(r io.Reader, file string) error {
lines, patterns, err := parseIgnoreFile(m.fs, r, file, m.changeDetector)
lines, patterns, err := parseIgnoreFile(m.fs, r, file, m.changeDetector, make(map[string]struct{}))
// Error is saved and returned at the end. We process the patterns
// (possibly blank) anyway.
@@ -179,7 +173,7 @@ func (m *Matcher) parseLocked(r io.Reader, file string) error {
}
func (m *Matcher) Match(file string) (result Result) {
if m == nil || file == "." {
if file == "." {
return resultNotMatched
}
@@ -234,10 +228,6 @@ func (m *Matcher) Lines() []string {
// Patterns return a list of the loaded patterns, as they've been parsed
func (m *Matcher) Patterns() []string {
if m == nil {
return nil
}
m.mut.Lock()
defer m.mut.Unlock()
@@ -278,10 +268,10 @@ func (m *Matcher) clean(d time.Duration) {
// ShouldIgnore returns true when a file is temporary, internal or ignored
func (m *Matcher) ShouldIgnore(filename string) bool {
switch {
case IsTemporary(filename):
case fs.IsTemporary(filename):
return true
case IsInternal(filename):
case fs.IsInternal(filename):
return true
case m.Match(filename).IsIgnored():
@@ -300,11 +290,21 @@ func hashPatterns(patterns []Pattern) string {
return fmt.Sprintf("%x", h.Sum(nil))
}
func loadIgnoreFile(filesystem fs.Filesystem, file string, cd ChangeDetector) ([]string, []Pattern, error) {
if cd.Seen(filesystem, file) {
return nil, nil, fmt.Errorf("multiple include of ignore file %q", file)
func loadIgnoreFile(fs fs.Filesystem, file string, cd ChangeDetector) (fs.File, fs.FileInfo, error) {
fd, err := fs.Open(file)
if err != nil {
return fd, nil, err
}
info, err := fd.Stat()
if err != nil {
fd.Close()
}
return fd, info, err
}
func loadParseIncludeFile(filesystem fs.Filesystem, file string, cd ChangeDetector, linesSeen map[string]struct{}) ([]string, []Pattern, error) {
// Allow escaping the folders filesystem.
// TODO: Deprecate, somehow?
if filesystem.Type() == fs.FilesystemTypeBasic {
@@ -316,23 +316,22 @@ func loadIgnoreFile(filesystem fs.Filesystem, file string, cd ChangeDetector) ([
}
}
fd, err := filesystem.Open(file)
if cd.Seen(filesystem, file) {
return nil, nil, fmt.Errorf("multiple include of ignore file %q", file)
}
fd, info, err := loadIgnoreFile(filesystem, file, cd)
if err != nil {
return nil, nil, err
}
defer fd.Close()
info, err := fd.Stat()
if err != nil {
return nil, nil, err
}
cd.Remember(filesystem, file, info.ModTime())
return parseIgnoreFile(filesystem, fd, file, cd)
return parseIgnoreFile(filesystem, fd, file, cd, linesSeen)
}
func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd ChangeDetector) ([]string, []Pattern, error) {
func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd ChangeDetector, linesSeen map[string]struct{}) ([]string, []Pattern, error) {
var lines []string
var patterns []Pattern
@@ -399,7 +398,7 @@ func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd Chan
} else if strings.HasPrefix(line, "#include ") {
includeRel := strings.TrimSpace(line[len("#include "):])
includeFile := filepath.Join(filepath.Dir(currentFile), includeRel)
_, includePatterns, err := loadIgnoreFile(fs, includeFile, cd)
_, includePatterns, err := loadParseIncludeFile(fs, includeFile, cd, linesSeen)
if err != nil {
return fmt.Errorf("include of %q: %v", includeRel, err)
}
@@ -429,6 +428,10 @@ func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd Chan
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
lines = append(lines, line)
if _, ok := linesSeen[line]; ok {
continue
}
linesSeen[line] = struct{}{}
switch {
case line == "":
continue
@@ -458,23 +461,6 @@ func parseIgnoreFile(fs fs.Filesystem, fd io.Reader, currentFile string, cd Chan
return lines, patterns, nil
}
// IsInternal returns true if the file, as a path relative to the folder
// root, represents an internal file that should always be ignored. The file
// path must be clean (i.e., in canonical shortest form).
func IsInternal(file string) bool {
internals := []string{".stfolder", ".stignore", ".stversions"}
pathSep := string(fs.PathSeparator)
for _, internal := range internals {
if file == internal {
return true
}
if strings.HasPrefix(file, internal+pathSep) {
return true
}
}
return false
}
// WriteIgnores is a convenience function to avoid code duplication
func WriteIgnores(filesystem fs.Filesystem, path string, content []string) error {
fd, err := osutil.CreateAtomicFilesystem(filesystem, path)

View File

@@ -837,37 +837,6 @@ func TestGobwasGlobIssue18(t *testing.T) {
}
}
func TestIsInternal(t *testing.T) {
cases := []struct {
file string
internal bool
}{
{".stfolder", true},
{".stignore", true},
{".stversions", true},
{".stfolder/foo", true},
{".stignore/foo", true},
{".stversions/foo", true},
{".stfolderfoo", false},
{".stignorefoo", false},
{".stversionsfoo", false},
{"foo.stfolder", false},
{"foo.stignore", false},
{"foo.stversions", false},
{"foo/.stfolder", false},
{"foo/.stignore", false},
{"foo/.stversions", false},
}
for _, tc := range cases {
res := IsInternal(filepath.FromSlash(tc.file))
if res != tc.internal {
t.Errorf("Unexpected result: IsInteral(%q): %v should be %v", tc.file, res, tc.internal)
}
}
}
func TestRoot(t *testing.T) {
stignore := `
!/a
@@ -903,6 +872,7 @@ func TestLines(t *testing.T) {
!/a
/*
!/a
`
pats := New(fs.NewFilesystem(fs.FilesystemTypeBasic, "."), WithCache(true))
@@ -917,6 +887,7 @@ func TestLines(t *testing.T) {
"",
"!/a",
"/*",
"!/a",
"",
}
@@ -929,5 +900,33 @@ func TestLines(t *testing.T) {
t.Fatalf("Lines()[%d] == %s, expected %s", i, lines[i], expectedLines[i])
}
}
}
func TestDuplicateLines(t *testing.T) {
stignore := `
!/a
/*
!/a
`
stignoreFiltered := `
!/a
/*
`
pats := New(fs.NewFilesystem(fs.FilesystemTypeBasic, "testdata"), WithCache(true))
err := pats.Parse(bytes.NewBufferString(stignore), ".stignore")
if err != nil {
t.Fatal(err)
}
patsLen := len(pats.patterns)
err = pats.Parse(bytes.NewBufferString(stignoreFiltered), ".stignore")
if err != nil {
t.Fatal(err)
}
if patsLen != len(pats.patterns) {
t.Fatalf("Parsed patterns differ when manually removing duplicate lines")
}
}

View File

@@ -9,10 +9,13 @@ package model
import (
"context"
"time"
"github.com/syncthing/syncthing/lib/config"
)
type folder struct {
stateTracker
config.FolderConfiguration
scan folderScanner
model *Model
@@ -21,9 +24,23 @@ type folder struct {
initialScanFinished chan struct{}
}
func (f *folder) IndexUpdated() {
func newFolder(model *Model, cfg config.FolderConfiguration) folder {
ctx, cancel := context.WithCancel(context.Background())
return folder{
stateTracker: newStateTracker(cfg.ID),
FolderConfiguration: cfg,
scan: newFolderScanner(cfg),
ctx: ctx,
cancel: cancel,
model: model,
initialScanFinished: make(chan struct{}),
}
}
func (f *folder) IndexUpdated() {
}
func (f *folder) DelayScan(next time.Duration) {
f.scan.Delay(next)
}
@@ -54,3 +71,20 @@ func (f *folder) scanSubdirs(subDirs []string) error {
}
return nil
}
func (f *folder) scanTimerFired() {
err := f.scanSubdirs(nil)
select {
case <-f.initialScanFinished:
default:
status := "Completed"
if err != nil {
status = "Failed"
}
l.Infoln(status, "initial scan of", f.Type.String(), "folder", f.Description())
close(f.initialScanFinished)
}
f.scan.Reschedule()
}

View File

@@ -57,7 +57,3 @@ func (f *folderScanner) Scan(subdirs []string) error {
func (f *folderScanner) Delay(next time.Duration) {
f.delay <- next
}
func (f *folderScanner) HasNoInterval() bool {
return f.interval == 0
}

View File

@@ -80,7 +80,6 @@ type Model struct {
clientVersion string
folderCfgs map[string]config.FolderConfiguration // folder -> cfg
folderFs map[string]fs.Filesystem // folder -> fs
folderFiles map[string]*db.FileSet // folder -> files
folderDevices folderDeviceSet // folder -> deviceIDs
deviceFolders map[protocol.DeviceID][]string // deviceID -> folders
@@ -137,7 +136,6 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, clientName, clientVersi
clientName: clientName,
clientVersion: clientVersion,
folderCfgs: make(map[string]config.FolderConfiguration),
folderFs: make(map[string]fs.Filesystem),
folderFiles: make(map[string]*db.FileSet),
folderDevices: make(folderDeviceSet),
deviceFolders: make(map[protocol.DeviceID][]string),
@@ -253,7 +251,14 @@ func (m *Model) startFolderLocked(folder string) config.FolderType {
}
}
p := folderFactory(m, cfg, ver, fs.MtimeFS())
ffs := fs.MtimeFS()
// These are our metadata files, and they should always be hidden.
ffs.Hide(".stfolder")
ffs.Hide(".stversions")
ffs.Hide(".stignore")
p := folderFactory(m, cfg, ver, ffs)
m.folderRunners[folder] = p
m.warnAboutOverwritingProtectedFiles(folder)
@@ -334,9 +339,16 @@ func (m *Model) RemoveFolder(folder string) {
m.pmut.Lock()
// Delete syncthing specific files
folderCfg := m.folderCfgs[folder]
folderCfg, ok := m.folderCfgs[folder]
if !ok {
// Folder might be paused
folderCfg, ok = m.cfg.Folder(folder)
}
if !ok {
panic("bug: remove non existing folder")
}
fs := folderCfg.Filesystem()
fs.Remove(".stfolder")
fs.RemoveAll(".stfolder")
m.tearDownFolderLocked(folder)
// Remove it from the database
@@ -1156,7 +1168,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
// acceptable relative to "folderPath" and in canonical form, so we can
// trust it.
if ignore.IsInternal(name) {
if fs.IsInternal(name) {
l.Debugf("%v REQ(in) for internal file: %s: %q / %q o=%d s=%d", m, deviceID, folder, name, offset, len(buf))
return protocol.ErrNoSuchFile
}
@@ -1174,7 +1186,7 @@ func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset
// Only check temp files if the flag is set, and if we are set to advertise
// the temp indexes.
if fromTemporary && !folderCfg.DisableTempIndexes {
tempFn := ignore.TempName(name)
tempFn := fs.TempName(name)
if info, err := folderFs.Lstat(tempFn); err != nil || !info.IsRegular() {
// Reject reads for anything that doesn't exist or is something
@@ -2552,7 +2564,7 @@ func unifySubs(dirs []string, exists func(dir string) bool) []string {
func trimUntilParentKnown(dirs []string, exists func(dir string) bool) []string {
var subs []string
for _, sub := range dirs {
for sub != "" && !ignore.IsInternal(sub) {
for sub != "" && !fs.IsInternal(sub) {
sub = filepath.Clean(sub)
parent := filepath.Dir(sub)
if parent == "." || exists(parent) {

View File

@@ -1026,7 +1026,8 @@ func changeIgnores(t *testing.T, m *Model, expected []string) {
func TestIgnores(t *testing.T) {
// Assure a clean start state
ioutil.WriteFile("testdata/.stfolder", nil, 0644)
os.RemoveAll("testdata/.stfolder")
os.MkdirAll("testdata/.stfolder", 0644)
ioutil.WriteFile("testdata/.stignore", []byte(".*\nquux\n"), 0644)
db := db.OpenMemory()
@@ -1901,6 +1902,52 @@ func TestIssue3164(t *testing.T) {
}
}
func TestIssue4357(t *testing.T) {
db := db.OpenMemory()
m := NewModel(defaultConfig, protocol.LocalDeviceID, "syncthing", "dev", db, nil)
m.ServeBackground()
defer m.Stop()
cfg := m.cfg.RawCopy()
m.CommitConfiguration(config.Configuration{}, cfg)
if _, ok := m.folderCfgs["default"]; !ok {
t.Error("Folder should be running")
}
newCfg := m.cfg.RawCopy()
newCfg.Folders[0].Paused = true
m.CommitConfiguration(cfg, newCfg)
if _, ok := m.folderCfgs["default"]; ok {
t.Error("Folder should not be running")
}
// Should not panic when removing a paused folder.
m.RemoveFolder("default")
// Add the folder back, should be running
m.CommitConfiguration(config.Configuration{}, cfg)
if _, ok := m.folderCfgs["default"]; !ok {
t.Error("Folder should be running")
}
// Should not panic when removing a running folder.
m.RemoveFolder("default")
if _, ok := m.folderCfgs["default"]; ok {
t.Error("Folder should not be running")
}
// Should panic when removing a non-existing folder
defer func() {
if recover() == nil {
t.Error("expected a panic")
}
}()
m.RemoveFolder("non-existing")
}
func TestScanNoDatabaseWrite(t *testing.T) {
// When scanning, nothing should be committed to database unless
// something actually changed.

View File

@@ -7,7 +7,6 @@
package model
import (
"context"
"fmt"
"github.com/syncthing/syncthing/lib/config"
@@ -21,23 +20,10 @@ func init() {
type sendOnlyFolder struct {
folder
config.FolderConfiguration
}
func newSendOnlyFolder(model *Model, cfg config.FolderConfiguration, _ versioner.Versioner, _ fs.Filesystem) service {
ctx, cancel := context.WithCancel(context.Background())
return &sendOnlyFolder{
folder: folder{
stateTracker: newStateTracker(cfg.ID),
scan: newFolderScanner(cfg),
ctx: ctx,
cancel: cancel,
model: model,
initialScanFinished: make(chan struct{}),
},
FolderConfiguration: cfg,
}
return &sendOnlyFolder{folder: newFolder(model, cfg)}
}
func (f *sendOnlyFolder) Serve() {
@@ -55,24 +41,7 @@ func (f *sendOnlyFolder) Serve() {
case <-f.scan.timer.C:
l.Debugln(f, "Scanning subdirectories")
err := f.scanSubdirs(nil)
select {
case <-f.initialScanFinished:
default:
status := "Completed"
if err != nil {
status = "Failed"
}
l.Infoln(status, "initial scan (ro) of", f.Description())
close(f.initialScanFinished)
}
if f.scan.HasNoInterval() {
continue
}
f.scan.Reschedule()
f.scanTimerFired()
case req := <-f.scan.now:
req.err <- f.scanSubdirs(req.subdirs)

View File

@@ -7,7 +7,6 @@
package model
import (
"context"
"errors"
"fmt"
"math/rand"
@@ -81,7 +80,6 @@ type dbUpdateJob struct {
type sendReceiveFolder struct {
folder
config.FolderConfiguration
fs fs.Filesystem
versioner versioner.Versioner
@@ -98,18 +96,8 @@ type sendReceiveFolder struct {
}
func newSendReceiveFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Versioner, fs fs.Filesystem) service {
ctx, cancel := context.WithCancel(context.Background())
f := &sendReceiveFolder{
folder: folder{
stateTracker: newStateTracker(cfg.ID),
scan: newFolderScanner(cfg),
ctx: ctx,
cancel: cancel,
model: model,
initialScanFinished: make(chan struct{}),
},
FolderConfiguration: cfg,
folder: newFolder(model, cfg),
fs: fs,
versioner: ver,
@@ -251,21 +239,24 @@ func (f *sendReceiveFolder) Serve() {
break
}
if tries > 10 {
if tries > 2 {
// We've tried a bunch of times to get in sync, but
// we're not making it. Probably there are write
// errors preventing us. Flag this with a warning and
// wait a bit longer before retrying.
l.Infof("Folder %q isn't making progress. Pausing puller for %v.", f.folderID, f.pause)
l.Debugln(f, "next pull in", f.pause)
if folderErrors := f.currentErrors(); len(folderErrors) > 0 {
for _, fileError := range folderErrors {
l.Infof("Puller (folder %v, dir %q): %v", f.Description(), fileError.Path, fileError.Err)
}
events.Default.Log(events.FolderErrors, map[string]interface{}{
"folder": f.folderID,
"errors": folderErrors,
})
}
l.Infof("Folder %v isn't making progress. Pausing puller for %v.", f.Description(), f.pause)
l.Debugln(f, "next pull in", f.pause)
f.pullTimer.Reset(f.pause)
break
}
@@ -277,18 +268,7 @@ func (f *sendReceiveFolder) Serve() {
// same time.
case <-f.scan.timer.C:
l.Debugln(f, "Scanning subdirectories")
err := f.scanSubdirs(nil)
f.scan.Reschedule()
select {
case <-f.initialScanFinished:
default:
close(f.initialScanFinished)
status := "Completed"
if err != nil {
status = "Failed"
}
l.Infoln(status, "initial scan (rw) of", f.Description())
}
f.scanTimerFired()
case req := <-f.scan.now:
req.err <- f.scanSubdirs(req.subdirs)
@@ -625,7 +605,7 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo) {
case err == nil && (!info.IsDir() || info.IsSymlink()):
err = osutil.InWritableDir(f.fs.Remove, f.fs, file.Name)
if err != nil {
l.Infof("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
return
}
@@ -656,14 +636,14 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo) {
if err = osutil.InWritableDir(mkdir, f.fs, file.Name); err == nil {
f.dbUpdates <- dbUpdateJob{file, dbUpdateHandleDir}
} else {
l.Infof("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
}
return
// Weird error when stat()'ing the dir. Probably won't work to do
// anything else with it if we can't even stat() it.
case err != nil:
l.Infof("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
return
}
@@ -676,7 +656,7 @@ func (f *sendReceiveFolder) handleDir(file protocol.FileInfo) {
} else if err := f.fs.Chmod(file.Name, mode|(fs.FileMode(info.Mode())&retainBits)); err == nil {
f.dbUpdates <- dbUpdateJob{file, dbUpdateHandleDir}
} else {
l.Infof("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
}
}
@@ -713,7 +693,7 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo) {
// Index entry from a Syncthing predating the support for including
// the link target in the index entry. We log this as an error.
err = errors.New("incompatible symlink entry; rescan with newer Syncthing on source")
l.Infof("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
return
}
@@ -724,7 +704,7 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo) {
// path.
err = osutil.InWritableDir(f.fs.Remove, f.fs, file.Name)
if err != nil {
l.Infof("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
return
}
@@ -739,7 +719,7 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo) {
if err = osutil.InWritableDir(createLink, f.fs, file.Name); err == nil {
f.dbUpdates <- dbUpdateJob{file, dbUpdateHandleSymlink}
} else {
l.Infof("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
}
}
@@ -772,7 +752,7 @@ func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, matcher *ignore.Ma
files, _ := f.fs.DirNames(file.Name)
for _, dirFile := range files {
fullDirFile := filepath.Join(file.Name, dirFile)
if ignore.IsTemporary(dirFile) || (matcher != nil && matcher.Match(fullDirFile).IsDeletable()) {
if fs.IsTemporary(dirFile) || (matcher != nil && matcher.Match(fullDirFile).IsDeletable()) {
f.fs.RemoveAll(fullDirFile)
}
}
@@ -788,7 +768,7 @@ func (f *sendReceiveFolder) deleteDir(file protocol.FileInfo, matcher *ignore.Ma
// file and not a directory etc) and that the delete is handled.
f.dbUpdates <- dbUpdateJob{file, dbUpdateDeleteDir}
} else {
l.Infof("Puller (folder %q, dir %q): delete: %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, dir %q): delete: %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
}
}
@@ -841,7 +821,7 @@ func (f *sendReceiveFolder) deleteFile(file protocol.FileInfo) {
// not a directory etc) and that the delete is handled.
f.dbUpdates <- dbUpdateJob{file, dbUpdateDeleteFile}
} else {
l.Infof("Puller (folder %q, file %q): delete: %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, file %q): delete: %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
}
}
@@ -903,7 +883,7 @@ func (f *sendReceiveFolder) renameFile(source, target protocol.FileInfo) {
err = f.shortcutFile(target)
if err != nil {
l.Infof("Puller (folder %q, file %q): rename from %q metadata: %v", f.folderID, target.Name, source.Name, err)
l.Debugf("Puller (folder %q, file %q): rename from %q metadata: %v", f.folderID, target.Name, source.Name, err)
f.newError(target.Name, err)
return
}
@@ -916,7 +896,7 @@ func (f *sendReceiveFolder) renameFile(source, target protocol.FileInfo) {
err = osutil.InWritableDir(f.fs.Remove, f.fs, source.Name)
if err != nil {
l.Infof("Puller (folder %q, file %q): delete %q after failed rename: %v", f.folderID, target.Name, source.Name, err)
l.Debugf("Puller (folder %q, file %q): delete %q after failed rename: %v", f.folderID, target.Name, source.Name, err)
f.newError(target.Name, err)
return
}
@@ -991,7 +971,7 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c
})
if err != nil {
l.Infoln("Puller: shortcut:", err)
l.Debugln("Puller: shortcut:", err)
f.newError(file.Name, err)
} else {
f.dbUpdates <- dbUpdateJob{file, dbUpdateShortcutFile}
@@ -1000,7 +980,7 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c
return
}
tempName := ignore.TempName(file.Name)
tempName := fs.TempName(file.Name)
scanner.PopulateOffsets(file.Blocks)
@@ -1102,7 +1082,7 @@ func (f *sendReceiveFolder) handleFile(file protocol.FileInfo, copyChan chan<- c
func (f *sendReceiveFolder) shortcutFile(file protocol.FileInfo) error {
if !f.ignorePermissions(file) {
if err := f.fs.Chmod(file.Name, fs.FileMode(file.Permissions&0777)); err != nil {
l.Infof("Puller (folder %q, file %q): shortcut: chmod: %v", f.folderID, file.Name, err)
l.Debugf("Puller (folder %q, file %q): shortcut: chmod: %v", f.folderID, file.Name, err)
f.newError(file.Name, err)
return err
}
@@ -1461,7 +1441,7 @@ func (f *sendReceiveFolder) finisherRoutine(in <-chan *sharedPullerState) {
}
if err != nil {
l.Infoln("Puller: final:", err)
l.Debugln("Puller: final:", err)
f.newError(state.file.Name, err)
}
events.Default.Log(events.ItemFinished, map[string]interface{}{
@@ -1491,13 +1471,10 @@ func (f *sendReceiveFolder) Jobs() ([]string, []string) {
// dbUpdaterRoutine aggregates db updates and commits them in batches no
// larger than 1000 items, and no more delayed than 2 seconds.
func (f *sendReceiveFolder) dbUpdaterRoutine() {
const (
maxBatchSize = 1000
maxBatchTime = 2 * time.Second
)
const maxBatchTime = 2 * time.Second
batch := make([]dbUpdateJob, 0, maxBatchSize)
files := make([]protocol.FileInfo, 0, maxBatchSize)
batch := make([]dbUpdateJob, 0, maxBatchSizeFiles)
files := make([]protocol.FileInfo, 0, maxBatchSizeFiles)
tick := time.NewTicker(maxBatchTime)
defer tick.Stop()
@@ -1557,6 +1534,7 @@ func (f *sendReceiveFolder) dbUpdaterRoutine() {
files = files[:0]
}
batchSizeBytes := 0
loop:
for {
select {
@@ -1568,13 +1546,16 @@ loop:
job.file.Sequence = 0
batch = append(batch, job)
if len(batch) == maxBatchSize {
batchSizeBytes += job.file.ProtoSize()
if len(batch) == maxBatchSizeFiles || batchSizeBytes > maxBatchSizeBytes {
handleBatch()
batchSizeBytes = 0
}
case <-tick.C:
if len(batch) > 0 {
handleBatch()
batchSizeBytes = 0
}
}
}

View File

@@ -17,7 +17,6 @@ import (
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/ignore"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/scanner"
"github.com/syncthing/syncthing/lib/sync"
@@ -27,15 +26,15 @@ func TestMain(m *testing.M) {
// We do this to make sure that the temp file required for the tests
// does not get removed during the tests. Also set the prefix so it's
// found correctly regardless of platform.
if ignore.TempPrefix != ignore.WindowsTempPrefix {
originalPrefix := ignore.TempPrefix
ignore.TempPrefix = ignore.WindowsTempPrefix
if fs.TempPrefix != fs.WindowsTempPrefix {
originalPrefix := fs.TempPrefix
fs.TempPrefix = fs.WindowsTempPrefix
defer func() {
ignore.TempPrefix = originalPrefix
fs.TempPrefix = originalPrefix
}()
}
future := time.Now().Add(time.Hour)
err := os.Chtimes(filepath.Join("testdata", ignore.TempName("file")), future, future)
err := os.Chtimes(filepath.Join("testdata", fs.TempName("file")), future, future)
if err != nil {
panic(err)
}
@@ -191,14 +190,14 @@ func TestCopierFinder(t *testing.T) {
// After dropping out blocks found locally:
// Pull: 1, 5, 6, 8
tempFile := filepath.Join("testdata", ignore.TempName("file2"))
tempFile := filepath.Join("testdata", fs.TempName("file2"))
err := os.Remove(tempFile)
if err != nil && !os.IsNotExist(err) {
t.Error(err)
}
existingBlocks := []int{0, 2, 3, 4, 0, 0, 7, 0}
existingFile := setUpFile(ignore.TempName("file"), existingBlocks)
existingFile := setUpFile(fs.TempName("file"), existingBlocks)
requiredFile := existingFile
requiredFile.Blocks = blocks[1:]
requiredFile.Name = "file2"
@@ -261,7 +260,7 @@ func TestCopierFinder(t *testing.T) {
}
func TestWeakHash(t *testing.T) {
tempFile := filepath.Join("testdata", ignore.TempName("weakhash"))
tempFile := filepath.Join("testdata", fs.TempName("weakhash"))
var shift int64 = 10
var size int64 = 1 << 20
expectBlocks := int(size / protocol.BlockSize)
@@ -466,12 +465,12 @@ func TestLastResortPulling(t *testing.T) {
}
(<-finisherChan).fd.Close()
os.Remove(filepath.Join("testdata", ignore.TempName("newfile")))
os.Remove(filepath.Join("testdata", fs.TempName("newfile")))
}
func TestDeregisterOnFailInCopy(t *testing.T) {
file := setUpFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
defer os.Remove("testdata/" + ignore.TempName("filex"))
defer os.Remove("testdata/" + fs.TempName("filex"))
db := db.OpenMemory()
@@ -545,7 +544,7 @@ func TestDeregisterOnFailInCopy(t *testing.T) {
func TestDeregisterOnFailInPull(t *testing.T) {
file := setUpFile("filex", []int{0, 2, 0, 0, 5, 0, 0, 8})
defer os.Remove("testdata/" + ignore.TempName("filex"))
defer os.Remove("testdata/" + fs.TempName("filex"))
db := db.OpenMemory()
m := NewModel(defaultConfig, protocol.LocalDeviceID, "syncthing", "dev", db, nil)

View File

@@ -164,6 +164,9 @@ func (s *sharedPullerState) tempFile() (io.WriterAt, error) {
return nil, err
}
// Hide the temporary file
s.fs.Hide(s.tempName)
// Don't truncate symlink files, as that will mean that the path will
// contain a bunch of nulls.
if s.sparse && !s.file.IsSymlink() {
@@ -307,6 +310,12 @@ func (s *sharedPullerState) finalClose() (bool, error) {
s.closed = true
// Unhide the temporary file when we close it, as it's likely to
// immediately be renamed to the final name. If this is a failed temp
// file we will also unhide it, but I'm fine with that as we're now
// leaving it around for potentially quite a while.
s.fs.Unhide(s.tempName)
return true, s.err
}

View File

@@ -8,8 +8,8 @@ import (
"net"
"testing"
"github.com/AudriusButkevicius/kcp-go"
"github.com/syncthing/syncthing/lib/dialer"
"github.com/xtaci/kcp-go"
)
func BenchmarkRequestsRawTCP(b *testing.B) {

View File

@@ -8,10 +8,8 @@ import (
"encoding/binary"
"errors"
"fmt"
"regexp"
"strings"
"github.com/calmh/luhn"
"github.com/syncthing/syncthing/lib/sha256"
)
@@ -155,16 +153,17 @@ func luhnify(s string) (string, error) {
panic("unsupported string length")
}
res := make([]string, 0, 4)
res := make([]byte, 4*(13+1))
for i := 0; i < 4; i++ {
p := s[i*13 : (i+1)*13]
l, err := luhn.Base32.Generate(p)
copy(res[i*(13+1):], p)
l, err := luhnBase32.generate(p)
if err != nil {
return "", err
}
res = append(res, fmt.Sprintf("%s%c", p, l))
res[(i+1)*(13)+i] = byte(l)
}
return res[0] + res[1] + res[2] + res[3], nil
return string(res), nil
}
func unluhnify(s string) (string, error) {
@@ -172,25 +171,31 @@ func unluhnify(s string) (string, error) {
return "", fmt.Errorf("%q: unsupported string length %d", s, len(s))
}
res := make([]string, 0, 4)
res := make([]byte, 52)
for i := 0; i < 4; i++ {
p := s[i*14 : (i+1)*14-1]
l, err := luhn.Base32.Generate(p)
p := s[i*(13+1) : (i+1)*(13+1)-1]
copy(res[i*13:], p)
l, err := luhnBase32.generate(p)
if err != nil {
return "", err
}
if g := fmt.Sprintf("%s%c", p, l); g != s[i*14:(i+1)*14] {
if s[(i+1)*14-1] != byte(l) {
return "", fmt.Errorf("%q: check digit incorrect", s)
}
res = append(res, p)
}
return res[0] + res[1] + res[2] + res[3], nil
return string(res), nil
}
func chunkify(s string) string {
s = regexp.MustCompile("(.{7})").ReplaceAllString(s, "$1-")
s = strings.Trim(s, "-")
return s
chunks := len(s) / 7
res := make([]byte, chunks*(7+1)-1)
for i := 0; i < chunks; i++ {
if i > 0 {
res[i*(7+1)-1] = '-'
}
copy(res[i*(7+1):], s[i*7:(i+1)*7])
}
return string(res)
}
func unchunkify(s string) string {

View File

@@ -150,3 +150,41 @@ func TestNewDeviceIDMarshalling(t *testing.T) {
t.Error("Mismatch in old -> new direction")
}
}
var resStr string
func BenchmarkLuhnify(b *testing.B) {
str := "ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJAB"
var err error
for i := 0; i < b.N; i++ {
resStr, err = luhnify(str)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkUnluhnify(b *testing.B) {
str, _ := luhnify("ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJAB")
var err error
for i := 0; i < b.N; i++ {
resStr, err = unluhnify(str)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkChunkify(b *testing.B) {
str := "ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJAB"
for i := 0; i < b.N; i++ {
resStr = chunkify(str)
}
}
func BenchmarkUnchunkify(b *testing.B) {
str := chunkify("ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJAB")
for i := 0; i < b.N; i++ {
resStr = unchunkify(str)
}
}

53
lib/protocol/luhn.go Normal file
View File

@@ -0,0 +1,53 @@
// Copyright (C) 2014 The Protocol Authors.
package protocol
import (
"fmt"
"strings"
)
// An alphabet is a string of N characters, representing the digits of a given
// base N.
type luhnAlphabet string
var (
luhnBase32 luhnAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
)
// generate returns a check digit for the string s, which should be composed
// of characters from the Alphabet a.
func (a luhnAlphabet) generate(s string) (rune, error) {
factor := 1
sum := 0
n := len(a)
for i := range s {
codepoint := strings.IndexByte(string(a), s[i])
if codepoint == -1 {
return 0, fmt.Errorf("Digit %q not valid in alphabet %q", s[i], a)
}
addend := factor * codepoint
if factor == 2 {
factor = 1
} else {
factor = 2
}
addend = (addend / n) + (addend % n)
sum += addend
}
remainder := sum % n
checkCodepoint := (n - remainder) % n
return rune(a[checkCodepoint]), nil
}
// luhnValidate returns true if the last character of the string s is correct, for
// a string s composed of characters in the alphabet a.
func (a luhnAlphabet) luhnValidate(s string) bool {
t := s[:len(s)-1]
c, err := a.generate(t)
if err != nil {
return false
}
return rune(s[len(s)-1]) == c
}

48
lib/protocol/luhn_test.go Normal file
View File

@@ -0,0 +1,48 @@
// Copyright (C) 2014 The Protocol Authors.
package protocol
import (
"testing"
)
func TestGenerate(t *testing.T) {
// Base 6 Luhn
a := luhnAlphabet("abcdef")
c, err := a.generate("abcdef")
if err != nil {
t.Fatal(err)
}
if c != 'e' {
t.Errorf("Incorrect check digit %c != e", c)
}
// Base 10 Luhn
a = luhnAlphabet("0123456789")
c, err = a.generate("7992739871")
if err != nil {
t.Fatal(err)
}
if c != '3' {
t.Errorf("Incorrect check digit %c != 3", c)
}
}
func TestInvalidString(t *testing.T) {
a := luhnAlphabet("ABC")
_, err := a.generate("7992739871")
t.Log(err)
if err == nil {
t.Error("Unexpected nil error")
}
}
func TestValidate(t *testing.T) {
a := luhnAlphabet("abcdef")
if !a.luhnValidate("abcdefe") {
t.Errorf("Incorrect validation response for abcdefe")
}
if a.luhnValidate("abcdefd") {
t.Errorf("Incorrect validation response for abcdefd")
}
}

View File

@@ -16,7 +16,7 @@ import (
)
const (
// BlockSize is the standard ata block size (128 KiB)
// BlockSize is the standard data block size (128 KiB)
BlockSize = 128 << 10
// MaxMessageLen is the largest message size allowed on the wire. (500 MB)

View File

@@ -85,6 +85,9 @@ func Walk(ctx context.Context, cfg Config) (chan protocol.FileInfo, error) {
if w.Filesystem == nil {
panic("no filesystem specified")
}
if w.Matcher == nil {
w.Matcher = ignore.New(w.Filesystem)
}
return w.walk(ctx)
}
@@ -230,7 +233,7 @@ func (w *walker) walkAndHashFiles(ctx context.Context, fchan, dchan chan protoco
return skip
}
if ignore.IsTemporary(path) {
if fs.IsTemporary(path) {
l.Debugln("temporary:", path)
if info.IsRegular() && info.ModTime().Add(w.TempLifetime).Before(now) {
w.Filesystem.Remove(path)
@@ -239,7 +242,7 @@ func (w *walker) walkAndHashFiles(ctx context.Context, fchan, dchan chan protoco
return nil
}
if ignore.IsInternal(path) {
if fs.IsInternal(path) {
l.Debugln("ignored (internal):", path)
return skip
}

View File

@@ -55,17 +55,13 @@ func SelectAlgo() {
}
case "minio":
// When set to "minio", use that. Benchmark anyway to be able to
// present the difference.
benchmark()
// When set to "minio", use that.
selectMinio()
default:
// When set to anything else, such as "standard", use the default Go
// implementation. Benchmark that anyway, so we can report something
// useful in Report(). Make sure not to touch the minio
// implementation. Make sure not to touch the minio
// implementation as it may be disabled for incompatibility reasons.
cryptoPerf = cpuBenchOnce(benchmarkingIterations*benchmarkingDuration, cryptoSha256.New)
}
verifyCorrectness()
@@ -89,6 +85,10 @@ func Report() {
otherImpl = defaultImpl
}
if selectedRate == 0 {
return
}
l.Infof("Single thread SHA256 performance is %s using %s (%s using %s).", formatRate(selectedRate), selectedImpl, formatRate(otherRate), otherImpl)
}

View File

@@ -1,10 +0,0 @@
// Copyright (C) 2016 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
// The existence of this file means we get 0% test coverage rather than no
// test coverage at all. Remove when implementing an actual test.
package tlsutil

View File

@@ -7,7 +7,6 @@
package tlsutil
import (
"bufio"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
@@ -16,7 +15,6 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"io"
"math/big"
"net"
"os"
@@ -130,27 +128,36 @@ func (l *DowngradingListener) AcceptNoWrapTLS() (net.Conn, bool, error) {
return nil, false, err
}
br := bufio.NewReader(conn)
var first [1]byte
conn.SetReadDeadline(time.Now().Add(1 * time.Second))
bs, err := br.Peek(1)
n, err := conn.Read(first[:])
conn.SetReadDeadline(time.Time{})
if err != nil {
if err != nil || n == 0 {
// We hit a read error here, but the Accept() call succeeded so we must not return an error.
// We return the connection as is with a special error which handles this
// special case in Accept().
return conn, false, ErrIdentificationFailed
}
return &UnionedConnection{br, conn}, bs[0] == 0x16, nil
return &UnionedConnection{&first, conn}, first[0] == 0x16, nil
}
type UnionedConnection struct {
io.Reader
first *[1]byte
net.Conn
}
func (c *UnionedConnection) Read(b []byte) (n int, err error) {
return c.Reader.Read(b)
if c.first != nil {
if len(b) == 0 {
// this probably doesn't happen, but handle it anyway
return 0, nil
}
b[0] = c.first[0]
c.first = nil
return 1, nil
}
return c.Conn.Read(b)
}
func publicKey(priv interface{}) interface{} {

110
lib/tlsutil/tlsutil_test.go Normal file
View File

@@ -0,0 +1,110 @@
// Copyright (C) 2016 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
// The existence of this file means we get 0% test coverage rather than no
// test coverage at all. Remove when implementing an actual test.
package tlsutil
import (
"bytes"
"io"
"net"
"testing"
"time"
)
func TestUnionedConnection(t *testing.T) {
cases := []struct {
data []byte
isTLS bool
}{
{[]byte{0}, false},
{[]byte{0x16}, true},
{[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, false},
{[]byte{0x16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, true},
}
for i, tc := range cases {
fc := &fakeAccepter{tc.data}
dl := DowngradingListener{fc, nil}
conn, isTLS, err := dl.AcceptNoWrapTLS()
if err != nil {
t.Fatalf("%d: %v", i, err)
}
if conn == nil {
t.Fatalf("%d: unexpected nil conn", i)
}
if isTLS != tc.isTLS {
t.Errorf("%d: isTLS=%v, expected %v", i, isTLS, tc.isTLS)
}
// Read all the data, check it's the same
var bs []byte
buf := make([]byte, 128)
for {
n, err := conn.Read(buf)
if err == io.EOF {
break
}
if err != nil {
t.Fatalf("%d: read error: %v", i, err)
}
if len(bs) == 0 {
// first read; should return just one byte
if n != 1 {
t.Errorf("%d: first read returned %d bytes, not 1", i, n)
}
// Check that we've nilled out the "first" thing
if conn.(*UnionedConnection).first != nil {
t.Errorf("%d: expected first read to clear out the `first` attribute", i)
}
}
bs = append(bs, buf[:n]...)
}
if !bytes.Equal(bs, tc.data) {
t.Errorf("%d: got wrong data", i)
}
t.Logf("%d: %v, %x", i, isTLS, bs)
}
}
type fakeAccepter struct {
data []byte
}
func (f *fakeAccepter) Accept() (net.Conn, error) {
return &fakeConn{f.data}, nil
}
func (f *fakeAccepter) Addr() net.Addr { return nil }
func (f *fakeAccepter) Close() error { return nil }
type fakeConn struct {
data []byte
}
func (f *fakeConn) Read(b []byte) (int, error) {
if len(f.data) == 0 {
return 0, io.EOF
}
n := copy(b, f.data)
f.data = f.data[n:]
return n, nil
}
func (f *fakeConn) Write(b []byte) (int, error) {
return len(b), nil
}
func (f *fakeConn) Close() error { return nil }
func (f *fakeConn) LocalAddr() net.Addr { return nil }
func (f *fakeConn) RemoteAddr() net.Addr { return nil }
func (f *fakeConn) SetDeadline(time.Time) error { return nil }
func (f *fakeConn) SetReadDeadline(time.Time) error { return nil }
func (f *fakeConn) SetWriteDeadline(time.Time) error { return nil }

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "STDISCOSRV" "1" "August 19, 2017" "v0.14" "Syncthing"
.TH "STDISCOSRV" "1" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
stdiscosrv \- Syncthing Discovery Server
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "STRELAYSRV" "1" "August 19, 2017" "v0.14" "Syncthing"
.TH "STRELAYSRV" "1" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
strelaysrv \- Syncthing Relay Server
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-BEP" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-BEP" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-bep \- Block Exchange Protocol v1
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-CONFIG" "5" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-CONFIG" "5" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-config \- Syncthing Configuration
.
@@ -139,6 +139,7 @@ The following shows an example of the default configuration file (IDs will diffe
<releasesURL>https://api.github.com/repos/syncthing/syncthing/releases?per_page=30</releasesURL>
<overwriteRemoteDeviceNamesOnConnect>false</overwriteRemoteDeviceNamesOnConnect>
<tempIndexMinBlocks>10</tempIndexMinBlocks>
<defaultFolderPath>~</defaultFolderPath>
</options>
</configuration>
.ft P
@@ -522,6 +523,7 @@ If set, this is the API key that enables usage of the REST interface.
<releasesURL>https://api.github.com/repos/syncthing/syncthing/releases?per_page=30</releasesURL>
<overwriteRemoteDeviceNamesOnConnect>false</overwriteRemoteDeviceNamesOnConnect>
<tempIndexMinBlocks>10</tempIndexMinBlocks>
<defaultFolderPath>~</defaultFolderPath>
</options>
.ft P
.fi
@@ -670,6 +672,10 @@ announces will only be adopted when a name has not already been set.
.B tempIndexMinBlocks
When exchanging index information for incomplete transfers, only take
into account files that have at least this many blocks.
.TP
.B defaultFolderPath
The UI will propose to create new folders at this path. This can be disabled by
setting this to an empty string.
.UNINDENT
.SS Listen Addresses
.sp

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-DEVICE-IDS" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-DEVICE-IDS" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-device-ids \- Understanding Device IDs
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-EVENT-API" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-EVENT-API" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-event-api \- Event API
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-FAQ" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-FAQ" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-faq \- Frequently Asked Questions
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-GLOBALDISCO" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-GLOBALDISCO" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-globaldisco \- Global Discovery Protocol v3
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-LOCALDISCO" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-LOCALDISCO" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-localdisco \- Local Discovery Protocol v4
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-NETWORKING" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-NETWORKING" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-networking \- Firewall Setup
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-RELAY" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-RELAY" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-relay \- Relay Protocol v1
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-REST-API" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-REST-API" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-rest-api \- REST API
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-SECURITY" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-SECURITY" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-security \- Security Principles
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-STIGNORE" "5" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-STIGNORE" "5" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-stignore \- Prevent files from being synchronized to other nodes
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-VERSIONING" "7" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING-VERSIONING" "7" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing-versioning \- Keep automatic backups of deleted files by other nodes
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING" "1" "August 19, 2017" "v0.14" "Syncthing"
.TH "SYNCTHING" "1" "September 08, 2017" "v0.14" "Syncthing"
.SH NAME
syncthing \- Syncthing
.

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