Rclone — Interfaces#
Interface catalog#
fs.Fs#
- Package:
github.com/rclone/rclone/fs - File:
fs/types.go:17 - Methods:
List(ctx context.Context, dir string) (DirEntries, error) NewObject(ctx context.Context, remote string) (Object, error) Put(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error) Mkdir(ctx context.Context, dir string) error Rmdir(ctx context.Context, dir string) error // + embedded Info (Name, Root, String, Precision, Hashes, Features) - Purpose: The universal storage backend contract. Every one of rclone’s 70+ backends implements this interface. It is deliberately minimal — only the 5 operations every object store must support, plus Info metadata.
- Implementations: All
backend/*/packages:s3.Fs,drive.Fs,sftp.Fs,b2.Fs,dropbox.Fs, etc. Also wrapping backends:crypt.Fs,compress.Fs,chunker.Fs,union.Fs. - Design quality: Exceptionally well-segregated. The required surface is kept to an absolute minimum (5 methods) to avoid burdening simple backends. All optional operations are moved to the
Featuresstruct (see below). Follows ISP strictly.
fs.Info#
- Package:
github.com/rclone/rclone/fs - File:
fs/types.go:62 - Methods:
Name() string Root() string String() string Precision() time.Duration Hashes() hash.Set Features() *Features - Purpose: Read-only metadata about a filesystem instance — its name, root path, modtime precision, supported hash types, and optional capabilities. Embedded in
Fs. - Implementations: Every
fs.Fsimplementation; alsounknownFs(zero-value sentinel). - Design quality: Clean separation between “what does the FS support” (Info) and “what can I do with it” (Fs operations). The
Features()return is the central capability discovery point.
fs.Object#
- Package:
github.com/rclone/rclone/fs - File:
fs/types.go:83 - Methods:
// Embedded ObjectInfo → DirEntry (Fs, String, Remote, ModTime, Size) + Hash, Storable SetModTime(ctx context.Context, t time.Time) error Open(ctx context.Context, options ...OpenOption) (io.ReadCloser, error) Update(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) error Remove(ctx context.Context) error - Purpose: Represents a single file in object storage. Extends
ObjectInfo(read-only metadata) with the four mutation/read operations needed by the sync engine. - Implementations: One per backend (e.g.,
s3.Object,drive.Object). Wrapping backends wrap the underlying Object. - Design quality: Well-balanced. The four required methods are exactly what the sync engine needs. Optional per-object capabilities (
MimeTyper,IDer,GetTierer,SetTierer,Metadataer,ObjectUnWrapper) are separate single-method interfaces discovered via type assertion.
fs.DirEntry / fs.ObjectInfo / fs.Directory (embedding chain)#
- Package:
github.com/rclone/rclone/fs - File:
fs/types.go:115–147 - Hierarchy:
DirEntry (Fs, String, Remote, ModTime, Size) └── ObjectInfo (+ Hash, Storable) └── Object (+ SetModTime, Open, Update, Remove) └── Directory (+ Items, ID) - Purpose:
DirEntryis the common supertype of both files and directories as returned byList(). Callers type-assert toObjectorDirectoryas needed. This avoids a union-type and lets backends return heterogeneous listings. - Design quality: The three-level hierarchy is clean and predictable.
FullObjectandFullObjectInfocomposite interfaces serve as compile-time completeness checks for wrapping backends.
Optional capability interfaces in fs/features.go (~25 interfaces)#
- Package:
github.com/rclone/rclone/fs - File:
fs/features.go:506–811 - Selected interfaces:
Purger — Purge(ctx, dir) error Copier — Copy(ctx, src Object, remote string) (Object, error) Mover — Move(ctx, src Object, remote string) (Object, error) DirMover — DirMove(ctx, src Fs, srcRemote, dstRemote string) error ListRer — ListR(ctx, dir string, callback ListRCallback) error ListPer — ListP(ctx, dir string, callback ListRCallback) error PutStreamer — PutStream(ctx, in io.Reader, src ObjectInfo, ...) (Object, error) OpenChunkWriter — OpenChunkWriter(ctx, remote, src, ...) (ChunkWriterInfo, ChunkWriter, err) ChunkWriter — WriteChunk, Close, Abort ChangeNotifier — ChangeNotify(ctx, fn, <-chan Duration) Abouter — About(ctx) (*Usage, error) PublicLinker — PublicLink(ctx, remote, expire, unlink) (string, error) UnWrapper — UnWrap() Fs Wrapper — WrapFs() Fs; SetWrapper(f Fs) Commander — Command(ctx, name, args, opts) (any, error) Shutdowner — Shutdown(ctx) error RangeSeeker — RangeSeek(ctx, offset, whence, length) (int64, error) - Purpose: Each encodes one optional backend capability. Backends implement the interfaces they support; callers check
f.Features().Copy != nil(where theFeaturesstruct holds function-typed fields pointing to each method) rather than doing type assertions. - Implementations: Varies per backend. S3 implements
Copier,Mover,ListRer,OpenChunkWriter. Google Drive implementsCopier,Mover,DirMover,ChangeNotifier, etc. Simple backends may implement none. - Design quality: Each interface is a single-method contract — perfect ISP. The indirection through the
Featuresstruct (which aggregates function fields) means capability discovery isO(1)with no type assertion required by callers. The trade-off:Featuresitself becomes a large struct that grows with each new capability (~50 fields).
march.Marcher#
- Package:
github.com/rclone/rclone/fs/march - File:
fs/march/march.go:52 - Methods:
SrcOnly(src fs.DirEntry) (recurse bool) DstOnly(dst fs.DirEntry) (recurse bool) Match(ctx context.Context, dst, src fs.DirEntry) (recurse bool) - Purpose: The callback protocol between the two-tree directory walker (
March) and the sync engine.March.Run()walks source and destination trees in parallel and calls these three methods for each entry classification. The sync engine (syncCopyMove) implementsMarcher. - Implementations:
fs/sync.syncCopyMove(sync engine),fs/operations(check operations), other callers that need paired directory walks. - Design quality: Minimal and well-designed. Three methods cover all cases exhaustively (src-only, dst-only, both). The
recurse boolreturn allows the caller to short-circuit subtree traversal, enabling pruning for performance.
vfs.Node#
- Package:
github.com/rclone/rclone/vfs - File:
vfs/vfs.go:57 - Methods:
os.FileInfo // embedded: Name, Size, Mode, ModTime, IsDir, Sys IsFile() bool Inode() uint64 SetModTime(time.Time) error Sync() error Remove() error RemoveAll() error DirEntry() fs.DirEntry VFS() *VFS Open(flags int) (Handle, error) Truncate(size int64) error Path() string SetSys(any) - Purpose: Common interface for both
DirandFilewithin the VFS POSIX layer. Extendsos.FileInfowith VFS-specific operations. All FUSE, WebDAV, FTP, SFTP, HTTP-serve, DLNA, NFS-serve commands operate onNodevalues. - Implementations:
*vfs.Fileand*vfs.Dir— enforced by compile-time checks (var _ Node = (*File)(nil)). - Design quality: Appropriately broad for a POSIX shim — it mirrors exactly what the OS-level
os.FileInfo+os.Fileparadigm requires. TheDirEntry()bridge method allows transparent transition back to thefslayer.
vfs.Handle#
- Package:
github.com/rclone/rclone/vfs - File:
vfs/vfs.go:127 - Methods:
OsFiler // embedded: all *os.File methods (Read, Write, Seek, Stat, Close, ...) Flush() error Release() error Node() Node Lock() error Unlock() error - Purpose: Represents an open file or directory handle within VFS, mirroring
*os.File’s API plus FUSE-specific lifecycle methods (Flush,Release). FUSE mounts and POSIX servers use this interface to abstract overReadFileHandle,WriteFileHandle, andRWFileHandle. - Implementations:
ReadFileHandle,WriteFileHandle,RWFileHandle,DirHandle— each embeddingbaseHandlefor ENOSYS defaults. - Design quality: The
baseHandledefault-ENOSYS pattern allows concrete handles to implement only the subset of methods they support. Appropriate for FUSE semantics.
configmap.Getter / Setter / Mapper#
- Package:
github.com/rclone/rclone/fs/config/configmap - File:
fs/config/configmap/configmap.go:25–42 - Methods:
Getter: Get(key string) (value string, ok bool) Setter: Set(key, value string) Mapper: Getter + Setter // composed interface - Purpose: The config delivery contract between the config subsystem and backends. A
Mapperis passed to every backend’sNewFs()factory. Backends callm.Get("access_key")to retrieve their config values — they never read the config file or flags directly. - Implementations:
configmap.Map(priority-ordered list ofGetters with one or moreSetters),configmap.Simple(plainmap[string]string, used in tests), and various adapter types for env vars, CLI flags, and the config file sections. - Design quality: Elegant layering. The priority queue in
configmap.Mapallows env vars to override config file values, which override defaults — all transparent to backends. ComposingGetter+SetterintoMapperfollows ISP.
fs/fserrors error classification interfaces#
- Package:
github.com/rclone/rclone/fs/fserrors - File:
fs/fserrors/error.go - Interfaces:
Retrier — error + Retry() bool Fataler — error + Fatal() bool NoRetrier — error + NoRetry() bool NoLowLevelRetrier — error + NoLowLevelRetry() bool RetryAfter — error + RetryAfter() time.Time CountableError — error + Count(stats *StatsInfo) - Purpose: A type-based error classification system for the retry engine. Backends return errors implementing these interfaces to signal to the outer
cmd.Run()retry loop whether the operation should be retried, aborted, or retried after a delay. Classified vialiberrors.Walk(recursive unwrap traversal). - Implementations:
retryError,wrappedRetryError,wrappedFatalError, etc. — concrete private types returned by various backends. - Design quality: Fine-grained and extensible. Each retry classification is an independent single-method interface. New classification categories can be added without changing existing backends. The recursive unwrap traversal handles wrapped errors correctly.
Interface patterns#
Size distribution: Remarkably small per interface. The core
fs.Fshas 5 methods (plus embeddedInfoat 6);fs.Objecthas 4 (+embedded); all optional capability interfaces have exactly 1 method;march.Marcherhas 3;vfs.Nodeis the outlier at ~12 (because it mirrorsos.FileInfo). Average outside VFS is 1–3 methods per interface.Embedding: Used heavily and consistently throughout the type hierarchy:
FsembedsInfoObjectembedsObjectInfowhich embedsDirEntryDirectoryembedsDirEntryvfs.HandleembedsOsFilervfs.Nodeembedsos.FileInfoconfigmap.MapperembedsGetter+SetterFullObject/FullObjectInfo/FullDirectoryembed all optional interfaces as compile-time completeness checks.
Implicit satisfaction: All interfaces are consumer-defined:
fs.Fsis defined in the kernel; backends satisfy it implicitly. Rclone usesvar _ fs.Fs = (*MyFs)(nil)compile-time assertions widely to catch missed implementations early.stdlib interfaces used:
io.Reader,io.ReadCloser,io.ReadSeeker— heavily used inObject.Open(),Fs.Put(),ChunkWriterio.WriterAt,io.Closer— composed intoWriterAtCloseros.FileInfo— embedded intovfs.Nodefmt.Stringer—DirEntry.String(),Info.String(),Noderjson.Unmarshaler—Flaggerinterface requires it for flag parsingerror— embedded into allfserrorsclassification interfaces
Key abstractions#
fs.Fs(fs/types.go:17) — The project’s foundational abstraction. Every backend’s existence is defined by this interface. Its deliberate minimalism (5 methods) is what allows 70+ backends to implement it without burden.Optional capability interfaces in
fs/features.go— The answer to the “optional method” problem in Go. Instead of fragmenting optionality across many small interfaces requiring type assertions everywhere, rclone routes them throughFeaturesfunction fields. The ~25 single-method interfaces are still defined (enabling type-safe implementation), but discovery is centralized.march.Marcher(fs/march/march.go:52) — The cleanest interface in the codebase. Three methods, complete coverage of all directory-entry pairings,recurse boolfor pruning. It decouples the tree-traversal mechanism from the sync logic entirely.vfs.Node/vfs.Handle(vfs/vfs.go:57, 127) — The POSIX shim abstractions that allow 7+ serve commands (FUSE, WebDAV, SFTP, FTP, HTTP, DLNA, NFS) to share a single filesystem model without each reimplementing object-storage-to-POSIX translation.configmap.Mapper(fs/config/configmap/configmap.go:39) — The config delivery interface that gives backends clean, layered access to their configuration (file → env → flag → default) without any knowledge of the config system’s internals.
Interface-driven extensibility#
Rclone’s extensibility model is almost entirely interface-driven:
Backend extensibility: Any third-party package can become a valid rclone backend by implementing fs.Fs (5 required methods) and calling fs.Register(&RegInfo{...}) from init(). No code generation, no framework registration, no build tags required. Optional capabilities are opt-in by implementing additional single-method interfaces from fs/features.go.
Wrapping backends: The UnWrapper/Wrapper interface pair (features.go:595–606) enables a chain of decorating backends. crypt.Fs wraps any fs.Fs to add encryption; compress.Fs wraps to add compression; chunker.Fs wraps to split large files. The UnWrapFs() utility function traverses the wrapper chain to reach the base backend. This is rclone’s composability mechanism — backends as decorators.
Config extensibility: The configmap.Getter/Setter/Mapper interfaces allow new config sources (env vars, in-memory overrides, test fixtures) to be plugged in without touching backend code.
VFS extensibility: vfs.Node and vfs.Handle allow new serve commands to be added. Any command that implements its protocol (FUSE, WebDAV, NFS, etc.) in terms of Node and Handle automatically inherits all backend support and VFS caching without writing backend-specific code.
Error extensibility: The fserrors classification interfaces allow new retry semantics to be added without changing the retry engine. A backend can return a RetryAfter error to request exponential back-off to a specific time, or a Fataler error to abort immediately, purely through type-based dispatch.