Files
qBHardlink/hardlink.go
2026-04-09 21:12:10 +02:00

78 lines
2.2 KiB
Go

package main
import (
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
)
// processHardlinks creates hardlinks in destBase/destSubdir mirroring the
// structure found at contentPath (either a single file or a directory tree).
// torrentName is used as the subdirectory name for single-file torrents.
func processHardlinks(cfg *Config, contentPath, destSubdir, torrentName string) error {
info, err := os.Stat(contentPath)
if err != nil {
return fmt.Errorf("stat %q: %w", contentPath, err)
}
destDir := filepath.Join(cfg.DestBase, destSubdir)
if info.IsDir() {
// Preserve the source directory name inside destDir
return hardlinkDir(contentPath, filepath.Join(destDir, filepath.Base(contentPath)))
}
// Single-file torrent: place the file inside a subdirectory named after the torrent
subdir := torrentName
if subdir == "" {
subdir = filepath.Base(contentPath)
}
return hardlinkFile(contentPath, filepath.Join(destDir, subdir, filepath.Base(contentPath)))
}
// hardlinkDir walks srcDir and recreates the directory tree under destDir,
// creating hardlinks for every file found.
func hardlinkDir(srcDir, destDir string) error {
return filepath.WalkDir(srcDir, func(srcPath string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(srcDir, srcPath)
if err != nil {
return err
}
destPath := filepath.Join(destDir, rel)
if d.IsDir() {
if err := os.MkdirAll(destPath, 0755); err != nil {
return fmt.Errorf("mkdir %q: %w", destPath, err)
}
return nil
}
return hardlinkFile(srcPath, destPath)
})
}
// hardlinkFile creates a hardlink at destPath pointing to srcPath.
// It creates parent directories as needed and skips if the link already exists.
func hardlinkFile(srcPath, destPath string) error {
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
return fmt.Errorf("mkdir %q: %w", filepath.Dir(destPath), err)
}
if _, err := os.Lstat(destPath); err == nil {
log.Printf("skip (already exists): %s", destPath)
return nil
}
if err := os.Link(srcPath, destPath); err != nil {
return fmt.Errorf("hardlink %q -> %q: %w", srcPath, destPath, err)
}
log.Printf("hardlinked: %s -> %s", srcPath, destPath)
return nil
}