Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -312,12 +312,6 @@ private static Version GetICUVersion()
version & 0xFF);
}

private static readonly Lazy<bool> _net5CompatFileStream = new Lazy<bool>(() => GetStaticNonPublicBooleanPropertyValue("System.IO.Strategies.FileStreamHelpers", "UseNet5CompatStrategy"));

public static bool IsNet5CompatFileStreamEnabled => _net5CompatFileStream.Value;

public static bool IsNet5CompatFileStreamDisabled => !IsNet5CompatFileStreamEnabled;

private static readonly Lazy<bool> s_fileLockingDisabled = new Lazy<bool>(() => GetStaticNonPublicBooleanPropertyValue("Microsoft.Win32.SafeHandles.SafeFileHandle", "DisableFileLocking"));

public static bool IsFileLockingEnabled => IsWindows || !s_fileLockingDisabled.Value;
Expand Down
2 changes: 0 additions & 2 deletions src/libraries/System.IO.FileSystem/System.IO.FileSystem.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Disabl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Manual.Tests", "tests\ManualTests\System.IO.FileSystem.Manual.Tests.csproj", "{534152EB-14A8-4EF4-B181-342A555337F1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Net5Compat.Tests", "tests\Net5CompatTests\System.IO.FileSystem.Net5Compat.Tests.csproj", "{48E07F12-8597-40DE-8A37-CCBEB9D54012}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Tests", "tests\System.IO.FileSystem.Tests.csproj", "{3A8E16D3-8A22-4076-BB48-2CD1FBFAF81B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj", "{79A74577-C550-4264-B352-51D304796B89}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public async Task ReadAsyncCanceledFile(int bufferSize, bool isAsync)
}
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported), nameof(PlatformDetection.IsNet5CompatFileStreamDisabled))]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[InlineData(FileShare.None, FileOptions.Asynchronous)] // FileShare.None: exclusive access
[InlineData(FileShare.ReadWrite, FileOptions.Asynchronous)] // FileShare.ReadWrite: others can write to the file, the length can't be cached
[InlineData(FileShare.None, FileOptions.None)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,89 +65,5 @@ public void AccessFlushesFileClosesHandle()
Assert.Equal(TestBuffer.Length, fsr.Length);
}
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNet5CompatFileStreamEnabled))]
public async Task ThrowWhenHandlePositionIsChanged_sync()
{
await ThrowWhenHandlePositionIsChanged(useAsync: false);
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported), nameof(PlatformDetection.IsNet5CompatFileStreamEnabled))]
public async Task ThrowWhenHandlePositionIsChanged_async()
{
await ThrowWhenHandlePositionIsChanged(useAsync: true);
}

