From 7c48b78783dc47f8ace55aea3609ed0fcab8ec71 Mon Sep 17 00:00:00 2001 From: krbtgt <144264613+goldenkirbi@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:38:59 +0000 Subject: [PATCH] Fixed: set permissions on created artist folders when SetPermissionsLinux is enabled --- .../DiskScanServiceTests/ScanFixture.cs | 79 +++++++++++++++++++ .../MediaFiles/DiskScanService.cs | 19 +++++ 2 files changed, 98 insertions(+) diff --git a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs index f69185008..cb232c584 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.TrackImport; @@ -560,5 +561,83 @@ public void should_update_fields_for_updated_files() l[0].MediaInfo.AudioFormat == localTrack.FileTrackInfo.MediaInfo.AudioFormat)), Times.Once()); } + + [Test] + public void should_create_missing_artist_folder_with_correct_permissions() + { + GivenRootFolder(); + + // Setup root folder to exist and NOT be empty + GivenRootFolder(_otherArtistFolder); + + Mocker.GetMock() + .Setup(s => s.CreateEmptyArtistFolders) + .Returns(true); + Mocker.GetMock() + .Setup(s => s.DeleteEmptyFolders) + .Returns(false); + Mocker.GetMock() + .Setup(s => s.SetPermissionsLinux) + .Returns(true); + Mocker.GetMock() + .Setup(s => s.ChmodFolder) + .Returns("755"); + Mocker.GetMock() + .Setup(s => s.ChownGroup) + .Returns("users"); + Mocker.GetMock() + .Setup(s => s.GetArtists(It.IsAny>())) + .Returns(new List { _artist }); + Mocker.GetMock() + .Setup(s => s.FolderExists(_artist.Path)) + .Returns(false); + + Subject.Scan(new List { _artist.Path }, FilterFilesType.Known, false, new List { _artist.Id }); + + Mocker.GetMock() + .Verify(v => v.CreateFolder(_artist.Path), Times.Once()); + + Mocker.GetMock() + .Verify(v => v.SetPermissions(_artist.Path, "755", "users"), Times.Once()); + } + + [Test] + public void should_not_change_folder_permissions_when_setpermissionslinux_false() + { + GivenRootFolder(); + + // Setup root folder to exist and NOT be empty + GivenRootFolder(_otherArtistFolder); + + Mocker.GetMock() + .Setup(s => s.CreateEmptyArtistFolders) + .Returns(true); + Mocker.GetMock() + .Setup(s => s.DeleteEmptyFolders) + .Returns(false); + Mocker.GetMock() + .Setup(s => s.SetPermissionsLinux) + .Returns(false); + Mocker.GetMock() + .Setup(s => s.ChmodFolder) + .Returns("755"); + Mocker.GetMock() + .Setup(s => s.ChownGroup) + .Returns("users"); + Mocker.GetMock() + .Setup(s => s.GetArtists(It.IsAny>())) + .Returns(new List { _artist }); + Mocker.GetMock() + .Setup(s => s.FolderExists(_artist.Path)) + .Returns(false); + + Subject.Scan(new List { _artist.Path }, FilterFilesType.Known, false, new List { _artist.Id }); + + Mocker.GetMock() + .Verify(v => v.CreateFolder(_artist.Path), Times.Once()); + + Mocker.GetMock() + .Verify(v => v.SetPermissions(_artist.Path, It.IsAny(), It.IsAny()), Times.Never()); + } } } diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index a77432497..fa6d0f85e 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -161,6 +161,7 @@ public void Scan(List folders = null, FilterFilesType filter = FilterFil { _logger.Debug("Creating missing artist folder: {0}", artist.Path); _diskProvider.CreateFolder(artist.Path); + SetPermissions(artist.Path); } } else @@ -291,6 +292,24 @@ public string[] GetNonAudioFiles(string path, bool allDirectories = true) return mediaFileList.ToArray(); } + private void SetPermissions(string path) + { + if (!_configService.SetPermissionsLinux) + { + return; + } + + try + { + _diskProvider.SetPermissions(path, _configService.ChmodFolder, _configService.ChownGroup); + } + catch (Exception ex) + { + _logger.Warn(ex, "Unable to apply permissions to: " + path); + _logger.Debug(ex, ex.Message); + } + } + public List FilterPaths(string basePath, IEnumerable paths) { return paths.Where(file => !ExcludedSubFoldersRegex.IsMatch(basePath.GetRelativePath(file)))