using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using NLog; namespace NzbDrone.Common { public class DiskProvider { enum TransferAction { Copy, Move } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, out ulong lpFreeBytesAvailable, out ulong lpTotalNumberOfBytes, out ulong lpTotalNumberOfFreeBytes); private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public virtual DateTime GetLastDirectoryWrite(string path) { if (!FolderExists(path)) { throw new DirectoryNotFoundException("Directory doesn't exist. " + path); } var dirFiles = GetFiles(path, SearchOption.AllDirectories).ToList(); if (!dirFiles.Any()) { return new DirectoryInfo(path).LastWriteTimeUtc; } return dirFiles.Select(f => new FileInfo(f)) .Max(c => c.LastWriteTimeUtc); } public virtual DateTime GetLastFileWrite(string path) { if (!FileExists(path)) throw new FileNotFoundException("File doesn't exist: " + path); return new FileInfo(path).LastWriteTimeUtc; } public virtual bool FolderExists(string path) { return Directory.Exists(path); } public virtual bool FileExists(string path) { return File.Exists(path); } public virtual string[] GetDirectories(string path) { return Directory.GetDirectories(path); } public virtual string[] GetFiles(string path, SearchOption searchOption) { return Directory.GetFiles(path, "*.*", searchOption); } public virtual long GetDirectorySize(string path) { return GetFiles(path, SearchOption.AllDirectories).Sum(e => new FileInfo(e).Length); } public virtual long GetSize(string path) { if (!FileExists(path)) throw new FileNotFoundException("File doesn't exist: " + path); var fi = new FileInfo(path); return fi.Length; } public virtual String CreateDirectory(string path) { return Directory.CreateDirectory(path).FullName; } public virtual void CopyDirectory(string source, string target) { TransferDirectory(source, target, TransferAction.Copy); } public virtual void MoveDirectory(string source, string destination) { try { TransferDirectory(source, destination, TransferAction.Move); Directory.Delete(source, true); } catch (Exception e) { e.Data.Add("Source", source); e.Data.Add("Destination", destination); throw; } } private void TransferDirectory(string source, string target, TransferAction transferAction) { Logger.Trace("{0} {1} -> {2}", transferAction, source, target); var sourceFolder = new DirectoryInfo(source); var targetFolder = new DirectoryInfo(target); if (!targetFolder.Exists) { targetFolder.Create(); } foreach (var subDir in sourceFolder.GetDirectories()) { TransferDirectory(subDir.FullName, Path.Combine(target, subDir.Name), transferAction); } foreach (var sourceFile in sourceFolder.GetFiles("*.*", SearchOption.TopDirectoryOnly)) { var destFile = Path.Combine(target, sourceFile.Name); switch (transferAction) { case TransferAction.Copy: { sourceFile.CopyTo(destFile, true); break; } case TransferAction.Move: { MoveFile(sourceFile.FullName, destFile); break; } } } } public virtual void DeleteFile(string path) { Logger.Trace("Deleting file: {0}", path); File.Delete(path); } public virtual void MoveFile(string source, string destination) { if (PathEquals(source, destination)) { Logger.Warn("Source and destination can't be the same {0}", source); return; } if (FileExists(destination)) { DeleteFile(destination); } File.Move(source, destination); } public virtual void DeleteFolder(string path, bool recursive) { Directory.Delete(path, recursive); } public virtual DateTime DirectoryDateCreated(string path) { return Directory.GetCreationTime(path); } public virtual IEnumerable GetFileInfos(string path, string pattern, SearchOption searchOption) { return new DirectoryInfo(path).EnumerateFiles(pattern, searchOption); } public virtual void InheritFolderPermissions(string filename) { var fs = File.GetAccessControl(filename); fs.SetAccessRuleProtection(false, false); File.SetAccessControl(filename, fs); } public virtual ulong FreeDiskSpace(DirectoryInfo directoryInfo) { if (!directoryInfo.Exists) throw new DirectoryNotFoundException(); ulong freeBytesAvailable; ulong totalNumberOfBytes; ulong totalNumberOfFreeBytes; bool success = GetDiskFreeSpaceEx(directoryInfo.FullName, out freeBytesAvailable, out totalNumberOfBytes, out totalNumberOfFreeBytes); if (!success) throw new System.ComponentModel.Win32Exception(); return freeBytesAvailable; } public virtual string ReadAllText(string filePath) { return File.ReadAllText(filePath); } public virtual void WriteAllText(string filename, string contents) { File.WriteAllText(filename, contents); } public static bool PathEquals(string firstPath, string secondPath) { return String.Equals(firstPath.NormalizePath(), secondPath.NormalizePath(), StringComparison.InvariantCultureIgnoreCase); } public virtual void FileSetLastWriteTimeUtc(string path, DateTime dateTime) { File.SetLastWriteTimeUtc(path, dateTime); } public virtual void DirectorySetLastWriteTimeUtc(string path, DateTime dateTime) { Directory.SetLastWriteTimeUtc(path, dateTime); } public virtual bool IsFolderLocked(string path) { var files = GetFileInfos(path, "*.*", SearchOption.AllDirectories); foreach(var fileInfo in files) { if (IsFileLocked(fileInfo)) return true; } return false; } public virtual bool IsFileLocked(FileInfo file) { FileStream stream = null; try { stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None); } catch (IOException) { return true; } finally { if (stream != null) stream.Close(); } //file is not locked return false; } public virtual bool IsChildOfPath(string child, string parent) { if (Path.GetFullPath(child).StartsWith(Path.GetFullPath(parent))) return true; return false; } } }