From e8e852100c9dcafe80f2e9c56b7625409bd042ae Mon Sep 17 00:00:00 2001 From: Taloth Saldono Date: Sat, 16 May 2020 19:08:55 +0200 Subject: [PATCH] Fixed recursion issue when emptying recycle bin --- .../DiskTests/DiskProviderFixtureBase.cs | 32 +++++++++++++++++++ src/NzbDrone.Common/Disk/DiskProviderBase.cs | 21 ++++++++---- .../MediaFiles/DiskScanService.cs | 8 ++--- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs b/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs index 16842e92e..8b9e72b4f 100644 --- a/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs +++ b/src/NzbDrone.Common.Test/DiskTests/DiskProviderFixtureBase.cs @@ -213,6 +213,38 @@ public void GetParentFolder_should_remove_trailing_slash_before_getting_parent_f Subject.GetParentFolder(path).Should().Be(parent); } + [Test] + public void RemoveEmptySubfolders_should_remove_nested_empty_folder() + { + var mainDir = GetTempFilePath(); + var subDir1 = Path.Combine(mainDir, "depth1"); + var subDir2 = Path.Combine(subDir1, "depth2"); + Directory.CreateDirectory(subDir2); + + Subject.RemoveEmptySubfolders(mainDir); + + Directory.Exists(mainDir).Should().Be(true); + Directory.Exists(subDir1).Should().Be(false); + } + + [Test] + public void RemoveEmptySubfolders_should_not_remove_nested_nonempty_folder() + { + var mainDir = GetTempFilePath(); + var subDir1 = Path.Combine(mainDir, "depth1"); + var subDir2 = Path.Combine(subDir1, "depth2"); + var file = Path.Combine(subDir1, "file1.txt"); + Directory.CreateDirectory(subDir2); + File.WriteAllText(file, "I should not be deleted"); + + Subject.RemoveEmptySubfolders(mainDir); + + Directory.Exists(mainDir).Should().Be(true); + Directory.Exists(subDir1).Should().Be(true); + Directory.Exists(subDir2).Should().Be(false); + File.Exists(file).Should().Be(true); + } + private void DoHardLinkRename(FileShare fileShare) { var sourceDir = GetTempFilePath(); diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index 2b8c32208..91614647e 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -146,7 +146,7 @@ public bool FolderEmpty(string path) { Ensure.That(path, () => path).IsValidPath(); - return Directory.EnumerateDirectories(path).Empty(); + return Directory.EnumerateFileSystemEntries(path).Empty(); } public string[] GetDirectories(string path) @@ -526,14 +526,21 @@ public List GetFileInfos(string path) public void RemoveEmptySubfolders(string path) { - var subfolders = GetDirectories(path); - var files = GetFiles(path, SearchOption.AllDirectories); - - foreach (var subfolder in subfolders) + // Depth first search for empty subdirectories + foreach (var subdir in Directory.EnumerateDirectories(path)) { - if (files.None(f => subfolder.IsParentPath(f))) + RemoveEmptySubfolders(subdir); + + if (Directory.EnumerateFileSystemEntries(subdir).Empty()) { - DeleteFolder(subfolder, false); + try + { + Directory.Delete(subdir, false); + } + catch (Exception ex) + { + Logger.Warn(ex, "Failed to remove empty directory {0}", subdir); + } } } } diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index 139986b78..45a8ff51d 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -206,14 +206,12 @@ private void RemoveEmptyMovieFolder(string path) { if (_configService.DeleteEmptyFolders) { - if (_diskProvider.GetFiles(path, SearchOption.AllDirectories).Empty()) + _diskProvider.RemoveEmptySubfolders(path); + + if (_diskProvider.FolderEmpty(path)) { _diskProvider.DeleteFolder(path, true); } - else - { - _diskProvider.RemoveEmptySubfolders(path); - } } }