diff --git a/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs b/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs index d1b40394f..483531975 100644 --- a/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs +++ b/src/NzbDrone.Core.Test/RootFolderTests/RootFolderServiceFixture.cs @@ -4,6 +4,7 @@ using Moq; using NUnit.Framework; using NzbDrone.Common.Disk; +using NzbDrone.Core.Configuration; using NzbDrone.Core.RootFolders; using NzbDrone.Core.Test.Framework; using NzbDrone.Test.Common; @@ -21,6 +22,10 @@ public void Setup() .Setup(m => m.FolderExists(It.IsAny())) .Returns(true); + Mocker.GetMock() + .Setup(m => m.FolderWritable(It.IsAny())) + .Returns(true); + Mocker.GetMock() .Setup(s => s.All()) .Returns(new List()); @@ -77,6 +82,26 @@ public void adding_duplicated_root_folder_should_throw() Assert.Throws(() => Subject.Add(new RootFolder { Path = @"C:\TV".AsOsAgnostic() })); } - + [Test] + public void should_throw_when_adding_not_writable_folder() + { + Mocker.GetMock() + .Setup(m => m.FolderWritable(It.IsAny())) + .Returns(false); + + Assert.Throws(() => Subject.Add(new RootFolder { Path = @"C:\TV".AsOsAgnostic() })); + } + + [Test] + public void should_throw_when_same_path_as_drone_factory() + { + var path = @"C:\TV".AsOsAgnostic(); + + Mocker.GetMock() + .SetupGet(s => s.DownloadedEpisodesFolder) + .Returns(path); + + Assert.Throws(() => Subject.Add(new RootFolder { Path = path })); + } } } \ No newline at end of file diff --git a/src/NzbDrone.Core/RootFolders/RootFolderService.cs b/src/NzbDrone.Core/RootFolders/RootFolderService.cs index e27f996a9..9577c7981 100644 --- a/src/NzbDrone.Core/RootFolders/RootFolderService.cs +++ b/src/NzbDrone.Core/RootFolders/RootFolderService.cs @@ -6,7 +6,6 @@ using NzbDrone.Common; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; -using NzbDrone.Common.Instrumentation; using NzbDrone.Core.Configuration; using NzbDrone.Core.Tv; @@ -68,10 +67,20 @@ public List AllWithUnmappedFolders() rootFolders.ForEach(folder => { - if (folder.Path.IsPathValid() && _diskProvider.FolderExists(folder.Path)) + try { - folder.FreeSpace = _diskProvider.GetAvailableSpace(folder.Path); - folder.UnmappedFolders = GetUnmappedFolders(folder.Path); + if (folder.Path.IsPathValid() && _diskProvider.FolderExists(folder.Path)) + { + folder.FreeSpace = _diskProvider.GetAvailableSpace(folder.Path); + folder.UnmappedFolders = GetUnmappedFolders(folder.Path); + } + } + //We don't want an exception to prevent the root folders from loading in the UI, so they can still be deleted + catch (Exception ex) + { + _logger.ErrorException("Unable to get free space and unmapped folders for root folder: " + folder.Path, ex); + folder.FreeSpace = 0; + folder.UnmappedFolders = new List(); } }); @@ -83,17 +92,29 @@ public RootFolder Add(RootFolder rootFolder) var all = All(); if (String.IsNullOrWhiteSpace(rootFolder.Path) || !Path.IsPathRooted(rootFolder.Path)) + { throw new ArgumentException("Invalid path"); + } if (!_diskProvider.FolderExists(rootFolder.Path)) + { throw new DirectoryNotFoundException("Can't add root directory that doesn't exist."); + } if (all.Exists(r => r.Path.PathEquals(rootFolder.Path))) + { throw new InvalidOperationException("Recent directory already exists."); + } - if (!String.IsNullOrWhiteSpace(_configService.DownloadedEpisodesFolder) && - _configService.DownloadedEpisodesFolder.PathEquals(rootFolder.Path)) + if (_configService.DownloadedEpisodesFolder.IsNotNullOrWhiteSpace() && _configService.DownloadedEpisodesFolder.PathEquals(rootFolder.Path)) + { throw new InvalidOperationException("Drone Factory folder cannot be used."); + } + + if (!_diskProvider.FolderWritable(rootFolder.Path)) + { + throw new UnauthorizedAccessException(String.Format("Root folder path '{0}' is not writable by user '{1}'", rootFolder.Path, Environment.UserName)); + } _rootFolderRepository.Insert(rootFolder);