Documentation
¶
Overview ¶
Package hardlinktree provides utilities for creating hardlink trees that mirror torrent file layouts for cross-seeding.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNoMatchingFile = &LinkPlanError{Kind: LinkPlanErrorNoMatchingFile} ErrNoAvailableFile = &LinkPlanError{Kind: LinkPlanErrorNoAvailableFile} ErrCouldNotMatch = &LinkPlanError{Kind: LinkPlanErrorCouldNotMatch} // ErrUnstorableName marks a path the destination dialect cannot store as a file name. ErrUnstorableName = errors.New("destination cannot store torrent path") )
Functions ¶
func HasCommonRootFolder ¶
func HasCommonRootFolder(files []TorrentFile) bool
HasCommonRootFolder checks if all files in the torrent share a common top-level directory. Returns true if a single root folder exists.
Examples:
- ["Movie/video.mkv", "Movie/subs.srt"] → true (common root "Movie")
- ["video.mkv", "subs.srt"] → false (files at root, no folder)
- ["Movie/video.mkv", "Other/subs.srt"] → false (different root folders)
- ["video.mkv"] → false (single file at root)
func MkdirAllTracked ¶ added in v1.26.0
MkdirAllTracked creates dir and any missing ancestors, like os.MkdirAll, and returns the directories it actually created (shallowest first). Pre-existing directories are not returned, so rollback never removes a directory another attempt made.
Types ¶
type ContentLayout ¶
type ContentLayout string
ContentLayout describes how qBittorrent organizes torrent content.
const ( LayoutOriginal ContentLayout = "Original" // Files placed as-is from torrent LayoutSubfolder ContentLayout = "Subfolder" // All files wrapped in a folder named after torrent LayoutNoSubfolder ContentLayout = "NoSubfolder" // Top-level folder stripped from multi-file torrent )
type Created ¶ added in v1.26.0
Created records the files and directories a single Create call actually made on disk. Rollback removes exactly those and nothing else: destinations can be shared between torrents, and a plan-wide cleanup would delete links belonging to a sibling torrent that succeeded (discussion #2282).
func Create ¶
Create materializes the hardlink tree plan on disk. Creates necessary directories and hardlinks files from source to target paths. On failure, attempts best-effort rollback of created files and returns a nil handle.
On success, returns a handle recording what this call created. Targets that already were hardlinks to the source are skipped and NOT recorded: they belong to whoever created them first.
type ExistingFile ¶
type ExistingFile struct {
AbsPath string // Absolute path on disk
RelPath string // Relative path within the torrent structure
Size int64 // File size in bytes
}
ExistingFile represents a file that already exists on disk.
type FilePlan ¶
type FilePlan struct {
SourcePath string // Absolute path to existing file on disk
TargetPath string // Absolute path where hardlink should be created
}
FilePlan describes a single hardlink to create.
type LinkPlanError ¶ added in v1.16.0
type LinkPlanError struct {
Kind LinkPlanErrorKind
File string
}
LinkPlanError describes a file-specific plan-building failure.
func (*LinkPlanError) Error ¶ added in v1.16.0
func (e *LinkPlanError) Error() string
func (*LinkPlanError) Is ¶ added in v1.16.0
func (e *LinkPlanError) Is(target error) bool
type LinkPlanErrorKind ¶ added in v1.16.0
type LinkPlanErrorKind string
LinkPlanErrorKind identifies a file-matching failure when building a plan.
const ( LinkPlanErrorNoMatchingFile LinkPlanErrorKind = "no_matching_file" LinkPlanErrorNoAvailableFile LinkPlanErrorKind = "no_available_file" LinkPlanErrorCouldNotMatch LinkPlanErrorKind = "could_not_match" )
type PathDialect ¶ added in v1.32.0
type PathDialect interface {
Join(base, name string) string
Rel(base, target string) (string, error)
FromSlash(p string) string
Separator() string
}
PathDialect is the path grammar of the filesystem a plan targets. fsops.PathDialect satisfies it; fsops imports this package, so it is declared here.
type TorrentFile ¶
type TorrentFile struct {
Path string // Relative path within the torrent (e.g., "Folder/file.mkv")
Size int64 // File size in bytes
}
TorrentFile represents a file in a torrent.
type TreePlan ¶
type TreePlan struct {
RootDir string // Root directory for the hardlink tree
Files []FilePlan // Files to hardlink
}
TreePlan describes the complete hardlink tree to create.
func BuildPlan ¶
func BuildPlan( d PathDialect, candidateFiles []TorrentFile, existingFiles []ExistingFile, layout ContentLayout, torrentName string, destDir string, ) (*TreePlan, error)
BuildPlan creates a hardlink tree plan that maps existing files to the incoming torrent's layout.
Parameters:
- d: Path grammar of the filesystem destDir and the existing files live on
- candidateFiles: Files as they appear in the INCOMING torrent (target layout)
- existingFiles: Files from the MATCHED torrent that already exist on disk
- layout: How qBittorrent will organize the torrent (from instance preferences)
- torrentName: Name of the incoming torrent (used for Subfolder layout)
- destDir: Base directory for the hardlink tree
The resulting tree will match what qBittorrent expects when adding the torrent.
func BuildSingleFilePlan ¶ added in v1.28.0
func BuildSingleFilePlan(d PathDialect, rootDir, relativePath, sourcePath string) (*TreePlan, error)
BuildSingleFilePlan creates an exact-path plan for one already-paired torrent file. It rejects unsafe or non-canonical slash paths and names the destination cannot store, performs no I/O, and never performs fuzzy matching or conflict renaming.