From 5215a764d579c3f3d0ed08e552d6e60096529156 Mon Sep 17 00:00:00 2001 From: Taloth Saldono Date: Sat, 7 Sep 2019 12:12:22 +0200 Subject: [PATCH] Fixed: Copy linux permission mask when moving folder to recycle bin folder fixes #3161 --- .../DiskTests/DiskTransferServiceFixture.cs | 6 ++++ src/NzbDrone.Common/Disk/DiskProviderBase.cs | 1 + .../Disk/DiskTransferService.cs | 2 ++ src/NzbDrone.Common/Disk/IDiskProvider.cs | 1 + .../DiskProviderTests/DiskProviderFixture.cs | 30 +++++++++++++++++++ src/NzbDrone.Mono/Disk/DiskProvider.cs | 23 ++++++++++++++ src/NzbDrone.Windows/Disk/DiskProvider.cs | 7 ++++- 7 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs b/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs index 5a216c719..3e2ed7590 100644 --- a/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs +++ b/src/NzbDrone.Common.Test/DiskTests/DiskTransferServiceFixture.cs @@ -989,6 +989,9 @@ namespace NzbDrone.Common.Test.DiskTests Mocker.GetMock() .Setup(v => v.GetFileInfos(It.IsAny(), It.IsAny())) .Returns(new List()); + + Mocker.GetMock() + .Setup(v => v.CopyPermissions(It.IsAny(), It.IsAny(), false)); } private void WithRealDiskProvider() @@ -1045,6 +1048,9 @@ namespace NzbDrone.Common.Test.DiskTests Mocker.GetMock() .Setup(v => v.OpenReadStream(It.IsAny())) .Returns(s => new FileStream(s, FileMode.Open, FileAccess.Read)); + + Mocker.GetMock() + .Setup(v => v.CopyPermissions(It.IsAny(), It.IsAny(), false)); } private void WithMockMount(string root) diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index 6bbbb3343..65b013954 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -39,6 +39,7 @@ namespace NzbDrone.Common.Disk public abstract long? GetAvailableSpace(string path); public abstract void InheritFolderPermissions(string filename); public abstract void SetPermissions(string path, string mask, string user, string group); + public abstract void CopyPermissions(string sourcePath, string targetPath, bool includeOwner); public abstract long? GetTotalSize(string path); public DateTime FolderGetCreationTime(string path) diff --git a/src/NzbDrone.Common/Disk/DiskTransferService.cs b/src/NzbDrone.Common/Disk/DiskTransferService.cs index 947ad16d3..661426210 100644 --- a/src/NzbDrone.Common/Disk/DiskTransferService.cs +++ b/src/NzbDrone.Common/Disk/DiskTransferService.cs @@ -76,6 +76,8 @@ namespace NzbDrone.Common.Disk if (!_diskProvider.FolderExists(targetPath)) { _diskProvider.CreateFolder(targetPath); + + _diskProvider.CopyPermissions(sourcePath, targetPath); } var result = mode; diff --git a/src/NzbDrone.Common/Disk/IDiskProvider.cs b/src/NzbDrone.Common/Disk/IDiskProvider.cs index c4cec3fc0..e3bbc23f7 100644 --- a/src/NzbDrone.Common/Disk/IDiskProvider.cs +++ b/src/NzbDrone.Common/Disk/IDiskProvider.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Common.Disk long? GetAvailableSpace(string path); void InheritFolderPermissions(string filename); void SetPermissions(string path, string mask, string user, string group); + void CopyPermissions(string sourcePath, string targetPath, bool includeOwner = false); long? GetTotalSize(string path); DateTime FolderGetCreationTime(string path); DateTime FolderGetLastWrite(string path); diff --git a/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs b/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs index 956734535..885d68688 100644 --- a/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs +++ b/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using FluentAssertions; using Mono.Unix; +using Mono.Unix.Native; using Moq; using NUnit.Framework; using NzbDrone.Common.Disk; @@ -127,5 +128,34 @@ namespace NzbDrone.Mono.Test.DiskProviderTests mount.Should().NotBeNull(); mount.RootDirectory.Should().Be(rootDir); } + + [Test] + public void should_copy_folder_permissions() + { + var src = GetTempFilePath(); + var dst = GetTempFilePath(); + + Directory.CreateDirectory(src); + + // Toggle one of the permission flags + Syscall.stat(src, out var origStat); + Syscall.chmod(src, origStat.st_mode ^ FilePermissions.S_IWGRP); + + // Verify test setup + Syscall.stat(src, out var srcStat); + srcStat.st_mode.Should().NotBe(origStat.st_mode); + + Subject.CreateFolder(dst); + + // Verify test setup + Syscall.stat(dst, out var dstStat); + dstStat.st_mode.Should().Be(origStat.st_mode); + + Subject.CopyPermissions(src, dst, false); + + // Verify CopyPermissions + Syscall.stat(dst, out dstStat); + dstStat.st_mode.Should().Be(srcStat.st_mode); + } } } diff --git a/src/NzbDrone.Mono/Disk/DiskProvider.cs b/src/NzbDrone.Mono/Disk/DiskProvider.cs index 2eb525966..820783be7 100644 --- a/src/NzbDrone.Mono/Disk/DiskProvider.cs +++ b/src/NzbDrone.Mono/Disk/DiskProvider.cs @@ -87,6 +87,29 @@ namespace NzbDrone.Mono.Disk SetOwner(path, user, group); } + public override void CopyPermissions(string sourcePath, string targetPath, bool includeOwner) + { + try + { + Syscall.stat(sourcePath, out var srcStat); + Syscall.stat(targetPath, out var tgtStat); + + if (srcStat.st_mode != tgtStat.st_mode) + { + Syscall.chmod(targetPath, srcStat.st_mode); + } + + if (includeOwner && (srcStat.st_uid != tgtStat.st_uid || srcStat.st_gid != tgtStat.st_gid)) + { + Syscall.chown(targetPath, srcStat.st_uid, srcStat.st_gid); + } + } + catch (Exception ex) + { + Logger.Debug(ex, "Failed to copy permissions from {0} to {1}", sourcePath, targetPath); + } + } + protected override List GetAllMounts() { return _procMountProvider.GetMounts() diff --git a/src/NzbDrone.Windows/Disk/DiskProvider.cs b/src/NzbDrone.Windows/Disk/DiskProvider.cs index 92a2567a1..18b286526 100644 --- a/src/NzbDrone.Windows/Disk/DiskProvider.cs +++ b/src/NzbDrone.Windows/Disk/DiskProvider.cs @@ -57,7 +57,12 @@ namespace NzbDrone.Windows.Disk public override void SetPermissions(string path, string mask, string user, string group) { - + + } + + public override void CopyPermissions(string sourcePath, string targetPath, bool includeOwner) + { + } public override long? GetTotalSize(string path)