Merge branch 'main' into v2

* main:
  feat(fs, config): add support for custom filesystem type construction (#9887)
  build(deps): update dependencies (#10020)
This commit is contained in:
Jakob Borg
2025-04-03 10:21:01 +02:00
14 changed files with 132 additions and 119 deletions
+8
View File
@@ -19,6 +19,8 @@ import (
"github.com/syncthing/syncthing/lib/build"
)
const FilesystemTypeBasic FilesystemType = "basic"
var (
errInvalidFilenameEmpty = errors.New("name is invalid, must not be empty")
errInvalidFilenameWindowsSpacePeriod = errors.New("name is invalid, must not end in space or period on Windows")
@@ -56,6 +58,12 @@ type (
groupCache = valueCache[string, *user.Group]
)
func init() {
RegisterFilesystemType(FilesystemTypeBasic, func(root string, opts ...Option) (Filesystem, error) {
return newBasicFilesystem(root, opts...), nil
})
}
func newBasicFilesystem(root string, opts ...Option) *BasicFilesystem {
if root == "" {
root = "." // Otherwise "" becomes "/" below
+8
View File
@@ -26,6 +26,14 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
)
const FilesystemTypeFake FilesystemType = "fake"
func init() {
RegisterFilesystemType(FilesystemTypeFake, func(root string, opts ...Option) (Filesystem, error) {
return newFakeFilesystem(root, opts...), nil
})
}
// see readShortAt()
const randomBlockShift = 14 // 128k
+14 -19
View File
@@ -9,6 +9,7 @@ package fs
import (
"context"
"errors"
"fmt"
"io"
"io/fs"
"os"
@@ -215,17 +216,6 @@ func IsPermission(err error) bool {
// IsPathSeparator is the equivalent of os.IsPathSeparator
var IsPathSeparator = os.IsPathSeparator
// Option modifies a filesystem at creation. An option might be specific
// to a filesystem-type.
//
// String is used to detect options with the same effect, i.e. must be different
// for options with different effects. Meaning if an option has parameters, a
// representation of those must be part of the returned string.
type Option interface {
String() string
apply(Filesystem) Filesystem
}
func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem {
var caseOpt Option
var mtimeOpt Option
@@ -246,18 +236,23 @@ func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem
}
opts = opts[:i]
// Construct file system using the registered factory function
var fs Filesystem
switch fsType {
case FilesystemTypeBasic:
fs = newBasicFilesystem(uri, opts...)
case FilesystemTypeFake:
fs = newFakeFilesystem(uri, opts...)
default:
l.Debugln("Unknown filesystem", fsType, uri)
var err error
filesystemFactoriesMutex.Lock()
fsFactory, factoryFound := filesystemFactories[fsType]
filesystemFactoriesMutex.Unlock()
if factoryFound {
fs, err = fsFactory(uri, opts...)
} else {
err = fmt.Errorf("File system type '%s' not recognized", fsType)
}
if err != nil {
fs = &errorFilesystem{
fsType: fsType,
uri: uri,
err: errors.New("filesystem with type " + fsType.String() + " does not exist."),
err: err,
}
}
+28 -14
View File
@@ -6,20 +6,34 @@
package fs
type FilesystemType int32
import "sync"
const (
FilesystemTypeBasic FilesystemType = 0
FilesystemTypeFake FilesystemType = 1
)
type FilesystemType string
func (t FilesystemType) String() string {
switch t {
case FilesystemTypeBasic:
return "basic"
case FilesystemTypeFake:
return "fake"
default:
return "unknown"
}
// Option modifies a filesystem at creation. An option might be specific
// to a filesystem-type.
//
// String is used to detect options with the same effect, i.e. must be different
// for options with different effects. Meaning if an option has parameters, a
// representation of those must be part of the returned string.
type Option interface {
String() string
apply(Filesystem) Filesystem
}
// Factory function type for constructing a custom file system. It takes the URI
// and options as its parameters.
type FilesystemFactory func(string, ...Option) (Filesystem, error)
// For each registered file system type, a function to construct a file system.
var filesystemFactories map[FilesystemType]FilesystemFactory = make(map[FilesystemType]FilesystemFactory)
var filesystemFactoriesMutex sync.Mutex = sync.Mutex{}
// Register a function to be called when a filesystem is to be constructed with
// the specified fsType. The function will receive the URI for the file system as well
// as all options.
func RegisterFilesystemType(fsType FilesystemType, fn FilesystemFactory) {
filesystemFactoriesMutex.Lock()
defer filesystemFactoriesMutex.Unlock()
filesystemFactories[fsType] = fn
}