diff --git a/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs b/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs index c60e99234..e54f6db0f 100644 --- a/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs +++ b/src/NzbDrone.Api/Config/DownloadClientConfigModule.cs @@ -7,16 +7,19 @@ namespace NzbDrone.Api.Config { public class DownloadClientConfigModule : NzbDroneConfigModule { - public DownloadClientConfigModule(IConfigService configService, RootFolderValidator rootFolderValidator, PathExistsValidator pathExistsValidator) + public DownloadClientConfigModule(IConfigService configService, + RootFolderValidator rootFolderValidator, + PathExistsValidator pathExistsValidator, + MappedNetworkDriveValidator mappedNetworkDriveValidator) : base(configService) { SharedValidator.RuleFor(c => c.DownloadedEpisodesFolder) .Cascade(CascadeMode.StopOnFirstFailure) .IsValidPath() .SetValidator(rootFolderValidator) + .SetValidator(mappedNetworkDriveValidator) .SetValidator(pathExistsValidator) .When(c => !String.IsNullOrWhiteSpace(c.DownloadedEpisodesFolder)); - } } } \ No newline at end of file diff --git a/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs b/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs index 43c5d13be..a9dd2472b 100644 --- a/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs +++ b/src/NzbDrone.Api/RemotePathMappings/RemotePathMappingModule.cs @@ -11,7 +11,9 @@ namespace NzbDrone.Api.RemotePathMappings { private readonly IRemotePathMappingService _remotePathMappingService; - public RemotePathMappingModule(IRemotePathMappingService remotePathMappingService, PathExistsValidator pathExistsValidator) + public RemotePathMappingModule(IRemotePathMappingService remotePathMappingService, + PathExistsValidator pathExistsValidator, + MappedNetworkDriveValidator mappedNetworkDriveValidator) { _remotePathMappingService = remotePathMappingService; @@ -31,6 +33,7 @@ namespace NzbDrone.Api.RemotePathMappings SharedValidator.RuleFor(c => c.LocalPath) .Cascade(CascadeMode.StopOnFirstFailure) .IsValidPath() + .SetValidator(mappedNetworkDriveValidator) .SetValidator(pathExistsValidator); } diff --git a/src/NzbDrone.Api/RootFolders/RootFolderModule.cs b/src/NzbDrone.Api/RootFolders/RootFolderModule.cs index fa6934cb4..9c9fed0d4 100644 --- a/src/NzbDrone.Api/RootFolders/RootFolderModule.cs +++ b/src/NzbDrone.Api/RootFolders/RootFolderModule.cs @@ -15,7 +15,8 @@ namespace NzbDrone.Api.RootFolders IBroadcastSignalRMessage signalRBroadcaster, RootFolderValidator rootFolderValidator, PathExistsValidator pathExistsValidator, - DroneFactoryValidator droneFactoryValidator) + DroneFactoryValidator droneFactoryValidator, + MappedNetworkDriveValidator mappedNetworkDriveValidator) : base(signalRBroadcaster) { _rootFolderService = rootFolderService; @@ -29,8 +30,9 @@ namespace NzbDrone.Api.RootFolders .Cascade(CascadeMode.StopOnFirstFailure) .IsValidPath() .SetValidator(rootFolderValidator) - .SetValidator(pathExistsValidator) - .SetValidator(droneFactoryValidator); + .SetValidator(droneFactoryValidator) + .SetValidator(mappedNetworkDriveValidator) + .SetValidator(pathExistsValidator); } private RootFolderResource GetRootFolder(int id) diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index ba8b068d8..f8ffa5b29 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -896,6 +896,7 @@ + diff --git a/src/NzbDrone.Core/Validation/Paths/MappedNetworkDriveValidator.cs b/src/NzbDrone.Core/Validation/Paths/MappedNetworkDriveValidator.cs new file mode 100644 index 000000000..1b2fd1d51 --- /dev/null +++ b/src/NzbDrone.Core/Validation/Paths/MappedNetworkDriveValidator.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; +using FluentValidation.Validators; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; + +namespace NzbDrone.Core.Validation.Paths +{ + public class MappedNetworkDriveValidator : PropertyValidator + { + private readonly IRuntimeInfo _runtimeInfo; + private readonly IDiskProvider _diskProvider; + + private static readonly Regex DriveRegex = new Regex(@"[a-z]\:\\", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public MappedNetworkDriveValidator(IRuntimeInfo runtimeInfo, IDiskProvider diskProvider) + : base("Mapped Network Drive and Windows Service") + { + _runtimeInfo = runtimeInfo; + _diskProvider = diskProvider; + } + + protected override bool IsValid(PropertyValidatorContext context) + { + if (context.PropertyValue == null) return false; + if (OsInfo.IsNotWindows) return true; + if (!_runtimeInfo.IsWindowsService) return true; + + var path = context.PropertyValue.ToString(); + + if (!DriveRegex.IsMatch(path)) return true; + + var drives = _diskProvider.GetDrives(); + + foreach (var drive in drives) + { + if (path.StartsWith(drive.Name, StringComparison.InvariantCultureIgnoreCase)) + { + if (drive.DriveType == DriveType.Network) + { + return false; + } + } + } + + return true; + } + } +} \ No newline at end of file