diff options
Diffstat (limited to 'Emby.Server.Implementations/IO')
5 files changed, 69 insertions, 128 deletions
diff --git a/Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs b/Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs deleted file mode 100644 index 545d73e05..000000000 --- a/Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -#pragma warning disable CS1591 - -namespace Emby.Server.Implementations.IO -{ - public class ExtendedFileSystemInfo - { - public bool IsHidden { get; set; } - - public bool IsReadOnly { get; set; } - - public bool Exists { get; set; } - } -} diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 0ad81b653..15b1836eb 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -85,7 +85,7 @@ namespace Emby.Server.Implementations.IO } } - public void ResetPath(string path, string affectedFile) + public void ResetPath(string path, string? affectedFile) { lock (_timerLock) { @@ -148,13 +148,6 @@ namespace Emby.Server.Implementations.IO { item.ChangedExternally(); } - catch (IOException ex) - { - // For now swallow and log. - // Research item: If an IOException occurs, the item may be in a disconnected state (media unavailable) - // Should we remove it from it's parent? - _logger.LogError(ex, "Error refreshing {Name}", item.Name); - } catch (Exception ex) { _logger.LogError(ex, "Error refreshing {Name}", item.Name); diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index f67a02be8..dde38906f 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -160,7 +158,7 @@ namespace Emby.Server.Implementations.IO /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> - private void OnLibraryManagerItemRemoved(object sender, ItemChangeEventArgs e) + private void OnLibraryManagerItemRemoved(object? sender, ItemChangeEventArgs e) { if (e.Parent is AggregateFolder) { @@ -173,7 +171,7 @@ namespace Emby.Server.Implementations.IO /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> - private void OnLibraryManagerItemAdded(object sender, ItemChangeEventArgs e) + private void OnLibraryManagerItemAdded(object? sender, ItemChangeEventArgs e) { if (e.Parent is AggregateFolder) { @@ -189,19 +187,28 @@ namespace Emby.Server.Implementations.IO /// <param name="path">The path.</param> /// <returns><c>true</c> if [contains parent folder] [the specified LST]; otherwise, <c>false</c>.</returns> /// <exception cref="ArgumentNullException"><paramref name="path"/> is <c>null</c>.</exception> - private static bool ContainsParentFolder(IEnumerable<string> lst, string path) + private static bool ContainsParentFolder(IReadOnlyList<string> lst, ReadOnlySpan<char> path) { - ArgumentException.ThrowIfNullOrEmpty(path); + if (path.IsEmpty) + { + throw new ArgumentException("Path can't be empty", nameof(path)); + } path = path.TrimEnd(Path.DirectorySeparatorChar); - return lst.Any(str => + foreach (var str in lst) { // this should be a little quicker than examining each actual parent folder... - var compare = str.TrimEnd(Path.DirectorySeparatorChar); + var compare = str.AsSpan().TrimEnd(Path.DirectorySeparatorChar); - return path.Equals(compare, StringComparison.OrdinalIgnoreCase) || (path.StartsWith(compare, StringComparison.OrdinalIgnoreCase) && path[compare.Length] == Path.DirectorySeparatorChar); - }); + if (path.Equals(compare, StringComparison.OrdinalIgnoreCase) + || (path.StartsWith(compare, StringComparison.OrdinalIgnoreCase) && path[compare.Length] == Path.DirectorySeparatorChar)) + { + return true; + } + } + + return false; } /// <summary> @@ -349,21 +356,19 @@ namespace Emby.Server.Implementations.IO { ArgumentException.ThrowIfNullOrEmpty(path); - var monitorPath = !IgnorePatterns.ShouldIgnore(path); + if (IgnorePatterns.ShouldIgnore(path)) + { + return; + } // Ignore certain files, If the parent of an ignored path has a change event, ignore that too - if (_tempIgnoredPaths.Keys.Any(i => + foreach (var i in _tempIgnoredPaths.Keys) { - if (_fileSystem.AreEqual(i, path)) - { - _logger.LogDebug("Ignoring change to {Path}", path); - return true; - } - - if (_fileSystem.ContainsSubPath(i, path)) + if (_fileSystem.AreEqual(i, path) + || _fileSystem.ContainsSubPath(i, path)) { _logger.LogDebug("Ignoring change to {Path}", path); - return true; + return; } // Go up a level @@ -371,20 +376,11 @@ namespace Emby.Server.Implementations.IO if (!string.IsNullOrEmpty(parent) && _fileSystem.AreEqual(parent, path)) { _logger.LogDebug("Ignoring change to {Path}", path); - return true; + return; } - - return false; - })) - { - monitorPath = false; } - if (monitorPath) - { - // Avoid implicitly captured closure - CreateRefresher(path); - } + CreateRefresher(path); } private void CreateRefresher(string path) @@ -417,7 +413,8 @@ namespace Emby.Server.Implementations.IO } // They are siblings. Rebase the refresher to the parent folder. - if (string.Equals(parentPath, Path.GetDirectoryName(refresher.Path), StringComparison.Ordinal)) + if (parentPath is not null + && Path.GetDirectoryName(refresher.Path.AsSpan()).Equals(parentPath, StringComparison.Ordinal)) { refresher.ResetPath(parentPath, path); return; @@ -430,8 +427,13 @@ namespace Emby.Server.Implementations.IO } } - private void OnNewRefresherCompleted(object sender, EventArgs e) + private void OnNewRefresherCompleted(object? sender, EventArgs e) { + if (sender is null) + { + return; + } + var refresher = (FileRefresher)sender; DisposeRefresher(refresher); } diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 55f384ae8..18b00ce0b 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -15,29 +15,34 @@ namespace Emby.Server.Implementations.IO /// </summary> public class ManagedFileSystem : IFileSystem { - private readonly ILogger<ManagedFileSystem> _logger; + private static readonly bool _isEnvironmentCaseInsensitive = OperatingSystem.IsWindows(); + private static readonly char[] _invalidPathCharacters = + { + '\"', '<', '>', '|', '\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, ':', '*', '?', '\\', '/' + }; - private readonly List<IShortcutHandler> _shortcutHandlers = new List<IShortcutHandler>(); + private readonly ILogger<ManagedFileSystem> _logger; + private readonly List<IShortcutHandler> _shortcutHandlers; private readonly string _tempPath; - private static readonly bool _isEnvironmentCaseInsensitive = OperatingSystem.IsWindows(); /// <summary> /// Initializes a new instance of the <see cref="ManagedFileSystem"/> class. /// </summary> /// <param name="logger">The <see cref="ILogger"/> instance to use.</param> /// <param name="applicationPaths">The <see cref="IApplicationPaths"/> instance to use.</param> + /// <param name="shortcutHandlers">the <see cref="IShortcutHandler"/>'s to use.</param> public ManagedFileSystem( ILogger<ManagedFileSystem> logger, - IApplicationPaths applicationPaths) + IApplicationPaths applicationPaths, + IEnumerable<IShortcutHandler> shortcutHandlers) { _logger = logger; _tempPath = applicationPaths.TempDirectory; - } - - /// <inheritdoc /> - public virtual void AddShortcutHandler(IShortcutHandler handler) - { - _shortcutHandlers.Add(handler); + _shortcutHandlers = shortcutHandlers.ToList(); } /// <summary> @@ -267,25 +272,6 @@ namespace Emby.Server.Implementations.IO return result; } - private static 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> /// Takes a filename and removes invalid characters. /// </summary> @@ -294,8 +280,7 @@ namespace Emby.Server.Implementations.IO /// <exception cref="ArgumentNullException">The filename is null.</exception> public string GetValidFilename(string filename) { - var invalid = Path.GetInvalidFileNameChars(); - var first = filename.IndexOfAny(invalid); + var first = filename.IndexOfAny(_invalidPathCharacters); if (first == -1) { // Fast path for clean strings @@ -304,7 +289,7 @@ namespace Emby.Server.Implementations.IO return string.Create( filename.Length, - (filename, invalid, first), + (filename, _invalidPathCharacters, first), (chars, state) => { state.filename.AsSpan().CopyTo(chars); @@ -312,7 +297,7 @@ namespace Emby.Server.Implementations.IO chars[state.first++] = ' '; var len = chars.Length; - foreach (var c in state.invalid) + foreach (var c in state._invalidPathCharacters) { for (int i = state.first; i < len; i++) { @@ -403,19 +388,18 @@ namespace Emby.Server.Implementations.IO return; } - var info = GetExtendedFileSystemInfo(path); + var info = new FileInfo(path); - if (info.Exists && info.IsHidden != isHidden) + if (info.Exists && + ((info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) != isHidden) { if (isHidden) { - File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden); + File.SetAttributes(path, info.Attributes | FileAttributes.Hidden); } else { - var attributes = File.GetAttributes(path); - attributes = RemoveAttribute(attributes, FileAttributes.Hidden); - File.SetAttributes(path, attributes); + File.SetAttributes(path, info.Attributes & ~FileAttributes.Hidden); } } } @@ -428,19 +412,20 @@ namespace Emby.Server.Implementations.IO return; } - var info = GetExtendedFileSystemInfo(path); + var info = new FileInfo(path); if (!info.Exists) { return; } - if (info.IsReadOnly == readOnly && info.IsHidden == isHidden) + if (((info.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) == readOnly + && ((info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) == isHidden) { return; } - var attributes = File.GetAttributes(path); + var attributes = info.Attributes; if (readOnly) { @@ -448,7 +433,7 @@ namespace Emby.Server.Implementations.IO } else { - attributes = RemoveAttribute(attributes, FileAttributes.ReadOnly); + attributes &= ~FileAttributes.ReadOnly; } if (isHidden) @@ -457,17 +442,12 @@ namespace Emby.Server.Implementations.IO } else { - attributes = RemoveAttribute(attributes, FileAttributes.Hidden); + attributes &= ~FileAttributes.Hidden; } File.SetAttributes(path, attributes); } - private static FileAttributes RemoveAttribute(FileAttributes attributes, FileAttributes attributesToRemove) - { - return attributes & ~attributesToRemove; - } - /// <summary> /// Swaps the files. /// </summary> @@ -503,24 +483,10 @@ namespace Emby.Server.Implementations.IO } /// <inheritdoc /> - public virtual string NormalizePath(string path) - { - ArgumentException.ThrowIfNullOrEmpty(path); - - if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase)) - { - return path; - } - - return Path.TrimEndingDirectorySeparator(path); - } - - /// <inheritdoc /> public virtual bool AreEqual(string path1, string path2) { - return string.Equals( - NormalizePath(path1), - NormalizePath(path2), + return Path.TrimEndingDirectorySeparator(path1).Equals( + Path.TrimEndingDirectorySeparator(path2), _isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); } diff --git a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs index c2aab3879..5776c7a7c 100644 --- a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs +++ b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs @@ -8,24 +8,17 @@ namespace Emby.Server.Implementations.IO { public class MbLinkShortcutHandler : IShortcutHandler { - private readonly IFileSystem _fileSystem; - - public MbLinkShortcutHandler(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - } - public string Extension => ".mblink"; public string? Resolve(string shortcutPath) { ArgumentException.ThrowIfNullOrEmpty(shortcutPath); - if (string.Equals(Path.GetExtension(shortcutPath), ".mblink", StringComparison.OrdinalIgnoreCase)) + if (Path.GetExtension(shortcutPath.AsSpan()).Equals(".mblink", StringComparison.OrdinalIgnoreCase)) { var path = File.ReadAllText(shortcutPath); - return _fileSystem.NormalizePath(path); + return Path.TrimEndingDirectorySeparator(path); } return null; |
