fsops

package
v1.28.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2026 License: GPL-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package fsops defines the Backend interface that abstracts filesystem operations for qui's services. Current implementations: Local (delegates to os.* on the qui host) and Noop (returns ErrNoFilesystemAccess for instances without filesystem access). A Remote implementation (SSH-backed) is planned. Services still call os.* directly; they adopt this interface in a separate callsite migration, after which the transport is transparent to them.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoFilesystemAccess is returned by the NoopBackend for instances that
	// have no filesystem access configured (neither local nor remote).
	ErrNoFilesystemAccess = errors.New("filesystem access is not configured for this instance")
)

Sentinel errors returned by Backend implementations.

Functions

This section is empty.

Types

type Backend

type Backend interface {

	// Stat returns metadata for a single path, following symlinks — FileID
	// and Nlinks describe the target, so symlinked torrent data keeps its
	// identity. Returns a non-nil error wrapping fs.ErrNotExist if the path
	// does not exist. A failure to resolve identity is reported in
	// LstatInfo.FileIDErr, not as a Stat error, so one identity-opaque file
	// cannot fail callers that only need metadata.
	Stat(ctx context.Context, path string) (*LstatInfo, error)

	// Lstat is like Stat but does not follow symlinks.
	Lstat(ctx context.Context, path string) (*LstatInfo, error)

	// ReadDir returns directory entries.
	ReadDir(ctx context.Context, path string) ([]DirEntry, error)

	// WalkDir walks a directory tree and streams entries on the returned channel.
	// The channel is closed when the walk completes, is cancelled via ctx, or
	// hits an unrecoverable error. Callers must drain the channel or cancel
	// ctx; abandoning it leaks the walk goroutine. Entries whose metadata
	// cannot be read are skipped, not emitted — WalkEntry.Err carries only
	// enumeration-level walk failures. Setting opts.EmitStatErrors emits
	// those entries instead, with WalkEntry.StatErr set and only Path/RelPath
	// valid, so delete preflights can fail closed on unverifiable paths.
	WalkDir(ctx context.Context, root string, opts WalkOptions) (<-chan WalkEntry, error)

	// Statfs returns free/total bytes for the filesystem containing path.
	Statfs(ctx context.Context, path string) (*StatfsResult, error)

	// SameFilesystem returns true if both paths reside on the same filesystem
	// (same device ID on Unix, same volume serial on Windows).
	SameFilesystem(ctx context.Context, p1, p2 string) (bool, error)

	// MkdirAll creates a directory and all parents. Equivalent to os.MkdirAll.
	// For torrent content and link-tree dirs, pass fsutil.ContentDirMode /
	// fsutil.LinkTreeBaseDirMode rather than a hand-typed mode (#1704, #2086).
	MkdirAll(ctx context.Context, path string, perm fs.FileMode) error

	// Remove removes a file or directory. If opts.Recursive is true, removes
	// the entire tree (like os.RemoveAll).
	Remove(ctx context.Context, path string, opts RemoveOptions) error

	// HardlinkTree creates a hardlink tree from plan. Rolls back what it
	// created on partial failure. The result records the files and dirs this
	// call made, for a later RemoveTree.
	HardlinkTree(ctx context.Context, plan *hardlinktree.TreePlan) (*TreeCreateResult, error)

	// ReflinkTree creates a reflink (CoW) tree from plan. Rolls back what it
	// created on partial failure. The result records the files and dirs this
	// call made, for a later RemoveTree.
	ReflinkTree(ctx context.Context, plan *hardlinktree.TreePlan) (*TreeCreateResult, error)

	// RemoveTree removes exactly the files and dirs recorded in created —
	// never the whole plan, which could delete links shared with sibling
	// torrents (discussion #2282). A plan root that already existed before
	// the create is therefore NOT removed; callers own pruning it. Safe to
	// call with a nil result.
	RemoveTree(ctx context.Context, created *TreeCreateResult) error

	// SupportsReflink returns whether the filesystem at path supports CoW
	// reflinks. The string return is a human-readable reason when unsupported.
	SupportsReflink(ctx context.Context, path string) (bool, string, error)
}

Backend abstracts filesystem operations so services work identically against a local filesystem or a future SSH-backed remote. It covers exactly the operations qui's services need: syscall-level primitives (stat, walk, mkdir, remove) plus the high-level tree operations (HardlinkTree, ReflinkTree, RemoveTree) that create-and-rollback as a unit. Path manipulation (filepath.Clean, filepath.Rel, etc.) is not part of this interface — it stays as direct calls in service code.

