fix(bt): always preserve the torrent root directory

This commit is contained in:
Levi committed 2026-09-18 09:23:46 +08:00
1 parent 7c33d978c4
commit 69b3e223ad
2 files changed
+24 -5

No files matched your search

+9 -2
View File
@@ -411,11 +411,18 @@ func (f *Fetcher) Wait() (err error) {
}
}
// Path already includes the torrent's root directory. Never prune the download
// directory itself, and only remove parent directories that are empty.
// Path already includes the torrent's root directory. Preserve that directory
// even when empty, and only prune empty directories below it.
func removeUnselectedFile(downloadDir, torrentPath string) error {
if !filepath.IsLocal(torrentPath) {
return fmt.Errorf("invalid torrent file path %q", torrentPath)
}
root := filepath.Clean(downloadDir)
torrentPath = filepath.Clean(torrentPath)
name := filepath.Join(root, torrentPath)
if torrentDir, _, hasDir := strings.Cut(torrentPath, string(filepath.Separator)); hasDir {
root = filepath.Join(root, torrentDir)
}
for _, candidate := range []string{name, name + ".part"} {
if err := util.SafeRemove(candidate); err != nil {
return fmt.Errorf("remove unselected torrent file %q: %w", candidate, err)
+15 -3
View File
@@ -200,13 +200,25 @@ func TestRemoveUnselectedFilePrunesOnlyEmptyParents(t *testing.T) {
if err != nil || string(data) != "keep" {
t.Fatalf("sibling changed: %q, %v", data, err)
}
} else if _, err := os.Stat(filepath.Join(root, "bundle")); !os.IsNotExist(err) {
t.Fatalf("empty torrent directory remains: %v", err)
}
if info, err := os.Stat(filepath.Join(root, "bundle")); err != nil || !info.IsDir() {
t.Fatalf("torrent root directory was removed: %v", err)
}
if _, err := os.Stat(root); err != nil {
t.Fatalf("download directory was removed: %v", err)
}
// Repeating cleanup after all files and directories are gone is harmless.
// A file directly inside the torrent root must not cause that root to be pruned.
rootFile := filepath.Join("bundle", "root.txt")
if err := os.WriteFile(filepath.Join(root, rootFile)+".part", []byte("partial"), 0644); err != nil {
t.Fatal(err)
}
if err := removeUnselectedFile(root, rootFile); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(root, "bundle")); err != nil {
t.Fatalf("torrent root directory was removed after root-level cleanup: %v", err)
}
// Repeating cleanup after the file and its subdirectories are gone is harmless.
if err := removeUnselectedFile(root, relative); err != nil {
t.Fatal(err)
}