From 0ebbe102c9da017f573e4389fd7df5a5fbe013cd Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Thu, 12 Sep 2013 21:59:29 -0700 Subject: [PATCH] disk provider removes readonly flag before trying to delete files. --- .../DirectoryLookupServiceFixture.cs | 3 - .../DiskProviderTests/DiskProviderFixture.cs | 59 +++++++++++++++++-- .../NzbDrone.Common.Test.ncrunchproject | 28 ++++++++- NzbDrone.Common.Test/PathExtensionFixture.cs | 5 +- NzbDrone.Common/DiskProvider.cs | 52 ++++++++-------- .../ParserTests/ParserFixture.cs | 1 + .../RootFolders/RootFolderService.cs | 7 ++- NzbDrone.Test.Common/TestBase.cs | 5 ++ .../UpdateEngine/BackupAndRestore.cs | 1 - NzbDrone.ncrunchsolution | 2 +- 10 files changed, 118 insertions(+), 45 deletions(-) diff --git a/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs b/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs index 7399a8f82..849773ddb 100644 --- a/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs +++ b/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs @@ -37,9 +37,6 @@ namespace NzbDrone.Api.Test "Windows" }; - Mocker.GetMock() - .SetupGet(s => s.SpecialFolders) - .Returns(new HashSet { "$recycle.bin", "system volume information", "recycler" }); } private void SetupFolders(string root) diff --git a/NzbDrone.Common.Test/DiskProviderTests/DiskProviderFixture.cs b/NzbDrone.Common.Test/DiskProviderTests/DiskProviderFixture.cs index 1bcb330f1..64be8603f 100644 --- a/NzbDrone.Common.Test/DiskProviderTests/DiskProviderFixture.cs +++ b/NzbDrone.Common.Test/DiskProviderTests/DiskProviderFixture.cs @@ -23,6 +23,10 @@ namespace NzbDrone.Common.Test.DiskProviderTests if (_binFolderCopy.Exists) { + foreach (var file in _binFolderCopy.GetFiles("*", SearchOption.AllDirectories)) + { + file.Attributes = FileAttributes.Normal; + } _binFolderCopy.Delete(true); } @@ -83,11 +87,7 @@ namespace NzbDrone.Common.Test.DiskProviderTests [Test] public void CopyFolder_should_copy_folder() { - - Subject.CopyFolder(_binFolder.FullName, _binFolderCopy.FullName); - - VerifyCopy(); } @@ -127,6 +127,22 @@ namespace NzbDrone.Common.Test.DiskProviderTests } + [Test] + public void move_read_only_file() + { + var source = GetTestFilePath(); + var destination = GetTestFilePath(); + + Subject.WriteAllText(source, "SourceFile"); + Subject.WriteAllText(destination, "DestinationFile"); + + File.SetAttributes(source, FileAttributes.ReadOnly); + File.SetAttributes(destination, FileAttributes.ReadOnly); + + Subject.MoveFile(source, destination); + } + + [Test] @@ -139,7 +155,7 @@ namespace NzbDrone.Common.Test.DiskProviderTests [Test] public void folder_should_return_correct_value_for_last_write() { - var testFile = Path.Combine(SandboxFolder, "newfile.txt"); + var testFile = GetTestFilePath(); TestLogger.Info("Path is: {0}", testFile); @@ -149,6 +165,39 @@ namespace NzbDrone.Common.Test.DiskProviderTests Subject.GetLastFolderWrite(SandboxFolder).Should().BeBefore(DateTime.UtcNow); } + [Test] + public void should_return_false_for_unlocked_file() + { + var testFile = GetTestFilePath(); + Subject.WriteAllText(testFile, new Guid().ToString()); + + Subject.IsFileLocked(testFile).Should().BeFalse(); + } + + [Test] + public void should_return_false_for_unlocked_and_readonly_file() + { + var testFile = GetTestFilePath(); + Subject.WriteAllText(testFile, new Guid().ToString()); + + File.SetAttributes(testFile, FileAttributes.ReadOnly); + + Subject.IsFileLocked(testFile).Should().BeFalse(); + } + + + [Test] + public void should_return_true_for_unlocked_file() + { + var testFile = GetTestFilePath(); + Subject.WriteAllText(testFile, new Guid().ToString()); + + using (var file = File.OpenWrite(testFile)) + { + Subject.IsFileLocked(testFile).Should().BeTrue(); + } + } + [Test] [Explicit] public void check_last_write() diff --git a/NzbDrone.Common.Test/NzbDrone.Common.Test.ncrunchproject b/NzbDrone.Common.Test/NzbDrone.Common.Test.ncrunchproject index 792b5fb01..21e25ddd5 100644 --- a/NzbDrone.Common.Test/NzbDrone.Common.Test.ncrunchproject +++ b/NzbDrone.Common.Test/NzbDrone.Common.Test.ncrunchproject @@ -27,10 +27,34 @@ NzbDrone\.Common\.Test\.EventingTests\.ServiceNameFixture\..* - NzbDrone\.Common\.Test\.ProcessProviderTests\..* + NzbDrone\.Common\.Test\.ServiceFactoryFixture\..* + + + NzbDrone.Common.Test.ProcessProviderTests.ToString_on_new_processInfo + + + NzbDrone.Common.Test.ProcessProviderTests.Should_be_able_to_start_process + + + NzbDrone.Common.Test.ProcessProviderTests.kill_all_should_kill_all_process_with_name + + + NzbDrone.Common.Test.ProcessProviderTests.GetProcessById_should_return_null_for_invalid_process(9999) + + + NzbDrone.Common.Test.ProcessProviderTests.GetProcessById_should_return_null_for_invalid_process(-1) + + + NzbDrone.Common.Test.ProcessProviderTests.GetProcessById_should_return_null_for_invalid_process(0) + + + NzbDrone\.Common\.Test\.ServiceProviderTests\..* + + NzbDrone.Common.Test.DiskProviderTests.DiskProviderFixture.folder_should_return_correct_value_for_last_write + - NzbDrone\.Common\.Test\.ServiceFactoryFixture\..* + NzbDrone\.Common\.Test\.DiskProviderTests\.DiskProviderFixture\..* \ No newline at end of file diff --git a/NzbDrone.Common.Test/PathExtensionFixture.cs b/NzbDrone.Common.Test/PathExtensionFixture.cs index 907d13d4c..fbc2fb6b6 100644 --- a/NzbDrone.Common.Test/PathExtensionFixture.cs +++ b/NzbDrone.Common.Test/PathExtensionFixture.cs @@ -126,17 +126,16 @@ namespace NzbDrone.Common.Test } - [Test] public void get_actual_casing_should_return_actual_casing_for_local_dir_in_windows() { WindowsOnly(); - var path = Directory.GetCurrentDirectory(); + var path = Directory.GetCurrentDirectory().Replace("c:\\","C:\\"); + path.ToUpper().GetActualCasing().Should().Be(path); path.ToLower().GetActualCasing().Should().Be(path); } - [Test] public void get_actual_casing_should_return_original_value_in_linux() { diff --git a/NzbDrone.Common/DiskProvider.cs b/NzbDrone.Common/DiskProvider.cs index 48a9e0602..1affaceb4 100644 --- a/NzbDrone.Common/DiskProvider.cs +++ b/NzbDrone.Common/DiskProvider.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -14,7 +13,6 @@ namespace NzbDrone.Common { public interface IDiskProvider { - HashSet SpecialFolders { get; } DateTime GetLastFolderWrite(string path); DateTime GetLastFileWrite(string path); void EnsureFolder(string path); @@ -62,14 +60,6 @@ namespace NzbDrone.Common private static readonly Logger Logger = NzbDroneLogger.GetLogger(); - public HashSet SpecialFolders - { - get - { - return new HashSet { "$recycle.bin", "system volume information", "recycler" }; - } - } - public DateTime GetLastFolderWrite(string path) { Ensure.That(() => path).IsValidPath(); @@ -95,7 +85,9 @@ namespace NzbDrone.Common Ensure.That(() => path).IsValidPath(); if (!FileExists(path)) + { throw new FileNotFoundException("File doesn't exist: " + path); + } return new FileInfo(path).LastWriteTimeUtc; } @@ -156,7 +148,9 @@ namespace NzbDrone.Common Ensure.That(() => path).IsValidPath(); if (!FileExists(path)) + { throw new FileNotFoundException("File doesn't exist: " + path); + } var fi = new FileInfo(path); return fi.Length; @@ -184,7 +178,7 @@ namespace NzbDrone.Common try { TransferFolder(source, destination, TransferAction.Move); - Directory.Delete(source, true); + DeleteFolder(source, true); } catch (Exception e) { @@ -239,8 +233,10 @@ namespace NzbDrone.Common public void DeleteFile(string path) { Ensure.That(() => path).IsValidPath(); - Logger.Trace("Deleting file: {0}", path); + + RemoveReadOnly(path); + File.Delete(path); } @@ -260,6 +256,7 @@ namespace NzbDrone.Common DeleteFile(destination); } + RemoveReadOnly(source); File.Move(source, destination); } @@ -348,7 +345,7 @@ namespace NzbDrone.Common public void WriteAllText(string filename, string contents) { Ensure.That(() => filename).IsValidPath(); - + RemoveReadOnly(filename); File.WriteAllText(filename, contents); } @@ -368,28 +365,17 @@ namespace NzbDrone.Common public bool IsFileLocked(string file) { - - //TOOD: Needs test - //TODO: move to using instead of trycatch - //TODO: prob should use OpenWrite to check for lock. - FileStream stream = null; - try { - stream = File.OpenRead(file); + using (File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None)) + { + return false; + } } catch (IOException) { return true; } - finally - { - if (stream != null) - stream.Close(); - } - - //file is not locked - return false; } public string GetPathRoot(string path) @@ -445,6 +431,16 @@ namespace NzbDrone.Common return false; } + + private static void RemoveReadOnly(string path) + { + if (File.Exists(path)) + { + var newAttributes = File.GetAttributes(path) & ~(FileAttributes.ReadOnly); + File.SetAttributes(path, newAttributes); + } + } + public FileAttributes GetFileAttributes(string path) { return File.GetAttributes(path); diff --git a/NzbDrone.Core.Test/ParserTests/ParserFixture.cs b/NzbDrone.Core.Test/ParserTests/ParserFixture.cs index 36c4faccb..aad858d36 100644 --- a/NzbDrone.Core.Test/ParserTests/ParserFixture.cs +++ b/NzbDrone.Core.Test/ParserTests/ParserFixture.cs @@ -81,6 +81,7 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("Portlandia.S03E10.Alexandra.720p.WEB-DL.AAC2.0.H.264-CROM.mkv", "Portlandia", 3, 10)] [TestCase("(Game of Thrones s03 e - \"Game of Thrones Season 3 Episode 10\"", "Game of Thrones", 3, 10)] [TestCase("House.Hunters.International.S05E607.720p.hdtv.x264", "House.Hunters.International", 5, 607)] + [TestCase("Adventure.Time.With.Finn.And.Jake.S01E20.720p.BluRay.x264-DEiMOS", "Adventure.Time.With.Finn.And.Jake", 1, 20)] public void ParseTitle_single(string postTitle, string title, int seasonNumber, int episodeNumber) { var result = Parser.Parser.ParseTitle(postTitle); diff --git a/NzbDrone.Core/RootFolders/RootFolderService.cs b/NzbDrone.Core/RootFolders/RootFolderService.cs index 7360f898c..9e441d91d 100644 --- a/NzbDrone.Core/RootFolders/RootFolderService.cs +++ b/NzbDrone.Core/RootFolders/RootFolderService.cs @@ -24,12 +24,15 @@ namespace NzbDrone.Core.RootFolders public class RootFolderService : IRootFolderService { - private static readonly Logger Logger = NzbDroneLogger.GetLogger(); + private static readonly Logger Logger = NzbDroneLogger.GetLogger(); private readonly IBasicRepository _rootFolderRepository; private readonly IDiskProvider _diskProvider; private readonly ISeriesRepository _seriesRepository; private readonly IConfigService _configService; + private static readonly HashSet SpecialFolders = new HashSet { "$recycle.bin", "system volume information", "recycler" }; + + public RootFolderService(IBasicRepository rootFolderRepository, IDiskProvider diskProvider, ISeriesRepository seriesRepository, @@ -119,7 +122,7 @@ namespace NzbDrone.Core.RootFolders if (Path.GetPathRoot(path).Equals(path, StringComparison.InvariantCultureIgnoreCase)) { - var setToRemove = _diskProvider.SpecialFolders; + var setToRemove = SpecialFolders; results.RemoveAll(x => setToRemove.Contains(new DirectoryInfo(x.Path.ToLowerInvariant()).Name)); } diff --git a/NzbDrone.Test.Common/TestBase.cs b/NzbDrone.Test.Common/TestBase.cs index 2b3d8ec47..4cbaad94e 100644 --- a/NzbDrone.Test.Common/TestBase.cs +++ b/NzbDrone.Test.Common/TestBase.cs @@ -157,6 +157,11 @@ namespace NzbDrone.Test.Common return Path.Combine(SandboxFolder, fileName); } + protected string GetTestFilePath() + { + return GetTestFilePath(Path.GetTempFileName()); + } + protected string SandboxFolder { get diff --git a/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs b/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs index 78c3b8c73..91552105c 100644 --- a/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs +++ b/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs @@ -31,7 +31,6 @@ namespace NzbDrone.Update.UpdateEngine public void Restore(string target) { - //TODO:this should ignore single file failures. _logger.Info("Attempting to rollback upgrade"); _diskProvider.CopyFolder(_appFolderInfo.GetUpdateBackUpFolder(), target); } diff --git a/NzbDrone.ncrunchsolution b/NzbDrone.ncrunchsolution index 04f007565..81e25e1f2 100644 --- a/NzbDrone.ncrunchsolution +++ b/NzbDrone.ncrunchsolution @@ -7,7 +7,7 @@ Disabled Disabled Disabled - Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk;Fast:DlN0cnVjdHVyYWxOb2RlBAAAABNEb2VzTm90SGF2ZUNhdGVnb3J5D0ludGVncmF0aW9uVGVzdBNEb2VzTm90SGF2ZUNhdGVnb3J5BkRiVGVzdApJc0ltcGFjdGVkCUlzRmFpbGluZwAAAAAAAAAAAQAAAA== + Run all tests automatically:BFRydWU=;Run all tests manually:BUZhbHNl;Run impacted tests automatically, others manually (experimental!):CklzSW1wYWN0ZWQ=;Run pinned tests automatically, others manually:CElzUGlubmVk;Fast:DlN0cnVjdHVyYWxOb2RlAwAAABNEb2VzTm90SGF2ZUNhdGVnb3J5D0ludGVncmF0aW9uVGVzdBNEb2VzTm90SGF2ZUNhdGVnb3J5BkRiVGVzdApJc0ltcGFjdGVkAAAAAAAAAAA= \ No newline at end of file