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.cs94
1 files changed, 63 insertions, 31 deletions
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 46c128dedc..4d68cb4444 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Security;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -152,6 +153,10 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public void MoveDirectory(string source, string destination)
{
+ // Make sure parent directory of target exists
+ var parent = Directory.GetParent(destination);
+ parent?.Create();
+
try
{
Directory.Move(source, destination);
@@ -160,12 +165,13 @@ namespace Emby.Server.Implementations.IO
{
// Cross device move requires a copy
Directory.CreateDirectory(destination);
- foreach (string file in Directory.GetFiles(source))
+ var sourceDir = new DirectoryInfo(source);
+ foreach (var file in sourceDir.EnumerateFiles())
{
- File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), true);
+ file.CopyTo(Path.Combine(destination, file.Name), true);
}
- Directory.Delete(source, true);
+ sourceDir.Delete(true);
}
}
@@ -247,40 +253,40 @@ namespace Emby.Server.Implementations.IO
{
result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
- // if (!result.IsDirectory)
- // {
- // result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
- // }
-
if (info is FileInfo fileInfo)
{
- result.Length = fileInfo.Length;
-
- // Issue #2354 get the size of files behind symbolic links. Also Enum.HasFlag is bad as it boxes!
- if ((fileInfo.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
+ result.CreationTimeUtc = GetCreationTimeUtc(info);
+ result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
+ if (fileInfo.LinkTarget is not null)
{
try
{
- using (var fileHandle = File.OpenHandle(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ var targetFileInfo = FileSystemHelper.ResolveLinkTarget(fileInfo, returnFinalTarget: true);
+ if (targetFileInfo is not null)
{
- result.Length = RandomAccess.GetLength(fileHandle);
+ result.Exists = targetFileInfo.Exists;
+ if (result.Exists)
+ {
+ result.Length = targetFileInfo.Length;
+ result.CreationTimeUtc = GetCreationTimeUtc(targetFileInfo);
+ result.LastWriteTimeUtc = GetLastWriteTimeUtc(targetFileInfo);
+ }
+ }
+ else
+ {
+ result.Exists = false;
}
- }
- catch (FileNotFoundException ex)
- {
- // Dangling symlinks cannot be detected before opening the file unfortunately...
- _logger.LogError(ex, "Reading the file size of the symlink at {Path} failed. Marking the file as not existing.", fileInfo.FullName);
- result.Exists = false;
}
catch (UnauthorizedAccessException ex)
{
_logger.LogError(ex, "Reading the file at {Path} failed due to a permissions exception.", fileInfo.FullName);
}
}
+ else
+ {
+ result.Length = fileInfo.Length;
+ }
}
-
- result.CreationTimeUtc = GetCreationTimeUtc(info);
- result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
}
else
{
@@ -491,8 +497,17 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public virtual bool AreEqual(string path1, string path2)
{
- return Path.TrimEndingDirectorySeparator(path1).Equals(
- Path.TrimEndingDirectorySeparator(path2),
+ if (string.IsNullOrWhiteSpace(path1) || string.IsNullOrWhiteSpace(path2))
+ {
+ return false;
+ }
+
+ var normalized1 = Path.TrimEndingDirectorySeparator(path1);
+ var normalized2 = Path.TrimEndingDirectorySeparator(path2);
+
+ return string.Equals(
+ normalized1,
+ normalized2,
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
}
@@ -534,8 +549,8 @@ namespace Emby.Server.Implementations.IO
return DriveInfo.GetDrives()
.Where(
d => (d.DriveType == DriveType.Fixed || d.DriveType == DriveType.Network || d.DriveType == DriveType.Removable)
- && d.IsReady
- && d.TotalSize != 0)
+ && d.IsReady
+ && d.TotalSize != 0)
.Select(d => new FileSystemMetadata
{
Name = d.Name,
@@ -553,11 +568,23 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false)
{
- return GetFiles(path, null, false, recursive);
+ return GetFiles(path, "*", recursive);
+ }
+
+ /// <inheritdoc />
+ public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, string searchPattern, bool recursive = false)
+ {
+ return GetFiles(path, searchPattern, null, false, recursive);
+ }
+
+ /// <inheritdoc />
+ public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive)
+ {
+ return GetFiles(path, "*", extensions, enableCaseSensitiveExtensions, recursive);
}
/// <inheritdoc />
- public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
+ public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, string searchPattern, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
{
var enumerationOptions = GetEnumerationOptions(recursive);
@@ -565,10 +592,12 @@ namespace Emby.Server.Implementations.IO
// If we're OK with case-sensitivity, and we're only filtering for one extension, then use the native method
if ((enableCaseSensitiveExtensions || _isEnvironmentCaseInsensitive) && extensions is not null && extensions.Count == 1)
{
- return ToMetadata(new DirectoryInfo(path).EnumerateFiles("*" + extensions[0], enumerationOptions));
+ searchPattern = searchPattern.EndsWith(extensions[0], StringComparison.Ordinal) ? searchPattern : searchPattern + extensions[0];
+
+ return ToMetadata(new DirectoryInfo(path).EnumerateFiles(searchPattern, enumerationOptions));
}
- var files = new DirectoryInfo(path).EnumerateFiles("*", enumerationOptions);
+ var files = new DirectoryInfo(path).EnumerateFiles(searchPattern, enumerationOptions);
if (extensions is not null && extensions.Count > 0)
{
@@ -590,6 +619,9 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public virtual IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false)
{
+ // Note: any of unhandled exceptions thrown by this method may cause the caller to believe the whole path is not accessible.
+ // But what causing the exception may be a single file under that path. This could lead to unexpected behavior.
+ // For example, the scanner will remove everything in that path due to unhandled errors.
var directoryInfo = new DirectoryInfo(path);
var enumerationOptions = GetEnumerationOptions(recursive);