mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-03 22:38:30 +01:00
Update to 3.5.2 and .net core 2.1
This commit is contained in:
13
Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs
Normal file
13
Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
public class ExtendedFileSystemInfo
|
||||
{
|
||||
public bool IsHidden { get; set; }
|
||||
public bool IsReadOnly { get; set; }
|
||||
public bool Exists { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.IO
|
||||
|
||||
private void AddAffectedPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
@@ -67,7 +67,7 @@ namespace Emby.Server.Implementations.IO
|
||||
|
||||
public void AddPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
@@ -113,7 +113,7 @@ namespace Emby.Server.Implementations.IO
|
||||
Path = path;
|
||||
AddAffectedPath(path);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(affectedFile))
|
||||
if (!string.IsNullOrEmpty(affectedFile))
|
||||
{
|
||||
AddAffectedPath(affectedFile);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ namespace Emby.Server.Implementations.IO
|
||||
// If the item has been deleted find the first valid parent that still exists
|
||||
while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
|
||||
{
|
||||
item = item.IsOwnedItem ? item.GetOwner() : item.GetParent();
|
||||
item = item.GetOwner() ?? item.GetParent();
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
@@ -231,7 +231,6 @@ namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
_disposed = true;
|
||||
DisposeTimer();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
mounter.Dispose();
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace Emby.Server.Implementations.IO
|
||||
/// <exception cref="System.ArgumentNullException">path</exception>
|
||||
private static bool ContainsParentFolder(IEnumerable<string> lst, string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
@@ -304,6 +304,12 @@ namespace Emby.Server.Implementations.IO
|
||||
}
|
||||
}
|
||||
|
||||
if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Android)
|
||||
{
|
||||
// causing crashing
|
||||
return;
|
||||
}
|
||||
|
||||
// Already being watched
|
||||
if (_fileSystemWatchers.ContainsKey(path))
|
||||
{
|
||||
@@ -320,11 +326,7 @@ namespace Emby.Server.Implementations.IO
|
||||
IncludeSubdirectories = true
|
||||
};
|
||||
|
||||
if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows ||
|
||||
_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
|
||||
{
|
||||
newWatcher.InternalBufferSize = 32767;
|
||||
}
|
||||
newWatcher.InternalBufferSize = 65536;
|
||||
|
||||
newWatcher.NotifyFilter = NotifyFilters.CreationTime |
|
||||
NotifyFilters.DirectoryName |
|
||||
@@ -337,7 +339,6 @@ namespace Emby.Server.Implementations.IO
|
||||
newWatcher.Deleted += watcher_Changed;
|
||||
newWatcher.Renamed += watcher_Changed;
|
||||
newWatcher.Changed += watcher_Changed;
|
||||
|
||||
newWatcher.Error += watcher_Error;
|
||||
|
||||
if (_fileSystemWatchers.TryAdd(path, newWatcher))
|
||||
@@ -347,7 +348,7 @@ namespace Emby.Server.Implementations.IO
|
||||
}
|
||||
else
|
||||
{
|
||||
newWatcher.Dispose();
|
||||
DisposeWatcher(newWatcher, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -368,15 +369,14 @@ namespace Emby.Server.Implementations.IO
|
||||
|
||||
if (_fileSystemWatchers.TryGetValue(path, out watcher))
|
||||
{
|
||||
DisposeWatcher(watcher);
|
||||
DisposeWatcher(watcher, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the watcher.
|
||||
/// </summary>
|
||||
/// <param name="watcher">The watcher.</param>
|
||||
private void DisposeWatcher(FileSystemWatcher watcher)
|
||||
private void DisposeWatcher(FileSystemWatcher watcher, bool removeFromList)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -384,16 +384,37 @@ namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
Logger.Info("Stopping directory watching for path {0}", watcher.Path);
|
||||
|
||||
watcher.EnableRaisingEvents = false;
|
||||
watcher.Created -= watcher_Changed;
|
||||
watcher.Deleted -= watcher_Changed;
|
||||
watcher.Renamed -= watcher_Changed;
|
||||
watcher.Changed -= watcher_Changed;
|
||||
watcher.Error -= watcher_Error;
|
||||
|
||||
try
|
||||
{
|
||||
watcher.EnableRaisingEvents = false;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// Seeing this under mono on linux sometimes
|
||||
// Collection was modified; enumeration operation may not execute.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
// the dispose method on FileSystemWatcher is sometimes throwing NotImplementedException on Xamarin Android
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
RemoveWatcherFromList(watcher);
|
||||
if (removeFromList)
|
||||
{
|
||||
RemoveWatcherFromList(watcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +441,7 @@ namespace Emby.Server.Implementations.IO
|
||||
|
||||
Logger.ErrorException("Error in Directory watcher for: " + dw.Path, ex);
|
||||
|
||||
DisposeWatcher(dw);
|
||||
DisposeWatcher(dw, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -452,7 +473,7 @@ namespace Emby.Server.Implementations.IO
|
||||
}
|
||||
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
|
||||
var monitorPath = !string.IsNullOrEmpty(filename) &&
|
||||
!_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) &&
|
||||
!_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase) &&
|
||||
@@ -466,13 +487,13 @@ namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
if (_fileSystem.AreEqual(i, path))
|
||||
{
|
||||
Logger.Debug("Ignoring change to {0}", path);
|
||||
//Logger.Debug("Ignoring change to {0}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_fileSystem.ContainsSubPath(i, path))
|
||||
{
|
||||
Logger.Debug("Ignoring change to {0}", path);
|
||||
//Logger.Debug("Ignoring change to {0}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -482,7 +503,7 @@ namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
if (_fileSystem.AreEqual(parent, path))
|
||||
{
|
||||
Logger.Debug("Ignoring change to {0}", path);
|
||||
//Logger.Debug("Ignoring change to {0}", path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -561,22 +582,7 @@ namespace Emby.Server.Implementations.IO
|
||||
|
||||
foreach (var watcher in _fileSystemWatchers.Values.ToList())
|
||||
{
|
||||
watcher.Created -= watcher_Changed;
|
||||
watcher.Deleted -= watcher_Changed;
|
||||
watcher.Renamed -= watcher_Changed;
|
||||
watcher.Changed -= watcher_Changed;
|
||||
|
||||
try
|
||||
{
|
||||
watcher.EnableRaisingEvents = false;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// Seeing this under mono on linux sometimes
|
||||
// Collection was modified; enumeration operation may not execute.
|
||||
}
|
||||
|
||||
watcher.Dispose();
|
||||
DisposeWatcher(watcher, false);
|
||||
}
|
||||
|
||||
_fileSystemWatchers.Clear();
|
||||
@@ -612,7 +618,6 @@ namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
_disposed = true;
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -644,7 +649,6 @@ namespace Emby.Server.Implementations.IO
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using System.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
public class MemoryStreamProvider : IMemoryStreamFactory
|
||||
{
|
||||
public MemoryStream CreateNew()
|
||||
{
|
||||
return new MemoryStream();
|
||||
}
|
||||
|
||||
public MemoryStream CreateNew(int capacity)
|
||||
{
|
||||
return new MemoryStream(capacity);
|
||||
}
|
||||
|
||||
public MemoryStream CreateNew(byte[] buffer)
|
||||
{
|
||||
return new MemoryStream(buffer);
|
||||
}
|
||||
|
||||
public bool TryGetBuffer(MemoryStream stream, out byte[] buffer)
|
||||
{
|
||||
buffer = stream.GetBuffer();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,9 +136,6 @@ namespace Emby.Server.Implementations.IO
|
||||
if (result.Exists)
|
||||
{
|
||||
result.IsDirectory = info.IsDirectory();
|
||||
result.IsHidden = info.IsHidden();
|
||||
|
||||
result.IsReadOnly = !info.CanWrite();
|
||||
|
||||
if (info.IsFile())
|
||||
{
|
||||
|
||||
190
Emby.Server.Implementations/IO/StreamHelper.cs
Normal file
190
Emby.Server.Implementations/IO/StreamHelper.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
public class StreamHelper : IStreamHelper
|
||||
{
|
||||
public async Task CopyToAsync(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken)
|
||||
{
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
int read;
|
||||
while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false);
|
||||
|
||||
if (onStarted != null)
|
||||
{
|
||||
onStarted();
|
||||
onStarted = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CopyToAsync(Stream source, Stream destination, int bufferSize, int emptyReadLimit, CancellationToken cancellationToken)
|
||||
{
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
|
||||
if (emptyReadLimit <= 0)
|
||||
{
|
||||
int read;
|
||||
while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var eofCount = 0;
|
||||
|
||||
while (eofCount < emptyReadLimit)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var bytesRead = source.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
eofCount++;
|
||||
await Task.Delay(50, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
eofCount = 0;
|
||||
|
||||
await destination.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int StreamCopyToBufferSize = 81920;
|
||||
public async Task<int> CopyToAsync(Stream source, Stream destination, CancellationToken cancellationToken)
|
||||
{
|
||||
var array = new byte[StreamCopyToBufferSize];
|
||||
int bytesRead;
|
||||
int totalBytesRead = 0;
|
||||
|
||||
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
||||
{
|
||||
var bytesToWrite = bytesRead;
|
||||
|
||||
if (bytesToWrite > 0)
|
||||
{
|
||||
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
public async Task<int> CopyToAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken)
|
||||
{
|
||||
var array = new byte[StreamCopyToBufferSize];
|
||||
int bytesRead;
|
||||
int totalBytesRead = 0;
|
||||
|
||||
while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
|
||||
{
|
||||
var bytesToWrite = bytesRead;
|
||||
|
||||
if (bytesToWrite > 0)
|
||||
{
|
||||
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
public async Task CopyToAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
|
||||
{
|
||||
var array = new byte[StreamCopyToBufferSize];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
|
||||
{
|
||||
var bytesToWrite = Math.Min(bytesRead, copyLength);
|
||||
|
||||
if (bytesToWrite > 0)
|
||||
{
|
||||
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
copyLength -= bytesToWrite;
|
||||
|
||||
if (copyLength <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CopyToAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
|
||||
{
|
||||
var array = new byte[StreamCopyToBufferSize];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
||||
{
|
||||
var bytesToWrite = Math.Min(bytesRead, copyLength);
|
||||
|
||||
if (bytesToWrite > 0)
|
||||
{
|
||||
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
copyLength -= bytesToWrite;
|
||||
|
||||
if (copyLength <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CopyUntilCancelled(Stream source, Stream target, int bufferSize, CancellationToken cancellationToken)
|
||||
{
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var bytesRead = await CopyToAsyncInternal(source, target, buffer, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
//var position = fs.Position;
|
||||
//_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<int> CopyToAsyncInternal(Stream source, Stream destination, byte[] buffer, CancellationToken cancellationToken)
|
||||
{
|
||||
int bytesRead;
|
||||
int totalBytesRead = 0;
|
||||
|
||||
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
||||
{
|
||||
await destination.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
|
||||
return totalBytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user