Every method accepts a context.Context and must respect cancellation.

Error semantics are portable across implementations: a missing path is reported compatibly with errors.Is(err, fs.ErrNotExist) and a denied one with errors.Is(err, fs.ErrPermission) — from Stat, Lstat, ReadDir, WalkDir (on entries), Remove, and Statfs alike. Remote backends must map their transport's errors onto the same sentinels.

type DirEntry

type DirEntry struct {
	Name      string
	IsDir     bool
	IsSymlink bool
}

DirEntry holds one entry from a ReadDir call.

type FileInfo

type FileInfo struct {
	Path      string
	Size      int64
	ModTime   time.Time
	IsDir     bool
	IsSymlink bool
	Mode      fs.FileMode
}

FileInfo holds metadata from a Stat call.

type LstatInfo

type LstatInfo struct {
	FileInfo
	FileID hardlink.FileID
	Nlinks uint64
	// FileIDErr is set when FileID/Nlinks could not be resolved (e.g. a
	// Windows ACL denial on an otherwise statable file). The rest of the
	// struct is still valid; callers that need identity must check this
	// instead of treating the whole stat as failed.
	FileIDErr error
}

LstatInfo holds metadata from an Lstat call, including hardlink identity.

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

Pool resolves an instance ID to the appropriate Backend. For instances with local filesystem access it returns the local backend; for instances without access it returns a noop backend that errors on every call. A future remote backend slots in here for instances with SSH access configured.

func NewPool

func NewPool(store instanceGetter, local Backend) *Pool

NewPool creates a Backend pool backed by the given instance store and local backend.

func (*Pool) GetBackend

func (p *Pool) GetBackend(ctx context.Context, instanceID int) (Backend, error)

GetBackend returns the appropriate Backend for the given instance ID. Returns ErrNoFilesystemAccess wrapped in a noop backend for instances without filesystem access configured.

type RemoveOptions

type RemoveOptions struct {
	Recursive bool
}

RemoveOptions controls the behavior of a Remove call.

type StatfsResult

type StatfsResult struct {
	BytesAvailable int64
	BytesTotal     int64
}

StatfsResult holds filesystem space information.

type TreeCreateResult

type TreeCreateResult struct {
	Created       int
	SkippedExists int
	Files         []string
	Dirs          []string
}

TreeCreateResult holds the outcome of a HardlinkTree or ReflinkTree call. Files and Dirs record what the call actually created on disk (pre-existing paths are excluded), so RemoveTree can undo exactly this call's work without touching links shared with sibling torrents (discussion #2282).

type WalkEntry

type WalkEntry struct {
	LstatInfo
	RelPath string
	Err     error
	// StatErr is set when the entry was enumerated but its metadata lookup
	// failed; only Path and RelPath are valid then. Such entries are emitted
	// only when WalkOptions.EmitStatErrors is set and skipped otherwise.
	StatErr error
}

WalkEntry is emitted by WalkDir for each filesystem entry encountered.

type WalkOptions

type WalkOptions struct {
	SkipHidden bool
	// IgnoreDirNames are directory basenames to skip, matched case-insensitively
	// (OS/NAS metadata dirs like $RECYCLE.BIN and @eaDir vary in on-disk case).
	IgnoreDirNames []string
	// IgnoreDirNamePrefixes are matched case-insensitively.
	IgnoreDirNamePrefixes []string
	IgnorePaths           []string
	// WantFileID populates FileID and Nlinks on regular-file entries.
	WantFileID bool
	// EmitStatErrors emits entries whose metadata lookup failed with StatErr
	// set instead of silently skipping them. Consumers that delete based on
	// walk results use this to fail closed on paths they cannot verify.
	EmitStatErrors bool
}

WalkOptions controls the behavior of a WalkDir call.

Directories

Path Synopsis
Package local implements fsops.Backend by delegating to the local filesystem via os.*, pkg/hardlinktree, pkg/reflinktree, pkg/hardlink, and pkg/fsutil.
Package local implements fsops.Backend by delegating to the local filesystem via os.*, pkg/hardlinktree, pkg/reflinktree, pkg/hardlink, and pkg/fsutil.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL