Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce FileStreamStrategy as a first step of FileStream rewrite #47128

Merged
merged 101 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
c0ded00
rename FileStream -> FileStreamImpl FILES
adamsitnik Jan 15, 2021
0fe40d1
rename FileStream -> FileStreamImpl CLASS, make it internal and sealed
adamsitnik Jan 15, 2021
e352313
restore orgiginal FileStream
adamsitnik Jan 15, 2021
550e63f
ctors
adamsitnik Jan 15, 2021
62d863c
introduce new abstract class to have Lock, Unlock and Handle methods …
adamsitnik Jan 15, 2021
14d2aa0
implement FlushAsync
adamsitnik Jan 15, 2021
796d7a3
add all virtual methods to the base abstrac class (and rename it)
adamsitnik Jan 15, 2021
2108bd6
implement Read(byte[] buffer, int offset, int count)
adamsitnik Jan 15, 2021
3cc6d07
ReadAsync(byte[] buffer, int offset, int count, CancellationToken can…
adamsitnik Jan 15, 2021
0a202c0
ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = …
adamsitnik Jan 15, 2021
c45e7eb
Write(byte[] buffer, int offset, int count)
adamsitnik Jan 15, 2021
cedc13a
Write(ReadOnlySpan<byte> buffer)
adamsitnik Jan 15, 2021
4b3d048
WriteAsync(byte[] buffer, int offset, int count, CancellationToken ca…
adamsitnik Jan 15, 2021
bafc099
WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellatio…
adamsitnik Jan 15, 2021
91513ed
Flush() and Flush(bool flushToDisk)
adamsitnik Jan 15, 2021
ecd62f0
CanRead and CanWrite
adamsitnik Jan 15, 2021
1faf34a
input validation should be always performed in the public type
adamsitnik Jan 15, 2021
fe308fe
SetLength(long value)
adamsitnik Jan 15, 2021
082d630
SafeFileHandle, Name, IsAsync and Length
adamsitnik Jan 15, 2021
cb6adc3
Position
adamsitnik Jan 15, 2021
2feeefa
IsClosed
adamsitnik Jan 15, 2021
1301318
ReadByte()
adamsitnik Jan 15, 2021
7f15975
WriteByte(byte value)
adamsitnik Jan 15, 2021
6089931
finalizer
adamsitnik Jan 15, 2021
d26deb4
BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callba…
adamsitnik Jan 15, 2021
0a9fd33
BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callb…
adamsitnik Jan 15, 2021
f681b6f
EndRead and EndWrite
adamsitnik Jan 15, 2021
f880335
FileStream(SafeFileHandle handle, FileAccess access, int bufferSize)
adamsitnik Jan 15, 2021
fceeb0d
fix compilation errors
adamsitnik Jan 15, 2021
80fdf68
remove unused fields and methods
adamsitnik Jan 15, 2021
e1459f1
CanSeek and Seek
adamsitnik Jan 15, 2021
7cf008d
fix all compilation errors
adamsitnik Jan 15, 2021
d1d6528
add missing overrides (implemented in OS-specific files and not caugh…
adamsitnik Jan 15, 2021
d30f371
make sure FileStream is not used in FileStreamImpl
adamsitnik Jan 15, 2021
99868c4
rename FileStreamImplBase to FileStreamStrategy and move it to a sepa…
adamsitnik Jan 15, 2021
07ed850
it might seem to have to sense now, but we plan to introduce dedicate…
adamsitnik Jan 15, 2021
19ef1a7
some minor polishing
adamsitnik Jan 15, 2021
50a6850
reference field can be null in finalizer
adamsitnik Jan 19, 2021
a0b3196
it looks like having this finalizer is mandatory, as we can not guara…
adamsitnik Jan 19, 2021
e3b23fd
fix a typo in the comments
adamsitnik Jan 19, 2021
2581181
rename _actualImplementation to _impl as suggested in code review
adamsitnik Jan 19, 2021
62580e8
move ctor argument validation logic back to FileStream (it's going to…
adamsitnik Jan 19, 2021
82ac0d7
move handle validation logic to FileStream, make _bufferLength readonly
adamsitnik Jan 19, 2021
d35bd15
move more validation logic to FileStream
adamsitnik Jan 19, 2021
7a4c761
more polishing
adamsitnik Jan 19, 2021
7c95a6c
reduce code duplication in ctors
adamsitnik Jan 19, 2021
85ab921
the Unix implementation was assuming type check is not needed
adamsitnik Jan 19, 2021
ccfea9a
fix the Flush bug that I've introduced
adamsitnik Jan 20, 2021
97a8c51
make sure base.CopyToAsync is called for all custom types that Derive…
adamsitnik Jan 20, 2021
a288c2a
introduce DerivedFileStreamImpl, remove GetType checks from FileStream
adamsitnik Jan 20, 2021
662fa2c
all FileStream methods should just delegate the actual logic to Strategy
adamsitnik Jan 21, 2021
233df39
clarify all "base" keyword usages
adamsitnik Jan 21, 2021
b4b31c4
clarify all "base" keyword usages, make sure the comments are in the …
adamsitnik Jan 21, 2021
19cec28
Flush() called from strategy.SafeFileHandle should call the virtual F…
adamsitnik Jan 21, 2021
3a2f106
remove the if statement (it's going to become switch)
adamsitnik Jan 21, 2021
4e3796c
get rid of the Impl word, use Strategy everywhere
adamsitnik Jan 22, 2021
227d98d
remove .Handle from the Strategy
adamsitnik Jan 22, 2021
8c865a8
rename FileStreamImpl => CommonFileStreamStrategyTemplate
adamsitnik Jan 22, 2021
e82a235
rename FileStreamImpl.Unix => UnixFileStreamStrategy
adamsitnik Jan 22, 2021
8756821
rename FileStreamImpl.Windows => WindowsFileStreamStrategy
adamsitnik Jan 22, 2021
d7dd225
make the fields protected so they can be accessed from derived types
adamsitnik Jan 22, 2021
23446ee
remove handle
adamsitnik Jan 22, 2021
4793717
fix finalizer
adamsitnik Jan 22, 2021
6c79ac5
fix the ctors, make init methods abstract and part of the template
adamsitnik Jan 22, 2021
cc65678
Lock & Unlock
adamsitnik Jan 22, 2021
6d2db24
FlushWriteBuffer
adamsitnik Jan 22, 2021
01899df
FlushOSBuffer
adamsitnik Jan 22, 2021
c2cc411
there is no need to have selead methods in a sealed type...
adamsitnik Jan 22, 2021
a92424d
SetLength
adamsitnik Jan 22, 2021
e360787
Length {get;}
adamsitnik Jan 22, 2021
3791ecc
OnBufferAllocated
adamsitnik Jan 22, 2021
c1a418a
FillReadBufferForReadByte
adamsitnik Jan 22, 2021
dab77a3
FlushWriteBufferForWriteByte
adamsitnik Jan 22, 2021
6e8d201
ReadSpan WriteSpan
adamsitnik Jan 22, 2021
08bbb0f
ReadAsyncInternal WriteAsyncInternal
adamsitnik Jan 22, 2021
4e86030
SeekCore
adamsitnik Jan 22, 2021
c85c303
make the private helpers protected so they can be accessed from deriv…
adamsitnik Jan 22, 2021
5802b83
replaces usages of FileStreamImpl with appropriate Strategy
adamsitnik Jan 22, 2021
33f58df
remove Handle from DerivedFileStreamStrategy
adamsitnik Jan 22, 2021
2e20ab9
fix the ctors, it compiles on Windows!
adamsitnik Jan 22, 2021
1704b83
this is not needed anymore
adamsitnik Jan 22, 2021
34b7822
fix compilation errors for Unix
adamsitnik Jan 22, 2021
81cd5eb
fix the build?
adamsitnik Jan 22, 2021
0a4c55c
rename CommonFileStreamStrategyTemplate to FileStreamStrategyBase bef…
adamsitnik Jan 25, 2021
01f0cc3
introduce FileStreamStrategyHelper and move some of the parameterless…
adamsitnik Jan 25, 2021
692b965
introduce ChooseStrategy method, remove #ifs
adamsitnik Jan 25, 2021
fe202db
fix the Unix build?
adamsitnik Jan 25, 2021
1258ad7
fix the Unix build
adamsitnik Jan 25, 2021
d9fc921
rename FileStreamStrategyHelper => FileStreamHelpers
adamsitnik Feb 5, 2021
2d820c3
move all internal Base* methods to the bottom of the source file
adamsitnik Feb 5, 2021
9706f3d
alphabetic order of files in project file
adamsitnik Feb 5, 2021
a76ed8c
it looks like the internal FileStream.IsClosed can be removed as we d…
adamsitnik Feb 5, 2021
6204ae5
call virtual Can methods where we used to and still can
adamsitnik Feb 5, 2021
ba34492
Merge remote-tracking branch 'upstream/master' into fileStream1stStep
adamsitnik Feb 8, 2021
a52f5a8
don't separate Unix and Windows strategies, introduce LegacyFileStrea…
adamsitnik Feb 22, 2021
3a3b3c9
address code review comment and fix last TODO
adamsitnik Feb 22, 2021
b41456a
fix Unix build 1/n
adamsitnik Feb 22, 2021
41c3263
update comment
adamsitnik Feb 22, 2021
a88f1a5
Update src/libraries/System.Private.CoreLib/src/System/IO/FileStream.cs
adamsitnik Feb 23, 2021
5ad9cbb
apply code review suggestions
adamsitnik Feb 23, 2021
835fa17
Apply suggestions from code review
adamsitnik Feb 24, 2021
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
12 changes: 12 additions & 0 deletions src/libraries/System.IO.FileSystem/tests/FileStream/Flush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ public void FlushCallsFlush_flushToDisk_False()
}
}

[Fact]
public void SafeFileHandleCallsFlush_flushToDisk_False()
{
using (StoreFlushArgFileStream fs = new StoreFlushArgFileStream(GetTestFilePath(), FileMode.Create))
{
GC.KeepAlive(fs.SafeFileHandle); // this should call Flush, which should call StoreFlushArgFileStream.Flush(false)

Assert.True(fs.LastFlushArg.HasValue);
Assert.False(fs.LastFlushArg.Value);
}
}

[Theory]
[InlineData(null)]
[InlineData(false)]
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.IO.FileSystem/tests/FileStream/Position.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,15 @@ public void SetPositionAppendModify()
Assert.Equal(length + 1, fs.Position);
}
}

[Fact]
public void GetPositionThrowsForUnseekableFileStream()
{
string fileName = GetTestFilePath();
using (FileStream fs = new UnseekableFileStream(fileName, FileMode.Create))
{
Assert.Throws<NotSupportedException>(() => _ = fs.Position);
}
}
}
}
20 changes: 20 additions & 0 deletions src/libraries/System.IO.FileSystem/tests/FileStream/SetLength.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,25 @@ public void SetLengthAppendModifyThrows()
Assert.Equal(length, fs.Length);
}
}

