diff --git a/MediaBrowser.Controller/IO/FileSystemHelper.cs b/MediaBrowser.Controller/IO/FileSystemHelper.cs
index 3e390ca428e..44b7fadf5ed 100644
--- a/MediaBrowser.Controller/IO/FileSystemHelper.cs
+++ b/MediaBrowser.Controller/IO/FileSystemHelper.cs
@@ -63,6 +63,29 @@ public static class FileSystemHelper
}
}
+ ///
+ /// Resolves a single link hop for the specified path.
+ ///
+ ///
+ /// Returns null if the path is not a symbolic link or the filesystem does not support link resolution (e.g., exFAT).
+ ///
+ /// The file path to resolve.
+ ///
+ /// A representing the next link target if the path is a link; otherwise, null.
+ ///
+ private static FileInfo? Resolve(string path)
+ {
+ try
+ {
+ return File.ResolveLinkTarget(path, returnFinalTarget: false) as FileInfo;
+ }
+ catch (IOException)
+ {
+ // Filesystem doesn't support links (e.g., exFAT).
+ return null;
+ }
+ }
+
///
/// Gets the target of the specified file link.
///
@@ -84,23 +107,26 @@ public static class FileSystemHelper
if (!returnFinalTarget)
{
- return File.ResolveLinkTarget(linkPath, returnFinalTarget: false) as FileInfo;
+ return Resolve(linkPath);
}
- if (File.ResolveLinkTarget(linkPath, returnFinalTarget: false) is not FileInfo targetInfo)
- {
- return null;
- }
-
- if (!targetInfo.Exists)
+ var targetInfo = Resolve(linkPath);
+ if (targetInfo is null || !targetInfo.Exists)
{
return targetInfo;
}
var currentPath = targetInfo.FullName;
var visited = new HashSet(StringComparer.Ordinal) { linkPath, currentPath };
- while (File.ResolveLinkTarget(currentPath, returnFinalTarget: false) is FileInfo linkInfo)
+
+ while (true)
{
+ var linkInfo = Resolve(currentPath);
+ if (linkInfo is null)
+ {
+ break;
+ }
+
var targetPath = linkInfo.FullName;
// If an infinite loop is detected, return the file info for the