78 lines
2.2 KiB
Go
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
|
|
}
|