[Fact]
public void SetLengthThrowsForUnseekableFileStream()
{
string fileName = GetTestFilePath();
using (FileStream fs = new UnseekableFileStream(fileName, FileMode.Create))
{
Assert.Throws<NotSupportedException>(() => fs.SetLength(1));
}
}

[Fact]
public void GetLengthThrowsForUnseekableFileStream()
{
string fileName = GetTestFilePath();
using (FileStream fs = new UnseekableFileStream(fileName, FileMode.Create))
{
Assert.Throws<NotSupportedException>(() => _ = fs.Length);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\BinaryReader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\BinaryWriter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\BufferedStream.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DerivedFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DirectoryNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\EncodingCache.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\EndOfStreamException.cs" />
Expand All @@ -400,10 +401,12 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileOptions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileShare.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\HandleInheritability.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\InvalidDataException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\IOException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\MemoryStream.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\LegacyFileStreamStrategy.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathTooLongException.cs" />
Expand Down Expand Up @@ -1620,14 +1623,14 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GlobalizationMode.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DisableMediaInsertionPrompt.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStreamHelpers.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStreamCompletionSource.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathHelper.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DisableMediaInsertionPrompt.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\LegacyFileStreamStrategy.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\PasteArguments.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\LibraryNameVariation.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Windows.cs" />
Expand Down Expand Up @@ -1826,12 +1829,13 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GlobalizationMode.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Lock.OSX.cs" Condition="'$(IsOSXLike)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Lock.Unix.cs" Condition="'$(IsOSXLike)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStreamHelpers.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PersistedFiles.Names.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\LegacyFileStreamStrategy.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\LegacyFileStreamStrategy.Lock.OSX.cs" Condition="'$(IsOSXLike)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\LegacyFileStreamStrategy.Lock.Unix.cs" Condition="'$(IsOSXLike)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\PasteArguments.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\LibraryNameVariation.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Unix.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;

namespace System.IO
{
// this type exists so we can avoid GetType() != typeof(FileStream) checks in FileStream
// when FileStream was supposed to call base.Method() for such cases, we just call _fileStream.BaseMethod()
// for everything else we fall back to the actual strategy (like FileStream does)
//
// it's crucial to NOT use the "base" keyoword here! everything must be using _fileStream or _strategy
internal sealed class DerivedFileStreamStrategy : FileStreamStrategy
Copy link
Member

@stephentoub stephentoub Feb 23, 2021

Choose a reason for hiding this comment

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

I think "Derived" is an odd name here, given that FileStreamStrategy is abstract and any implementation will necessarily be "derived". We often use the term "Delegating" in such cases, e.g. DelegatingHandler, DelegatingStream, etc.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think "Derived" is an odd name here, given that FileStreamStrategy is abstract and any implementation will necessarily be "derived"

In this particular context, it meant a strategy for a type that derives from FileStream. Does it make more sense or would you like me to rename it to DelegatingFileStreamStrategy ?

Copy link
Member

Choose a reason for hiding this comment

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

So "DerivedFileStreamFileStreamStrategy" :)

I don't have a strong opinion. If you want to stick with DerivedFileStreamStrategy, that's fine.

{
private readonly FileStreamStrategy _strategy;

internal DerivedFileStreamStrategy(FileStream fileStream, FileStreamStrategy strategy) : base(fileStream) => _strategy = strategy;

public override bool CanRead => _strategy.CanRead;

public override bool CanWrite => _strategy.CanWrite;

public override bool CanSeek => _strategy.CanSeek;

public override long Length => _strategy.Length;

public override long Position
{
get => _strategy.Position;
set => _strategy.Position = value;
}

internal override bool IsAsync => _strategy.IsAsync;

internal override string Name => _strategy.Name;

internal override SafeFileHandle SafeFileHandle => _strategy.SafeFileHandle;

internal override bool IsClosed => _strategy.IsClosed;

internal override void Lock(long position, long length) => _strategy.Lock(position, length);

internal override void Unlock(long position, long length) => _strategy.Unlock(position, length);

public override long Seek(long offset, SeekOrigin origin) => _strategy.Seek(offset, origin);

public override void SetLength(long value) => _strategy.SetLength(value);

public override int ReadByte() => _strategy.ReadByte();

public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
=> _strategy.IsAsync
? _strategy.BeginRead(buffer, offset, count, callback, state)
: _fileStream.BaseBeginRead(buffer, offset, count, callback, state);

public override int EndRead(IAsyncResult asyncResult)
=> _strategy.IsAsync ? _strategy.EndRead(asyncResult) : _fileStream.BaseEndRead(asyncResult);

public override int Read(byte[] buffer, int offset, int count) => _strategy.Read(buffer, offset, count);

// If this is a derived type, it may have overridden Read(byte[], int, int) prior to this Read(Span<byte>)
// overload being introduced. In that case, this Read(Span<byte>) overload should use the behavior
// of Read(byte[],int,int) overload.
public override int Read(Span<byte> buffer)
=> _fileStream.BaseRead(buffer);

// If we have been inherited into a subclass, the Strategy implementation could be incorrect
adamsitnik marked this conversation as resolved.
Show resolved Hide resolved
// since it does not call through to Read() which a subclass might have overridden.
// To be safe we will only use this implementation in cases where we know it is safe to do so,
// and delegate to FileStream base class (which will call into Read/ReadAsync) when we are not sure.
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> _fileStream.BaseReadAsync(buffer, offset, count, cancellationToken);

// If this isn't a concrete FileStream, a derived type may have overridden ReadAsync(byte[],...),
// which was introduced first, so delegate to the base which will delegate to that.
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
=> _fileStream.BaseReadAsync(buffer, cancellationToken);

public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
=> _strategy.IsAsync
? _strategy.BeginWrite(buffer, offset, count, callback, state)
: _fileStream.BaseBeginWrite(buffer, offset, count, callback, state);

public override void EndWrite(IAsyncResult asyncResult)
{
if (_strategy.IsAsync)
{
_strategy.EndWrite(asyncResult);
}
else
{
_fileStream.BaseEndWrite(asyncResult);
}
}

public override void WriteByte(byte value) => _strategy.WriteByte(value);

public override void Write(byte[] buffer, int offset, int count) => _strategy.Write(buffer, offset, count);

// If this is a derived type, it may have overridden Write(byte[], int, int) prior to this Write(ReadOnlySpan<byte>)
// overload being introduced. In that case, this Write(ReadOnlySpan<byte>) overload should use the behavior
// of Write(byte[],int,int) overload.
public override void Write(ReadOnlySpan<byte> buffer)
=> _fileStream.BaseWrite(buffer);

// If we have been inherited into a subclass, the Strategy implementation could be incorrect
// since it does not call through to Write() or WriteAsync() which a subclass might have overridden.
// To be safe we will only use this implementation in cases where we know it is safe to do so,
// and delegate to our base class (which will call into Write/WriteAsync) when we are not sure.
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> _fileStream.BaseWriteAsync(buffer, offset, count, cancellationToken);

// If this isn't a concrete FileStream, a derived type may have overridden WriteAsync(byte[],...),
// which was introduced first, so delegate to the base which will delegate to that.
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
=> _fileStream.BaseWriteAsync(buffer, cancellationToken);

public override void Flush() => throw new InvalidOperationException("FileStream should never call this method.");

internal override void Flush(bool flushToDisk) => _strategy.Flush(flushToDisk);

// If we have been inherited into a subclass, the following implementation could be incorrect
// since it does not call through to Flush() which a subclass might have overridden. To be safe
// we will only use this implementation in cases where we know it is safe to do so,
// and delegate to our base class (which will call into Flush) when we are not sure.
public override Task FlushAsync(CancellationToken cancellationToken)
=> _fileStream.BaseFlushAsync(cancellationToken);

// We also need to take this path if this is a derived
// instance from FileStream, as a derived type could have overridden ReadAsync, in which
// case our custom CopyToAsync implementation isn't necessarily correct.
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
=> _fileStream.BaseCopyToAsync(destination, bufferSize, cancellationToken);

public override ValueTask DisposeAsync() => _fileStream.BaseDisposeAsync();

internal override void DisposeInternal(bool disposing) => _strategy.DisposeInternal(disposing);
}
}
Loading