private async Task ThrowWhenHandlePositionIsChanged(bool useAsync)
{
string fileName = GetTestFilePath();

using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 0x100, useAsync))
{
// write some data to move the position, flush to ensure OS position is updated
fs.Write(TestBuffer, 0, TestBuffer.Length);
fs.Flush();

if (fs.SafeFileHandle.IsInvalid)
{
// nothing to test
return;
}

using (FileStream fsr = new FileStream(fs.SafeFileHandle, FileAccess.Read, TestBuffer.Length, useAsync))
{
Assert.Equal(TestBuffer.Length, fs.Position);
Assert.Equal(TestBuffer.Length, fsr.Position);

// Operations on original filestream will fail if data is in buffer and position changes.

// Put data in FS write buffer and update position from FSR
fs.WriteByte(0);
fsr.Position = 0;

if (useAsync
// Async I/O behaviors differ due to kernel-based implementation on Windows
&& OperatingSystem.IsWindows()
// ReadAsync which in this case (single byte written to buffer) calls FlushAsync is now 100% async
// so it does not complete synchronously anymore
&& PlatformDetection.IsNet5CompatFileStreamEnabled)
{
Assert.Throws<IOException>(() => FSAssert.CompletesSynchronously(fs.ReadAsync(new byte[1], 0, 1)));
}
else
{
await Assert.ThrowsAsync<IOException>(() => fs.ReadAsync(new byte[1], 0, 1));
}

fs.WriteByte(0);
fsr.Position++;
Assert.Throws<IOException>(() => fs.Read(new byte[1], 0, 1));

fs.WriteByte(0);
fsr.Position++;
await Assert.ThrowsAsync<IOException>(() => fs.ReadAsync(new byte[1], 0, 1));

fs.WriteByte(0);
fsr.Position++;
Assert.Throws<IOException>(() => fs.ReadByte());

fs.WriteByte(0);
fsr.Position++;
Assert.Throws<IOException>(() => fs.Seek(0, SeekOrigin.End));

fs.WriteByte(0);
fsr.Position++;
Assert.Throws<IOException>(() => fs.SetLength(2));

fs.WriteByte(0);
fsr.Position++;
Assert.Throws<IOException>(() => fs.Flush());

fs.WriteByte(0);
fsr.Position++;
Assert.Throws<IOException>(() => fs.Dispose());
}
}
}
}
}
12 changes: 0 additions & 12 deletions src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,18 +229,6 @@ public async Task ManyConcurrentWriteAsyncs_OuterLoop(
{
writes[i] = WriteAsync(fs, expectedData, i * writeSize, writeSize, cancellationToken);
Assert.Null(writes[i].Exception);
if (useAsync)
{
// To ensure that the buffer of a FileStream opened for async IO is flushed
// by FlushAsync in asynchronous way, we aquire a lock for every buffered WriteAsync.
// The side effect of this is that the Position of FileStream is not updated until
// the lock is released by a previous operation.
// So now all WriteAsync calls should be awaited before starting another async file operation.
if (PlatformDetection.IsNet5CompatFileStreamEnabled)
{
Assert.Equal((i + 1) * writeSize, fs.Position);
}
}
}

await Task.WhenAll(writes);
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions src/libraries/System.IO/System.IO.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO", "ref\System.IO.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO", "src\System.IO.csproj", "{0769544B-1A5D-4D74-94FD-899DF6C39D62}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.Net5Compat.Tests", "tests\Net5CompatTests\System.IO.Net5Compat.Tests.csproj", "{0217540D-FA86-41B3-9754-7BB5096ABA3E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.Tests", "tests\System.IO.Tests.csproj", "{72923407-7B7B-44A8-BCA6-2DB562835A8F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj", "{602525FF-EE47-4938-8979-32DC962109E4}"
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\DerivedFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\FileStreamHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\FileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\Net5CompatFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\OSFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IObservable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IObserver.cs" />
Expand Down Expand Up @@ -1843,8 +1842,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Enumeration\FileSystemEnumerator.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\AsyncWindowsFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\FileStreamHelpers.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\Net5CompatFileStreamStrategy.CompletionSource.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\Net5CompatFileStreamStrategy.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\SyncWindowsFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\PasteArguments.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\LibraryNameVariation.Windows.cs" />
Expand Down Expand Up @@ -2133,7 +2130,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Enumeration\FileSystemEntry.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Enumeration\FileSystemEnumerator.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\FileStreamHelpers.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\Net5CompatFileStreamStrategy.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Strategies\UnixFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\PasteArguments.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\LibraryNameVariation.Unix.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ namespace System.IO.Strategies
// this type defines a set of stateless FileStream/FileStreamStrategy helper methods
internal static partial class FileStreamHelpers
{
// Async completion/return codes shared by:
// - AsyncWindowsFileStreamStrategy.ValueTaskSource
// - Net5CompatFileStreamStrategy.CompletionSource
// Async completion/return codes used by
// SafeFileHandle.OverlappedValueTaskSource
internal static class TaskSourceCodes
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is unused but I didn't remove it to avoid surprising any new code that might decide to use it in the meantime until the PR is merged.

{
internal const long NoResult = 0;
Expand Down Expand Up @@ -338,7 +337,7 @@ internal static async Task AsyncModeCopyToAsync(SafeFileHandle handle, bool canS
}
}

/// <summary>Used by AsyncWindowsFileStreamStrategy and Net5CompatFileStreamStrategy CopyToAsync to enable awaiting the result of an overlapped I/O operation with minimal overhead.</summary>
/// <summary>Used by AsyncWindowsFileStreamStrategy.CopyToAsync to enable awaiting the result of an overlapped I/O operation with minimal overhead.</summary>
private sealed unsafe class AsyncCopyToAwaitable : ICriticalNotifyCompletion
{
/// <summary>Sentinel object used to indicate that the I/O operation has completed before being awaited.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,17 @@ internal static partial class FileStreamHelpers
/// <summary>Caches whether Serialization Guard has been disabled for file writes</summary>
private static int s_cachedSerializationSwitch;

internal static bool UseNet5CompatStrategy { get; } = AppContextConfigHelper.GetBooleanConfig("System.IO.UseNet5CompatFileStream", "DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM");

internal static FileStreamStrategy ChooseStrategy(FileStream fileStream, SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync)
{
// The .NET 5 Compat strategy does not support bufferSize == 0.
// To minimize the risk of introducing bugs to it, we just pass 1 to disable the buffering.

FileStreamStrategy strategy = UseNet5CompatStrategy ?
new Net5CompatFileStreamStrategy(handle, access, bufferSize == 0 ? 1 : bufferSize, isAsync) :
FileStreamStrategy strategy =
EnableBufferingIfNeeded(ChooseStrategyCore(handle, access, isAsync), bufferSize);

return WrapIfDerivedType(fileStream, strategy);
}

internal static FileStreamStrategy ChooseStrategy(FileStream fileStream, string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, long preallocationSize)
{
FileStreamStrategy strategy = UseNet5CompatStrategy ?
new Net5CompatFileStreamStrategy(path, mode, access, share, bufferSize == 0 ? 1 : bufferSize, options, preallocationSize) :
FileStreamStrategy strategy =
EnableBufferingIfNeeded(ChooseStrategyCore(path, mode, access, share, options, preallocationSize), bufferSize);

return WrapIfDerivedType(fileStream, strategy);
Expand Down
Loading