[Kernel] Take APR file sizes from the mount check's stat instead of listing directories
Resolving an APR path already stats every component to rule out links out of the mount. The same stat now records the file's size, so size lookup no longer lists the file's whole directory. Listing stats every entry: Demon's Souls keeps up to 7,390 files per asset directory on a slow disk, and each first lookup in one paid for all of them. FileInfo reports a missing component as -1 instead of throwing; it still ends the check.
This commit is contained in:
parent
467877d046
commit
997b7df06f
|
|
@ -126,7 +126,6 @@ public static partial class KernelMemoryCompatExports
|
|||
// every asset path at startup; re-reading each directory's attributes costs seconds.
|
||||
private static readonly ConcurrentDictionary<string, byte> _verifiedMountComponents = new(HostFsPath.Comparer);
|
||||
private static readonly ConcurrentDictionary<string, string> _fullMountRoots = new(StringComparer.Ordinal);
|
||||
private static readonly ConcurrentDictionary<string, byte> _aprScannedDirectories = new(HostFsPath.Comparer);
|
||||
private static long _nextFileDescriptor = 2;
|
||||
private static string _applicationTitleId = "UNKNOWN";
|
||||
|
||||
|
|
@ -5173,11 +5172,26 @@ public static partial class KernelMemoryCompatExports
|
|||
|
||||
try
|
||||
{
|
||||
if ((File.GetAttributes(current) & FileAttributes.ReparsePoint) != 0)
|
||||
// One lstat answers both questions a resolved asset path asks: whether the
|
||||
// component is a link, and (for the file itself) its size for APR resolution.
|
||||
var component = new FileInfo(current);
|
||||
var attributes = component.Attributes;
|
||||
if ((int)attributes == -1)
|
||||
{
|
||||
// Component does not exist yet (create path); nothing to follow.
|
||||
break;
|
||||
}
|
||||
|
||||
if ((attributes & FileAttributes.ReparsePoint) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((attributes & FileAttributes.Directory) == 0)
|
||||
{
|
||||
_aprFileSizeCache.TryAdd(current, component.Length < 0 ? 0UL : unchecked((ulong)component.Length));
|
||||
}
|
||||
|
||||
_verifiedMountComponents.TryAdd(current, 0);
|
||||
}
|
||||
catch (Exception ex) when (ex is FileNotFoundException or DirectoryNotFoundException)
|
||||
|
|
@ -6902,27 +6916,6 @@ public static partial class KernelMemoryCompatExports
|
|||
return false;
|
||||
}
|
||||
|
||||
// One directory listing returns every file's size; titles resolve whole asset
|
||||
// directories at startup, so this replaces one host query per file.
|
||||
if (Path.GetDirectoryName(cachePath) is { } directory && _aprScannedDirectories.TryAdd(directory, 0))
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var file in new DirectoryInfo(directory).EnumerateFiles())
|
||||
{
|
||||
_aprFileSizeCache.TryAdd(file.FullName, file.Length < 0 ? 0UL : unchecked((ulong)file.Length));
|
||||
}
|
||||
}
|
||||
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or System.Security.SecurityException)
|
||||
{
|
||||
}
|
||||
|
||||
if (_aprFileSizeCache.TryGetValue(cachePath, out size))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(cachePath);
|
||||
|
|
|
|||
Loading…
Reference in New Issue