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
This commit is contained in:
Jakob Borg 2017-02-07 08:34:24 +00:00
parent 9fda9642d3
commit c4ba580cbb
28 changed files with 227 additions and 707 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

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

View File

@ -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"`

15
lib/config/testdata/v19.xml vendored Normal file
View File

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

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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},

View File

@ -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 {

View File

@ -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
}

View File

@ -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")

View File

@ -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,
}

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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 (

View File

@ -1,10 +0,0 @@
// Copyright (C) 2016 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at 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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
)

View File

@ -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...)
}

View File

@ -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)
}

View File

@ -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
}