aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/IO/ManagedFileSystem.cs
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2017-08-16 02:43:41 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2017-08-16 02:43:41 -0400
commitbfcd1b520fd79b893e721ba916ae5e1656407d2f (patch)
tree6a05119800484435fb384da25c6390054a27c3c3 /Emby.Server.Implementations/IO/ManagedFileSystem.cs
parente3531534b85aeaaa3e4aaf462d5e77ea142dc762 (diff)
merge common implementations and server implementations
Diffstat (limited to 'Emby.Server.Implementations/IO/ManagedFileSystem.cs')
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs1057
1 files changed, 1057 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
new file mode 100644
index 000000000..0d85a977c
--- /dev/null
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -0,0 +1,1057 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.System;
+
+namespace Emby.Server.Implementations.IO
+{
+ /// <summary>
+ /// Class ManagedFileSystem
+ /// </summary>
+ public class ManagedFileSystem : IFileSystem
+ {
+ protected ILogger Logger;
+
+ private readonly bool _supportsAsyncFileStreams;
+ private char[] _invalidFileNameChars;
+ private readonly List<IShortcutHandler> _shortcutHandlers = new List<IShortcutHandler>();
+ private bool EnableFileSystemRequestConcat;
+
+ private string _tempPath;
+
+ private SharpCifsFileSystem _sharpCifsFileSystem;
+
+ public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string tempPath)
+ {
+ Logger = logger;
+ _supportsAsyncFileStreams = true;
+ _tempPath = tempPath;
+
+ // On Linux, this needs to be true or symbolic links are ignored
+ EnableFileSystemRequestConcat = environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows &&
+ environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX;
+
+ SetInvalidFileNameChars(environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows);
+
+ _sharpCifsFileSystem = new SharpCifsFileSystem(environmentInfo.OperatingSystem);
+ }
+
+ public void AddShortcutHandler(IShortcutHandler handler)
+ {
+ _shortcutHandlers.Add(handler);
+ }
+
+ protected void SetInvalidFileNameChars(bool enableManagedInvalidFileNameChars)
+ {
+ if (enableManagedInvalidFileNameChars)
+ {
+ _invalidFileNameChars = Path.GetInvalidFileNameChars();
+ }
+ else
+ {
+ // GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac.
+ _invalidFileNameChars = new char[41] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+ '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12',
+ '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D',
+ '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' };
+ }
+ }
+
+ public char DirectorySeparatorChar
+ {
+ get
+ {
+ return Path.DirectorySeparatorChar;
+ }
+ }
+
+ public string GetFullPath(string path)
+ {
+ return Path.GetFullPath(path);
+ }
+
+ /// <summary>
+ /// Determines whether the specified filename is shortcut.
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
+ /// <exception cref="System.ArgumentNullException">filename</exception>
+ public virtual bool IsShortcut(string filename)
+ {
+ if (string.IsNullOrEmpty(filename))
+ {
+ throw new ArgumentNullException("filename");
+ }
+
+ var extension = Path.GetExtension(filename);
+ return _shortcutHandlers.Any(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
+ }
+
+ /// <summary>
+ /// Resolves the shortcut.
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns>System.String.</returns>
+ /// <exception cref="System.ArgumentNullException">filename</exception>
+ public virtual string ResolveShortcut(string filename)
+ {
+ if (string.IsNullOrEmpty(filename))
+ {
+ throw new ArgumentNullException("filename");
+ }
+
+ var extension = Path.GetExtension(filename);
+ var handler = _shortcutHandlers.FirstOrDefault(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
+
+ if (handler != null)
+ {
+ return handler.Resolve(filename);
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Creates the shortcut.
+ /// </summary>
+ /// <param name="shortcutPath">The shortcut path.</param>
+ /// <param name="target">The target.</param>
+ /// <exception cref="System.ArgumentNullException">
+ /// shortcutPath
+ /// or
+ /// target
+ /// </exception>
+ public void CreateShortcut(string shortcutPath, string target)
+ {
+ if (string.IsNullOrEmpty(shortcutPath))
+ {
+ throw new ArgumentNullException("shortcutPath");
+ }
+
+ if (string.IsNullOrEmpty(target))
+ {
+ throw new ArgumentNullException("target");
+ }
+
+ var extension = Path.GetExtension(shortcutPath);
+ var handler = _shortcutHandlers.FirstOrDefault(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
+
+ if (handler != null)
+ {
+ handler.Create(shortcutPath, target);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Returns a <see cref="FileSystemMetadata"/> object for the specified file or directory path.
+ /// </summary>
+ /// <param name="path">A path to a file or directory.</param>
+ /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
+ /// <remarks>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's
+ /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and all other properties will reflect the properties of the directory.</remarks>
+ public FileSystemMetadata GetFileSystemInfo(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFileSystemInfo(path);
+ }
+
+ // Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists
+ if (Path.HasExtension(path))
+ {
+ var fileInfo = new FileInfo(path);
+
+ if (fileInfo.Exists)
+ {
+ return GetFileSystemMetadata(fileInfo);
+ }
+
+ return GetFileSystemMetadata(new DirectoryInfo(path));
+ }
+ else
+ {
+ var fileInfo = new DirectoryInfo(path);
+
+ if (fileInfo.Exists)
+ {
+ return GetFileSystemMetadata(fileInfo);
+ }
+
+ return GetFileSystemMetadata(new FileInfo(path));
+ }
+ }
+
+ /// <summary>
+ /// Returns a <see cref="FileSystemMetadata"/> object for the specified file path.
+ /// </summary>
+ /// <param name="path">A path to a file.</param>
+ /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
+ /// <remarks><para>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's
+ /// <see cref="FileSystemMetadata.IsDirectory"/> property and the <see cref="FileSystemMetadata.Exists"/> property will both be set to false.</para>
+ /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks>
+ public FileSystemMetadata GetFileInfo(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFileInfo(path);
+ }
+
+ var fileInfo = new FileInfo(path);
+
+ return GetFileSystemMetadata(fileInfo);
+ }
+
+ /// <summary>
+ /// Returns a <see cref="FileSystemMetadata"/> object for the specified directory path.
+ /// </summary>
+ /// <param name="path">A path to a directory.</param>
+ /// <returns>A <see cref="FileSystemMetadata"/> object.</returns>
+ /// <remarks><para>If the specified path points to a file, the returned <see cref="FileSystemMetadata"/> object's
+ /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and the <see cref="FileSystemMetadata.Exists"/> property will be set to false.</para>
+ /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks>
+ public FileSystemMetadata GetDirectoryInfo(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetDirectoryInfo(path);
+ }
+
+ var fileInfo = new DirectoryInfo(path);
+
+ return GetFileSystemMetadata(fileInfo);
+ }
+
+ private FileSystemMetadata GetFileSystemMetadata(FileSystemInfo info)
+ {
+ var result = new FileSystemMetadata();
+
+ result.Exists = info.Exists;
+ result.FullName = info.FullName;
+ result.Extension = info.Extension;
+ result.Name = info.Name;
+
+ if (result.Exists)
+ {
+ var attributes = info.Attributes;
+ result.IsDirectory = info is DirectoryInfo || (attributes & FileAttributes.Directory) == FileAttributes.Directory;
+ result.IsHidden = (attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
+ result.IsReadOnly = (attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;
+
+ var fileInfo = info as FileInfo;
+ if (fileInfo != null)
+ {
+ result.Length = fileInfo.Length;
+ result.DirectoryName = fileInfo.DirectoryName;
+ }
+
+ result.CreationTimeUtc = GetCreationTimeUtc(info);
+ result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
+ }
+ else
+ {
+ result.IsDirectory = info is DirectoryInfo;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// The space char
+ /// </summary>
+ private const char SpaceChar = ' ';
+
+ /// <summary>
+ /// Takes a filename and removes invalid characters
+ /// </summary>
+ /// <param name="filename">The filename.</param>
+ /// <returns>System.String.</returns>
+ /// <exception cref="System.ArgumentNullException">filename</exception>
+ public string GetValidFilename(string filename)
+ {
+ if (string.IsNullOrEmpty(filename))
+ {
+ throw new ArgumentNullException("filename");
+ }
+
+ var builder = new StringBuilder(filename);
+
+ foreach (var c in _invalidFileNameChars)
+ {
+ builder = builder.Replace(c, SpaceChar);
+ }
+
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Gets the creation time UTC.
+ /// </summary>
+ /// <param name="info">The info.</param>
+ /// <returns>DateTime.</returns>
+ public DateTime GetCreationTimeUtc(FileSystemInfo info)
+ {
+ // This could throw an error on some file systems that have dates out of range
+ try
+ {
+ return info.CreationTimeUtc;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error determining CreationTimeUtc for {0}", ex, info.FullName);
+ return DateTime.MinValue;
+ }
+ }
+
+ /// <summary>
+ /// Gets the creation time UTC.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>DateTime.</returns>
+ public DateTime GetCreationTimeUtc(string path)
+ {
+ return GetCreationTimeUtc(GetFileSystemInfo(path));
+ }
+
+ public DateTime GetCreationTimeUtc(FileSystemMetadata info)
+ {
+ return info.CreationTimeUtc;
+ }
+
+ public DateTime GetLastWriteTimeUtc(FileSystemMetadata info)
+ {
+ return info.LastWriteTimeUtc;
+ }
+
+ /// <summary>
+ /// Gets the creation time UTC.
+ /// </summary>
+ /// <param name="info">The info.</param>
+ /// <returns>DateTime.</returns>
+ public DateTime GetLastWriteTimeUtc(FileSystemInfo info)
+ {
+ // This could throw an error on some file systems that have dates out of range
+ try
+ {
+ return info.LastWriteTimeUtc;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error determining LastAccessTimeUtc for {0}", ex, info.FullName);
+ return DateTime.MinValue;
+ }
+ }
+
+ /// <summary>
+ /// Gets the last write time UTC.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>DateTime.</returns>
+ public DateTime GetLastWriteTimeUtc(string path)
+ {
+ return GetLastWriteTimeUtc(GetFileSystemInfo(path));
+ }
+
+ /// <summary>
+ /// Gets the file stream.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="mode">The mode.</param>
+ /// <param name="access">The access.</param>
+ /// <param name="share">The share.</param>
+ /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
+ /// <returns>FileStream.</returns>
+ public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFileStream(path, mode, access, share);
+ }
+
+ if (_supportsAsyncFileStreams && isAsync)
+ {
+ return GetFileStream(path, mode, access, share, FileOpenOptions.Asynchronous);
+ }
+
+ return GetFileStream(path, mode, access, share, FileOpenOptions.None);
+ }
+
+ public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFileStream(path, mode, access, share);
+ }
+
+ var defaultBufferSize = 4096;
+ return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), defaultBufferSize, GetFileOptions(fileOpenOptions));
+ }
+
+ private FileOptions GetFileOptions(FileOpenOptions mode)
+ {
+ var val = (int)mode;
+ return (FileOptions)val;
+ }
+
+ private FileMode GetFileMode(FileOpenMode mode)
+ {
+ switch (mode)
+ {
+ //case FileOpenMode.Append:
+ // return FileMode.Append;
+ case FileOpenMode.Create:
+ return FileMode.Create;
+ case FileOpenMode.CreateNew:
+ return FileMode.CreateNew;
+ case FileOpenMode.Open:
+ return FileMode.Open;
+ case FileOpenMode.OpenOrCreate:
+ return FileMode.OpenOrCreate;
+ //case FileOpenMode.Truncate:
+ // return FileMode.Truncate;
+ default:
+ throw new Exception("Unrecognized FileOpenMode");
+ }
+ }
+
+ private FileAccess GetFileAccess(FileAccessMode mode)
+ {
+ switch (mode)
+ {
+ //case FileAccessMode.ReadWrite:
+ // return FileAccess.ReadWrite;
+ case FileAccessMode.Write:
+ return FileAccess.Write;
+ case FileAccessMode.Read:
+ return FileAccess.Read;
+ default:
+ throw new Exception("Unrecognized FileAccessMode");
+ }
+ }
+
+ private FileShare GetFileShare(FileShareMode mode)
+ {
+ switch (mode)
+ {
+ case FileShareMode.ReadWrite:
+ return FileShare.ReadWrite;
+ case FileShareMode.Write:
+ return FileShare.Write;
+ case FileShareMode.Read:
+ return FileShare.Read;
+ case FileShareMode.None:
+ return FileShare.None;
+ default:
+ throw new Exception("Unrecognized FileShareMode");
+ }
+ }
+
+ public void SetHidden(string path, bool isHidden)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.SetHidden(path, isHidden);
+ return;
+ }
+
+ var info = GetFileInfo(path);
+
+ if (info.Exists && info.IsHidden != isHidden)
+ {
+ if (isHidden)
+ {
+ File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden);
+ }
+ else
+ {
+ FileAttributes attributes = File.GetAttributes(path);
+ attributes = RemoveAttribute(attributes, FileAttributes.Hidden);
+ File.SetAttributes(path, attributes);
+ }
+ }
+ }
+
+ public void SetReadOnly(string path, bool isReadOnly)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.SetReadOnly(path, isReadOnly);
+ return;
+ }
+
+ var info = GetFileInfo(path);
+
+ if (info.Exists && info.IsReadOnly != isReadOnly)
+ {
+ if (isReadOnly)
+ {
+ File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.ReadOnly);
+ }
+ else
+ {
+ FileAttributes attributes = File.GetAttributes(path);
+ attributes = RemoveAttribute(attributes, FileAttributes.ReadOnly);
+ File.SetAttributes(path, attributes);
+ }
+ }
+ }
+
+ public void SetAttributes(string path, bool isHidden, bool isReadOnly)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.SetAttributes(path, isHidden, isReadOnly);
+ return;
+ }
+
+ var info = GetFileInfo(path);
+
+ if (!info.Exists)
+ {
+ return;
+ }
+
+ if (info.IsReadOnly == isReadOnly && info.IsHidden == isHidden)
+ {
+ return;
+ }
+
+ var attributes = File.GetAttributes(path);
+
+ if (isReadOnly)
+ {
+ attributes = attributes | FileAttributes.ReadOnly;
+ }
+ else
+ {
+ attributes = RemoveAttribute(attributes, FileAttributes.ReadOnly);
+ }
+
+ if (isHidden)
+ {
+ attributes = attributes | FileAttributes.Hidden;
+ }
+ else
+ {
+ attributes = RemoveAttribute(attributes, FileAttributes.Hidden);
+ }
+
+ File.SetAttributes(path, attributes);
+ }
+
+ private static FileAttributes RemoveAttribute(FileAttributes attributes, FileAttributes attributesToRemove)
+ {
+ return attributes & ~attributesToRemove;
+ }
+
+ /// <summary>
+ /// Swaps the files.
+ /// </summary>
+ /// <param name="file1">The file1.</param>
+ /// <param name="file2">The file2.</param>
+ public void SwapFiles(string file1, string file2)
+ {
+ if (string.IsNullOrEmpty(file1))
+ {
+ throw new ArgumentNullException("file1");
+ }
+
+ if (string.IsNullOrEmpty(file2))
+ {
+ throw new ArgumentNullException("file2");
+ }
+
+ var temp1 = Path.Combine(_tempPath, Guid.NewGuid().ToString("N"));
+
+ // Copying over will fail against hidden files
+ SetHidden(file1, false);
+ SetHidden(file2, false);
+
+ Directory.CreateDirectory(_tempPath);
+ CopyFile(file1, temp1, true);
+
+ CopyFile(file2, file1, true);
+ CopyFile(temp1, file2, true);
+ }
+
+ private char GetDirectorySeparatorChar(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetDirectorySeparatorChar(path);
+ }
+
+ return Path.DirectorySeparatorChar;
+ }
+
+ public bool ContainsSubPath(string parentPath, string path)
+ {
+ if (string.IsNullOrEmpty(parentPath))
+ {
+ throw new ArgumentNullException("parentPath");
+ }
+
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ var separatorChar = GetDirectorySeparatorChar(parentPath);
+
+ return path.IndexOf(parentPath.TrimEnd(separatorChar) + separatorChar, StringComparison.OrdinalIgnoreCase) != -1;
+ }
+
+ public bool IsRootPath(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ var parent = GetDirectoryName(path);
+
+ if (!string.IsNullOrEmpty(parent))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public string GetDirectoryName(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetDirectoryName(path);
+ }
+
+ return Path.GetDirectoryName(path);
+ }
+
+ public string NormalizePath(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.NormalizePath(path);
+ }
+
+ if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase))
+ {
+ return path;
+ }
+
+ return path.TrimEnd(GetDirectorySeparatorChar(path));
+ }
+
+ public bool AreEqual(string path1, string path2)
+ {
+ if (path1 == null && path2 == null)
+ {
+ return true;
+ }
+
+ if (path1 == null || path2 == null)
+ {
+ return false;
+ }
+
+ return string.Equals(NormalizePath(path1), NormalizePath(path2), StringComparison.OrdinalIgnoreCase);
+ }
+
+ public string GetFileNameWithoutExtension(FileSystemMetadata info)
+ {
+ if (info.IsDirectory)
+ {
+ return info.Name;
+ }
+
+ return Path.GetFileNameWithoutExtension(info.FullName);
+ }
+
+ public string GetFileNameWithoutExtension(string path)
+ {
+ return Path.GetFileNameWithoutExtension(path);
+ }
+
+ public bool IsPathFile(string path)
+ {
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\
+
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return true;
+ }
+
+ if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 &&
+ !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ return true;
+
+ //return Path.IsPathRooted(path);
+ }
+
+ public void DeleteFile(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.DeleteFile(path);
+ return;
+ }
+
+ SetAttributes(path, false, false);
+ File.Delete(path);
+ }
+
+ public void DeleteDirectory(string path, bool recursive)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.DeleteDirectory(path, recursive);
+ return;
+ }
+
+ Directory.Delete(path, recursive);
+ }
+
+ public void CreateDirectory(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.CreateDirectory(path);
+ return;
+ }
+
+ Directory.CreateDirectory(path);
+ }
+
+ public List<FileSystemMetadata> GetDrives()
+ {
+ // Only include drives in the ready state or this method could end up being very slow, waiting for drives to timeout
+ return DriveInfo.GetDrives().Where(d => d.IsReady).Select(d => new FileSystemMetadata
+ {
+ Name = GetName(d),
+ FullName = d.RootDirectory.FullName,
+ IsDirectory = true
+
+ }).ToList();
+ }
+
+ private string GetName(DriveInfo drive)
+ {
+ return drive.Name;
+ }
+
+ public IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetDirectories(path, recursive);
+ }
+
+ var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
+
+ return ToMetadata(new DirectoryInfo(path).EnumerateDirectories("*", searchOption));
+ }
+
+ public IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false)
+ {
+ return GetFiles(path, null, false, recursive);
+ }
+
+ public IEnumerable<FileSystemMetadata> GetFiles(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFiles(path, extensions, enableCaseSensitiveExtensions, recursive);
+ }
+
+ var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
+
+ // On linux and osx the search pattern is case sensitive
+ // If we're OK with case-sensitivity, and we're only filtering for one extension, then use the native method
+ if (enableCaseSensitiveExtensions && extensions != null && extensions.Length == 1)
+ {
+ return ToMetadata(new DirectoryInfo(path).EnumerateFiles("*" + extensions[0], searchOption));
+ }
+
+ var files = new DirectoryInfo(path).EnumerateFiles("*", searchOption);
+
+ if (extensions != null && extensions.Length > 0)
+ {
+ files = files.Where(i =>
+ {
+ var ext = i.Extension;
+ if (ext == null)
+ {
+ return false;
+ }
+ return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
+ });
+ }
+
+ return ToMetadata(files);
+ }
+
+ public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFileSystemEntries(path, recursive);
+ }
+
+ var directoryInfo = new DirectoryInfo(path);
+ var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
+
+ if (EnableFileSystemRequestConcat)
+ {
+ return ToMetadata(directoryInfo.EnumerateDirectories("*", searchOption))
+ .Concat(ToMetadata(directoryInfo.EnumerateFiles("*", searchOption)));
+ }
+
+ return ToMetadata(directoryInfo.EnumerateFileSystemInfos("*", searchOption));
+ }
+
+ private IEnumerable<FileSystemMetadata> ToMetadata(IEnumerable<FileSystemInfo> infos)
+ {
+ return infos.Select(GetFileSystemMetadata);
+ }
+
+ public string[] ReadAllLines(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.ReadAllLines(path);
+ }
+ return File.ReadAllLines(path);
+ }
+
+ public void WriteAllLines(string path, IEnumerable<string> lines)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.WriteAllLines(path, lines);
+ return;
+ }
+ File.WriteAllLines(path, lines);
+ }
+
+ public Stream OpenRead(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.OpenRead(path);
+ }
+ return File.OpenRead(path);
+ }
+
+ public void CopyFile(string source, string target, bool overwrite)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(source))
+ {
+ _sharpCifsFileSystem.CopyFile(source, target, overwrite);
+ return;
+ }
+ File.Copy(source, target, overwrite);
+ }
+
+ public void MoveFile(string source, string target)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(source))
+ {
+ _sharpCifsFileSystem.MoveFile(source, target);
+ return;
+ }
+ File.Move(source, target);
+ }
+
+ public void MoveDirectory(string source, string target)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(source))
+ {
+ _sharpCifsFileSystem.MoveDirectory(source, target);
+ return;
+ }
+ Directory.Move(source, target);
+ }
+
+ public bool DirectoryExists(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.DirectoryExists(path);
+ }
+ return Directory.Exists(path);
+ }
+
+ public bool FileExists(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.FileExists(path);
+ }
+ return File.Exists(path);
+ }
+
+ public string ReadAllText(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.ReadAllText(path);
+ }
+ return File.ReadAllText(path);
+ }
+
+ public byte[] ReadAllBytes(string path)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.ReadAllBytes(path);
+ }
+ return File.ReadAllBytes(path);
+ }
+
+ public void WriteAllText(string path, string text, Encoding encoding)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.WriteAllText(path, text, encoding);
+ return;
+ }
+
+ File.WriteAllText(path, text, encoding);
+ }
+
+ public void WriteAllText(string path, string text)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.WriteAllText(path, text);
+ return;
+ }
+
+ File.WriteAllText(path, text);
+ }
+
+ public void WriteAllBytes(string path, byte[] bytes)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.WriteAllBytes(path, bytes);
+ return;
+ }
+
+ File.WriteAllBytes(path, bytes);
+ }
+
+ public string ReadAllText(string path, Encoding encoding)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.ReadAllText(path, encoding);
+ }
+
+ return File.ReadAllText(path, encoding);
+ }
+
+ public IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetDirectoryPaths(path, recursive);
+ }
+
+ var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
+ return Directory.EnumerateDirectories(path, "*", searchOption);
+ }
+
+ public IEnumerable<string> GetFilePaths(string path, bool recursive = false)
+ {
+ return GetFilePaths(path, null, false, recursive);
+ }
+
+ public IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFilePaths(path, extensions, enableCaseSensitiveExtensions, recursive);
+ }
+
+ var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
+
+ // On linux and osx the search pattern is case sensitive
+ // If we're OK with case-sensitivity, and we're only filtering for one extension, then use the native method
+ if (enableCaseSensitiveExtensions && extensions != null && extensions.Length == 1)
+ {
+ return Directory.EnumerateFiles(path, "*" + extensions[0], searchOption);
+ }
+
+ var files = Directory.EnumerateFiles(path, "*", searchOption);
+
+ if (extensions != null && extensions.Length > 0)
+ {
+ files = files.Where(i =>
+ {
+ var ext = Path.GetExtension(i);
+ if (ext == null)
+ {
+ return false;
+ }
+ return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
+ });
+ }
+
+ return files;
+ }
+
+ public IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFileSystemEntryPaths(path, recursive);
+ }
+
+ var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
+ return Directory.EnumerateFileSystemEntries(path, "*", searchOption);
+ }
+
+ public virtual void SetExecutable(string path)
+ {
+
+ }
+ }
+}