From 239727e8967c87610e4807b2b8051a3d33aac131 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Mon, 18 Mar 2024 16:09:00 +0100 Subject: [PATCH] fix: skip library folders that are inaccessible or empty (#9291) --- .../IO/ManagedFileSystem.cs | 11 ++++++- MediaBrowser.Controller/Entities/Folder.cs | 29 +++++++++++++++++-- .../Providers/DirectoryService.cs | 5 ++++ .../Providers/IDirectoryService.cs | 2 ++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index c380d67db1..67854a2a7a 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Security; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.IO; @@ -643,7 +644,15 @@ namespace Emby.Server.Implementations.IO /// public virtual IEnumerable GetFileSystemEntryPaths(string path, bool recursive = false) { - return Directory.EnumerateFileSystemEntries(path, "*", GetEnumerationOptions(recursive)); + try + { + return Directory.EnumerateFileSystemEntries(path, "*", GetEnumerationOptions(recursive)); + } + catch (Exception ex) when (ex is UnauthorizedAccessException or DirectoryNotFoundException or SecurityException) + { + _logger.LogError(ex, "Failed to enumerate path {Path}", path); + return Enumerable.Empty(); + } } /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 1f13c833b6..a2957cdca4 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -331,8 +331,25 @@ namespace MediaBrowser.Controller.Entities } } + private static bool IsLibraryFolderAccessible(IDirectoryService directoryService, BaseItem item) + { + // For top parents i.e. Library folders, skip the validation if it's empty or inaccessible + if (item.IsTopParent && !directoryService.IsAccessible(item.ContainingFolderPath)) + { + Logger.LogWarning("Library folder {LibraryFolderPath} is inaccessible or empty, skipping", item.ContainingFolderPath); + return false; + } + + return true; + } + private async Task ValidateChildrenInternal2(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { + if (!IsLibraryFolderAccessible(directoryService, this)) + { + return; + } + cancellationToken.ThrowIfCancellationRequested(); var validChildren = new List(); @@ -369,6 +386,11 @@ namespace MediaBrowser.Controller.Entities foreach (var child in nonCachedChildren) { + if (!IsLibraryFolderAccessible(directoryService, child)) + { + continue; + } + if (currentChildren.TryGetValue(child.Id, out BaseItem currentChild)) { validChildren.Add(currentChild); @@ -392,8 +414,8 @@ namespace MediaBrowser.Controller.Entities validChildren.Add(child); } - // If any items were added or removed.... - if (newItems.Count > 0 || currentChildren.Count != validChildren.Count) + // If it's an AggregateFolder, don't remove + if (!IsRoot && currentChildren.Count != validChildren.Count) { // That's all the new and changed ones - now see if there are any that are missing var itemsRemoved = currentChildren.Values.Except(validChildren).ToList(); @@ -408,7 +430,10 @@ namespace MediaBrowser.Controller.Entities LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }, this, false); } } + } + if (newItems.Count > 0) + { LibraryManager.CreateItems(newItems, this, cancellationToken); } } diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index d4de97651f..7fe2f64af3 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -78,5 +78,10 @@ namespace MediaBrowser.Controller.Providers return filePaths; } + + public bool IsAccessible(string path) + { + return _fileSystem.GetFileSystemEntryPaths(path).Any(); + } } } diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs index 48d6276918..6d7550ab53 100644 --- a/MediaBrowser.Controller/Providers/IDirectoryService.cs +++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs @@ -16,5 +16,7 @@ namespace MediaBrowser.Controller.Providers IReadOnlyList GetFilePaths(string path); IReadOnlyList GetFilePaths(string path, bool clearCache, bool sort = false); + + bool IsAccessible(string path); } }