up
This commit is contained in:
70
hardlink.go
Normal file
70
hardlink.go
Normal file
@@ -0,0 +1,70 @@
|
||||
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).
|
||||
func processHardlinks(cfg *Config, contentPath, destSubdir 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() {
|
||||
return hardlinkDir(contentPath, destDir)
|
||||
}
|
||||
return hardlinkFile(contentPath, filepath.Join(destDir, 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
|
||||
}
|
||||
Reference in New Issue
Block a user