mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-16 02:18:44 -07:00
This commit is contained in:
parent
ce4d149bf5
commit
fc2c46e82f
@ -31,7 +31,7 @@ import (
|
||||
|
||||
const (
|
||||
OldestHandledVersion = 10
|
||||
CurrentVersion = 31
|
||||
CurrentVersion = 32
|
||||
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
||||
)
|
||||
|
||||
|
@ -126,6 +126,7 @@ func TestDeviceConfig(t *testing.T) {
|
||||
},
|
||||
WeakHashThresholdPct: 25,
|
||||
MarkerName: DefaultMarkerName,
|
||||
JunctionsAsDirs: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ type FolderConfiguration struct {
|
||||
BlockPullOrder BlockPullOrder `xml:"blockPullOrder" json:"blockPullOrder"`
|
||||
CopyRangeMethod fs.CopyRangeMethod `xml:"copyRangeMethod" json:"copyRangeMethod" default:"standard"`
|
||||
CaseSensitiveFS bool `xml:"caseSensitiveFS" json:"caseSensitiveFS"`
|
||||
JunctionsAsDirs bool `xml:"junctionsAsDirs" json:"junctionsAsDirs"`
|
||||
|
||||
cachedModTimeWindow time.Duration
|
||||
|
||||
@ -101,7 +102,11 @@ func (f FolderConfiguration) Copy() FolderConfiguration {
|
||||
func (f FolderConfiguration) Filesystem() fs.Filesystem {
|
||||
// This is intentionally not a pointer method, because things like
|
||||
// cfg.Folders["default"].Filesystem() should be valid.
|
||||
filesystem := fs.NewFilesystem(f.FilesystemType, f.Path)
|
||||
var opts []fs.Option
|
||||
if f.FilesystemType == fs.FilesystemTypeBasic && f.JunctionsAsDirs {
|
||||
opts = append(opts, fs.WithJunctionsAsDirs())
|
||||
}
|
||||
filesystem := fs.NewFilesystem(f.FilesystemType, f.Path, opts...)
|
||||
if !f.CaseSensitiveFS {
|
||||
filesystem = fs.NewCaseFilesystem(filesystem)
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
// update the config version. The order of migrations doesn't matter here,
|
||||
// put the newest on top for readability.
|
||||
var migrations = migrationSet{
|
||||
{32, migrateToConfigV32},
|
||||
{31, migrateToConfigV31},
|
||||
{30, migrateToConfigV30},
|
||||
{29, migrateToConfigV29},
|
||||
@ -91,6 +92,12 @@ func migrateToConfigV31(cfg *Configuration) {
|
||||
cfg.Options.UnackedNotificationIDs = append(cfg.Options.UnackedNotificationIDs, "authenticationUserAndPassword")
|
||||
}
|
||||
|
||||
func migrateToConfigV32(cfg *Configuration) {
|
||||
for i := range cfg.Folders {
|
||||
cfg.Folders[i].JunctionsAsDirs = true
|
||||
}
|
||||
}
|
||||
|
||||
func migrateToConfigV30(cfg *Configuration) {
|
||||
// The "max concurrent scans" option is now spelled "max folder concurrency"
|
||||
// to be more general.
|
||||
|
@ -23,13 +23,24 @@ var (
|
||||
ErrNotRelative = errors.New("not a relative path")
|
||||
)
|
||||
|
||||
func WithJunctionsAsDirs() Option {
|
||||
return func(fs Filesystem) {
|
||||
if basic, ok := fs.(*BasicFilesystem); !ok {
|
||||
l.Warnln("WithJunctionsAsDirs must only be used with FilesystemTypeBasic")
|
||||
} else {
|
||||
basic.junctionsAsDirs = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The BasicFilesystem implements all aspects by delegating to package os.
|
||||
// All paths are relative to the root and cannot (should not) escape the root directory.
|
||||
type BasicFilesystem struct {
|
||||
root string
|
||||
root string
|
||||
junctionsAsDirs bool
|
||||
}
|
||||
|
||||
func newBasicFilesystem(root string) *BasicFilesystem {
|
||||
func newBasicFilesystem(root string, opts ...Option) *BasicFilesystem {
|
||||
if root == "" {
|
||||
root = "." // Otherwise "" becomes "/" below
|
||||
}
|
||||
@ -64,7 +75,13 @@ func newBasicFilesystem(root string) *BasicFilesystem {
|
||||
root = longFilenameSupport(root)
|
||||
}
|
||||
|
||||
return &BasicFilesystem{root}
|
||||
fs := &BasicFilesystem{
|
||||
root: root,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(fs)
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// rooted expands the relative path to the full path that is then used with os
|
||||
@ -145,7 +162,7 @@ func (f *BasicFilesystem) Lstat(name string) (FileInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fi, err := underlyingLstat(name)
|
||||
fi, err := f.underlyingLstat(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
|
||||
// Lstat is like os.Lstat, except lobotomized for Android. See
|
||||
// https://forum.syncthing.net/t/2395
|
||||
func underlyingLstat(name string) (fi os.FileInfo, err error) {
|
||||
func (*BasicFilesystem) underlyingLstat(name string) (fi os.FileInfo, err error) {
|
||||
for i := 0; i < 10; i++ { // We have to draw the line somewhere
|
||||
fi, err = os.Lstat(name)
|
||||
if err, ok := err.(*os.PathError); ok && err.Err == syscall.EINTR {
|
@ -10,6 +10,6 @@ package fs
|
||||
|
||||
import "os"
|
||||
|
||||
func underlyingLstat(name string) (fi os.FileInfo, err error) {
|
||||
func (*BasicFilesystem) underlyingLstat(name string) (fi os.FileInfo, err error) {
|
||||
return os.Lstat(name)
|
||||
}
|
@ -66,12 +66,12 @@ func (fi *dirJunctFileInfo) IsDir() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func underlyingLstat(name string) (os.FileInfo, error) {
|
||||
func (f *BasicFilesystem) underlyingLstat(name string) (os.FileInfo, error) {
|
||||
var fi, err = os.Lstat(name)
|
||||
|
||||
// NTFS directory junctions are treated as ordinary directories,
|
||||
// NTFS directory junctions can be treated as ordinary directories,
|
||||
// see https://forum.syncthing.net/t/option-to-follow-directory-junctions-symbolic-links/14750
|
||||
if err == nil && fi.Mode()&os.ModeSymlink != 0 {
|
||||
if err == nil && f.junctionsAsDirs && fi.Mode()&os.ModeSymlink != 0 {
|
||||
var isJunct bool
|
||||
isJunct, err = isDirectoryJunction(name)
|
||||
if err == nil && isJunct {
|
@ -66,7 +66,7 @@ var (
|
||||
fakefsFs = make(map[string]*fakefs)
|
||||
)
|
||||
|
||||
func newFakeFilesystem(rootURI string) *fakefs {
|
||||
func newFakeFilesystem(rootURI string, _ ...Option) *fakefs {
|
||||
fakefsMut.Lock()
|
||||
defer fakefsMut.Unlock()
|
||||
|
||||
|
@ -178,13 +178,15 @@ var IsPermission = os.IsPermission
|
||||
// IsPathSeparator is the equivalent of os.IsPathSeparator
|
||||
var IsPathSeparator = os.IsPathSeparator
|
||||
|
||||
func NewFilesystem(fsType FilesystemType, uri string) Filesystem {
|
||||
type Option func(Filesystem)
|
||||
|
||||
func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem {
|
||||
var fs Filesystem
|
||||
switch fsType {
|
||||
case FilesystemTypeBasic:
|
||||
fs = newBasicFilesystem(uri)
|
||||
fs = newBasicFilesystem(uri, opts...)
|
||||
case FilesystemTypeFake:
|
||||
fs = newFakeFilesystem(uri)
|
||||
fs = newFakeFilesystem(uri, opts...)
|
||||
default:
|
||||
l.Debugln("Unknown filesystem", fsType, uri)
|
||||
fs = &errorFilesystem{
|
||||
|
@ -57,7 +57,7 @@ func testWalkTraverseDirJunct(t *testing.T, fsType FilesystemType, uri string) {
|
||||
t.Skip("Directory junctions are available and tested on windows only")
|
||||
}
|
||||
|
||||
fs := NewFilesystem(fsType, uri)
|
||||
fs := NewFilesystem(fsType, uri, WithJunctionsAsDirs())
|
||||
|
||||
if err := fs.MkdirAll("target/foo", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -90,7 +90,7 @@ func testWalkInfiniteRecursion(t *testing.T, fsType FilesystemType, uri string)
|
||||
t.Skip("Infinite recursion detection is tested on windows only")
|
||||
}
|
||||
|
||||
fs := NewFilesystem(fsType, uri)
|
||||
fs := NewFilesystem(fsType, uri, WithJunctionsAsDirs())
|
||||
|
||||
if err := fs.MkdirAll("target/foo", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
|
Loading…
Reference in New Issue
Block a user