From c4ba580cbb64521e6ca66b4f6bbbb3b3b14a39d7 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 7 Feb 2017 08:34:24 +0000 Subject: [PATCH] all: Remove symlink support on Windows, SymlinksEnabled config After this change, - Symlinks on Windows are always unsupported. Sorry. - Symlinks are always enabled on other platforms. They are just a small file like anything else. There is no need to special case them. If you don't want to sync some symlinks, ignore them. - The protocol doesn't differentiate between different "types" of symlinks. If that distinction ever does become relevant the individual devices can figure it out by looking at the destination when they create the link. It's backwards compatible in that all the old symlink types are still understood to be symlinks, and the new SYMLINK type is equivalent to the old SYMLINK_UNKNOWN which was always a valid way to do it. GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3962 LGTM: AudriusButkevicius --- cmd/stcompdirs/main.go | 4 +- cmd/syncthing/main.go | 9 +- lib/config/config.go | 10 +- lib/config/config_test.go | 2 - lib/config/optionsconfiguration.go | 1 - lib/config/testdata/v19.xml | 15 ++ lib/db/leveldb_dbinstance.go | 35 +++++ lib/db/structs.go | 2 +- lib/fs/basicfs_symlink_unix.go | 20 +-- lib/fs/basicfs_symlink_windows.go | 184 +--------------------- lib/fs/filesystem.go | 13 +- lib/model/model.go | 29 +--- lib/model/progressemitter_test.go | 2 +- lib/model/requests_test.go | 8 +- lib/model/rwfolder.go | 11 +- lib/osutil/traversessymlink_test.go | 10 +- lib/protocol/bep.pb.go | 234 ++++++++++++++-------------- lib/protocol/bep.proto | 6 +- lib/protocol/bep_extensions.go | 4 +- lib/scanner/walk.go | 46 +----- lib/scanner/walk_test.go | 33 +--- lib/symlinks/empty_test.go | 10 -- lib/symlinks/symlink_unix.go | 37 ----- lib/symlinks/symlink_windows.go | 168 -------------------- lib/symlinks/targets.go | 15 -- test/ignore_test.go | 4 +- test/symlink_test.go | 19 ++- test/util.go | 3 +- 28 files changed, 227 insertions(+), 707 deletions(-) create mode 100644 lib/config/testdata/v19.xml delete mode 100644 lib/symlinks/empty_test.go delete mode 100644 lib/symlinks/symlink_unix.go delete mode 100644 lib/symlinks/symlink_windows.go delete mode 100644 lib/symlinks/targets.go diff --git a/cmd/stcompdirs/main.go b/cmd/stcompdirs/main.go index 74ae6c2d..00d9914d 100644 --- a/cmd/stcompdirs/main.go +++ b/cmd/stcompdirs/main.go @@ -15,8 +15,6 @@ import ( "log" "os" "path/filepath" - - "github.com/syncthing/syncthing/lib/symlinks" ) func main() { @@ -104,7 +102,7 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er mode: os.ModeSymlink, } - tgt, _, err := symlinks.Read(path) + tgt, err := os.Readlink(path) if err != nil { return err } diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 4b225946..78ebdaac 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -43,7 +43,6 @@ import ( "github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/rand" "github.com/syncthing/syncthing/lib/sha256" - "github.com/syncthing/syncthing/lib/symlinks" "github.com/syncthing/syncthing/lib/tlsutil" "github.com/syncthing/syncthing/lib/upgrade" "github.com/syncthing/syncthing/lib/weakhash" @@ -679,10 +678,6 @@ func syncthingMain(runtimeOptions RuntimeOptions) { opts := cfg.Options() - if !opts.SymlinksEnabled { - symlinks.Supported = false - } - if opts.WeakHashSelectionMethod == config.WeakHashAuto { if perfWithoutWeakHash*0.8 > perfWithWeakHash { l.Infof("Weak hash disabled, as it has an unacceptable performance impact.") @@ -751,6 +746,10 @@ func syncthingMain(runtimeOptions RuntimeOptions) { // have been incorrectly ignore filtered. ldb.DropDeltaIndexIDs() } + if cfg.RawCopy().OriginalVersion < 19 { + // Converts old symlink types to new in the entire database. + ldb.ConvertSymlinkTypes() + } m := model.NewModel(cfg, myID, myDeviceName(cfg), "syncthing", Version, ldb, protectedFiles) diff --git a/lib/config/config.go b/lib/config/config.go index fc56db76..f575587d 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -27,7 +27,7 @@ import ( const ( OldestHandledVersion = 10 - CurrentVersion = 18 + CurrentVersion = 19 MaxRescanIntervalS = 365 * 24 * 60 * 60 ) @@ -261,6 +261,9 @@ func (cfg *Configuration) clean() error { if cfg.Version == 17 { convertV17V18(cfg) } + if cfg.Version == 18 { + convertV18V19(cfg) + } // Build a list of available devices existingDevices := make(map[protocol.DeviceID]bool) @@ -314,6 +317,11 @@ func (cfg *Configuration) clean() error { return nil } +func convertV18V19(cfg *Configuration) { + // Triggers a database tweak + cfg.Version = 19 +} + func convertV17V18(cfg *Configuration) { // Do channel selection for existing users. Those who have auto upgrades // and usage reporting on default to the candidate channel. Others get diff --git a/lib/config/config_test.go b/lib/config/config_test.go index e7a60ded..a104a06b 100644 --- a/lib/config/config_test.go +++ b/lib/config/config_test.go @@ -54,7 +54,6 @@ func TestDefaultValues(t *testing.T) { KeepTemporariesH: 24, CacheIgnoredFiles: false, ProgressUpdateIntervalS: 5, - SymlinksEnabled: true, LimitBandwidthInLan: false, MinHomeDiskFreePct: 1, URURL: "https://data.syncthing.net/newdata", @@ -191,7 +190,6 @@ func TestOverriddenValues(t *testing.T) { KeepTemporariesH: 48, CacheIgnoredFiles: true, ProgressUpdateIntervalS: 10, - SymlinksEnabled: false, LimitBandwidthInLan: true, MinHomeDiskFreePct: 5.2, URURL: "https://localhost/newdata", diff --git a/lib/config/optionsconfiguration.go b/lib/config/optionsconfiguration.go index 2663570a..51da0cfa 100644 --- a/lib/config/optionsconfiguration.go +++ b/lib/config/optionsconfiguration.go @@ -122,7 +122,6 @@ type OptionsConfiguration struct { KeepTemporariesH int `xml:"keepTemporariesH" json:"keepTemporariesH" default:"24"` // 0 for off CacheIgnoredFiles bool `xml:"cacheIgnoredFiles" json:"cacheIgnoredFiles" default:"false"` ProgressUpdateIntervalS int `xml:"progressUpdateIntervalS" json:"progressUpdateIntervalS" default:"5"` - SymlinksEnabled bool `xml:"symlinksEnabled" json:"symlinksEnabled" default:"true"` LimitBandwidthInLan bool `xml:"limitBandwidthInLan" json:"limitBandwidthInLan" default:"false"` MinHomeDiskFreePct float64 `xml:"minHomeDiskFreePct" json:"minHomeDiskFreePct" default:"1"` ReleasesURL string `xml:"releasesURL" json:"releasesURL" default:"https://upgrades.syncthing.net/meta.json"` diff --git a/lib/config/testdata/v19.xml b/lib/config/testdata/v19.xml new file mode 100644 index 00000000..29d17601 --- /dev/null +++ b/lib/config/testdata/v19.xml @@ -0,0 +1,15 @@ + + + + + 1 + -1 + true + + +
tcp://a
+
+ +
tcp://b
+
+
diff --git a/lib/db/leveldb_dbinstance.go b/lib/db/leveldb_dbinstance.go index ffc3d5d3..84e92f0c 100644 --- a/lib/db/leveldb_dbinstance.go +++ b/lib/db/leveldb_dbinstance.go @@ -618,6 +618,41 @@ func (db *Instance) checkGlobals(folder []byte, globalSize *sizeTracker) { l.Debugf("db check completed for %q", folder) } +// ConvertSymlinkTypes should be run once only on an old database. It +// changes SYMLINK_FILE and SYMLINK_DIRECTORY types to the current SYMLINK +// type (previously SYMLINK_UNKNOWN). It does this for all devices, both +// local and remote, and does not reset delta indexes. It shouldn't really +// matter what the symlink type is, but this cleans it up for a possible +// future when SYMLINK_FILE and SYMLINK_DIRECTORY are no longer understood. +func (db *Instance) ConvertSymlinkTypes() { + t := db.newReadWriteTransaction() + defer t.close() + + dbi := t.NewIterator(util.BytesPrefix([]byte{KeyTypeDevice}), nil) + defer dbi.Release() + + conv := 0 + for dbi.Next() { + var f protocol.FileInfo + if err := f.Unmarshal(dbi.Value()); err != nil { + // probably can't happen + continue + } + if f.Type == protocol.FileInfoTypeDeprecatedSymlinkDirectory || f.Type == protocol.FileInfoTypeDeprecatedSymlinkFile { + f.Type = protocol.FileInfoTypeSymlink + bs, err := f.Marshal() + if err != nil { + panic("can't happen: " + err.Error()) + } + t.Put(dbi.Key(), bs) + t.checkFlush() + conv++ + } + } + + l.Infof("Updated symlink type for %d index entries", conv) +} + // deviceKey returns a byte slice encoding the following information: // keyTypeDevice (1 byte) // folder (4 bytes) diff --git a/lib/db/structs.go b/lib/db/structs.go index 7d8c5468..6ecc7afd 100644 --- a/lib/db/structs.go +++ b/lib/db/structs.go @@ -35,7 +35,7 @@ func (f FileInfoTruncated) IsDirectory() bool { func (f FileInfoTruncated) IsSymlink() bool { switch f.Type { - case protocol.FileInfoTypeSymlinkDirectory, protocol.FileInfoTypeSymlinkFile, protocol.FileInfoTypeSymlinkUnknown: + case protocol.FileInfoTypeSymlink, protocol.FileInfoTypeDeprecatedSymlinkDirectory, protocol.FileInfoTypeDeprecatedSymlinkFile: return true default: return false diff --git a/lib/fs/basicfs_symlink_unix.go b/lib/fs/basicfs_symlink_unix.go index ee21c7ce..44ecf6bb 100644 --- a/lib/fs/basicfs_symlink_unix.go +++ b/lib/fs/basicfs_symlink_unix.go @@ -20,24 +20,10 @@ func (BasicFilesystem) SymlinksSupported() bool { return symlinksSupported } -func (BasicFilesystem) CreateSymlink(name, target string, _ LinkTargetType) error { +func (BasicFilesystem) CreateSymlink(name, target string) 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 +func (BasicFilesystem) ReadSymlink(path string) (string, error) { + return os.Readlink(path) } diff --git a/lib/fs/basicfs_symlink_windows.go b/lib/fs/basicfs_symlink_windows.go index e4c3a854..a1299048 100644 --- a/lib/fs/basicfs_symlink_windows.go +++ b/lib/fs/basicfs_symlink_windows.go @@ -8,188 +8,20 @@ package fs -import ( - "os" - "path/filepath" +import "errors" - "github.com/syncthing/syncthing/lib/osutil" +var errNotSupported = errors.New("symlinks not supported") - "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 DisableSymlinks() {} func (BasicFilesystem) SymlinksSupported() bool { - return symlinksSupported + return false } -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) ReadSymlink(path string) (string, error) { + return "", errNotSupported } -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])) +func (BasicFilesystem) CreateSymlink(path, target string) error { + return errNotSupported } diff --git a/lib/fs/filesystem.go b/lib/fs/filesystem.go index cd96e880..1c94add4 100644 --- a/lib/fs/filesystem.go +++ b/lib/fs/filesystem.go @@ -12,26 +12,17 @@ import ( "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 + CreateSymlink(name, target string) 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) + ReadSymlink(name string) (string, error) Remove(name string) error Rename(oldname, newname string) error Stat(name string) (FileInfo, error) diff --git a/lib/model/model.go b/lib/model/model.go index 5070e63f..8f0f8e35 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -20,7 +20,6 @@ import ( "runtime" "sort" "strings" - stdsync "sync" "time" "github.com/syncthing/syncthing/lib/config" @@ -33,7 +32,6 @@ import ( "github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/scanner" "github.com/syncthing/syncthing/lib/stats" - "github.com/syncthing/syncthing/lib/symlinks" "github.com/syncthing/syncthing/lib/sync" "github.com/syncthing/syncthing/lib/upgrade" "github.com/syncthing/syncthing/lib/versioner" @@ -105,7 +103,6 @@ type Model struct { type folderFactory func(*Model, config.FolderConfiguration, versioner.Versioner, *fs.MtimeFS) service var ( - symlinkWarning = stdsync.Once{} folderFactories = make(map[config.FolderType]folderFactory, 0) ) @@ -116,7 +113,6 @@ var ( errFolderMarkerMissing = errors.New("folder marker missing") errHomeDiskNoSpace = errors.New("home disk has insufficient free space") errFolderNoSpace = errors.New("folder has insufficient free space") - errUnsupportedSymlink = errors.New("symlink not supported") errInvalidFilename = errors.New("filename is invalid") errDeviceUnknown = errors.New("unknown device") errDevicePaused = errors.New("device is paused") @@ -1879,9 +1875,8 @@ func (m *Model) internalScanFolderSubdirs(folder string, subDirs []string) error } switch { - case !f.IsInvalid() && (ignores.Match(f.Name).IsIgnored() || symlinkInvalid(folder, f)): - // File was valid at last pass but has been ignored or is an - // unsupported symlink. Set invalid bit. + case !f.IsInvalid() && ignores.Match(f.Name).IsIgnored(): + // File was valid at last pass but has been ignored. Set invalid bit. l.Debugln("setting invalid bit on ignored", f) nf := protocol.FileInfo{ Name: f.Name, @@ -2490,26 +2485,6 @@ func mapDeviceConfigs(devices []config.DeviceConfiguration) map[protocol.DeviceI return m } -func symlinkInvalid(folder string, fi db.FileIntf) bool { - if !symlinks.Supported && fi.IsSymlink() && !fi.IsInvalid() && !fi.IsDeleted() { - symlinkWarning.Do(func() { - l.Warnln("Symlinks are disabled, unsupported or require Administrator privileges. This might cause your folder to appear out of sync.") - }) - - // Need to type switch for the concrete type to be able to access fields... - var name string - switch fi := fi.(type) { - case protocol.FileInfo: - name = fi.Name - case db.FileInfoTruncated: - name = fi.Name - } - l.Infoln("Unsupported symlink", name, "in folder", folder) - return true - } - return false -} - // Skips `skip` elements and retrieves up to `get` elements from a given slice. // Returns the resulting slice, plus how much elements are left to skip or // copy to satisfy the values which were provided, given the slice is not diff --git a/lib/model/progressemitter_test.go b/lib/model/progressemitter_test.go index 00ba1d15..2f5d7650 100644 --- a/lib/model/progressemitter_test.go +++ b/lib/model/progressemitter_test.go @@ -359,7 +359,7 @@ func TestSendDownloadProgressMessages(t *testing.T) { file: protocol.FileInfo{ Name: "state6", Version: v1, - Type: protocol.FileInfoTypeSymlinkUnknown, + Type: protocol.FileInfoTypeSymlink, }, mut: sync.NewRWMutex(), available: []int32{1, 2, 3}, diff --git a/lib/model/requests_test.go b/lib/model/requests_test.go index 30b0efc6..b39a67c5 100644 --- a/lib/model/requests_test.go +++ b/lib/model/requests_test.go @@ -89,7 +89,7 @@ func TestSymlinkTraversalRead(t *testing.T) { // Send an update for the symlink, wait for it to sync and be reported back. contents := []byte("..") - fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlinkDirectory, contents) + fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlink, contents) fc.sendIndexUpdate() <-done @@ -142,7 +142,7 @@ func TestSymlinkTraversalWrite(t *testing.T) { // Send an update for the symlink, wait for it to sync and be reported back. contents := []byte("..") - fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlinkDirectory, contents) + fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlink, contents) fc.sendIndexUpdate() <-done @@ -152,7 +152,7 @@ func TestSymlinkTraversalWrite(t *testing.T) { contents = []byte("testdata testdata\n") fc.addFile("symlink/testfile", 0644, protocol.FileInfoTypeFile, contents) fc.addFile("symlink/testdir", 0644, protocol.FileInfoTypeDirectory, contents) - fc.addFile("symlink/testsyml", 0644, protocol.FileInfoTypeSymlinkFile, contents) + fc.addFile("symlink/testsyml", 0644, protocol.FileInfoTypeSymlink, contents) fc.sendIndexUpdate() select { @@ -191,7 +191,7 @@ func TestRequestCreateTmpSymlink(t *testing.T) { fc.mut.Unlock() // Send an update for the test file, wait for it to sync and be reported back. - fc.addFile(".syncthing.testlink.tmp", 0644, protocol.FileInfoTypeSymlinkDirectory, []byte("..")) + fc.addFile(".syncthing.testlink.tmp", 0644, protocol.FileInfoTypeSymlink, []byte("..")) fc.sendIndexUpdate() select { diff --git a/lib/model/rwfolder.go b/lib/model/rwfolder.go index fb8d249d..1eb469f9 100644 --- a/lib/model/rwfolder.go +++ b/lib/model/rwfolder.go @@ -25,7 +25,6 @@ import ( "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/scanner" - "github.com/syncthing/syncthing/lib/symlinks" "github.com/syncthing/syncthing/lib/sync" "github.com/syncthing/syncthing/lib/versioner" "github.com/syncthing/syncthing/lib/weakhash" @@ -741,15 +740,10 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo) { } } - tt := symlinks.TargetFile - if file.IsDirectory() { - tt = symlinks.TargetDirectory - } - // We declare a function that acts on only the path name, so // we can pass it to InWritableDir. createLink := func(path string) error { - return symlinks.Create(path, file.SymlinkTarget, tt) + return os.Symlink(file.SymlinkTarget, path) } if err = osutil.InWritableDir(createLink, realName); err == nil { @@ -1765,9 +1759,6 @@ func fileValid(file db.FileIntf) error { // We don't care about file validity if we're not supposed to have it return nil - case !symlinks.Supported && file.IsSymlink(): - return errUnsupportedSymlink - case runtime.GOOS == "windows" && windowsInvalidFilename(file.FileName()): return errInvalidFilename } diff --git a/lib/osutil/traversessymlink_test.go b/lib/osutil/traversessymlink_test.go index 6a58663c..9c4b7cb4 100644 --- a/lib/osutil/traversessymlink_test.go +++ b/lib/osutil/traversessymlink_test.go @@ -4,6 +4,8 @@ // 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 osutil_test import ( @@ -11,19 +13,13 @@ import ( "testing" "github.com/syncthing/syncthing/lib/osutil" - "github.com/syncthing/syncthing/lib/symlinks" ) func TestTraversesSymlink(t *testing.T) { - if !symlinks.Supported { - t.Skip("pointless test") - return - } - os.RemoveAll("testdata") defer os.RemoveAll("testdata") os.MkdirAll("testdata/a/b/c", 0755) - symlinks.Create("testdata/a/l", "b", symlinks.TargetDirectory) + os.Symlink("b", "testdata/a/l") // a/l -> b, so a/l/c should resolve by normal stat info, err := osutil.Lstat("testdata/a/l/c") diff --git a/lib/protocol/bep.pb.go b/lib/protocol/bep.pb.go index fd973b3a..23c613a7 100644 --- a/lib/protocol/bep.pb.go +++ b/lib/protocol/bep.pb.go @@ -134,11 +134,11 @@ func (Compression) EnumDescriptor() ([]byte, []int) { return fileDescriptorBep, type FileInfoType int32 const ( - FileInfoTypeFile FileInfoType = 0 - FileInfoTypeDirectory FileInfoType = 1 - FileInfoTypeSymlinkFile FileInfoType = 2 - FileInfoTypeSymlinkDirectory FileInfoType = 3 - FileInfoTypeSymlinkUnknown FileInfoType = 4 + FileInfoTypeFile FileInfoType = 0 + FileInfoTypeDirectory FileInfoType = 1 + FileInfoTypeDeprecatedSymlinkFile FileInfoType = 2 + FileInfoTypeDeprecatedSymlinkDirectory FileInfoType = 3 + FileInfoTypeSymlink FileInfoType = 4 ) var FileInfoType_name = map[int32]string{ @@ -146,14 +146,14 @@ var FileInfoType_name = map[int32]string{ 1: "DIRECTORY", 2: "SYMLINK_FILE", 3: "SYMLINK_DIRECTORY", - 4: "SYMLINK_UNKNOWN", + 4: "SYMLINK", } var FileInfoType_value = map[string]int32{ "FILE": 0, "DIRECTORY": 1, "SYMLINK_FILE": 2, "SYMLINK_DIRECTORY": 3, - "SYMLINK_UNKNOWN": 4, + "SYMLINK": 4, } func (x FileInfoType) String() string { @@ -4165,114 +4165,114 @@ var ( func init() { proto.RegisterFile("bep.proto", fileDescriptorBep) } var fileDescriptorBep = []byte{ - // 1732 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x73, 0xdb, 0xc6, - 0x15, 0xe7, 0x07, 0xf8, 0xf5, 0x48, 0xc9, 0xd0, 0xda, 0x56, 0x50, 0x58, 0xa1, 0x10, 0x26, 0x6e, - 0x14, 0x4d, 0xe3, 0xb8, 0x71, 0xda, 0xcc, 0x74, 0xda, 0xce, 0xf0, 0x03, 0x92, 0x39, 0xa1, 0x41, - 0x76, 0x49, 0xd9, 0x75, 0x0e, 0xc5, 0x80, 0xc4, 0x92, 0xc2, 0x08, 0xc4, 0xb2, 0x00, 0x28, 0x9b, - 0xfd, 0x13, 0xf8, 0x17, 0xf4, 0xc2, 0x99, 0xcc, 0xf4, 0xd4, 0x7b, 0xff, 0x08, 0x1f, 0x33, 0x3d, - 0xf4, 0xd0, 0x83, 0xa7, 0x51, 0x2f, 0x3d, 0xf6, 0xd2, 0x53, 0x2f, 0x9d, 0xdd, 0x05, 0x48, 0x50, - 0x92, 0x3b, 0x39, 0xe4, 0x84, 0x7d, 0xef, 0xfd, 0xf6, 0xed, 0xbe, 0x8f, 0xdf, 0x5b, 0x40, 0x69, - 0x48, 0x66, 0x8f, 0x66, 0x3e, 0x0d, 0x29, 0x2a, 0xf2, 0xcf, 0x88, 0xba, 0xea, 0xa7, 0x13, 0x27, - 0x3c, 0x9f, 0x0f, 0x1f, 0x8d, 0xe8, 0xf4, 0xb3, 0x09, 0x9d, 0xd0, 0xcf, 0xb8, 0x65, 0x38, 0x1f, - 0x73, 0x89, 0x0b, 0x7c, 0x25, 0x36, 0xd6, 0x66, 0x90, 0x7b, 0x4a, 0x5c, 0x97, 0xa2, 0x43, 0x28, - 0xdb, 0xe4, 0xd2, 0x19, 0x11, 0xd3, 0xb3, 0xa6, 0x44, 0x49, 0x6b, 0xe9, 0xa3, 0x12, 0x06, 0xa1, - 0x32, 0xac, 0x29, 0x61, 0x80, 0x91, 0xeb, 0x10, 0x2f, 0x14, 0x80, 0x8c, 0x00, 0x08, 0x15, 0x07, - 0x3c, 0x84, 0xdd, 0x08, 0x70, 0x49, 0xfc, 0xc0, 0xa1, 0x9e, 0x92, 0xe5, 0x98, 0x1d, 0xa1, 0x7d, - 0x2e, 0x94, 0xb5, 0x00, 0xf2, 0x4f, 0x89, 0x65, 0x13, 0x1f, 0x7d, 0x02, 0x52, 0xb8, 0x98, 0x89, - 0xb3, 0x76, 0x3f, 0xbf, 0xff, 0x28, 0x8e, 0xe1, 0xd1, 0x33, 0x12, 0x04, 0xd6, 0x84, 0x0c, 0x16, - 0x33, 0x82, 0x39, 0x04, 0xfd, 0x1a, 0xca, 0x23, 0x3a, 0x9d, 0xf9, 0x24, 0xe0, 0x8e, 0x33, 0x7c, - 0xc7, 0xc1, 0x8d, 0x1d, 0xcd, 0x0d, 0x06, 0x27, 0x37, 0xd4, 0xea, 0xb0, 0xd3, 0x74, 0xe7, 0x41, - 0x48, 0xfc, 0x26, 0xf5, 0xc6, 0xce, 0x04, 0x3d, 0x86, 0xc2, 0x98, 0xba, 0x36, 0xf1, 0x03, 0x25, - 0xad, 0x65, 0x8f, 0xca, 0x9f, 0xcb, 0x1b, 0x67, 0x27, 0xdc, 0xd0, 0x90, 0xde, 0xbc, 0x3d, 0x4c, - 0xe1, 0x18, 0x56, 0xfb, 0x53, 0x06, 0xf2, 0xc2, 0x82, 0xf6, 0x21, 0xe3, 0xd8, 0x22, 0x45, 0x8d, - 0xfc, 0xd5, 0xdb, 0xc3, 0x4c, 0xbb, 0x85, 0x33, 0x8e, 0x8d, 0xee, 0x41, 0xce, 0xb5, 0x86, 0xc4, - 0x8d, 0x92, 0x23, 0x04, 0xf4, 0x00, 0x4a, 0x3e, 0xb1, 0x6c, 0x93, 0x7a, 0xee, 0x82, 0xa7, 0xa4, - 0x88, 0x8b, 0x4c, 0xd1, 0xf5, 0xdc, 0x05, 0xfa, 0x14, 0x90, 0x33, 0xf1, 0xa8, 0x4f, 0xcc, 0x19, - 0xf1, 0xa7, 0x0e, 0xbf, 0x6d, 0xa0, 0x48, 0x1c, 0xb5, 0x27, 0x2c, 0xbd, 0x8d, 0x01, 0x7d, 0x08, - 0x3b, 0x11, 0xdc, 0x26, 0x2e, 0x09, 0x89, 0x92, 0xe3, 0xc8, 0x8a, 0x50, 0xb6, 0xb8, 0x0e, 0x3d, - 0x86, 0x7b, 0xb6, 0x13, 0x58, 0x43, 0x97, 0x98, 0x21, 0x99, 0xce, 0x4c, 0xc7, 0xb3, 0xc9, 0x6b, - 0x12, 0x28, 0x79, 0x8e, 0x45, 0x91, 0x6d, 0x40, 0xa6, 0xb3, 0xb6, 0xb0, 0xa0, 0x7d, 0xc8, 0xcf, - 0xac, 0x79, 0x40, 0x6c, 0xa5, 0xc0, 0x31, 0x91, 0xc4, 0xb2, 0x24, 0x3a, 0x20, 0x50, 0xe4, 0xeb, - 0x59, 0x6a, 0x71, 0x43, 0x9c, 0xa5, 0x08, 0x56, 0xfb, 0x77, 0x06, 0xf2, 0xc2, 0x82, 0x7e, 0xbc, - 0xce, 0x52, 0xa5, 0xb1, 0xcf, 0x50, 0x7f, 0x7f, 0x7b, 0x58, 0x14, 0xb6, 0x76, 0x2b, 0x91, 0x35, - 0x04, 0x52, 0xa2, 0xa3, 0xf8, 0x1a, 0x1d, 0x40, 0xc9, 0xb2, 0x6d, 0x56, 0x3d, 0x12, 0x28, 0x59, - 0x2d, 0x7b, 0x54, 0xc2, 0x1b, 0x05, 0xfa, 0x72, 0xbb, 0x1b, 0xa4, 0xeb, 0xfd, 0xf3, 0xae, 0x36, - 0x60, 0xa5, 0x18, 0x11, 0x3f, 0xea, 0xe0, 0x1c, 0x3f, 0xaf, 0xc8, 0x14, 0xbc, 0x7f, 0x3f, 0x80, - 0xca, 0xd4, 0x7a, 0x6d, 0x06, 0xe4, 0xf7, 0x73, 0xe2, 0x8d, 0x08, 0x4f, 0x57, 0x16, 0x97, 0xa7, - 0xd6, 0xeb, 0x7e, 0xa4, 0x42, 0x55, 0x00, 0xc7, 0x0b, 0x7d, 0x6a, 0xcf, 0x47, 0xc4, 0x8f, 0x72, - 0x95, 0xd0, 0xa0, 0x9f, 0x41, 0x91, 0x27, 0xdb, 0x74, 0x6c, 0xa5, 0xa8, 0xa5, 0x8f, 0xa4, 0x86, - 0x1a, 0x05, 0x5e, 0xe0, 0xa9, 0xe6, 0x71, 0xc7, 0x4b, 0x5c, 0xe0, 0xd8, 0xb6, 0x8d, 0x7e, 0x09, - 0x6a, 0x70, 0xe1, 0xb0, 0x42, 0x09, 0x4f, 0xa1, 0x43, 0x3d, 0xd3, 0x27, 0x53, 0x7a, 0x69, 0xb9, - 0x81, 0x52, 0xe2, 0xc7, 0x28, 0x0c, 0xd1, 0x4e, 0x00, 0x70, 0x64, 0xaf, 0x75, 0x21, 0xc7, 0x3d, - 0xb2, 0x2a, 0x8a, 0x66, 0x8d, 0xd8, 0x1b, 0x49, 0xe8, 0x11, 0xe4, 0xc6, 0x8e, 0x4b, 0x02, 0x25, - 0xc3, 0x6b, 0x88, 0x12, 0x9d, 0xee, 0xb8, 0xa4, 0xed, 0x8d, 0x69, 0x54, 0x45, 0x01, 0xab, 0x9d, - 0x41, 0x99, 0x3b, 0x3c, 0x9b, 0xd9, 0x56, 0x48, 0x7e, 0x30, 0xb7, 0xff, 0xcd, 0x42, 0x31, 0xb6, - 0xac, 0x8b, 0x9e, 0x4e, 0x14, 0xfd, 0x38, 0x9a, 0x07, 0x82, 0xdd, 0xfb, 0x37, 0xfd, 0x25, 0x06, - 0x02, 0x02, 0x29, 0x70, 0xfe, 0x40, 0x38, 0x9f, 0xb2, 0x98, 0xaf, 0x91, 0x06, 0xe5, 0xeb, 0x24, - 0xda, 0xc1, 0x49, 0x15, 0x7a, 0x1f, 0x60, 0x4a, 0x6d, 0x67, 0xec, 0x10, 0xdb, 0x0c, 0x78, 0x03, - 0x64, 0x71, 0x29, 0xd6, 0xf4, 0x91, 0xc2, 0xda, 0x9d, 0x51, 0xc8, 0x8e, 0xb8, 0x12, 0x8b, 0xcc, - 0xe2, 0x78, 0x97, 0x96, 0xeb, 0xc4, 0x0c, 0x89, 0x45, 0x36, 0xf5, 0x3c, 0xba, 0x45, 0xde, 0x22, - 0x07, 0xec, 0x78, 0x34, 0x49, 0xdc, 0xc7, 0x50, 0x88, 0xa7, 0x22, 0xab, 0xe7, 0x16, 0x93, 0x9e, - 0x93, 0x51, 0x48, 0xd7, 0xf3, 0x26, 0x82, 0x21, 0x15, 0x8a, 0xeb, 0x56, 0x04, 0x7e, 0xd3, 0xb5, - 0xcc, 0x66, 0xf1, 0x3a, 0x0e, 0x2f, 0x50, 0xca, 0x5a, 0xfa, 0x28, 0x87, 0xd7, 0xa1, 0x19, 0xec, - 0xb8, 0x0d, 0x60, 0xb8, 0x50, 0x2a, 0xbc, 0x17, 0xef, 0xc4, 0xbd, 0xd8, 0x3f, 0xa7, 0x7e, 0xd8, - 0x6e, 0x6d, 0x76, 0x34, 0x16, 0xe8, 0xa7, 0x90, 0x6f, 0xb8, 0x74, 0x74, 0x11, 0x33, 0xfd, 0xee, - 0xe6, 0x7e, 0x5c, 0x9f, 0xa8, 0x67, 0x04, 0x64, 0xa1, 0x07, 0x8b, 0xa9, 0xeb, 0x78, 0x17, 0x66, - 0x68, 0xf9, 0x13, 0x12, 0x2a, 0x7b, 0x62, 0xe0, 0x47, 0xda, 0x01, 0x57, 0xfe, 0x42, 0xfa, 0xe3, - 0x37, 0x87, 0xa9, 0x9a, 0x07, 0xa5, 0xb5, 0x1f, 0xd6, 0x52, 0x74, 0x3c, 0x0e, 0x48, 0xc8, 0xeb, - 0x9f, 0xc5, 0x91, 0xb4, 0xae, 0x6a, 0x86, 0x07, 0x24, 0xaa, 0x8a, 0x40, 0x3a, 0xb7, 0x82, 0x73, - 0x5e, 0xe9, 0x0a, 0xe6, 0x6b, 0xc6, 0xe3, 0x57, 0xc4, 0xba, 0x30, 0xb9, 0x41, 0xd4, 0xb9, 0xc8, - 0x14, 0x4f, 0xad, 0xe0, 0x3c, 0x3a, 0xef, 0x57, 0x90, 0x17, 0x79, 0x45, 0x4f, 0xa0, 0x38, 0xa2, - 0x73, 0x2f, 0xdc, 0xcc, 0xfa, 0xbd, 0xe4, 0xa8, 0xe0, 0x96, 0x28, 0xb2, 0x35, 0xb0, 0x76, 0x02, - 0x85, 0xc8, 0x84, 0x1e, 0xae, 0xe7, 0x98, 0xd4, 0xb8, 0x7f, 0x2d, 0x85, 0xdb, 0xc3, 0xff, 0xd2, - 0x72, 0xe7, 0xe2, 0xf2, 0x12, 0x16, 0x42, 0xed, 0x2f, 0x69, 0x28, 0x60, 0x56, 0xb6, 0x20, 0x4c, - 0x3c, 0x1b, 0xb9, 0xad, 0x67, 0x63, 0x43, 0xb0, 0xcc, 0x16, 0xc1, 0x62, 0x8e, 0x64, 0x13, 0x1c, - 0xd9, 0x64, 0x4e, 0xba, 0x35, 0x73, 0xb9, 0x5b, 0x32, 0x97, 0x4f, 0x64, 0xee, 0x21, 0xec, 0x8e, - 0x7d, 0x3a, 0xe5, 0x0f, 0x03, 0xf5, 0x2d, 0x7f, 0x11, 0xf5, 0xf3, 0x0e, 0xd3, 0x0e, 0x62, 0x65, - 0xcd, 0x84, 0x22, 0x26, 0xc1, 0x8c, 0x7a, 0x01, 0x79, 0xe7, 0xb5, 0x11, 0x48, 0xb6, 0x15, 0x5a, - 0xfc, 0xd2, 0x15, 0xcc, 0xd7, 0xe8, 0x63, 0x90, 0x46, 0xd4, 0x16, 0x57, 0xde, 0x4d, 0xf6, 0x90, - 0xee, 0xfb, 0xd4, 0x6f, 0x52, 0x9b, 0x60, 0x0e, 0xa8, 0xcd, 0x40, 0x6e, 0xd1, 0x57, 0x9e, 0x4b, - 0x2d, 0xbb, 0xe7, 0xd3, 0x09, 0x1b, 0xd0, 0xef, 0x1c, 0x34, 0x2d, 0x28, 0xcc, 0xf9, 0x28, 0x8a, - 0x47, 0xcd, 0x47, 0xdb, 0xa3, 0xe1, 0xba, 0x23, 0x31, 0xb7, 0x62, 0x3e, 0x45, 0x5b, 0x6b, 0x7f, - 0x4b, 0x83, 0xfa, 0x6e, 0x34, 0x6a, 0x43, 0x59, 0x20, 0xcd, 0xc4, 0x3f, 0xc9, 0xd1, 0xf7, 0x39, - 0x88, 0x4f, 0x25, 0x98, 0xaf, 0xd7, 0xb7, 0x3e, 0x68, 0x09, 0xfe, 0x67, 0xbf, 0x1f, 0xff, 0x3f, - 0x86, 0x9d, 0x21, 0x23, 0xcc, 0xfa, 0xf9, 0x96, 0xb4, 0xec, 0x51, 0xae, 0x91, 0x91, 0x53, 0xb8, - 0x32, 0x14, 0x4c, 0xe2, 0xfa, 0x5a, 0x1e, 0xa4, 0x9e, 0xe3, 0x4d, 0x6a, 0x87, 0x90, 0x6b, 0xba, - 0x94, 0x17, 0x2c, 0xef, 0x13, 0x2b, 0xa0, 0x5e, 0x9c, 0x47, 0x21, 0x1d, 0xff, 0x35, 0x03, 0xe5, - 0xc4, 0xaf, 0x15, 0x7a, 0x0c, 0xbb, 0xcd, 0xce, 0x59, 0x7f, 0xa0, 0x63, 0xb3, 0xd9, 0x35, 0x4e, - 0xda, 0xa7, 0x72, 0x4a, 0x3d, 0x58, 0xae, 0x34, 0x65, 0xba, 0x01, 0x6d, 0xff, 0x35, 0x1d, 0x42, - 0xae, 0x6d, 0xb4, 0xf4, 0xdf, 0xca, 0x69, 0xf5, 0xde, 0x72, 0xa5, 0xc9, 0x09, 0xa0, 0x78, 0x82, - 0x7e, 0x02, 0x15, 0x0e, 0x30, 0xcf, 0x7a, 0xad, 0xfa, 0x40, 0x97, 0x33, 0xaa, 0xba, 0x5c, 0x69, - 0xfb, 0xd7, 0x71, 0x51, 0xce, 0x3f, 0x84, 0x02, 0xd6, 0x7f, 0x73, 0xa6, 0xf7, 0x07, 0x72, 0x56, - 0xdd, 0x5f, 0xae, 0x34, 0x94, 0x00, 0xc6, 0xac, 0x79, 0x08, 0x45, 0xac, 0xf7, 0x7b, 0x5d, 0xa3, - 0xaf, 0xcb, 0x92, 0xfa, 0xde, 0x72, 0xa5, 0xdd, 0xdd, 0x42, 0x45, 0x5d, 0xfa, 0x73, 0xd8, 0x6b, - 0x75, 0x5f, 0x18, 0x9d, 0x6e, 0xbd, 0x65, 0xf6, 0x70, 0xf7, 0x14, 0xeb, 0xfd, 0xbe, 0x9c, 0x53, - 0x0f, 0x97, 0x2b, 0xed, 0x41, 0x02, 0x7f, 0xa3, 0xe9, 0xde, 0x07, 0xa9, 0xd7, 0x36, 0x4e, 0xe5, - 0xbc, 0x7a, 0x77, 0xb9, 0xd2, 0xee, 0x24, 0xa0, 0x2c, 0xa9, 0x2c, 0xe2, 0x66, 0xa7, 0xdb, 0xd7, - 0xe5, 0xc2, 0x8d, 0x88, 0x79, 0xb2, 0x8f, 0x7f, 0x07, 0xe8, 0xe6, 0xcf, 0x27, 0xfa, 0x08, 0x24, - 0xa3, 0x6b, 0xe8, 0x72, 0x4a, 0xc4, 0x7f, 0x13, 0x61, 0x50, 0x8f, 0xa0, 0x1a, 0x64, 0x3b, 0x5f, - 0x7f, 0x21, 0xa7, 0xd5, 0x1f, 0x2d, 0x57, 0xda, 0xfd, 0x9b, 0xa0, 0xce, 0xd7, 0x5f, 0x1c, 0x53, - 0x28, 0x27, 0x1d, 0xd7, 0xa0, 0xf8, 0x4c, 0x1f, 0xd4, 0x5b, 0xf5, 0x41, 0x5d, 0x4e, 0x89, 0x2b, - 0xc5, 0xe6, 0x67, 0x24, 0xb4, 0x38, 0x09, 0x0f, 0x20, 0x67, 0xe8, 0xcf, 0x75, 0x2c, 0xa7, 0xd5, - 0xbd, 0xe5, 0x4a, 0xdb, 0x89, 0x01, 0x06, 0xb9, 0x24, 0x3e, 0xaa, 0x42, 0xbe, 0xde, 0x79, 0x51, - 0x7f, 0xd9, 0x97, 0x33, 0x2a, 0x5a, 0xae, 0xb4, 0xdd, 0xd8, 0x5c, 0x77, 0x5f, 0x59, 0x8b, 0xe0, - 0xf8, 0x3f, 0x69, 0xa8, 0x24, 0x1f, 0x5c, 0x54, 0x05, 0xe9, 0xa4, 0xdd, 0xd1, 0xe3, 0xe3, 0x92, - 0x36, 0xb6, 0x46, 0x47, 0x50, 0x6a, 0xb5, 0xb1, 0xde, 0x1c, 0x74, 0xf1, 0xcb, 0x38, 0x96, 0x24, - 0xa8, 0xe5, 0xf8, 0xbc, 0xc1, 0xd9, 0xcf, 0x6e, 0xa5, 0xff, 0xf2, 0x59, 0xa7, 0x6d, 0x7c, 0x65, - 0x72, 0x8f, 0x19, 0xf5, 0xc1, 0x72, 0xa5, 0xbd, 0x97, 0x04, 0xf7, 0xc5, 0xd3, 0xc1, 0x1d, 0x7f, - 0x09, 0x7b, 0x31, 0x7c, 0x73, 0x40, 0x56, 0xd5, 0x96, 0x2b, 0xed, 0xe0, 0x96, 0x3d, 0x9b, 0x73, - 0x9e, 0xc0, 0x9d, 0x78, 0xe3, 0x99, 0xf1, 0x95, 0xd1, 0x7d, 0x61, 0xc8, 0x92, 0x5a, 0x5d, 0xae, - 0x34, 0xf5, 0x96, 0x6d, 0x67, 0xde, 0x85, 0x47, 0x5f, 0x79, 0xc7, 0x7f, 0x4e, 0x43, 0x69, 0x3d, - 0xa5, 0x58, 0x9e, 0x8d, 0xae, 0xa9, 0x63, 0xdc, 0xc5, 0x71, 0xe0, 0x6b, 0xa3, 0x41, 0xf9, 0x12, - 0x7d, 0x00, 0x85, 0x53, 0xdd, 0xd0, 0x71, 0xbb, 0x19, 0xf3, 0x61, 0x0d, 0x39, 0x25, 0x1e, 0xf1, - 0x9d, 0x11, 0xfa, 0x04, 0x2a, 0x46, 0xd7, 0xec, 0x9f, 0x35, 0x9f, 0xc6, 0x11, 0xf3, 0x06, 0x4e, - 0xb8, 0xea, 0xcf, 0x47, 0xe7, 0x3c, 0xda, 0x63, 0x46, 0x9d, 0xe7, 0xf5, 0x4e, 0xbb, 0x25, 0xa0, - 0x59, 0x55, 0x59, 0xae, 0xb4, 0x7b, 0x6b, 0x68, 0x5b, 0xfc, 0x70, 0x30, 0xec, 0xb1, 0x0d, 0xd5, - 0xff, 0x3f, 0x8f, 0x90, 0x06, 0xf9, 0x7a, 0xaf, 0xa7, 0x1b, 0xad, 0xf8, 0xf6, 0x1b, 0x5b, 0x7d, - 0x36, 0x23, 0x9e, 0xcd, 0x10, 0x27, 0x5d, 0x7c, 0xaa, 0x0f, 0xe2, 0xcb, 0x6f, 0x10, 0x27, 0x94, - 0x3d, 0xdc, 0x8d, 0x83, 0x37, 0xdf, 0x55, 0x53, 0xdf, 0x7e, 0x57, 0x4d, 0xbd, 0xb9, 0xaa, 0xa6, - 0xbf, 0xbd, 0xaa, 0xa6, 0xff, 0x71, 0x55, 0x4d, 0xfd, 0xeb, 0xaa, 0x9a, 0xfe, 0xe6, 0x9f, 0xd5, - 0xf4, 0x30, 0xcf, 0xe7, 0xd7, 0x93, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xeb, 0xb3, 0x61, 0xe0, - 0x86, 0x0e, 0x00, 0x00, + // 1729 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x8f, 0xdb, 0xc6, + 0x15, 0x17, 0x25, 0xea, 0xdf, 0x93, 0x76, 0xc3, 0x1d, 0xdb, 0x5b, 0x96, 0xd9, 0x68, 0x69, 0xc5, + 0x8e, 0x37, 0x8b, 0x64, 0xe3, 0x26, 0x69, 0x8b, 0x16, 0x6d, 0x01, 0xfd, 0xe1, 0xae, 0x85, 0xca, + 0x94, 0x3a, 0xd2, 0x3a, 0x75, 0x0e, 0x25, 0x28, 0x71, 0xa4, 0x25, 0x4c, 0x71, 0x54, 0x92, 0x5a, + 0x5b, 0xfd, 0x08, 0xfa, 0x04, 0xbd, 0x08, 0x08, 0xd0, 0x53, 0xef, 0xfd, 0x10, 0x3e, 0x06, 0x3d, + 0xf4, 0xd0, 0x83, 0xd1, 0x6c, 0x2f, 0x3d, 0xf6, 0x5e, 0xa0, 0x28, 0x38, 0x43, 0x52, 0xd4, 0xae, + 0x37, 0xf0, 0xa1, 0x27, 0xce, 0xbc, 0xf7, 0x9b, 0x3f, 0xef, 0xf7, 0xde, 0xef, 0x0d, 0xa1, 0x3c, + 0x22, 0xf3, 0x93, 0xb9, 0x47, 0x03, 0x8a, 0x4a, 0xec, 0x33, 0xa6, 0x8e, 0xf2, 0xe9, 0xd4, 0x0e, + 0x2e, 0x16, 0xa3, 0x93, 0x31, 0x9d, 0x7d, 0x36, 0xa5, 0x53, 0xfa, 0x19, 0xf3, 0x8c, 0x16, 0x13, + 0x36, 0x63, 0x13, 0x36, 0xe2, 0x0b, 0xeb, 0x73, 0xc8, 0x3f, 0x21, 0x8e, 0x43, 0xd1, 0x21, 0x54, + 0x2c, 0x72, 0x69, 0x8f, 0x89, 0xe1, 0x9a, 0x33, 0x22, 0x0b, 0xaa, 0x70, 0x54, 0xc6, 0xc0, 0x4d, + 0xba, 0x39, 0x23, 0x21, 0x60, 0xec, 0xd8, 0xc4, 0x0d, 0x38, 0x20, 0xcb, 0x01, 0xdc, 0xc4, 0x00, + 0x0f, 0x61, 0x37, 0x02, 0x5c, 0x12, 0xcf, 0xb7, 0xa9, 0x2b, 0xe7, 0x18, 0x66, 0x87, 0x5b, 0x9f, + 0x71, 0x63, 0xdd, 0x87, 0xc2, 0x13, 0x62, 0x5a, 0xc4, 0x43, 0x1f, 0x83, 0x18, 0x2c, 0xe7, 0xfc, + 0xac, 0xdd, 0xcf, 0xef, 0x9d, 0xc4, 0x31, 0x9c, 0x3c, 0x25, 0xbe, 0x6f, 0x4e, 0xc9, 0x70, 0x39, + 0x27, 0x98, 0x41, 0xd0, 0xaf, 0xa0, 0x32, 0xa6, 0xb3, 0xb9, 0x47, 0x7c, 0xb6, 0x71, 0x96, 0xad, + 0x38, 0xb8, 0xb1, 0xa2, 0xb5, 0xc1, 0xe0, 0xf4, 0x82, 0x7a, 0x03, 0x76, 0x5a, 0xce, 0xc2, 0x0f, + 0x88, 0xd7, 0xa2, 0xee, 0xc4, 0x9e, 0xa2, 0xc7, 0x50, 0x9c, 0x50, 0xc7, 0x22, 0x9e, 0x2f, 0x0b, + 0x6a, 0xee, 0xa8, 0xf2, 0xb9, 0xb4, 0xd9, 0xec, 0x94, 0x39, 0x9a, 0xe2, 0xeb, 0x37, 0x87, 0x19, + 0x1c, 0xc3, 0xea, 0x7f, 0xca, 0x42, 0x81, 0x7b, 0xd0, 0x3e, 0x64, 0x6d, 0x8b, 0x53, 0xd4, 0x2c, + 0x5c, 0xbd, 0x39, 0xcc, 0x76, 0xda, 0x38, 0x6b, 0x5b, 0xe8, 0x2e, 0xe4, 0x1d, 0x73, 0x44, 0x9c, + 0x88, 0x1c, 0x3e, 0x41, 0xef, 0x43, 0xd9, 0x23, 0xa6, 0x65, 0x50, 0xd7, 0x59, 0x32, 0x4a, 0x4a, + 0xb8, 0x14, 0x1a, 0x7a, 0xae, 0xb3, 0x44, 0x9f, 0x02, 0xb2, 0xa7, 0x2e, 0xf5, 0x88, 0x31, 0x27, + 0xde, 0xcc, 0x66, 0xb7, 0xf5, 0x65, 0x91, 0xa1, 0xf6, 0xb8, 0xa7, 0xbf, 0x71, 0xa0, 0x0f, 0x61, + 0x27, 0x82, 0x5b, 0xc4, 0x21, 0x01, 0x91, 0xf3, 0x0c, 0x59, 0xe5, 0xc6, 0x36, 0xb3, 0xa1, 0xc7, + 0x70, 0xd7, 0xb2, 0x7d, 0x73, 0xe4, 0x10, 0x23, 0x20, 0xb3, 0xb9, 0x61, 0xbb, 0x16, 0x79, 0x45, + 0x7c, 0xb9, 0xc0, 0xb0, 0x28, 0xf2, 0x0d, 0xc9, 0x6c, 0xde, 0xe1, 0x1e, 0xb4, 0x0f, 0x85, 0xb9, + 0xb9, 0xf0, 0x89, 0x25, 0x17, 0x19, 0x26, 0x9a, 0x85, 0x2c, 0xf1, 0x0a, 0xf0, 0x65, 0xe9, 0x3a, + 0x4b, 0x6d, 0xe6, 0x88, 0x59, 0x8a, 0x60, 0xf5, 0x7f, 0x67, 0xa1, 0xc0, 0x3d, 0xe8, 0xa3, 0x84, + 0xa5, 0x6a, 0x73, 0x3f, 0x44, 0xfd, 0xfd, 0xcd, 0x61, 0x89, 0xfb, 0x3a, 0xed, 0x14, 0x6b, 0x08, + 0xc4, 0x54, 0x45, 0xb1, 0x31, 0x3a, 0x80, 0xb2, 0x69, 0x59, 0x61, 0xf6, 0x88, 0x2f, 0xe7, 0xd4, + 0xdc, 0x51, 0x19, 0x6f, 0x0c, 0xe8, 0xa7, 0xdb, 0xd5, 0x20, 0x5e, 0xaf, 0x9f, 0xdb, 0xca, 0x20, + 0x4c, 0xc5, 0x98, 0x78, 0x51, 0x05, 0xe7, 0xd9, 0x79, 0xa5, 0xd0, 0xc0, 0xea, 0xf7, 0x3e, 0x54, + 0x67, 0xe6, 0x2b, 0xc3, 0x27, 0xbf, 0x5f, 0x10, 0x77, 0x4c, 0x18, 0x5d, 0x39, 0x5c, 0x99, 0x99, + 0xaf, 0x06, 0x91, 0x09, 0xd5, 0x00, 0x6c, 0x37, 0xf0, 0xa8, 0xb5, 0x18, 0x13, 0x2f, 0xe2, 0x2a, + 0x65, 0x41, 0x3f, 0x86, 0x12, 0x23, 0xdb, 0xb0, 0x2d, 0xb9, 0xa4, 0x0a, 0x47, 0x62, 0x53, 0x89, + 0x02, 0x2f, 0x32, 0xaa, 0x59, 0xdc, 0xf1, 0x10, 0x17, 0x19, 0xb6, 0x63, 0xa1, 0x5f, 0x80, 0xe2, + 0xbf, 0xb0, 0xc3, 0x44, 0xf1, 0x9d, 0x02, 0x9b, 0xba, 0x86, 0x47, 0x66, 0xf4, 0xd2, 0x74, 0x7c, + 0xb9, 0xcc, 0x8e, 0x91, 0x43, 0x44, 0x27, 0x05, 0xc0, 0x91, 0xbf, 0xde, 0x83, 0x3c, 0xdb, 0x31, + 0xcc, 0x22, 0x2f, 0xd6, 0x48, 0xbd, 0xd1, 0x0c, 0x9d, 0x40, 0x7e, 0x62, 0x3b, 0xc4, 0x97, 0xb3, + 0x2c, 0x87, 0x28, 0x55, 0xe9, 0xb6, 0x43, 0x3a, 0xee, 0x84, 0x46, 0x59, 0xe4, 0xb0, 0xfa, 0x39, + 0x54, 0xd8, 0x86, 0xe7, 0x73, 0xcb, 0x0c, 0xc8, 0xff, 0x6d, 0xdb, 0xff, 0xe4, 0xa0, 0x14, 0x7b, + 0x92, 0xa4, 0x0b, 0xa9, 0xa4, 0x1f, 0x47, 0xfd, 0x80, 0xab, 0x7b, 0xff, 0xe6, 0x7e, 0xa9, 0x86, + 0x80, 0x40, 0xf4, 0xed, 0x3f, 0x10, 0xa6, 0xa7, 0x1c, 0x66, 0x63, 0xa4, 0x42, 0xe5, 0xba, 0x88, + 0x76, 0x70, 0xda, 0x84, 0x3e, 0x00, 0x98, 0x51, 0xcb, 0x9e, 0xd8, 0xc4, 0x32, 0x7c, 0x56, 0x00, + 0x39, 0x5c, 0x8e, 0x2d, 0x03, 0x24, 0x87, 0xe5, 0x1e, 0x4a, 0xc8, 0x8a, 0xb4, 0x12, 0x4f, 0x43, + 0x8f, 0xed, 0x5e, 0x9a, 0x8e, 0x1d, 0x2b, 0x24, 0x9e, 0x86, 0x5d, 0xcf, 0xa5, 0x5b, 0xe2, 0x2d, + 0x31, 0xc0, 0x8e, 0x4b, 0xd3, 0xc2, 0x7d, 0x0c, 0xc5, 0xb8, 0x2b, 0x86, 0xf9, 0xdc, 0x52, 0xd2, + 0x33, 0x32, 0x0e, 0x68, 0xd2, 0x6f, 0x22, 0x18, 0x52, 0xa0, 0x94, 0x94, 0x22, 0xb0, 0x9b, 0x26, + 0xf3, 0xb0, 0x17, 0x27, 0x71, 0xb8, 0xbe, 0x5c, 0x51, 0x85, 0xa3, 0x3c, 0x4e, 0x42, 0xd3, 0xc3, + 0xe3, 0x36, 0x80, 0xd1, 0x52, 0xae, 0xb2, 0x5a, 0x7c, 0x2f, 0xae, 0xc5, 0xc1, 0x05, 0xf5, 0x82, + 0x4e, 0x7b, 0xb3, 0xa2, 0xb9, 0x44, 0x3f, 0x82, 0x42, 0xd3, 0xa1, 0xe3, 0x17, 0xb1, 0xd2, 0xef, + 0x6c, 0xee, 0xc7, 0xec, 0xa9, 0x7c, 0x46, 0xc0, 0x30, 0x74, 0x7f, 0x39, 0x73, 0x6c, 0xf7, 0x85, + 0x11, 0x98, 0xde, 0x94, 0x04, 0xf2, 0x1e, 0x6f, 0xf8, 0x91, 0x75, 0xc8, 0x8c, 0x3f, 0x17, 0xff, + 0xf8, 0xcd, 0x61, 0xa6, 0xee, 0x42, 0x39, 0xd9, 0x27, 0x2c, 0x29, 0x3a, 0x99, 0xf8, 0x24, 0x60, + 0xf9, 0xcf, 0xe1, 0x68, 0x96, 0x64, 0x35, 0xcb, 0x02, 0xe2, 0x59, 0x45, 0x20, 0x5e, 0x98, 0xfe, + 0x05, 0xcb, 0x74, 0x15, 0xb3, 0x71, 0xa8, 0xe3, 0x97, 0xc4, 0x7c, 0x61, 0x30, 0x07, 0xcf, 0x73, + 0x29, 0x34, 0x3c, 0x31, 0xfd, 0x8b, 0xe8, 0xbc, 0x5f, 0x42, 0x81, 0xf3, 0x8a, 0xbe, 0x80, 0xd2, + 0x98, 0x2e, 0xdc, 0x60, 0xd3, 0xeb, 0xf7, 0xd2, 0xad, 0x82, 0x79, 0xa2, 0xc8, 0x12, 0x60, 0xfd, + 0x14, 0x8a, 0x91, 0x0b, 0x3d, 0x4c, 0xfa, 0x98, 0xd8, 0xbc, 0x77, 0x8d, 0xc2, 0xed, 0xe6, 0x7f, + 0x69, 0x3a, 0x0b, 0x7e, 0x79, 0x11, 0xf3, 0x49, 0xfd, 0x2f, 0x02, 0x14, 0x71, 0x98, 0x36, 0x3f, + 0x48, 0x3d, 0x1b, 0xf9, 0xad, 0x67, 0x63, 0x23, 0xb0, 0xec, 0x96, 0xc0, 0x62, 0x8d, 0xe4, 0x52, + 0x1a, 0xd9, 0x30, 0x27, 0xbe, 0x95, 0xb9, 0xfc, 0x5b, 0x98, 0x2b, 0xa4, 0x98, 0x7b, 0x08, 0xbb, + 0x13, 0x8f, 0xce, 0xd8, 0xc3, 0x40, 0x3d, 0xd3, 0x5b, 0x46, 0xf5, 0xbc, 0x13, 0x5a, 0x87, 0xb1, + 0xb1, 0x6e, 0x40, 0x09, 0x13, 0x7f, 0x4e, 0x5d, 0x9f, 0xdc, 0x7a, 0x6d, 0x04, 0xa2, 0x65, 0x06, + 0x26, 0xbb, 0x74, 0x15, 0xb3, 0x31, 0x7a, 0x04, 0xe2, 0x98, 0x5a, 0xfc, 0xca, 0xbb, 0xe9, 0x1a, + 0xd2, 0x3c, 0x8f, 0x7a, 0x2d, 0x6a, 0x11, 0xcc, 0x00, 0xf5, 0x39, 0x48, 0x6d, 0xfa, 0xd2, 0x75, + 0xa8, 0x69, 0xf5, 0x3d, 0x3a, 0x0d, 0x1b, 0xf4, 0xad, 0x8d, 0xa6, 0x0d, 0xc5, 0x05, 0x6b, 0x45, + 0x71, 0xab, 0x79, 0xb0, 0xdd, 0x1a, 0xae, 0x6f, 0xc4, 0xfb, 0x56, 0xac, 0xa7, 0x68, 0x69, 0xfd, + 0x6f, 0x02, 0x28, 0xb7, 0xa3, 0x51, 0x07, 0x2a, 0x1c, 0x69, 0xa4, 0xfe, 0x49, 0x8e, 0xde, 0xe5, + 0x20, 0xd6, 0x95, 0x60, 0x91, 0x8c, 0xdf, 0xfa, 0xa0, 0xa5, 0xf4, 0x9f, 0x7b, 0x37, 0xfd, 0x3f, + 0x82, 0x9d, 0x51, 0x28, 0x98, 0xe4, 0xf9, 0x16, 0xd5, 0xdc, 0x51, 0xbe, 0x99, 0x95, 0x32, 0xb8, + 0x3a, 0xe2, 0x4a, 0x62, 0xf6, 0x7a, 0x01, 0xc4, 0xbe, 0xed, 0x4e, 0xeb, 0x87, 0x90, 0x6f, 0x39, + 0x94, 0x25, 0xac, 0xe0, 0x11, 0xd3, 0xa7, 0x6e, 0xcc, 0x23, 0x9f, 0x1d, 0xff, 0x35, 0x0b, 0x95, + 0xd4, 0xaf, 0x15, 0x7a, 0x0c, 0xbb, 0xad, 0xee, 0xf9, 0x60, 0xa8, 0x61, 0xa3, 0xd5, 0xd3, 0x4f, + 0x3b, 0x67, 0x52, 0x46, 0x39, 0x58, 0xad, 0x55, 0x79, 0xb6, 0x01, 0x6d, 0xff, 0x35, 0x1d, 0x42, + 0xbe, 0xa3, 0xb7, 0xb5, 0xdf, 0x4a, 0x82, 0x72, 0x77, 0xb5, 0x56, 0xa5, 0x14, 0x90, 0x3f, 0x41, + 0x9f, 0x40, 0x95, 0x01, 0x8c, 0xf3, 0x7e, 0xbb, 0x31, 0xd4, 0xa4, 0xac, 0xa2, 0xac, 0xd6, 0xea, + 0xfe, 0x75, 0x5c, 0xc4, 0xf9, 0x87, 0x50, 0xc4, 0xda, 0x6f, 0xce, 0xb5, 0xc1, 0x50, 0xca, 0x29, + 0xfb, 0xab, 0xb5, 0x8a, 0x52, 0xc0, 0x58, 0x35, 0x0f, 0xa1, 0x84, 0xb5, 0x41, 0xbf, 0xa7, 0x0f, + 0x34, 0x49, 0x54, 0x7e, 0xb0, 0x5a, 0xab, 0x77, 0xb6, 0x50, 0x51, 0x95, 0xfe, 0x04, 0xf6, 0xda, + 0xbd, 0xaf, 0xf4, 0x6e, 0xaf, 0xd1, 0x36, 0xfa, 0xb8, 0x77, 0x86, 0xb5, 0xc1, 0x40, 0xca, 0x2b, + 0x87, 0xab, 0xb5, 0xfa, 0x7e, 0x0a, 0x7f, 0xa3, 0xe8, 0x3e, 0x00, 0xb1, 0xdf, 0xd1, 0xcf, 0xa4, + 0x82, 0x72, 0x67, 0xb5, 0x56, 0xdf, 0x4b, 0x41, 0x43, 0x52, 0xc3, 0x88, 0x5b, 0xdd, 0xde, 0x40, + 0x93, 0x8a, 0x37, 0x22, 0x66, 0x64, 0x1f, 0xff, 0x0e, 0xd0, 0xcd, 0x9f, 0x4f, 0xf4, 0x00, 0x44, + 0xbd, 0xa7, 0x6b, 0x52, 0x86, 0xc7, 0x7f, 0x13, 0xa1, 0x53, 0x97, 0xa0, 0x3a, 0xe4, 0xba, 0x5f, + 0x7f, 0x29, 0x09, 0xca, 0x0f, 0x57, 0x6b, 0xf5, 0xde, 0x4d, 0x50, 0xf7, 0xeb, 0x2f, 0x8f, 0x29, + 0x54, 0xd2, 0x1b, 0xd7, 0xa1, 0xf4, 0x54, 0x1b, 0x36, 0xda, 0x8d, 0x61, 0x43, 0xca, 0xf0, 0x2b, + 0xc5, 0xee, 0xa7, 0x24, 0x30, 0x99, 0x08, 0x0f, 0x20, 0xaf, 0x6b, 0xcf, 0x34, 0x2c, 0x09, 0xca, + 0xde, 0x6a, 0xad, 0xee, 0xc4, 0x00, 0x9d, 0x5c, 0x12, 0x0f, 0xd5, 0xa0, 0xd0, 0xe8, 0x7e, 0xd5, + 0x78, 0x3e, 0x90, 0xb2, 0x0a, 0x5a, 0xad, 0xd5, 0xdd, 0xd8, 0xdd, 0x70, 0x5e, 0x9a, 0x4b, 0xff, + 0xf8, 0xbf, 0x02, 0x54, 0xd3, 0x0f, 0x2e, 0xaa, 0x81, 0x78, 0xda, 0xe9, 0x6a, 0xf1, 0x71, 0x69, + 0x5f, 0x38, 0x46, 0x47, 0x50, 0x6e, 0x77, 0xb0, 0xd6, 0x1a, 0xf6, 0xf0, 0xf3, 0x38, 0x96, 0x34, + 0xa8, 0x6d, 0x7b, 0xac, 0xc0, 0x97, 0xe8, 0x67, 0x50, 0x1d, 0x3c, 0x7f, 0xda, 0xed, 0xe8, 0xbf, + 0x36, 0xd8, 0x8e, 0x59, 0xe5, 0xd1, 0x6a, 0xad, 0xde, 0xdf, 0x02, 0x93, 0xb9, 0x47, 0xc6, 0x66, + 0x40, 0xac, 0x01, 0x7f, 0x44, 0x42, 0x67, 0x49, 0x40, 0x2d, 0xd8, 0x8b, 0x97, 0x6e, 0x0e, 0xcb, + 0x29, 0x9f, 0xac, 0xd6, 0xea, 0x47, 0xdf, 0xbb, 0x3e, 0x39, 0xbd, 0x24, 0xa0, 0x07, 0x50, 0x8c, + 0x36, 0x89, 0x2b, 0x29, 0xbd, 0x34, 0x5a, 0x70, 0xfc, 0x67, 0x01, 0xca, 0x49, 0xbb, 0x0a, 0x09, + 0xd7, 0x7b, 0x86, 0x86, 0x71, 0x0f, 0xc7, 0x0c, 0x24, 0x4e, 0x9d, 0xb2, 0x21, 0xba, 0x0f, 0xc5, + 0x33, 0x4d, 0xd7, 0x70, 0xa7, 0x15, 0x0b, 0x23, 0x81, 0x9c, 0x11, 0x97, 0x78, 0xf6, 0x18, 0x7d, + 0x0c, 0x55, 0xbd, 0x67, 0x0c, 0xce, 0x5b, 0x4f, 0xe2, 0xd0, 0xd9, 0xf9, 0xa9, 0xad, 0x06, 0x8b, + 0xf1, 0x05, 0xe3, 0xf3, 0x38, 0xd4, 0xd0, 0xb3, 0x46, 0xb7, 0xd3, 0xe6, 0xd0, 0x9c, 0x22, 0xaf, + 0xd6, 0xea, 0xdd, 0x04, 0xda, 0xe1, 0x7f, 0x1e, 0x21, 0xf6, 0xd8, 0x82, 0xda, 0xf7, 0x37, 0x26, + 0xa4, 0x42, 0xa1, 0xd1, 0xef, 0x6b, 0x7a, 0x3b, 0xbe, 0xfd, 0xc6, 0xd7, 0x98, 0xcf, 0x89, 0x6b, + 0x85, 0x88, 0xd3, 0x1e, 0x3e, 0xd3, 0x86, 0xf1, 0xe5, 0x37, 0x88, 0x53, 0x1a, 0xbe, 0xe0, 0xcd, + 0x83, 0xd7, 0xdf, 0xd5, 0x32, 0xdf, 0x7e, 0x57, 0xcb, 0xbc, 0xbe, 0xaa, 0x09, 0xdf, 0x5e, 0xd5, + 0x84, 0x7f, 0x5c, 0xd5, 0x32, 0xff, 0xba, 0xaa, 0x09, 0xdf, 0xfc, 0xb3, 0x26, 0x8c, 0x0a, 0xac, + 0x91, 0x7d, 0xf1, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xad, 0x8a, 0xef, 0x7f, 0x8f, 0x0e, 0x00, + 0x00, } diff --git a/lib/protocol/bep.proto b/lib/protocol/bep.proto index 5645163e..fc6c9d9c 100644 --- a/lib/protocol/bep.proto +++ b/lib/protocol/bep.proto @@ -113,9 +113,9 @@ message FileInfo { enum FileInfoType { FILE = 0 [(gogoproto.enumvalue_customname) = "FileInfoTypeFile"]; DIRECTORY = 1 [(gogoproto.enumvalue_customname) = "FileInfoTypeDirectory"]; - SYMLINK_FILE = 2 [(gogoproto.enumvalue_customname) = "FileInfoTypeSymlinkFile"]; - SYMLINK_DIRECTORY = 3 [(gogoproto.enumvalue_customname) = "FileInfoTypeSymlinkDirectory"]; - SYMLINK_UNKNOWN = 4 [(gogoproto.enumvalue_customname) = "FileInfoTypeSymlinkUnknown"]; + SYMLINK_FILE = 2 [(gogoproto.enumvalue_customname) = "FileInfoTypeDeprecatedSymlinkFile", deprecated = true]; + SYMLINK_DIRECTORY = 3 [(gogoproto.enumvalue_customname) = "FileInfoTypeDeprecatedSymlinkDirectory", deprecated = true]; + SYMLINK = 4 [(gogoproto.enumvalue_customname) = "FileInfoTypeSymlink"]; } message BlockInfo { diff --git a/lib/protocol/bep_extensions.go b/lib/protocol/bep_extensions.go index 5408c6e0..de543f7d 100644 --- a/lib/protocol/bep_extensions.go +++ b/lib/protocol/bep_extensions.go @@ -37,7 +37,7 @@ func (f FileInfo) String() string { case FileInfoTypeFile: return fmt.Sprintf("File{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v, Blocks:%v}", f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions, f.Blocks) - case FileInfoTypeSymlinkDirectory, FileInfoTypeSymlinkFile, FileInfoTypeSymlinkUnknown: + case FileInfoTypeSymlink, FileInfoTypeDeprecatedSymlinkDirectory, FileInfoTypeDeprecatedSymlinkFile: return fmt.Sprintf("Symlink{Name:%q, Type:%v, Sequence:%d, Version:%v, Deleted:%v, Invalid:%v, NoPermissions:%v, SymlinkTarget:%q}", f.Name, f.Type, f.Sequence, f.Version, f.Deleted, f.Invalid, f.NoPermissions, f.SymlinkTarget) default: @@ -59,7 +59,7 @@ func (f FileInfo) IsDirectory() bool { func (f FileInfo) IsSymlink() bool { switch f.Type { - case FileInfoTypeSymlinkDirectory, FileInfoTypeSymlinkFile, FileInfoTypeSymlinkUnknown: + case FileInfoTypeSymlink, FileInfoTypeDeprecatedSymlinkDirectory, FileInfoTypeDeprecatedSymlinkFile: return true default: return false diff --git a/lib/scanner/walk.go b/lib/scanner/walk.go index d3ceb9b9..45967100 100644 --- a/lib/scanner/walk.go +++ b/lib/scanner/walk.go @@ -20,7 +20,6 @@ import ( "github.com/syncthing/syncthing/lib/ignore" "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/symlinks" "golang.org/x/text/unicode/norm" ) @@ -374,19 +373,12 @@ func (w *walker) walkDir(relPath string, info os.FileInfo, dchan chan protocol.F // walkSymlink returns nil or an error, if the error is of the nature that // it should stop the entire walk. func (w *walker) walkSymlink(absPath, relPath string, dchan chan protocol.FileInfo) error { - // If the target is a directory, do NOT descend down there. This will - // cause files to get tracked, and removing the symlink will as a result - // remove files in their real location. - if !symlinks.Supported { - return nil - } - // We always rehash symlinks as they have no modtime or // permissions. We check if they point to the old target by // checking that their existing blocks match with the blocks in // the index. - target, targetType, err := symlinks.Read(absPath) + target, err := os.Readlink(absPath) if err != nil { l.Debugln("readlink error:", absPath, err) return nil @@ -400,13 +392,13 @@ func (w *walker) walkSymlink(absPath, relPath string, dchan chan protocol.FileIn // - the symlink type (file/dir) was the same // - the target was the same cf, ok := w.CurrentFiler.CurrentFile(relPath) - if ok && !cf.IsDeleted() && cf.IsSymlink() && !cf.IsInvalid() && SymlinkTypeEqual(targetType, cf) && cf.SymlinkTarget == target { + if ok && !cf.IsDeleted() && cf.IsSymlink() && !cf.IsInvalid() && cf.SymlinkTarget == target { return nil } f := protocol.FileInfo{ Name: relPath, - Type: SymlinkType(targetType), + Type: protocol.FileInfoTypeSymlink, Version: cf.Version.Update(w.ShortID), NoPermissions: true, // Symlinks don't have permissions of their own SymlinkTarget: target, @@ -489,38 +481,6 @@ func PermsEqual(a, b uint32) bool { } } -func SymlinkTypeEqual(disk symlinks.TargetType, f protocol.FileInfo) bool { - // If the target is missing, Unix never knows what type of symlink it is - // and Windows always knows even if there is no target. Which means that - // without this special check a Unix node would be fighting with a Windows - // node about whether or not the target is known. Basically, if you don't - // know and someone else knows, just accept it. The fact that you don't - // know means you are on Unix, and on Unix you don't really care what the - // target type is. The moment you do know, and if something doesn't match, - // that will propagate through the cluster. - switch disk { - case symlinks.TargetUnknown: - return true - case symlinks.TargetDirectory: - return f.Type == protocol.FileInfoTypeSymlinkDirectory - case symlinks.TargetFile: - return f.Type == protocol.FileInfoTypeSymlinkFile - } - panic("unknown symlink TargetType") -} - -func SymlinkType(t symlinks.TargetType) protocol.FileInfoType { - switch t { - case symlinks.TargetFile: - return protocol.FileInfoTypeSymlinkFile - case symlinks.TargetDirectory: - return protocol.FileInfoTypeSymlinkDirectory - case symlinks.TargetUnknown: - return protocol.FileInfoTypeSymlinkUnknown - } - panic("unknown symlink TargetType") -} - // A byteCounter gets bytes added to it via Update() and then provides the // Total() and one minute moving average Rate() in bytes per second. type byteCounter struct { diff --git a/lib/scanner/walk_test.go b/lib/scanner/walk_test.go index 48f27981..48599fe2 100644 --- a/lib/scanner/walk_test.go +++ b/lib/scanner/walk_test.go @@ -23,7 +23,6 @@ import ( "github.com/syncthing/syncthing/lib/ignore" "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/symlinks" "golang.org/x/text/unicode/norm" ) @@ -282,7 +281,7 @@ func TestIssue1507(t *testing.T) { } func TestWalkSymlink(t *testing.T) { - if !symlinks.Supported { + if runtime.GOOS == "windows" { t.Skip("skipping unsupported symlink test") return } @@ -293,7 +292,7 @@ func TestWalkSymlink(t *testing.T) { defer os.RemoveAll("_symlinks") os.Mkdir("_symlinks", 0755) - symlinks.Create("_symlinks/link", "destination", symlinks.TargetUnknown) + os.Symlink("destination", "_symlinks/link") // Scan it @@ -383,34 +382,6 @@ func (l testfileList) String() string { return b.String() } -func TestSymlinkTypeEqual(t *testing.T) { - testcases := []struct { - onDiskType symlinks.TargetType - fiType protocol.FileInfoType - equal bool - }{ - // File is only equal to file - {symlinks.TargetFile, protocol.FileInfoTypeSymlinkFile, true}, - {symlinks.TargetFile, protocol.FileInfoTypeSymlinkDirectory, false}, - {symlinks.TargetFile, protocol.FileInfoTypeSymlinkUnknown, false}, - // Directory is only equal to directory - {symlinks.TargetDirectory, protocol.FileInfoTypeSymlinkFile, false}, - {symlinks.TargetDirectory, protocol.FileInfoTypeSymlinkDirectory, true}, - {symlinks.TargetDirectory, protocol.FileInfoTypeSymlinkUnknown, false}, - // Unknown is equal to anything - {symlinks.TargetUnknown, protocol.FileInfoTypeSymlinkFile, true}, - {symlinks.TargetUnknown, protocol.FileInfoTypeSymlinkDirectory, true}, - {symlinks.TargetUnknown, protocol.FileInfoTypeSymlinkUnknown, true}, - } - - for _, tc := range testcases { - res := SymlinkTypeEqual(tc.onDiskType, protocol.FileInfo{Type: tc.fiType}) - if res != tc.equal { - t.Errorf("Incorrect result %v for %v, %v", res, tc.onDiskType, tc.fiType) - } - } -} - var initOnce sync.Once const ( diff --git a/lib/symlinks/empty_test.go b/lib/symlinks/empty_test.go deleted file mode 100644 index 1ce3acc8..00000000 --- a/lib/symlinks/empty_test.go +++ /dev/null @@ -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 http://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 symlinks diff --git a/lib/symlinks/symlink_unix.go b/lib/symlinks/symlink_unix.go deleted file mode 100644 index fa7cab3d..00000000 --- a/lib/symlinks/symlink_unix.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2014 The Syncthing Authors. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build !windows - -package symlinks - -import ( - "os" - - "github.com/syncthing/syncthing/lib/osutil" -) - -var ( - Supported = true -) - -func Read(path string) (string, TargetType, error) { - tt := TargetUnknown - if stat, err := os.Stat(path); err == nil { - if stat.IsDir() { - tt = TargetDirectory - } else { - tt = TargetFile - } - } - path, err := os.Readlink(path) - - return osutil.NormalizedFilename(path), tt, err -} - -func Create(source, target string, tt TargetType) error { - return os.Symlink(osutil.NativeFilename(target), source) -} diff --git a/lib/symlinks/symlink_windows.go b/lib/symlinks/symlink_windows.go deleted file mode 100644 index ce0b019b..00000000 --- a/lib/symlinks/symlink_windows.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (C) 2014 The Syncthing Authors. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build windows - -package symlinks - -import ( - "os" - "path/filepath" - - "github.com/syncthing/syncthing/lib/osutil" - - "syscall" - "unicode/utf16" - "unsafe" -) - -const ( - Win32FsctlGetReparsePoint = 0x900a8 - Win32FileFlagOpenReparsePoint = 0x00200000 - Win32FileAttributeReparsePoint = 0x400 - Win32IOReparseTagSymlink = 0xA000000C - Win32SymbolicLinkFlagDirectory = 0x1 -) - -var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") - procCreateSymbolicLink = modkernel32.NewProc("CreateSymbolicLinkW") - - Supported = 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. - Supported = 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 := Create(path, base, TargetDirectory) - if err != nil { - return - } - - stat, err := osutil.Lstat(path) - if err != nil || stat.Mode()&os.ModeSymlink == 0 { - return - } - - target, tt, err := Read(path) - if err != nil || osutil.NativeFilename(target) != base || tt != TargetDirectory { - return - } - Supported = true -} - -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]uint16 -} - -func (r *reparseData) PrintName() string { - // No clue why the offset and length is doubled... - offset := r.printNameOffset / 2 - length := r.printNameLength / 2 - return string(utf16.Decode(r.buffer[offset : offset+length])) -} - -func (r *reparseData) SubstituteName() string { - // No clue why the offset and length is doubled... - offset := r.substitueNameOffset / 2 - length := r.substitueNameLength / 2 - return string(utf16.Decode(r.buffer[offset : offset+length])) -} - -func Read(path string) (string, TargetType, error) { - ptr, err := syscall.UTF16PtrFromString(path) - if err != nil { - return "", TargetUnknown, 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 "", TargetUnknown, 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 "", TargetUnknown, err - } - - tt := TargetUnknown - if attr, err := syscall.GetFileAttributes(ptr); err == nil { - if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - tt = TargetDirectory - } else { - tt = TargetFile - } - } - - return osutil.NormalizedFilename(data.PrintName()), tt, nil -} - -func Create(source, target string, tt TargetType) error { - srcp, err := syscall.UTF16PtrFromString(source) - 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 == TargetUnknown { - path := target - if !filepath.IsAbs(target) { - path = filepath.Join(filepath.Dir(source), target) - } - - stat, err := os.Stat(path) - if err == nil && stat.IsDir() { - mode = Win32SymbolicLinkFlagDirectory - } - } else if tt == TargetDirectory { - 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 -} diff --git a/lib/symlinks/targets.go b/lib/symlinks/targets.go deleted file mode 100644 index 9f54062c..00000000 --- a/lib/symlinks/targets.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2015 The Syncthing Authors. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package symlinks - -type TargetType int - -const ( - TargetFile TargetType = iota - TargetDirectory - TargetUnknown -) diff --git a/test/ignore_test.go b/test/ignore_test.go index 8fc8edfd..969c3066 100644 --- a/test/ignore_test.go +++ b/test/ignore_test.go @@ -13,8 +13,6 @@ import ( "os" "path/filepath" "testing" - - "github.com/syncthing/syncthing/lib/symlinks" ) func TestIgnores(t *testing.T) { @@ -55,7 +53,7 @@ func TestIgnores(t *testing.T) { syms = []string{"s1", "s2", "s3", "s4", "s11", "s12", "s13", "s14"} for _, sym := range syms { p := filepath.Join("s1", sym) - symlinks.Create(p, p, 0) + os.Symlink(p, p) } all = append(all, syms...) } diff --git a/test/symlink_test.go b/test/symlink_test.go index d6baf396..44adb5d0 100644 --- a/test/symlink_test.go +++ b/test/symlink_test.go @@ -16,7 +16,6 @@ import ( "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/rc" - "github.com/syncthing/syncthing/lib/symlinks" ) func TestSymlinks(t *testing.T) { @@ -107,7 +106,7 @@ func testSymlinks(t *testing.T) { t.Fatal(err) } fd.Close() - err = symlinks.Create("s1/fileLink", "file", 0) + err = os.Symlink("file", "s1/fileLink") if err != nil { log.Fatal(err) } @@ -118,35 +117,35 @@ func testSymlinks(t *testing.T) { if err != nil { t.Fatal(err) } - err = symlinks.Create("s1/dirLink", "dir", 0) + err = os.Symlink("dir", "s1/dirLink") if err != nil { log.Fatal(err) } // A link to something in the repo that does not exist - err = symlinks.Create("s1/noneLink", "does/not/exist", 0) + err = os.Symlink("does/not/exist", "s1/noneLink") if err != nil { log.Fatal(err) } // A link we will replace with a file later - err = symlinks.Create("s1/repFileLink", "does/not/exist", 0) + err = os.Symlink("does/not/exist", "s1/repFileLink") if err != nil { log.Fatal(err) } // A link we will replace with a directory later - err = symlinks.Create("s1/repDirLink", "does/not/exist", 0) + err = os.Symlink("does/not/exist", "s1/repDirLink") if err != nil { log.Fatal(err) } // A link we will remove later - err = symlinks.Create("s1/removeLink", "does/not/exist", 0) + err = os.Symlink("does/not/exist", "s1/removeLink") if err != nil { log.Fatal(err) } @@ -183,7 +182,7 @@ func testSymlinks(t *testing.T) { if err != nil { log.Fatal(err) } - err = symlinks.Create("s1/dirLink", "file", 0) + err = os.Symlink("file", "s1/dirLink") if err != nil { log.Fatal(err) } @@ -219,7 +218,7 @@ func testSymlinks(t *testing.T) { if err != nil { log.Fatal(err) } - err = symlinks.Create("s1/fileToReplace", "somewhere/non/existent", 0) + err = os.Symlink("somewhere/non/existent", "s1/fileToReplace") if err != nil { log.Fatal(err) } @@ -230,7 +229,7 @@ func testSymlinks(t *testing.T) { if err != nil { log.Fatal(err) } - err = symlinks.Create("s1/dirToReplace", "somewhere/non/existent", 0) + err = os.Symlink("somewhere/non/existent", "s1/dirToReplace") if err != nil { log.Fatal(err) } diff --git a/test/util.go b/test/util.go index b2ed3ab9..b5dcd0a0 100644 --- a/test/util.go +++ b/test/util.go @@ -28,7 +28,6 @@ import ( "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/rc" - "github.com/syncthing/syncthing/lib/symlinks" ) func init() { @@ -436,7 +435,7 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er mode: os.ModeSymlink, } - tgt, _, err := symlinks.Read(path) + tgt, err := os.Readlink(path) if err != nil { return err }