From d5fe6399319092acc047368bf553e96eda81fe05 Mon Sep 17 00:00:00 2001 From: rameel Date: Wed, 17 Sep 2025 04:53:21 +0500 Subject: [PATCH 1/5] Make EnumerableExtensions internal --- .../Utilities/EnumerableExtensions.cs | 2 +- .../Ramstack.FileSystem.Adapters.csproj | 3 +++ .../Ramstack.FileSystem.Physical.csproj | 3 +++ .../Ramstack.FileSystem.Prefixed.csproj | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Ramstack.FileSystem.Abstractions/Utilities/EnumerableExtensions.cs b/src/Ramstack.FileSystem.Abstractions/Utilities/EnumerableExtensions.cs index bf52954..9173c27 100644 --- a/src/Ramstack.FileSystem.Abstractions/Utilities/EnumerableExtensions.cs +++ b/src/Ramstack.FileSystem.Abstractions/Utilities/EnumerableExtensions.cs @@ -3,7 +3,7 @@ namespace Ramstack.FileSystem.Utilities; /// /// Provides extension methods for the . /// -public static class EnumerableExtensions +internal static class EnumerableExtensions { /// /// Converts an enumerable sequence to an async-enumerable sequence. diff --git a/src/Ramstack.FileSystem.Adapters/Ramstack.FileSystem.Adapters.csproj b/src/Ramstack.FileSystem.Adapters/Ramstack.FileSystem.Adapters.csproj index 82f0333..2a245bd 100644 --- a/src/Ramstack.FileSystem.Adapters/Ramstack.FileSystem.Adapters.csproj +++ b/src/Ramstack.FileSystem.Adapters/Ramstack.FileSystem.Adapters.csproj @@ -38,6 +38,9 @@ Properties\AssemblyInfo.cs + + Utilities\EnumerableExtensions.cs + diff --git a/src/Ramstack.FileSystem.Physical/Ramstack.FileSystem.Physical.csproj b/src/Ramstack.FileSystem.Physical/Ramstack.FileSystem.Physical.csproj index df8d3ad..23dd7b5 100644 --- a/src/Ramstack.FileSystem.Physical/Ramstack.FileSystem.Physical.csproj +++ b/src/Ramstack.FileSystem.Physical/Ramstack.FileSystem.Physical.csproj @@ -38,6 +38,9 @@ Properties\AssemblyInfo.cs + + Utilities\EnumerableExtensions.cs + diff --git a/src/Ramstack.FileSystem.Prefixed/Ramstack.FileSystem.Prefixed.csproj b/src/Ramstack.FileSystem.Prefixed/Ramstack.FileSystem.Prefixed.csproj index d116662..d04e3e8 100644 --- a/src/Ramstack.FileSystem.Prefixed/Ramstack.FileSystem.Prefixed.csproj +++ b/src/Ramstack.FileSystem.Prefixed/Ramstack.FileSystem.Prefixed.csproj @@ -38,6 +38,9 @@ Properties\AssemblyInfo.cs + + Utilities\EnumerableExtensions.cs + From 554694018f441fb1794abf0c37514438e35a1006 Mon Sep 17 00:00:00 2001 From: rameel Date: Wed, 17 Sep 2025 04:55:17 +0500 Subject: [PATCH 2/5] Remove unnecessary using --- src/Ramstack.FileSystem.Abstractions/Utilities/PathTokenizer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Ramstack.FileSystem.Abstractions/Utilities/PathTokenizer.cs b/src/Ramstack.FileSystem.Abstractions/Utilities/PathTokenizer.cs index b53bb50..f34a401 100644 --- a/src/Ramstack.FileSystem.Abstractions/Utilities/PathTokenizer.cs +++ b/src/Ramstack.FileSystem.Abstractions/Utilities/PathTokenizer.cs @@ -1,5 +1,3 @@ -using System.Runtime.CompilerServices; - namespace Ramstack.FileSystem.Utilities; /// From 9faaac4c0baf92048a0da8443b96e704573b23bd Mon Sep 17 00:00:00 2001 From: rameel Date: Wed, 17 Sep 2025 04:58:50 +0500 Subject: [PATCH 3/5] Clarify precedences --- src/Ramstack.FileSystem.Abstractions/VirtualPath.cs | 2 +- src/Ramstack.FileSystem.Globbing/GlobbingFileSystem.cs | 2 +- src/Ramstack.FileSystem.Globbing/Internal/PathHelper.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Ramstack.FileSystem.Abstractions/VirtualPath.cs b/src/Ramstack.FileSystem.Abstractions/VirtualPath.cs index 1ae6b0c..236a08e 100644 --- a/src/Ramstack.FileSystem.Abstractions/VirtualPath.cs +++ b/src/Ramstack.FileSystem.Abstractions/VirtualPath.cs @@ -173,7 +173,7 @@ public static bool IsNormalized(ReadOnlySpan path) for (var j = 1; (uint)j < (uint)path.Length; j++) { var ch = path[j]; - if (ch == '\\' || ch == '/' && prior == '/') + if (ch == '\\' || (ch == '/' && prior == '/')) return false; if (ch == '.' && prior == '/') diff --git a/src/Ramstack.FileSystem.Globbing/GlobbingFileSystem.cs b/src/Ramstack.FileSystem.Globbing/GlobbingFileSystem.cs index 18a793b..ced4273 100644 --- a/src/Ramstack.FileSystem.Globbing/GlobbingFileSystem.cs +++ b/src/Ramstack.FileSystem.Globbing/GlobbingFileSystem.cs @@ -103,5 +103,5 @@ internal bool IsFileIncluded(string path) => /// otherwise, . /// internal bool IsDirectoryIncluded(string path) => - path == "/" || !PathHelper.IsMatch(path, _excludes) && PathHelper.IsPartialMatch(path, _patterns); + path == "/" || (!PathHelper.IsMatch(path, _excludes) && PathHelper.IsPartialMatch(path, _patterns)); } diff --git a/src/Ramstack.FileSystem.Globbing/Internal/PathHelper.cs b/src/Ramstack.FileSystem.Globbing/Internal/PathHelper.cs index b2fd46c..8b22129 100644 --- a/src/Ramstack.FileSystem.Globbing/Internal/PathHelper.cs +++ b/src/Ramstack.FileSystem.Globbing/Internal/PathHelper.cs @@ -118,7 +118,7 @@ public static ReadOnlySpan GetPartialPattern(string pattern, int depth) static bool IsGlobStar(ref char s, int index, int final) => index + 2 == final && Unsafe.ReadUnaligned( ref Unsafe.As( - ref Unsafe.Add(ref s, (nint)(uint)index))) == ('*' << 16 | '*'); + ref Unsafe.Add(ref s, (nint)(uint)index))) == (('*' << 16) | '*'); } #region Vector helper methods From f6c2b7de5a01e81742483b357ea5d6e071b5526d Mon Sep 17 00:00:00 2001 From: rameel Date: Wed, 17 Sep 2025 05:00:46 +0500 Subject: [PATCH 4/5] Replace Path.DirectorySeparatorChar checks with OperatingSystem.IsWindows --- src/Ramstack.FileSystem.Physical/PhysicalFile.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ramstack.FileSystem.Physical/PhysicalFile.cs b/src/Ramstack.FileSystem.Physical/PhysicalFile.cs index d648470..6e2455a 100644 --- a/src/Ramstack.FileSystem.Physical/PhysicalFile.cs +++ b/src/Ramstack.FileSystem.Physical/PhysicalFile.cs @@ -45,7 +45,7 @@ protected override ValueTask OpenReadCoreAsync(CancellationToken cancell { // SequentialScan is a performance hint that requires extra sys-call on non-Windows systems. // https://github.com/dotnet/runtime/blob/46c9a4fff83f35ec659e6659050440aadccf3201/src/libraries/System.Private.CoreLib/src/System/IO/File.cs#L694 - var options = Path.DirectorySeparatorChar == '\\' + var options = OperatingSystem.IsWindows() ? FileOptions.Asynchronous | FileOptions.SequentialScan : FileOptions.Asynchronous; @@ -108,7 +108,7 @@ protected override async ValueTask WriteCoreAsync(Stream stream, bool overwrite, const int WIN32_ERROR_FILE_EXISTS = unchecked((int)0x80070050); const int POSIX_EEXIST = 17; - var exists = Path.DirectorySeparatorChar == '\\' + var exists = OperatingSystem.IsWindows() ? exception.HResult == WIN32_ERROR_FILE_EXISTS : exception.HResult == POSIX_EEXIST; From 4f7745dcf2265d6278ea6fa98b96a512ee21e7ff Mon Sep 17 00:00:00 2001 From: rameel Date: Wed, 17 Sep 2025 05:02:54 +0500 Subject: [PATCH 5/5] Remove FileOptions.SequentialScan for write operations --- src/Ramstack.FileSystem.Physical/PhysicalFile.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Ramstack.FileSystem.Physical/PhysicalFile.cs b/src/Ramstack.FileSystem.Physical/PhysicalFile.cs index 6e2455a..1839201 100644 --- a/src/Ramstack.FileSystem.Physical/PhysicalFile.cs +++ b/src/Ramstack.FileSystem.Physical/PhysicalFile.cs @@ -59,11 +59,7 @@ protected override ValueTask OpenWriteCoreAsync(CancellationToken cancel { EnsureDirectoryExists(); - var options = Path.DirectorySeparatorChar == '\\' - ? FileOptions.Asynchronous | FileOptions.SequentialScan - : FileOptions.Asynchronous; - - var stream = new FileStream(_physicalPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, DefaultBufferSize, options); + var stream = new FileStream(_physicalPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, DefaultBufferSize, FileOptions.Asynchronous); // Since FileMode.OpenOrCreate doesn't truncate the file, we manually // set the file length to zero to remove any leftover data. @@ -79,16 +75,12 @@ protected override async ValueTask WriteCoreAsync(Stream stream, bool overwrite, try { - var options = Path.DirectorySeparatorChar == '\\' - ? FileOptions.Asynchronous | FileOptions.SequentialScan - : FileOptions.Asynchronous; - // To overwrite the file, we use FileMode.OpenOrCreate instead of FileMode.Create. // This avoids a System.UnauthorizedAccessException: Access to the path is denied, // which can occur if the file has the FileAttributes.Hidden attribute. var fileMode = overwrite ? FileMode.OpenOrCreate : FileMode.CreateNew; - await using var fs = new FileStream(_physicalPath, fileMode, FileAccess.Write, FileShare.None, DefaultBufferSize, options); + await using var fs = new FileStream(_physicalPath, fileMode, FileAccess.Write, FileShare.None, DefaultBufferSize, FileOptions.Asynchronous); // Since FileMode.OpenOrCreate doesn't truncate the file, we manually // set the file length to zero to remove any leftover data.