mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-09 20:02:11 +01:00
Merge pull request #16456 from joshuaboniface/fix-path-filesystem-logic
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
Tests / run-tests (macos-latest) (push) Has been cancelled
Tests / run-tests (ubuntu-latest) (push) Has been cancelled
Tests / run-tests (windows-latest) (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Artifact (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Unstable Spec (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Stable Spec (push) Has been cancelled
Project Automation / Project board (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
Tests / run-tests (macos-latest) (push) Has been cancelled
Tests / run-tests (ubuntu-latest) (push) Has been cancelled
Tests / run-tests (windows-latest) (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Artifact (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Unstable Spec (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Stable Spec (push) Has been cancelled
Project Automation / Project board (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
This commit is contained in:
@@ -28,22 +28,44 @@ public static class StorageHelper
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the free space of a specific directory.
|
||||
/// Gets the free space of the parent filesystem of a specific directory.
|
||||
/// </summary>
|
||||
/// <param name="path">Path to a folder.</param>
|
||||
/// <returns>The number of bytes available space.</returns>
|
||||
/// <returns>Various details about the parent filesystem containing the directory.</returns>
|
||||
public static FolderStorageInfo GetFreeSpaceOf(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var driveInfo = new DriveInfo(path);
|
||||
// Fully resolve the given path to an actual filesystem target, in case it's a symlink or similar.
|
||||
var resolvedPath = ResolvePath(path);
|
||||
// We iterate all filesystems reported by GetDrives() here, and attempt to find the best
|
||||
// match that contains, as deep as possible, the given path.
|
||||
// This is required because simply calling `DriveInfo` on a path returns that path as
|
||||
// the Name and RootDevice, which is not at all how this should work.
|
||||
var allDrives = DriveInfo.GetDrives();
|
||||
DriveInfo? bestMatch = null;
|
||||
foreach (DriveInfo d in allDrives)
|
||||
{
|
||||
if (resolvedPath.StartsWith(d.RootDirectory.FullName, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
(bestMatch is null || d.RootDirectory.FullName.Length > bestMatch.RootDirectory.FullName.Length))
|
||||
{
|
||||
bestMatch = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestMatch is null)
|
||||
{
|
||||
throw new InvalidOperationException($"The path `{path}` has no matching parent device. Space check invalid.");
|
||||
}
|
||||
|
||||
return new FolderStorageInfo()
|
||||
{
|
||||
Path = path,
|
||||
FreeSpace = driveInfo.AvailableFreeSpace,
|
||||
UsedSpace = driveInfo.TotalSize - driveInfo.AvailableFreeSpace,
|
||||
StorageType = driveInfo.DriveType.ToString(),
|
||||
DeviceId = driveInfo.Name,
|
||||
ResolvedPath = resolvedPath,
|
||||
FreeSpace = bestMatch.AvailableFreeSpace,
|
||||
UsedSpace = bestMatch.TotalSize - bestMatch.AvailableFreeSpace,
|
||||
StorageType = bestMatch.DriveType.ToString(),
|
||||
DeviceId = bestMatch.Name,
|
||||
};
|
||||
}
|
||||
catch
|
||||
@@ -51,6 +73,7 @@ public static class StorageHelper
|
||||
return new FolderStorageInfo()
|
||||
{
|
||||
Path = path,
|
||||
ResolvedPath = path,
|
||||
FreeSpace = -1,
|
||||
UsedSpace = -1,
|
||||
StorageType = null,
|
||||
@@ -59,6 +82,26 @@ public static class StorageHelper
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walk a path and fully resolve any symlinks within it.
|
||||
/// </summary>
|
||||
private static string ResolvePath(string path)
|
||||
{
|
||||
var parts = path.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries);
|
||||
var current = Path.DirectorySeparatorChar.ToString();
|
||||
foreach (var part in parts)
|
||||
{
|
||||
current = Path.Combine(current, part);
|
||||
var resolved = new DirectoryInfo(current).ResolveLinkTarget(returnFinalTarget: true);
|
||||
if (resolved is not null)
|
||||
{
|
||||
current = resolved.FullName;
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying drive data from a given path and checks if the available storage capacity matches the threshold.
|
||||
/// </summary>
|
||||
|
||||
@@ -11,17 +11,22 @@ public record FolderStorageInfo
|
||||
public required string Path { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the free space of the underlying storage device of the <see cref="Path"/>.
|
||||
/// Gets the fully resolved path of the folder in question (interpolating any symlinks if present).
|
||||
/// </summary>
|
||||
public required string ResolvedPath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the free space of the underlying storage device of the <see cref="ResolvedPath"/>.
|
||||
/// </summary>
|
||||
public long FreeSpace { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the used space of the underlying storage device of the <see cref="Path"/>.
|
||||
/// Gets the used space of the underlying storage device of the <see cref="ResolvedPath"/>.
|
||||
/// </summary>
|
||||
public long UsedSpace { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the kind of storage device of the <see cref="Path"/>.
|
||||
/// Gets the kind of storage device of the <see cref="ResolvedPath"/>.
|
||||
/// </summary>
|
||||
public string? StorageType { get; init; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user