mirror of
https://github.com/octoleo/syncthing.git
synced 2025-02-02 11:58:28 +00:00
This commit is contained in:
parent
ce4d149bf5
commit
fc2c46e82f
@ -31,7 +31,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
OldestHandledVersion = 10
|
OldestHandledVersion = 10
|
||||||
CurrentVersion = 31
|
CurrentVersion = 32
|
||||||
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -126,6 +126,7 @@ func TestDeviceConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
WeakHashThresholdPct: 25,
|
WeakHashThresholdPct: 25,
|
||||||
MarkerName: DefaultMarkerName,
|
MarkerName: DefaultMarkerName,
|
||||||
|
JunctionsAsDirs: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ type FolderConfiguration struct {
|
|||||||
BlockPullOrder BlockPullOrder `xml:"blockPullOrder" json:"blockPullOrder"`
|
BlockPullOrder BlockPullOrder `xml:"blockPullOrder" json:"blockPullOrder"`
|
||||||
CopyRangeMethod fs.CopyRangeMethod `xml:"copyRangeMethod" json:"copyRangeMethod" default:"standard"`
|
CopyRangeMethod fs.CopyRangeMethod `xml:"copyRangeMethod" json:"copyRangeMethod" default:"standard"`
|
||||||
CaseSensitiveFS bool `xml:"caseSensitiveFS" json:"caseSensitiveFS"`
|
CaseSensitiveFS bool `xml:"caseSensitiveFS" json:"caseSensitiveFS"`
|
||||||
|
JunctionsAsDirs bool `xml:"junctionsAsDirs" json:"junctionsAsDirs"`
|
||||||
|
|
||||||
cachedModTimeWindow time.Duration
|
cachedModTimeWindow time.Duration
|
||||||
|
|
||||||
@ -101,7 +102,11 @@ func (f FolderConfiguration) Copy() FolderConfiguration {
|
|||||||
func (f FolderConfiguration) Filesystem() fs.Filesystem {
|
func (f FolderConfiguration) Filesystem() fs.Filesystem {
|
||||||
// This is intentionally not a pointer method, because things like
|
// This is intentionally not a pointer method, because things like
|
||||||
// cfg.Folders["default"].Filesystem() should be valid.
|
// 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 {
|
if !f.CaseSensitiveFS {
|
||||||
filesystem = fs.NewCaseFilesystem(filesystem)
|
filesystem = fs.NewCaseFilesystem(filesystem)
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
// update the config version. The order of migrations doesn't matter here,
|
// update the config version. The order of migrations doesn't matter here,
|
||||||
// put the newest on top for readability.
|
// put the newest on top for readability.
|
||||||
var migrations = migrationSet{
|
var migrations = migrationSet{
|
||||||
|
{32, migrateToConfigV32},
|
||||||
{31, migrateToConfigV31},
|
{31, migrateToConfigV31},
|
||||||
{30, migrateToConfigV30},
|
{30, migrateToConfigV30},
|
||||||
{29, migrateToConfigV29},
|
{29, migrateToConfigV29},
|
||||||
@ -91,6 +92,12 @@ func migrateToConfigV31(cfg *Configuration) {
|
|||||||
cfg.Options.UnackedNotificationIDs = append(cfg.Options.UnackedNotificationIDs, "authenticationUserAndPassword")
|
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) {
|
func migrateToConfigV30(cfg *Configuration) {
|
||||||
// The "max concurrent scans" option is now spelled "max folder concurrency"
|
// The "max concurrent scans" option is now spelled "max folder concurrency"
|
||||||
// to be more general.
|
// to be more general.
|
||||||
|
@ -23,13 +23,24 @@ var (
|
|||||||
ErrNotRelative = errors.New("not a relative path")
|
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.
|
// 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.
|
// All paths are relative to the root and cannot (should not) escape the root directory.
|
||||||
type BasicFilesystem struct {
|
type BasicFilesystem struct {
|
||||||
root string
|
root string
|
||||||
|
junctionsAsDirs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBasicFilesystem(root string) *BasicFilesystem {
|
func newBasicFilesystem(root string, opts ...Option) *BasicFilesystem {
|
||||||
if root == "" {
|
if root == "" {
|
||||||
root = "." // Otherwise "" becomes "/" below
|
root = "." // Otherwise "" becomes "/" below
|
||||||
}
|
}
|
||||||
@ -64,7 +75,13 @@ func newBasicFilesystem(root string) *BasicFilesystem {
|
|||||||
root = longFilenameSupport(root)
|
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
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fi, err := underlyingLstat(name)
|
fi, err := f.underlyingLstat(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
|
|
||||||
// Lstat is like os.Lstat, except lobotomized for Android. See
|
// Lstat is like os.Lstat, except lobotomized for Android. See
|
||||||
// https://forum.syncthing.net/t/2395
|
// 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
|
for i := 0; i < 10; i++ { // We have to draw the line somewhere
|
||||||
fi, err = os.Lstat(name)
|
fi, err = os.Lstat(name)
|
||||||
if err, ok := err.(*os.PathError); ok && err.Err == syscall.EINTR {
|
if err, ok := err.(*os.PathError); ok && err.Err == syscall.EINTR {
|
@ -10,6 +10,6 @@ package fs
|
|||||||
|
|
||||||
import "os"
|
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)
|
return os.Lstat(name)
|
||||||
}
|
}
|
@ -66,12 +66,12 @@ func (fi *dirJunctFileInfo) IsDir() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func underlyingLstat(name string) (os.FileInfo, error) {
|
func (f *BasicFilesystem) underlyingLstat(name string) (os.FileInfo, error) {
|
||||||
var fi, err = os.Lstat(name)
|
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
|
// 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
|
var isJunct bool
|
||||||
isJunct, err = isDirectoryJunction(name)
|
isJunct, err = isDirectoryJunction(name)
|
||||||
if err == nil && isJunct {
|
if err == nil && isJunct {
|
@ -66,7 +66,7 @@ var (
|
|||||||
fakefsFs = make(map[string]*fakefs)
|
fakefsFs = make(map[string]*fakefs)
|
||||||
)
|
)
|
||||||
|
|
||||||
func newFakeFilesystem(rootURI string) *fakefs {
|
func newFakeFilesystem(rootURI string, _ ...Option) *fakefs {
|
||||||
fakefsMut.Lock()
|
fakefsMut.Lock()
|
||||||
defer fakefsMut.Unlock()
|
defer fakefsMut.Unlock()
|
||||||
|
|
||||||
|
@ -178,13 +178,15 @@ var IsPermission = os.IsPermission
|
|||||||
// IsPathSeparator is the equivalent of os.IsPathSeparator
|
// IsPathSeparator is the equivalent of os.IsPathSeparator
|
||||||
var IsPathSeparator = 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
|
var fs Filesystem
|
||||||
switch fsType {
|
switch fsType {
|
||||||
case FilesystemTypeBasic:
|
case FilesystemTypeBasic:
|
||||||
fs = newBasicFilesystem(uri)
|
fs = newBasicFilesystem(uri, opts...)
|
||||||
case FilesystemTypeFake:
|
case FilesystemTypeFake:
|
||||||
fs = newFakeFilesystem(uri)
|
fs = newFakeFilesystem(uri, opts...)
|
||||||
default:
|
default:
|
||||||
l.Debugln("Unknown filesystem", fsType, uri)
|
l.Debugln("Unknown filesystem", fsType, uri)
|
||||||
fs = &errorFilesystem{
|
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")
|
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 {
|
if err := fs.MkdirAll("target/foo", 0); err != nil {
|
||||||
t.Fatal(err)
|
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")
|
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 {
|
if err := fs.MkdirAll("target/foo", 0); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user