// // DiscUtils Copyright (c) 2008-2011, Kenneth Bell // // Original NativeFileSystem contributed by bsobel: // http://discutils.codeplex.com/workitem/5190 // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // using System; using System.IO; using DiscUtils.Internal; using DiscUtils.Streams; namespace DiscUtils { /// /// Provides an implementation for OS-mounted file systems. /// public class NativeFileSystem : DiscFileSystem { private readonly bool _readOnly; /// /// Initializes a new instance of the NativeFileSystem class. /// /// The 'root' directory of the new instance. /// Only permit 'read' activities. public NativeFileSystem(string basePath, bool readOnly) { BasePath = basePath; if (!BasePath.EndsWith(@"\", StringComparison.OrdinalIgnoreCase)) { BasePath += @"\"; } _readOnly = readOnly; } /// /// Gets the base path used to create the file system. /// public string BasePath { get; } /// /// Indicates whether the file system is read-only or read-write. /// /// true if the file system is read-write. public override bool CanWrite { get { return !_readOnly; } } /// /// Provides a friendly description of the file system type. /// public override string FriendlyName { get { return "Native"; } } /// /// Gets a value indicating whether the file system is thread-safe. /// /// The Native File System is thread safe. public override bool IsThreadSafe { get { return true; } } /// /// Gets the root directory of the file system. /// public override DiscDirectoryInfo Root { get { return new DiscDirectoryInfo(this, string.Empty); } } /// /// Gets the volume label. /// public override string VolumeLabel { get { return string.Empty; } } /// /// Copies an existing file to a new file. /// /// The source file. /// The destination file. public override void CopyFile(string sourceFile, string destinationFile) { CopyFile(sourceFile, destinationFile, true); } /// /// Copies an existing file to a new file, allowing overwriting of an existing file. /// /// The source file. /// The destination file. /// Whether to permit over-writing of an existing file. public override void CopyFile(string sourceFile, string destinationFile, bool overwrite) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (sourceFile.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { sourceFile = sourceFile.Substring(1); } if (destinationFile.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { destinationFile = destinationFile.Substring(1); } File.Copy(Path.Combine(BasePath, sourceFile), Path.Combine(BasePath, destinationFile), true); } /// /// Creates a directory. /// /// The path of the new directory. public override void CreateDirectory(string path) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } Directory.CreateDirectory(Path.Combine(BasePath, path)); } /// /// Deletes a directory. /// /// The path of the directory to delete. public override void DeleteDirectory(string path) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } Directory.Delete(Path.Combine(BasePath, path)); } /// /// Deletes a directory, optionally with all descendants. /// /// The path of the directory to delete. /// Determines if the all descendants should be deleted. public override void DeleteDirectory(string path, bool recursive) { if (recursive) { foreach (string dir in GetDirectories(path)) { DeleteDirectory(dir, true); } foreach (string file in GetFiles(path)) { DeleteFile(file); } } DeleteDirectory(path); } /// /// Deletes a file. /// /// The path of the file to delete. public override void DeleteFile(string path) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } File.Delete(Path.Combine(BasePath, path)); } /// /// Indicates if a directory exists. /// /// The path to test. /// true if the directory exists. public override bool DirectoryExists(string path) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } return Directory.Exists(Path.Combine(BasePath, path)); } /// /// Indicates if a file exists. /// /// The path to test. /// true if the file exists. public override bool FileExists(string path) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } return File.Exists(Path.Combine(BasePath, path)); } /// /// Indicates if a file or directory exists. /// /// The path to test. /// true if the file or directory exists. public override bool Exists(string path) { return FileExists(path) || DirectoryExists(path); } /// /// Gets the names of subdirectories in a specified directory. /// /// The path to search. /// Array of directories. public override string[] GetDirectories(string path) { return GetDirectories(path, "*.*", SearchOption.TopDirectoryOnly); } /// /// Gets the names of subdirectories in a specified directory matching a specified /// search pattern. /// /// The path to search. /// The search string to match against. /// Array of directories matching the search pattern. public override string[] GetDirectories(string path, string searchPattern) { return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly); } /// /// Gets the names of subdirectories in a specified directory matching a specified /// search pattern, using a value to determine whether to search subdirectories. /// /// The path to search. /// The search string to match against. /// Indicates whether to search subdirectories. /// Array of directories matching the search pattern. public override string[] GetDirectories(string path, string searchPattern, SearchOption searchOption) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } try { return CleanItems(Directory.GetDirectories(Path.Combine(BasePath, path), searchPattern, searchOption)); } catch (IOException) { return new string[0]; } catch (UnauthorizedAccessException) { return new string[0]; } } /// /// Gets the names of files in a specified directory. /// /// The path to search. /// Array of files. public override string[] GetFiles(string path) { return GetFiles(path, "*.*", SearchOption.TopDirectoryOnly); } /// /// Gets the names of files in a specified directory. /// /// The path to search. /// The search string to match against. /// Array of files matching the search pattern. public override string[] GetFiles(string path, string searchPattern) { return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly); } /// /// Gets the names of files in a specified directory matching a specified /// search pattern, using a value to determine whether to search subdirectories. /// /// The path to search. /// The search string to match against. /// Indicates whether to search subdirectories. /// Array of files matching the search pattern. public override string[] GetFiles(string path, string searchPattern, SearchOption searchOption) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } try { return CleanItems(Directory.GetFiles(Path.Combine(BasePath, path), searchPattern, searchOption)); } catch (IOException) { return new string[0]; } catch (UnauthorizedAccessException) { return new string[0]; } } /// /// Gets the names of all files and subdirectories in a specified directory. /// /// The path to search. /// Array of files and subdirectories matching the search pattern. public override string[] GetFileSystemEntries(string path) { return GetFileSystemEntries(path, "*.*"); } /// /// Gets the names of files and subdirectories in a specified directory matching a specified /// search pattern. /// /// The path to search. /// The search string to match against. /// Array of files and subdirectories matching the search pattern. public override string[] GetFileSystemEntries(string path, string searchPattern) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } try { return CleanItems(Directory.GetFileSystemEntries(Path.Combine(BasePath, path), searchPattern)); } catch (IOException) { return new string[0]; } catch (UnauthorizedAccessException) { return new string[0]; } } /// /// Moves a directory. /// /// The directory to move. /// The target directory name. public override void MoveDirectory(string sourceDirectoryName, string destinationDirectoryName) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (sourceDirectoryName.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { sourceDirectoryName = sourceDirectoryName.Substring(1); } if (destinationDirectoryName.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { destinationDirectoryName = destinationDirectoryName.Substring(1); } Directory.Move(Path.Combine(BasePath, sourceDirectoryName), Path.Combine(BasePath, destinationDirectoryName)); } /// /// Moves a file. /// /// The file to move. /// The target file name. public override void MoveFile(string sourceName, string destinationName) { MoveFile(sourceName, destinationName, false); } /// /// Moves a file, allowing an existing file to be overwritten. /// /// The file to move. /// The target file name. /// Whether to permit a destination file to be overwritten. public override void MoveFile(string sourceName, string destinationName, bool overwrite) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (destinationName.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { destinationName = destinationName.Substring(1); } if (FileExists(Path.Combine(BasePath, destinationName))) { if (overwrite) { DeleteFile(Path.Combine(BasePath, destinationName)); } else { throw new IOException("File already exists"); } } if (sourceName.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { sourceName = sourceName.Substring(1); } File.Move(Path.Combine(BasePath, sourceName), Path.Combine(BasePath, destinationName)); } /// /// Opens the specified file. /// /// The full path of the file to open. /// The file mode for the created stream. /// The new stream. public override SparseStream OpenFile(string path, FileMode mode) { return OpenFile(path, mode, FileAccess.ReadWrite); } /// /// Opens the specified file. /// /// The full path of the file to open. /// The file mode for the created stream. /// The access permissions for the created stream. /// The new stream. public override SparseStream OpenFile(string path, FileMode mode, FileAccess access) { if (_readOnly && access != FileAccess.Read) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } FileShare fileShare = FileShare.None; if (access == FileAccess.Read) { fileShare = FileShare.Read; } var locator = new LocalFileLocator(BasePath); return SparseStream.FromStream(locator.Open(path, mode, access, fileShare), Ownership.Dispose); } /// /// Gets the attributes of a file or directory. /// /// The file or directory to inspect. /// The attributes of the file or directory. public override FileAttributes GetAttributes(string path) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } return File.GetAttributes(Path.Combine(BasePath, path)); } /// /// Sets the attributes of a file or directory. /// /// The file or directory to change. /// The new attributes of the file or directory. public override void SetAttributes(string path, FileAttributes newValue) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } File.SetAttributes(Path.Combine(BasePath, path), newValue); } /// /// Gets the creation time (in local time) of a file or directory. /// /// The path of the file or directory. /// The creation time. public override DateTime GetCreationTime(string path) { return GetCreationTimeUtc(path).ToLocalTime(); } /// /// Sets the creation time (in local time) of a file or directory. /// /// The path of the file or directory. /// The new time to set. public override void SetCreationTime(string path, DateTime newTime) { SetCreationTimeUtc(path, newTime.ToUniversalTime()); } /// /// Gets the creation time (in UTC) of a file or directory. /// /// The path of the file or directory. /// The creation time. public override DateTime GetCreationTimeUtc(string path) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } return File.GetCreationTimeUtc(Path.Combine(BasePath, path)); } /// /// Sets the creation time (in UTC) of a file or directory. /// /// The path of the file or directory. /// The new time to set. public override void SetCreationTimeUtc(string path, DateTime newTime) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } File.SetCreationTimeUtc(Path.Combine(BasePath, path), newTime); } /// /// Gets the last access time (in local time) of a file or directory. /// /// The path of the file or directory. /// The last access time. public override DateTime GetLastAccessTime(string path) { return GetLastAccessTimeUtc(path).ToLocalTime(); } /// /// Sets the last access time (in local time) of a file or directory. /// /// The path of the file or directory. /// The new time to set. public override void SetLastAccessTime(string path, DateTime newTime) { SetLastAccessTimeUtc(path, newTime.ToUniversalTime()); } /// /// Gets the last access time (in UTC) of a file or directory. /// /// The path of the file or directory. /// The last access time. public override DateTime GetLastAccessTimeUtc(string path) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } return File.GetLastAccessTimeUtc(Path.Combine(BasePath, path)); } /// /// Sets the last access time (in UTC) of a file or directory. /// /// The path of the file or directory. /// The new time to set. public override void SetLastAccessTimeUtc(string path, DateTime newTime) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } File.SetLastAccessTimeUtc(Path.Combine(BasePath, path), newTime); } /// /// Gets the last modification time (in local time) of a file or directory. /// /// The path of the file or directory. /// The last write time. public override DateTime GetLastWriteTime(string path) { return GetLastWriteTimeUtc(path).ToLocalTime(); } /// /// Sets the last modification time (in local time) of a file or directory. /// /// The path of the file or directory. /// The new time to set. public override void SetLastWriteTime(string path, DateTime newTime) { SetLastWriteTimeUtc(path, newTime.ToUniversalTime()); } /// /// Gets the last modification time (in UTC) of a file or directory. /// /// The path of the file or directory. /// The last write time. public override DateTime GetLastWriteTimeUtc(string path) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } return File.GetLastWriteTimeUtc(Path.Combine(BasePath, path)); } /// /// Sets the last modification time (in UTC) of a file or directory. /// /// The path of the file or directory. /// The new time to set. public override void SetLastWriteTimeUtc(string path, DateTime newTime) { if (_readOnly) { throw new UnauthorizedAccessException(); } if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } File.SetLastWriteTimeUtc(Path.Combine(BasePath, path), newTime); } /// /// Gets the length of a file. /// /// The path to the file. /// The length in bytes. public override long GetFileLength(string path) { if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase)) { path = path.Substring(1); } return new FileInfo(Path.Combine(BasePath, path)).Length; } /// /// Gets an object representing a possible file. /// /// The file path. /// The representing object. /// The file does not need to exist. public override DiscFileInfo GetFileInfo(string path) { return new DiscFileInfo(this, path); } /// /// Gets an object representing a possible directory. /// /// The directory path. /// The representing object. /// The directory does not need to exist. public override DiscDirectoryInfo GetDirectoryInfo(string path) { return new DiscDirectoryInfo(this, path); } /// /// Gets an object representing a possible file system object (file or directory). /// /// The file system path. /// The representing object. /// The file system object does not need to exist. public override DiscFileSystemInfo GetFileSystemInfo(string path) { return new DiscFileSystemInfo(this, path); } /// /// Size of the Filesystem in bytes /// public override long Size { get { DriveInfo info = new DriveInfo(BasePath); return info.TotalSize; } } /// /// Used space of the Filesystem in bytes /// public override long UsedSpace { get { return Size - AvailableSpace; } } /// /// Available space of the Filesystem in bytes /// public override long AvailableSpace { get { DriveInfo info = new DriveInfo(BasePath); return info.AvailableFreeSpace; } } private string[] CleanItems(string[] dirtyItems) { string[] cleanList = new string[dirtyItems.Length]; for (int x = 0; x < dirtyItems.Length; x++) { cleanList[x] = dirtyItems[x].Substring(BasePath.Length - 1); } return cleanList; } } }