diff options
Diffstat (limited to 'Emby.Server.Implementations/IO/ManagedFileSystem.cs')
| -rw-r--r-- | Emby.Server.Implementations/IO/ManagedFileSystem.cs | 178 |
1 files changed, 132 insertions, 46 deletions
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index c8e4031a9..66d7802c6 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -20,27 +20,57 @@ namespace Emby.Server.Implementations.IO private readonly bool _supportsAsyncFileStreams; private char[] _invalidFileNameChars; private readonly List<IShortcutHandler> _shortcutHandlers = new List<IShortcutHandler>(); - private bool EnableFileSystemRequestConcat; + private bool EnableSeparateFileAndDirectoryQueries; private string _tempPath; private SharpCifsFileSystem _sharpCifsFileSystem; private IEnvironmentInfo _environmentInfo; + private bool _isEnvironmentCaseInsensitive; - public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string tempPath) + private string _defaultDirectory; + + public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string defaultDirectory, string tempPath, bool enableSeparateFileAndDirectoryQueries) { Logger = logger; _supportsAsyncFileStreams = true; _tempPath = tempPath; _environmentInfo = environmentInfo; + _defaultDirectory = defaultDirectory; - // 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; + // On Linux with mono, this needs to be true or symbolic links are ignored + EnableSeparateFileAndDirectoryQueries = enableSeparateFileAndDirectoryQueries; SetInvalidFileNameChars(environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows); _sharpCifsFileSystem = new SharpCifsFileSystem(environmentInfo.OperatingSystem); + + _isEnvironmentCaseInsensitive = environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows; + } + + public string DefaultDirectory + { + get + { + var value = _defaultDirectory; + + if (!string.IsNullOrEmpty(value)) + { + try + { + if (DirectoryExists(value)) + { + return value; + } + } + catch + { + + } + } + + return null; + } } public void AddShortcutHandler(IShortcutHandler handler) @@ -56,11 +86,9 @@ namespace Emby.Server.Implementations.IO } 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', ':', '*', '?', '\\', '/' }; + // Be consistent across platforms because the windows server will fail to query network shares that don't follow windows conventions + // https://referencesource.microsoft.com/#mscorlib/system/io/path.cs + _invalidFileNameChars = new char[] { '\"', '<', '>', '|', '\0', (Char)1, (Char)2, (Char)3, (Char)4, (Char)5, (Char)6, (Char)7, (Char)8, (Char)9, (Char)10, (Char)11, (Char)12, (Char)13, (Char)14, (Char)15, (Char)16, (Char)17, (Char)18, (Char)19, (Char)20, (Char)21, (Char)22, (Char)23, (Char)24, (Char)25, (Char)26, (Char)27, (Char)28, (Char)29, (Char)30, (Char)31, ':', '*', '?', '\\', '/' }; } } @@ -118,6 +146,49 @@ namespace Emby.Server.Implementations.IO return null; } + public string MakeAbsolutePath(string folderPath, string filePath) + { + if (String.IsNullOrWhiteSpace(filePath)) return filePath; + + if (filePath.Contains(@"://")) return filePath; //stream + if (filePath.Length > 3 && filePath[1] == ':' && filePath[2] == '/') return filePath; //absolute local path + + // unc path + if (filePath.StartsWith("\\\\")) + { + return filePath; + } + + var firstChar = filePath[0]; + if (firstChar == '/') + { + // For this we don't really know. + return filePath; + } + if (firstChar == '\\') //relative path + { + filePath = filePath.Substring(1); + } + try + { + string path = System.IO.Path.Combine(folderPath, filePath); + path = System.IO.Path.GetFullPath(path); + return path; + } + catch (ArgumentException ex) + { + return filePath; + } + catch (PathTooLongException) + { + return filePath; + } + catch (NotSupportedException) + { + return filePath; + } + } + /// <summary> /// Creates the shortcut. /// </summary> @@ -162,11 +233,6 @@ namespace Emby.Server.Implementations.IO /// <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); @@ -207,11 +273,6 @@ namespace Emby.Server.Implementations.IO /// <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); @@ -232,11 +293,6 @@ namespace Emby.Server.Implementations.IO /// <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); @@ -258,10 +314,12 @@ namespace Emby.Server.Implementations.IO 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; + result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory; + + //if (!result.IsDirectory) + //{ + // result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; + //} var fileInfo = info as FileInfo; if (fileInfo != null) @@ -281,6 +339,25 @@ namespace Emby.Server.Implementations.IO return result; } + private ExtendedFileSystemInfo GetExtendedFileSystemInfo(string path) + { + var result = new ExtendedFileSystemInfo(); + + var info = new FileInfo(path); + + if (info.Exists) + { + result.Exists = true; + + var attributes = info.Attributes; + + result.IsHidden = (attributes & FileAttributes.Hidden) == FileAttributes.Hidden; + result.IsReadOnly = (attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly; + } + + return result; + } + /// <summary> /// The space char /// </summary> @@ -294,11 +371,6 @@ namespace Emby.Server.Implementations.IO /// <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) @@ -484,7 +556,7 @@ namespace Emby.Server.Implementations.IO return; } - var info = GetFileInfo(path); + var info = GetExtendedFileSystemInfo(path); if (info.Exists && info.IsHidden != isHidden) { @@ -514,7 +586,7 @@ namespace Emby.Server.Implementations.IO return; } - var info = GetFileInfo(path); + var info = GetExtendedFileSystemInfo(path); if (info.Exists && info.IsReadOnly != isReadOnly) { @@ -544,7 +616,7 @@ namespace Emby.Server.Implementations.IO return; } - var info = GetFileInfo(path); + var info = GetExtendedFileSystemInfo(path); if (!info.Exists) { @@ -720,11 +792,6 @@ namespace Emby.Server.Implementations.IO 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)) @@ -822,7 +889,7 @@ namespace Emby.Server.Implementations.IO // 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) + if ((enableCaseSensitiveExtensions || _isEnvironmentCaseInsensitive) && extensions != null && extensions.Length == 1) { return ToMetadata(new DirectoryInfo(path).EnumerateFiles("*" + extensions[0], searchOption)); } @@ -855,7 +922,7 @@ namespace Emby.Server.Implementations.IO var directoryInfo = new DirectoryInfo(path); var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; - if (EnableFileSystemRequestConcat) + if (EnableSeparateFileAndDirectoryQueries) { return ToMetadata(directoryInfo.EnumerateDirectories("*", searchOption)) .Concat(ToMetadata(directoryInfo.EnumerateFiles("*", searchOption))); @@ -897,9 +964,28 @@ namespace Emby.Server.Implementations.IO return File.OpenRead(path); } + private void CopyFileUsingStreams(string source, string target, bool overwrite) + { + using (var sourceStream = OpenRead(source)) + { + using (var targetStream = GetFileStream(target, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) + { + sourceStream.CopyTo(targetStream); + } + } + } + public void CopyFile(string source, string target, bool overwrite) { - if (_sharpCifsFileSystem.IsEnabledForPath(source)) + var enableSharpCifsForSource = _sharpCifsFileSystem.IsEnabledForPath(source); + + if (enableSharpCifsForSource != _sharpCifsFileSystem.IsEnabledForPath(target)) + { + CopyFileUsingStreams(source, target, overwrite); + return; + } + + if (enableSharpCifsForSource) { _sharpCifsFileSystem.CopyFile(source, target, overwrite); return; @@ -1033,7 +1119,7 @@ namespace Emby.Server.Implementations.IO // 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) + if ((enableCaseSensitiveExtensions || _isEnvironmentCaseInsensitive) && extensions != null && extensions.Length == 1) { return Directory.EnumerateFiles(path, "*" + extensions[0], searchOption); } |
