aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/IO/ManagedFileSystem.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/IO/ManagedFileSystem.cs')
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs178
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);
}