Compare commits

...

17 Commits

Author SHA1 Message Date
Jakob Borg
9da422f1c5 gui, man: Update docs & translations 2016-11-29 11:56:02 +01:00
Stefan Tatschner
ab1739ba34 cmd/syncthing: Trigger usage message on extra CLI parameters
fixes: #3690

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3763
2016-11-27 11:21:05 +00:00
Jakob Borg
fc1430aa92 lib/fs: The interface and basicfs
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3748
2016-11-24 12:07:14 +00:00
Jakob Borg
3cde608eda lib/db: Fix ineffassign lint issue 2016-11-24 12:08:44 +01:00
Jakob Borg
2898552f4b build: Setup should insteall deadcode metalinter 2016-11-24 12:05:04 +01:00
Jakob Borg
911c148c71 build: Improve setup, add metalint ineffasign 2016-11-24 11:33:43 +01:00
Jakob Borg
91568a173a lib/model: Remove ineffectual assignment in test 2016-11-24 11:33:27 +01:00
Jakob Borg
e57f5499a1 lib/sync: Remove unused struct field 2016-11-24 11:30:55 +01:00
Jakob Borg
9abb7b71a9 lib/osutil: Fix lint warning on error formatting (fixes #3760) 2016-11-24 11:20:51 +01:00
Jakob Borg
724c354d62 cmd/stdiscosrv: Fix lint warning on Context keys (fixes #3760) 2016-11-24 11:20:51 +01:00
Jakob Borg
c44779094d build: Setup should download latest version of linters etc 2016-11-24 11:20:51 +01:00
Wulf Weich
eeedab4091 gui: bottom nav always behind dropdown (fixes #3758)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3759
2016-11-23 17:03:43 +00:00
Jakob Borg
8559e20237 lib/osutil: Don't chmod in atomic file creation (fixes #2472)
Instead, trust (and test) that the temp file has appropriate permissions
from the start. The only place where this changes our behavior is for
ignores which go from 0644 to 0600. I'm OK with that.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3756
2016-11-23 14:06:08 +00:00
Jakob Borg
26730eb083 lib/model: Fix test that relies on ignore reloading 2016-11-23 14:42:29 +01:00
Simon Frei
4160ce674d model: consistently use cfg when referring to config instance and not package
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3755
2016-11-22 23:14:20 +00:00
Jakob Borg
2dbeea21c4 lib/ignore: Don't slow down tests by sleeping 2016-11-22 22:44:04 +01:00
Jakob Borg
a2b8485a89 lib/ignore: Fast reload of unchanged ignores (fixes #3394)
This changes the "seen" map that we're anyway keeping around to track
the modtimes of loaded files instead. When doing a Load() we check that
1) the file we are loading is in the modtime set, and 2) that none of
the files in the modtime set have changed modtimes. If that's the case
we do a quick return without parsing anything or clearing the cache.

This required adding two one seconds sleeps in the tests to make sure
the modtimes were updated when we expect cache reloads, because I'm on a
crappy filesystem with one second timestamp granularity. That also
proves it works...

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3754
2016-11-22 21:30:45 +00:00
45 changed files with 729 additions and 115 deletions

View File

@@ -298,6 +298,7 @@ func runCommand(cmd string, target target) {
ok := gometalinter("deadcode", dirs, "test/util.go")
ok = gometalinter("structcheck", dirs) && ok
ok = gometalinter("varcheck", dirs) && ok
ok = gometalinter("ineffassign", dirs) && ok
if !ok {
os.Exit(1)
}
@@ -356,14 +357,23 @@ func checkRequiredGoVersion() (float64, bool) {
}
func setup() {
runPrint("go", "get", "-v", "github.com/golang/lint/golint")
runPrint("go", "get", "-v", "golang.org/x/tools/cmd/cover")
runPrint("go", "get", "-v", "golang.org/x/net/html")
runPrint("go", "get", "-v", "github.com/FiloSottile/gvt")
runPrint("go", "get", "-v", "github.com/axw/gocov/gocov")
runPrint("go", "get", "-v", "github.com/AlekSi/gocov-xml")
runPrint("go", "get", "-v", "github.com/alecthomas/gometalinter")
runPrint("go", "get", "-v", "github.com/mitchellh/go-wordwrap")
packages := []string{
"github.com/alecthomas/gometalinter",
"github.com/AlekSi/gocov-xml",
"github.com/axw/gocov/gocov",
"github.com/FiloSottile/gvt",
"github.com/golang/lint/golint",
"github.com/gordonklaus/ineffassign",
"github.com/mitchellh/go-wordwrap",
"github.com/opennota/check/cmd/...",
"github.com/tsenart/deadcode",
"golang.org/x/net/html",
"golang.org/x/tools/cmd/cover",
}
for _, pkg := range packages {
fmt.Println(pkg)
runPrint("go", "get", "-u", pkg)
}
}
func test(pkgs ...string) {

View File

@@ -62,6 +62,10 @@ func (i requestID) String() string {
return fmt.Sprintf("%016x", int64(i))
}
type contextKey int
const idKey contextKey = iota
func negCacheFor(lastSeen time.Time) int {
since := time.Since(lastSeen).Seconds()
if since >= maxDeviceAge {
@@ -132,7 +136,7 @@ var topCtx = context.Background()
func (s *querysrv) handler(w http.ResponseWriter, req *http.Request) {
reqID := requestID(rand.Int63())
ctx := context.WithValue(topCtx, "id", reqID)
ctx := context.WithValue(topCtx, idKey, reqID)
if debug {
log.Println(reqID, req.Method, req.URL)
@@ -186,7 +190,7 @@ func (s *querysrv) handler(w http.ResponseWriter, req *http.Request) {
}
func (s *querysrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http.Request) {
reqID := ctx.Value("id").(requestID)
reqID := ctx.Value(idKey).(requestID)
deviceID, err := protocol.DeviceIDFromString(req.URL.Query().Get("device"))
if err != nil {
@@ -238,7 +242,7 @@ func (s *querysrv) handleGET(ctx context.Context, w http.ResponseWriter, req *ht
}
func (s *querysrv) handlePOST(ctx context.Context, remoteIP net.IP, w http.ResponseWriter, req *http.Request) {
reqID := ctx.Value("id").(requestID)
reqID := ctx.Value(idKey).(requestID)
rawCert := certificateBytes(req)
if rawCert == nil {
@@ -299,7 +303,7 @@ func (s *querysrv) Stop() {
}
func (s *querysrv) handleAnnounce(ctx context.Context, remote net.IP, deviceID protocol.DeviceID, addresses []string) (userErr, internalErr error) {
reqID := ctx.Value("id").(requestID)
reqID := ctx.Value(idKey).(requestID)
tx, err := s.db.Begin()
if err != nil {
@@ -383,7 +387,7 @@ func (s *querysrv) limit(remote net.IP) bool {
}
func (s *querysrv) updateDevice(ctx context.Context, tx *sql.Tx, device protocol.DeviceID) error {
reqID := ctx.Value("id").(requestID)
reqID := ctx.Value(idKey).(requestID)
t0 := time.Now()
res, err := tx.Stmt(s.prep["updateDevice"]).Exec(device.String())
if err != nil {

View File

@@ -116,7 +116,7 @@ func saveCsrfTokens() {
// nothing relevant we can do about them anyway...
name := locations[locCsrfTokens]
f, err := osutil.CreateAtomic(name, 0600)
f, err := osutil.CreateAtomic(name)
if err != nil {
return
}

View File

@@ -507,6 +507,9 @@ func TestCSRFRequired(t *testing.T) {
cfg := new(mockedConfig)
cfg.gui.APIKey = testAPIKey
baseURL, err := startHTTP(cfg)
if err != nil {
t.Fatal("Unexpected error from getting base URL:", err)
}
cli := &http.Client{
Timeout: time.Second,

View File

@@ -278,6 +278,11 @@ func parseCommandLineOptions() RuntimeOptions {
flag.Usage = usageFor(flag.CommandLine, usage, longUsage)
flag.Parse()
if len(flag.Args()) > 0 {
flag.Usage()
os.Exit(2)
}
return options
}

View File

@@ -249,6 +249,10 @@ ul.three-columns li, ul.two-columns li {
text-indent: -0.5em;
}
.navbar-fixed-bottom {
z-index: 980;
}
/** Footer nav on small devices **/
@media (max-width: 1199px) {
/* Stay at the end of the page, with space reserved for the footer

View File

@@ -86,7 +86,7 @@
"Ignore Patterns": "Πρότυπο για αγνόηση",
"Ignore Permissions": "Αγνόησε τα δικαιώματα",
"Incoming Rate Limit (KiB/s)": "Περιορισμός ταχύτητας λήψης (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Με μια εσφαλμένη ρύθμιση μπορεί να προκληθεί ζημιά στο περιεχόμενο των φακέλων και το Syncthing ενδέχεται να σταματήσει να λειτουργεί.",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Με μια εσφαλμένη ρύθμιση μπορεί να προκληθεί ζημιά στα περιεχόμενα των φακέλων και το Syncthing ενδέχεται να σταματήσει να λειτουργεί.",
"Introducer": "Βασικός κόμβος",
"Inversion of the given condition (i.e. do not exclude)": "Αντιστροφή της δοσμένης συνθήκης (π.χ. να μην εξαιρείς) ",
"Keep Versions": "Διατήρηση εκδόσεων",

View File

@@ -50,7 +50,7 @@
"Documentation": "Dokumentazio",
"Download Rate": "Deskargatze emari",
"Downloaded": "Telekargatua",
"Downloading": "Deskargatua",
"Downloading": "Deskargatze",
"Edit": "Aldatu",
"Editing": "Aldaketa",
"Enable NAT traversal": "Ahalbidetu NAT",

View File

@@ -50,7 +50,7 @@
"Documentation": "Documentation",
"Download Rate": "Débit de réception",
"Downloaded": "Téléchargé",
"Downloading": "En cours de téléchargement",
"Downloading": "Téléchargement",
"Edit": "Modifier",
"Editing": "Modifications",
"Enable NAT traversal": "Activer transfert d'adresses NAT",

View File

@@ -50,7 +50,7 @@
"Documentation": "Documentation",
"Download Rate": "Vitesse de réception",
"Downloaded": "Téléchargé",
"Downloading": "En cours de téléchargement",
"Downloading": "Téléchargement",
"Edit": "Modifier",
"Editing": "Modifications",
"Enable NAT traversal": "Activer la translation d'adresses (NAT)",

View File

@@ -135,7 +135,7 @@
"Quick guide to supported patterns": "Krótki przewodnik po obsługiwanych wzorcach",
"RAM Utilization": "Użycie pamięci RAM",
"Random": "Losowo",
"Reduced by ignore patterns": "Reduced by ignore patterns",
"Reduced by ignore patterns": "Ograniczono przez wzorce ignorowania",
"Release Notes": "Informacje o wydaniu",
"Remote Devices": "Urządzenia zdalne",
"Remove": "Usuń",
@@ -231,8 +231,8 @@
"Yes": "Tak",
"You must keep at least one version.": "Musisz posiadać przynajmniej jedną wersję",
"days": "dni",
"directories": "directories",
"files": "files",
"directories": "katalogi",
"files": "pliki",
"full documentation": "pełna dokumentacja",
"items": "pozycji",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} chce udostępnić folder \"{{folder}}\"",

View File

@@ -325,7 +325,7 @@ func (w *Wrapper) Device(id protocol.DeviceID) (DeviceConfiguration, bool) {
// Save writes the configuration to disk, and generates a ConfigSaved event.
func (w *Wrapper) Save() error {
fd, err := osutil.CreateAtomic(w.path, 0600)
fd, err := osutil.CreateAtomic(w.path)
if err != nil {
l.Debugln("CreateAtomic:", err)
return err

View File

@@ -128,7 +128,7 @@ func (t readWriteTransaction) updateGlobal(folder, device []byte, file protocol.
Version: file.Version,
}
insertedAt := -1
var insertedAt int
// Find a position in the list to insert this file. The file at the front
// of the list is the newer, the "global".
for i := range fl.Versions {

96
lib/fs/basicfs.go Normal file
View File

@@ -0,0 +1,96 @@
// 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 http://mozilla.org/MPL/2.0/.
package fs
import (
"os"
"time"
)
// The BasicFilesystem implements all aspects by delegating to package os.
type BasicFilesystem struct {
}
func NewBasicFilesystem() *BasicFilesystem {
return new(BasicFilesystem)
}
func (f *BasicFilesystem) Chmod(name string, mode FileMode) error {
return os.Chmod(name, os.FileMode(mode))
}
func (f *BasicFilesystem) Chtimes(name string, atime time.Time, mtime time.Time) error {
return os.Chtimes(name, atime, mtime)
}
func (f *BasicFilesystem) Mkdir(name string, perm FileMode) error {
return os.Mkdir(name, os.FileMode(perm))
}
func (f *BasicFilesystem) Lstat(name string) (FileInfo, error) {
fi, err := os.Lstat(name)
if err != nil {
return nil, err
}
return fsFileInfo{fi}, err
}
func (f *BasicFilesystem) Remove(name string) error {
return os.Remove(name)
}
func (f *BasicFilesystem) Rename(oldpath, newpath string) error {
return os.Rename(oldpath, newpath)
}
func (f *BasicFilesystem) Stat(name string) (FileInfo, error) {
fi, err := os.Stat(name)
if err != nil {
return nil, err
}
return fsFileInfo{fi}, err
}
func (f *BasicFilesystem) DirNames(name string) ([]string, error) {
fd, err := os.OpenFile(name, os.O_RDONLY, 0777)
if err != nil {
return nil, err
}
defer fd.Close()
names, err := fd.Readdirnames(-1)
if err != nil {
return nil, err
}
return names, nil
}
func (f *BasicFilesystem) Open(name string) (File, error) {
return os.Open(name)
}
func (f *BasicFilesystem) Create(name string) (File, error) {
return os.Create(name)
}
// fsFileInfo implements the fs.FileInfo interface on top of an os.FileInfo.
type fsFileInfo struct {
os.FileInfo
}
func (e fsFileInfo) Mode() FileMode {
return FileMode(e.FileInfo.Mode())
}
func (e fsFileInfo) IsRegular() bool {
return e.FileInfo.Mode().IsRegular()
}
func (e fsFileInfo) IsSymlink() bool {
return e.FileInfo.Mode()&os.ModeSymlink == os.ModeSymlink
}

View File

@@ -0,0 +1,43 @@
// 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 http://mozilla.org/MPL/2.0/.
// +build !windows
package fs
import "os"
var symlinksSupported = true
func DisableSymlinks() {
symlinksSupported = false
}
func (BasicFilesystem) SymlinksSupported() bool {
return symlinksSupported
}
func (BasicFilesystem) CreateSymlink(name, target string, _ LinkTargetType) error {
return os.Symlink(target, name)
}
func (BasicFilesystem) ChangeSymlinkType(_ string, _ LinkTargetType) error {
return nil
}
func (BasicFilesystem) ReadSymlink(path string) (string, LinkTargetType, error) {
tt := LinkTargetUnknown
if stat, err := os.Stat(path); err == nil {
if stat.IsDir() {
tt = LinkTargetDirectory
} else {
tt = LinkTargetFile
}
}
path, err := os.Readlink(path)
return path, tt, err
}

View File

@@ -0,0 +1,195 @@
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
// +build windows
package fs
import (
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/osutil"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
win32FsctlGetReparsePoint = 0x900a8
win32FileFlagOpenReparsePoint = 0x00200000
win32SymbolicLinkFlagDirectory = 0x1
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procDeviceIoControl = modkernel32.NewProc("DeviceIoControl")
procCreateSymbolicLink = modkernel32.NewProc("CreateSymbolicLinkW")
symlinksSupported = false
)
func init() {
defer func() {
if err := recover(); err != nil {
// Ensure that the supported flag is disabled when we hit an
// error, even though it should already be. Also, silently swallow
// the error since it's fine for a system not to support symlinks.
symlinksSupported = false
}
}()
// Needs administrator privileges.
// Let's check that everything works.
// This could be done more officially:
// http://stackoverflow.com/questions/2094663/determine-if-windows-process-has-privilege-to-create-symbolic-link
// But I don't want to define 10 more structs just to look this up.
base := os.TempDir()
path := filepath.Join(base, "symlinktest")
defer os.Remove(path)
err := DefaultFilesystem.CreateSymlink(path, base, LinkTargetDirectory)
if err != nil {
return
}
stat, err := osutil.Lstat(path)
if err != nil || stat.Mode()&os.ModeSymlink == 0 {
return
}
target, tt, err := DefaultFilesystem.ReadSymlink(path)
if err != nil || osutil.NativeFilename(target) != base || tt != LinkTargetDirectory {
return
}
symlinksSupported = true
}
func DisableSymlinks() {
symlinksSupported = false
}
func (BasicFilesystem) SymlinksSupported() bool {
return symlinksSupported
}
func (BasicFilesystem) ReadSymlink(path string) (string, LinkTargetType, error) {
ptr, err := syscall.UTF16PtrFromString(path)
if err != nil {
return "", LinkTargetUnknown, err
}
handle, err := syscall.CreateFile(ptr, 0, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS|win32FileFlagOpenReparsePoint, 0)
if err != nil || handle == syscall.InvalidHandle {
return "", LinkTargetUnknown, err
}
defer syscall.Close(handle)
var ret uint16
var data reparseData
r1, _, err := syscall.Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), win32FsctlGetReparsePoint, 0, 0, uintptr(unsafe.Pointer(&data)), unsafe.Sizeof(data), uintptr(unsafe.Pointer(&ret)), 0, 0)
if r1 == 0 {
return "", LinkTargetUnknown, err
}
tt := LinkTargetUnknown
if attr, err := syscall.GetFileAttributes(ptr); err == nil {
if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
tt = LinkTargetDirectory
} else {
tt = LinkTargetFile
}
}
return osutil.NormalizedFilename(data.printName()), tt, nil
}
func (BasicFilesystem) CreateSymlink(path, target string, tt LinkTargetType) error {
srcp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return err
}
trgp, err := syscall.UTF16PtrFromString(osutil.NativeFilename(target))
if err != nil {
return err
}
// Sadly for Windows we need to specify the type of the symlink,
// whether it's a directory symlink or a file symlink.
// If the flags doesn't reveal the target type, try to evaluate it
// ourselves, and worst case default to the symlink pointing to a file.
mode := 0
if tt == LinkTargetUnknown {
path := target
if !filepath.IsAbs(target) {
path = filepath.Join(filepath.Dir(path), target)
}
stat, err := os.Stat(path)
if err == nil && stat.IsDir() {
mode = win32SymbolicLinkFlagDirectory
}
} else if tt == LinkTargetDirectory {
mode = win32SymbolicLinkFlagDirectory
}
r0, _, err := syscall.Syscall(procCreateSymbolicLink.Addr(), 3, uintptr(unsafe.Pointer(srcp)), uintptr(unsafe.Pointer(trgp)), uintptr(mode))
if r0 == 1 {
return nil
}
return err
}
func (fs BasicFilesystem) ChangeSymlinkType(path string, tt LinkTargetType) error {
target, existingTargetType, err := fs.ReadSymlink(path)
if err != nil {
return err
}
// If it's the same type, nothing to do.
if tt == existingTargetType {
return nil
}
// If the actual type is unknown, but the new type is file, nothing to do
if existingTargetType == LinkTargetUnknown && tt != LinkTargetDirectory {
return nil
}
return osutil.InWritableDir(func(path string) error {
// It should be a symlink as well hence no need to change permissions on
// the file.
os.Remove(path)
return fs.CreateSymlink(path, target, tt)
}, path)
}
type reparseData struct {
reparseTag uint32
reparseDataLength uint16
reserved uint16
substitueNameOffset uint16
substitueNameLength uint16
printNameOffset uint16
printNameLength uint16
flags uint32
// substituteName - 264 widechars max = 528 bytes
// printName - 260 widechars max = 520 bytes
// = 1048 bytes total
buffer [1048 / 2]uint16
}
func (r *reparseData) printName() string {
// offset and length are in bytes but we're indexing a []uint16
offset := r.printNameOffset / 2
length := r.printNameLength / 2
return string(utf16.Decode(r.buffer[offset : offset+length]))
}
func (r *reparseData) substituteName() string {
// offset and length are in bytes but we're indexing a []uint16
offset := r.substitueNameOffset / 2
length := r.substitueNameLength / 2
return string(utf16.Decode(r.buffer[offset : offset+length]))
}

81
lib/fs/basicfs_walk.go Normal file
View File

@@ -0,0 +1,81 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This part copied directly from golang.org/src/path/filepath/path.go (Go
// 1.6) and lightly modified to be methods on BasicFilesystem.
// In our Walk() all paths given to a WalkFunc() are relative to the
// filesystem root.
package fs
import "path/filepath"
// WalkFunc is the type of the function called for each file or directory
// visited by Walk. The path argument contains the argument to Walk as a
// prefix; that is, if Walk is called with "dir", which is a directory
// containing the file "a", the walk function will be called with argument
// "dir/a". The info argument is the FileInfo for the named path.
//
// If there was a problem walking to the file or directory named by path, the
// incoming error will describe the problem and the function can decide how
// to handle that error (and Walk will not descend into that directory). If
// an error is returned, processing stops. The sole exception is when the function
// returns the special value SkipDir. If the function returns SkipDir when invoked
// on a directory, Walk skips the directory's contents entirely.
// If the function returns SkipDir when invoked on a non-directory file,
// Walk skips the remaining files in the containing directory.
type WalkFunc func(path string, info FileInfo, err error) error
// walk recursively descends path, calling walkFn.
func (f *BasicFilesystem) walk(path string, info FileInfo, walkFn WalkFunc) error {
err := walkFn(path, info, nil)
if err != nil {
if info.IsDir() && err == SkipDir {
return nil
}
return err
}
if !info.IsDir() {
return nil
}
names, err := f.DirNames(path)
if err != nil {
return walkFn(path, info, err)
}
for _, name := range names {
filename := filepath.Join(path, name)
fileInfo, err := f.Lstat(filename)
if err != nil {
if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir {
return err
}
} else {
err = f.walk(filename, fileInfo, walkFn)
if err != nil {
if !fileInfo.IsDir() || err != SkipDir {
return err
}
}
}
}
return nil
}
// Walk walks the file tree rooted at root, calling walkFn for each file or
// directory in the tree, including root. All errors that arise visiting files
// and directories are filtered by walkFn. The files are walked in lexical
// order, which makes the output deterministic but means that for very
// large directories Walk can be inefficient.
// Walk does not follow symbolic links.
func (f *BasicFilesystem) Walk(root string, walkFn WalkFunc) error {
info, err := f.Lstat(root)
if err != nil {
return walkFn(root, nil, err)
}
return f.walk(root, info, walkFn)
}

77
lib/fs/filesystem.go Normal file
View File

@@ -0,0 +1,77 @@
// 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 http://mozilla.org/MPL/2.0/.
package fs
import (
"errors"
"io"
"time"
)
type LinkTargetType int
const (
LinkTargetFile LinkTargetType = iota
LinkTargetDirectory
LinkTargetUnknown
)
// The Filesystem interface abstracts access to the file system.
type Filesystem interface {
ChangeSymlinkType(name string, tt LinkTargetType) error
Chmod(name string, mode FileMode) error
Chtimes(name string, atime time.Time, mtime time.Time) error
Create(name string) (File, error)
CreateSymlink(name, target string, tt LinkTargetType) error
DirNames(name string) ([]string, error)
Lstat(name string) (FileInfo, error)
Mkdir(name string, perm FileMode) error
Open(name string) (File, error)
ReadSymlink(name string) (string, LinkTargetType, error)
Remove(name string) error
Rename(oldname, newname string) error
Stat(name string) (FileInfo, error)
SymlinksSupported() bool
Walk(root string, walkFn WalkFunc) error
}
// The File interface abstracts access to a regular file, being a somewhat
// smaller interface than os.File
type File interface {
io.Reader
io.WriterAt
io.Closer
Truncate(size int64) error
}
// The FileInfo interface is almost the same as os.FileInfo, but with the
// Sys method removed (as we don't want to expose whatever is underlying)
// and with a couple of convenience methods added.
type FileInfo interface {
// Standard things present in os.FileInfo
Name() string
Mode() FileMode
Size() int64
ModTime() time.Time
IsDir() bool
// Extensions
IsRegular() bool
IsSymlink() bool
}
// FileMode is similar to os.FileMode
type FileMode uint32
// DefaultFilesystem is the fallback to use when nothing explicitly has
// been passed.
var DefaultFilesystem Filesystem = new(BasicFilesystem)
// SkipDir is used as a return value from WalkFuncs to indicate that
// the directory named in the call is to be skipped. It is not returned
// as an error by any function.
var errSkipDir = errors.New("skip this directory")
var SkipDir = errSkipDir // silences the lint warning...

View File

@@ -69,6 +69,7 @@ type Matcher struct {
matches *cache
curHash string
stop chan struct{}
modtimes map[string]time.Time
mut sync.Mutex
}
@@ -85,25 +86,41 @@ func New(withCache bool) *Matcher {
}
func (m *Matcher) Load(file string) error {
// No locking, Parse() does the locking
m.mut.Lock()
defer m.mut.Unlock()
if m.patternsUnchanged(file) {
return nil
}
fd, err := os.Open(file)
if err != nil {
// We do a parse with empty patterns to clear out the hash, cache etc.
m.Parse(&bytes.Buffer{}, file)
m.parseLocked(&bytes.Buffer{}, file)
return err
}
defer fd.Close()
return m.Parse(fd, file)
info, err := fd.Stat()
if err != nil {
m.parseLocked(&bytes.Buffer{}, file)
return err
}
m.modtimes = map[string]time.Time{
file: info.ModTime(),
}
return m.parseLocked(fd, file)
}
func (m *Matcher) Parse(r io.Reader, file string) error {
m.mut.Lock()
defer m.mut.Unlock()
return m.parseLocked(r, file)
}
seen := map[string]bool{file: true}
patterns, err := parseIgnoreFile(r, file, seen)
func (m *Matcher) parseLocked(r io.Reader, file string) error {
patterns, err := parseIgnoreFile(r, file, m.modtimes)
// Error is saved and returned at the end. We process the patterns
// (possibly blank) anyway.
@@ -122,6 +139,26 @@ func (m *Matcher) Parse(r io.Reader, file string) error {
return err
}
// patternsUnchanged returns true if none of the files making up the loaded
// patterns have changed since last check.
func (m *Matcher) patternsUnchanged(file string) bool {
if _, ok := m.modtimes[file]; !ok {
return false
}
for filename, modtime := range m.modtimes {
info, err := os.Stat(filename)
if err != nil {
return false
}
if !info.ModTime().Equal(modtime) {
return false
}
}
return true
}
func (m *Matcher) Match(file string) (result Result) {
if m == nil {
return resultNotMatched
@@ -221,11 +258,10 @@ func hashPatterns(patterns []Pattern) string {
return fmt.Sprintf("%x", h.Sum(nil))
}
func loadIgnoreFile(file string, seen map[string]bool) ([]Pattern, error) {
if seen[file] {
func loadIgnoreFile(file string, modtimes map[string]time.Time) ([]Pattern, error) {
if _, ok := modtimes[file]; ok {
return nil, fmt.Errorf("Multiple include of ignore file %q", file)
}
seen[file] = true
fd, err := os.Open(file)
if err != nil {
@@ -233,10 +269,16 @@ func loadIgnoreFile(file string, seen map[string]bool) ([]Pattern, error) {
}
defer fd.Close()
return parseIgnoreFile(fd, file, seen)
info, err := fd.Stat()
if err != nil {
return nil, err
}
modtimes[file] = info.ModTime()
return parseIgnoreFile(fd, file, modtimes)
}
func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]Pattern, error) {
func parseIgnoreFile(fd io.Reader, currentFile string, modtimes map[string]time.Time) ([]Pattern, error) {
var patterns []Pattern
defaultResult := resultInclude
@@ -302,7 +344,7 @@ func parseIgnoreFile(fd io.Reader, currentFile string, seen map[string]bool) ([]
} else if strings.HasPrefix(line, "#include ") {
includeRel := line[len("#include "):]
includeFile := filepath.Join(filepath.Dir(currentFile), includeRel)
includes, err := loadIgnoreFile(includeFile, seen)
includes, err := loadIgnoreFile(includeFile, modtimes)
if err != nil {
return fmt.Errorf("include of %q: %v", includeRel, err)
}

View File

@@ -14,6 +14,7 @@ import (
"path/filepath"
"runtime"
"testing"
"time"
)
func TestIgnore(t *testing.T) {
@@ -276,9 +277,13 @@ func TestCaching(t *testing.T) {
t.Fatal("Expected 4 cached results")
}
// Modify the include file, expect empty cache
// Modify the include file, expect empty cache. Ensure the timestamp on
// the file changes.
fd2.WriteString("/z/\n")
fd2.Sync()
fakeTime := time.Now().Add(5 * time.Second)
os.Chtimes(fd2.Name(), fakeTime, fakeTime)
err = pats.Load(fd1.Name())
if err != nil {
@@ -308,6 +313,9 @@ func TestCaching(t *testing.T) {
// Modify the root file, expect cache to be invalidated
fd1.WriteString("/a/\n")
fd1.Sync()
fakeTime = time.Now().Add(5 * time.Second)
os.Chtimes(fd1.Name(), fakeTime, fakeTime)
err = pats.Load(fd1.Name())
if err != nil {
@@ -484,6 +492,9 @@ func TestCacheReload(t *testing.T) {
if err != nil {
t.Fatal(err)
}
fd.Sync()
fakeTime := time.Now().Add(5 * time.Second)
os.Chtimes(fd.Name(), fakeTime, fakeTime)
err = pats.Load(fd.Name())
if err != nil {

View File

@@ -1248,7 +1248,7 @@ func (m *Model) SetIgnores(folder string, content []string) error {
path := filepath.Join(cfg.Path(), ".stignore")
fd, err := osutil.CreateAtomic(path, 0644)
fd, err := osutil.CreateAtomic(path)
if err != nil {
l.Warnln("Saving .stignore:", err)
return err

View File

@@ -921,7 +921,7 @@ func TestIgnores(t *testing.T) {
t.Errorf("Incorrect ignores: %v != %v", ignores, expected)
}
ignores, _, err = m.GetIgnores("doesnotexist")
_, _, err = m.GetIgnores("doesnotexist")
if err == nil {
t.Error("No error")
}
@@ -1773,6 +1773,8 @@ func TestScanNoDatabaseWrite(t *testing.T) {
}
defer m.SetIgnores("default", curIgn)
m.SetIgnores("default", nil)
fakeTime := time.Now().Add(5 * time.Second)
os.Chtimes("testdata/.stignore", fakeTime, fakeTime)
// Scan the folder twice. The second scan should be a no-op database wise
@@ -1789,6 +1791,8 @@ func TestScanNoDatabaseWrite(t *testing.T) {
// Ignore a file we know exists. It'll be updated in the database.
m.SetIgnores("default", []string{"foo"})
fakeTime = time.Now().Add(10 * time.Second)
os.Chtimes("testdata/.stignore", fakeTime, fakeTime)
m.ScanFolder("default")
c2 := db.Committed()

View File

@@ -22,11 +22,11 @@ type roFolder struct {
folder
}
func newROFolder(model *Model, config config.FolderConfiguration, _ versioner.Versioner, _ *fs.MtimeFS) service {
func newROFolder(model *Model, cfg config.FolderConfiguration, _ versioner.Versioner, _ *fs.MtimeFS) service {
return &roFolder{
folder: folder{
stateTracker: newStateTracker(config.ID),
scan: newFolderScanner(config),
stateTracker: newStateTracker(cfg.ID),
scan: newFolderScanner(cfg),
stop: make(chan struct{}),
model: model,
},

View File

@@ -143,7 +143,7 @@ func newRWFolder(model *Model, cfg config.FolderConfiguration, ver versioner.Ver
return f
}
func (f *rwFolder) configureCopiersAndPullers(config config.FolderConfiguration) {
func (f *rwFolder) configureCopiersAndPullers(cfg config.FolderConfiguration) {
if f.copiers == 0 {
f.copiers = defaultCopiers
}
@@ -151,16 +151,16 @@ func (f *rwFolder) configureCopiersAndPullers(config config.FolderConfiguration)
f.pullers = defaultPullers
}
if config.PullerPauseS == 0 {
if cfg.PullerPauseS == 0 {
f.pause = defaultPullerPause
} else {
f.pause = time.Duration(config.PullerPauseS) * time.Second
f.pause = time.Duration(cfg.PullerPauseS) * time.Second
}
if config.PullerSleepS == 0 {
if cfg.PullerSleepS == 0 {
f.sleep = defaultPullerSleep
} else {
f.sleep = time.Duration(config.PullerSleepS) * time.Second
f.sleep = time.Duration(cfg.PullerSleepS) * time.Second
}
}

View File

@@ -29,23 +29,19 @@ type AtomicWriter struct {
err error
}
// CreateAtomic is like os.Create with a FileMode, except a temporary file
// name is used instead of the given name.
func CreateAtomic(path string, mode os.FileMode) (*AtomicWriter, error) {
// CreateAtomic is like os.Create, except a temporary file name is used
// instead of the given name. The file is created with secure (0600)
// permissions.
func CreateAtomic(path string) (*AtomicWriter, error) {
// The security of this depends on the tempfile having secure
// permissions, 0600, from the beginning. This is what ioutil.TempFile
// does. We have a test that verifies that that is the case, should this
// ever change in the standard library in the future.
fd, err := ioutil.TempFile(filepath.Dir(path), TempPrefix)
if err != nil {
return nil, err
}
// chmod fails on Android so don't even try
if runtime.GOOS != "android" {
if err := os.Chmod(fd.Name(), mode); err != nil {
fd.Close()
os.Remove(fd.Name())
return nil, err
}
}
w := &AtomicWriter{
path: path,
next: fd,

View File

@@ -21,7 +21,7 @@ func TestCreateAtomicCreate(t *testing.T) {
t.Fatal(err)
}
w, err := CreateAtomic("testdata/file", 0644)
w, err := CreateAtomic("testdata/file")
if err != nil {
t.Fatal(err)
}
@@ -63,7 +63,7 @@ func TestCreateAtomicReplace(t *testing.T) {
t.Fatal(err)
}
w, err := CreateAtomic("testdata/file", 0644)
w, err := CreateAtomic("testdata/file")
if err != nil {
t.Fatal(err)
}

View File

@@ -0,0 +1,44 @@
// 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 http://mozilla.org/MPL/2.0/.
//+build !windows
// (No syscall.Umask or the equivalent on Windows)
package osutil
import (
"io/ioutil"
"os"
"syscall"
"testing"
)
func TestTempFilePermissions(t *testing.T) {
// Set a zero umask, so any files created will have the permission bits
// asked for in the create call and nothing less.
oldMask := syscall.Umask(0)
defer syscall.Umask(oldMask)
fd, err := ioutil.TempFile("", "test")
if err != nil {
t.Fatal(err)
}
info, err := fd.Stat()
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
defer fd.Close()
// The temp file should have 0600 permissions at the most, or we have a
// security problem in CreateAtomic.
t.Logf("Got 0%03o", info.Mode())
if info.Mode()&^0600 != 0 {
t.Errorf("Permission 0%03o is too generous", info.Mode())
}
}

View File

@@ -20,7 +20,7 @@ import (
"github.com/syncthing/syncthing/lib/sync"
)
var ErrNoHome = errors.New("No home directory found - set $HOME (or the platform equivalent).")
var errNoHome = errors.New("no home directory found - set $HOME (or the platform equivalent)")
// Try to keep this entire operation atomic-like. We shouldn't be doing this
// often enough that there is any contention on this lock.
@@ -123,7 +123,7 @@ func getHomeDir() (string, error) {
}
if home == "" {
return "", ErrNoHome
return "", errNoHome
}
return home, nil

View File

@@ -85,7 +85,6 @@ func (h holder) String() string {
type loggedMutex struct {
sync.Mutex
start time.Time
holder atomic.Value
}

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "STDISCOSRV" "1" "November 21, 2016" "v0.14" "Syncthing"
.TH "STDISCOSRV" "1" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
stdiscosrv \- Syncthing Discovery Server
.
@@ -46,7 +46,7 @@ stdiscosrv [\-cert=<file>] [\-db\-backend=<string>] [\-db\-dsn=<string>] [\-debu
.SH DESCRIPTION
.sp
Syncthing relies on a discovery server to find peers on the internet. Anyone
can run a discovery server and point its syncthing installations to it.
can run a discovery server and point Syncthing installations to it.
.SH OPTIONS
.INDENT 0.0
.TP
@@ -137,9 +137,9 @@ to select a different location.
\fBNOTE:\fP
.INDENT 0.0
.INDENT 3.5
If you are running an instance of syncthing on the discovery server,
you must either add that instance to other nodes using a static
address or bind the discovery server and syncthing instances to
If you are running an instance of Syncthing on the discovery server,
you must either add that instance to other devices using a static
address or bind the discovery server and Syncthing instances to
different IP addresses.
.UNINDENT
.UNINDENT

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "STRELAYSRV" "1" "November 21, 2016" "v0.14" "Syncthing"
.TH "STRELAYSRV" "1" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
strelaysrv \- Syncthing Relay Server
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-BEP" "7" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-BEP" "7" "November 25, 2016" "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" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-CONFIG" "5" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing-config \- Syncthing Configuration
.
@@ -233,7 +233,7 @@ If the original introducer unshares this folder with this device, our device wil
and unshare the folder (subject to skipIntroductionRemovals being false on the introducer device).
All mentioned devices are those that will be sharing the folder in question.
Each mentioned device must have a separate \fBdevice\fP element later in the file.
It is customary that the local device ID is included in all repositories.
It is customary that the local device ID is included in all folders.
Syncthing will currently add this automatically if it is not present in
the configuration file.
.TP

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-DEVICE-IDS" "7" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-DEVICE-IDS" "7" "November 25, 2016" "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" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-EVENT-API" "7" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing-event-api \- Event API
.
@@ -572,7 +572,7 @@ New in version 0.11.10: The \fBmetadata\fP action.
.sp
Generated upon scan whenever the local disk has discovered an updated file from the
previous scan. This does NOT include events that are discovered and copied from
other nodes, only files that were changed on the local filesystem.
other devices, only files that were changed on the local filesystem.
.INDENT 0.0
.INDENT 3.5
.sp

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-FAQ" "7" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-FAQ" "7" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing-faq \- Frequently Asked Questions
.
@@ -45,12 +45,12 @@ It\(aqs \fBSyncthing\fP, although the command and source repository is spelled
\fBsyncthing\fP so it may be referred to in that way as well. It\(aqs definitely not
SyncThing, even though the abbreviation \fBst\fP is used in some
circumstances and file names.
.SS How does Syncthing differ from BitTorrent Sync?
.SS How does Syncthing differ from BitTorrent/Resilio Sync?
.sp
The two are different and not related. Syncthing and BitTorrent Sync accomplish
The two are different and not related. Syncthing and BitTorrent/Resilio Sync accomplish
some of the same things, namely syncing files between two or more computers.
.sp
BitTorrent Sync by BitTorrent, Inc is a proprietary peer\-to\-peer file
BitTorrent Sync, now called Resilio Sync, is a proprietary peer\-to\-peer file
synchronization tool available for Windows, Mac, Linux, Android, iOS, Windows
Phone, Amazon Kindle Fire and BSD. [1] Syncthing is an open source file
synchronization tool.
@@ -103,8 +103,8 @@ Sparse file sparseness (will become sparse, when supported by the OS & filesyste
.sp
Syncthing segments files into pieces, called blocks, to transfer data from one
device to another. Therefore, multiple devices can share the synchronization
load, in a similar way as the torrent protocol. The more devices you have online
(and synchronized), the faster an additional device will receive the data
load, in a similar way to the torrent protocol. The more devices you have online,
the faster an additional device will receive the data
because small blocks will be fetched from all devices in parallel.
.sp
Syncthing handles renaming files and updating their metadata in an efficient
@@ -176,11 +176,11 @@ Android. For other setups, consider using \fI\%syncthing\-inotify\fP <\fBhttps:/
.SS Should I keep my device IDs secret?
.sp
No. The IDs are not sensitive. Given a device ID it\(aqs possible to find the IP
address for that node, if global discovery is enabled on it. Knowing the device
ID doesn\(aqt help you actually establish a connection to that node or get a list
address for that device, if global discovery is enabled on it. Knowing the device
ID doesn\(aqt help you actually establish a connection to that device or get a list
of files, etc.
.sp
For a connection to be established, both nodes need to know about the other\(aqs
For a connection to be established, both devices need to know about the other\(aqs
device ID. It\(aqs not possible (in practice) to forge a device ID. (To forge a
device ID you need to create a TLS certificate with that specific SHA\-256 hash.
If you can do that, you can spoof any TLS certificate. The world is your
@@ -226,12 +226,12 @@ the new path.
.sp
It\(aqs best to do this when the folder is already in sync between your
devices, as it is otherwise unpredictable which changes will "win" after the
move. Changes made on other devices may be overwritten, or changed made
move. Changes made on other devices may be overwritten, or changes made
locally may be overwritten by those on other devices.
.sp
An alternative way is to shut down Syncthing, move the folder on disk, edit
the path directly in the configuration file and then start Syncthing again.
.SS How to configure multiple users on a single machine?
.SS How do I configure multiple users on a single machine?
.sp
Each user should run their own Syncthing instance. Be aware that you might need
to configure listening ports such that they do not overlap (see config).
@@ -243,7 +243,7 @@ programs to achieve this such as rsync or Unison.
.SS Is Syncthing my ideal backup application?
.sp
No. Syncthing is not a great backup application because all changes to your
files (modifications, deletions, etc) will be propagated to all your
files (modifications, deletions, etc.) will be propagated to all your
devices. You can enable versioning, but we encourage the use of other tools
to keep your data safe from your (or our) mistakes.
.SS Why is there no iOS client?
@@ -264,11 +264,11 @@ the brackets, like so: \fBq\e[abc\e]x\fP\&.
On Windows, escaping special characters is not supported as the \fB\e\fP
character is used as a path separator. On the other hand, special characters
such as \fB[\fP and \fB?\fP are not allowed in file names on Windows.
.SS Why is the setup more complicated than BTSync?
.SS Why is the setup more complicated than BitTorrent/Resilio Sync?
.sp
Security over convenience. In Syncthing you have to setup both sides to
connect two nodes. An attacker can\(aqt do much with a stolen node ID, because
you have to add the node on the other side too. You have better control
connect two devices. An attacker can\(aqt do much with a stolen device ID, because
you have to add the device on the other side too. You have better control
where your files are transferred.
.sp
This is an area that we are working to improve in the long term.
@@ -306,7 +306,7 @@ to
Then the GUI is accessible from everywhere. You should set a password and
enable HTTPS with this configuration. You can do this from inside the GUI.
.sp
If both your computers are Unixy (Linux, Mac, etc) You can also leave the
If both your computers are Unix\-like (Linux, Mac, etc.) you can also leave the
GUI settings at default and use an ssh port forward to access it. For
example,
.INDENT 0.0
@@ -336,7 +336,7 @@ $ ssh \-N \-L 9090:127.0.0.1:8384 user@othercomputer.example.com
.UNINDENT
.UNINDENT
.sp
If only your remote computer is Unixy,
If only your remote computer is Unix\-like,
you can still access it with ssh from Windows.
.sp
Under Windows 10 (64 bit) you can use the same ssh command if you install
@@ -374,7 +374,7 @@ In all cases, username/password authentication and HTTPS should be used.
.SS My Syncthing database is corrupt
.sp
This is almost always a result of bad RAM, storage device or other hardware. When the index database is found to be corrupt Syncthing cannot operate and will note this in the logs and exit. To overcome this delete the \fI\%database folder\fP <\fBhttps://docs.syncthing.net/users/config.html#description\fP> inside Syncthing\(aqs home directory and re\-start Syncthing. It will then need to perform a full re\-hashing of all shared folders. You should check your system in case the underlying cause is indeed faulty hardware which may put the system at risk of further data loss.
.SS I don\(aqt like the GUI / Theme. Can it be changed?
.SS I don\(aqt like the GUI or the theme. Can it be changed?
.sp
You can change the theme in the settings. Syncthing ships with other themes
than the default.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-GLOBALDISCO" "7" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-GLOBALDISCO" "7" "November 25, 2016" "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" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-LOCALDISCO" "7" "November 25, 2016" "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" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-NETWORKING" "7" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing-networking \- Firewall Setup
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-RELAY" "7" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-RELAY" "7" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing-relay \- Relay Protocol v1
.
@@ -604,12 +604,12 @@ did capture all the traffic, and even if the attacker did get their hands on the
device keys, they would still not be able to recover/decrypt any traffic which
was transported via the relay.
.sp
After establishing a relay session, syncthing looks at the SessionInvitation
After establishing a relay session, Syncthing looks at the SessionInvitation
message, and depending which side it has received, wraps the raw socket in
either a TLS client socket or a TLS server socket depending on the ServerSocket
boolean value in the SessionInvitation, and starts the TLS handshake.
.sp
From that point onwards it functions exactly the same way as if syncthing was
From that point onwards it functions exactly the same way as if Syncthing was
establishing a direct connection with the other device over the internet,
performing device ID validation, and full TLS encryption, and provides the same
security properties as it would provide when connecting over the internet.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-REST-API" "7" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-REST-API" "7" "November 25, 2016" "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" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-SECURITY" "7" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing-security \- Security Principles
.
@@ -36,9 +36,9 @@ possible for an attacker to join a cluster uninvited, and it should not be
possible to extract private information from intercepted traffic. Currently this
is implemented as follows.
.sp
All device to device traffic is protected by TLS. To prevent uninvited nodes
from joining a cluster, the certificate fingerprint of each node is compared
to a preset list of acceptable nodes at connection establishment. The
All device to device traffic is protected by TLS. To prevent uninvited devices
from joining a cluster, the certificate fingerprint of each device is compared
to a preset list of acceptable devices at connection establishment. The
fingerprint is computed as the SHA\-256 hash of the certificate and displayed
in BASE32 encoding to form a reasonably compact and convenient string.
.sp

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-STIGNORE" "5" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-STIGNORE" "5" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing-stignore \- Prevent files from being synchronized to other nodes
.
@@ -43,12 +43,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.UNINDENT
.SH DESCRIPTION
.sp
If some files should not be synchronized to other nodes, a file called
If some files should not be synchronized to other devices, a file called
\fB\&.stignore\fP can be created containing file patterns to ignore. The
\fB\&.stignore\fP file must be placed in the root of the repository. The
\fB\&.stignore\fP file itself will never be synced to other nodes, although it can
\fB#include\fP files that \fIare\fP synchronized between nodes. All patterns are
relative to the repository root.
\fB\&.stignore\fP file must be placed in the root of the folder. The
\fB\&.stignore\fP file itself will never be synced to other devices, although it can
\fB#include\fP files that \fIare\fP synchronized between devices. All patterns are
relative to the folder root.
.sp
\fBNOTE:\fP
.INDENT 0.0
@@ -88,7 +88,7 @@ A pattern beginning with \fB#include\fP results in loading patterns
from the named file. It is an error for a file to not exist or be
included more than once. Note that while this can be used to include
patterns from a file in a subdirectory, the patterns themselves are
still relative to the repository \fIroot\fP\&. Example:
still relative to the folder \fIroot\fP\&. Example:
\fB#include more\-patterns.txt\fP\&.
.IP \(bu 2
A pattern beginning with a \fB!\fP prefix negates the pattern: matching files
@@ -201,7 +201,7 @@ Currently the effects on who is in sync with what can be a bit confusing
when using ignore patterns. This should be cleared up in a future
version...
.sp
Assume two nodes, Alice and Bob, where Alice has 100 files to share, but
Assume two devices, Alice and Bob, where Alice has 100 files to share, but
Bob ignores 25 of these. From Alice\(aqs point of view Bob will become
about 75% in sync (the actual number depends on the sizes of the
individual files) and remain in "Syncing" state even though it is in
@@ -211,7 +211,7 @@ view.
.sp
If Bob adds files that have already been synced to the ignore list, they
will remain in the "global" view but disappear from the "local" view.
The end result is more files in the global repository than in the local,
The end result is more files in the global folder than in the local,
but still 100% in sync (\fI\%issue #624\fP <\fBhttps://github.com/syncthing/syncthing/issues/624\fP>). From Alice\(aqs point of view, Bob
will remain 100% in sync until the next reconnect, because Bob has
already announced that he has the files that are now suddenly ignored.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-VERSIONING" "7" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING-VERSIONING" "7" "November 25, 2016" "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" "November 21, 2016" "v0.14" "Syncthing"
.TH "SYNCTHING" "1" "November 25, 2016" "v0.14" "Syncthing"
.SH NAME
syncthing \- Syncthing
.