| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078 | using System;using System.Collections.Generic;using System.Diagnostics;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;        private IEnvironmentInfo _environmentInfo;        public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string tempPath)        {            Logger = logger;            _supportsAsyncFileStreams = true;            _tempPath = tempPath;            _environmentInfo = environmentInfo;            // 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)        {            if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)            {                RunProcess("chmod", "+x \"" + path + "\"", GetDirectoryName(path));            }        }        private void RunProcess(string path, string args, string workingDirectory)        {            using (var process = Process.Start(new ProcessStartInfo            {                Arguments = args,                FileName = path,                CreateNoWindow = true,                WorkingDirectory = workingDirectory,                WindowStyle = ProcessWindowStyle.Normal            }))            {                process.WaitForExit();            }        }    }}
 |