Skip to content

Commit

Permalink
Cache GetFileInformationByHandleEx (Length) when FileShare does not a…
Browse files Browse the repository at this point in the history
…llow other processes to modify it
  • Loading branch information
jozkee committed Mar 15, 2021
1 parent 60eedb4 commit 72a4e94
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ private unsafe Task WriteAsyncInternalCore(ReadOnlyMemory<byte> source, Cancella
// touch the file pointer location at all. We will adjust it
// ourselves, but only in memory. This isn't threadsafe.
_filePosition += source.Length;
UpdateLengthOnChangePosition();
}

// queue an async WriteFile operation and pass in a packed overlapped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace System.IO
public class FileStream : Stream
{
internal const int DefaultBufferSize = 4096;
private const FileShare DefaultShare = FileShare.Read;
internal const FileShare DefaultShare = FileShare.Read;
private const bool DefaultIsAsync = false;

/// <summary>Caches whether Serialization Guard has been disabled for file writes</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ private unsafe void WriteSpan(ReadOnlySpan<byte> source)
}
Debug.Assert(r >= 0, "FileStream's WriteCore is likely broken.");
_filePosition += r;
return;
UpdateLengthOnChangePosition();
}

private NativeOverlapped GetNativeOverlappedForCurrentPosition()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ internal abstract class WindowsFileStreamStrategy : FileStreamStrategy
/// <summary>Whether the file is opened for reading, writing, or both.</summary>
private readonly FileAccess _access;

private readonly FileShare _share;

/// <summary>The path to the opened file.</summary>
protected readonly string? _path;

Expand All @@ -32,6 +34,7 @@ internal abstract class WindowsFileStreamStrategy : FileStreamStrategy
private readonly bool _isPipe; // Whether to disable async buffering code.

private long _appendStart; // When appending, prevent overwriting file.
private long? _length;

internal WindowsFileStreamStrategy(SafeFileHandle handle, FileAccess access)
{
Expand All @@ -40,6 +43,7 @@ internal WindowsFileStreamStrategy(SafeFileHandle handle, FileAccess access)
// Note: Cleaner to set the following fields in ValidateAndInitFromHandle,
// but we can't as they're readonly.
_access = access;
_share = FileStream.DefaultShare;

// As the handle was passed in, we must set the handle field at the very end to
// avoid the finalizer closing the handle when we throw errors.
Expand All @@ -52,6 +56,7 @@ internal WindowsFileStreamStrategy(string path, FileMode mode, FileAccess access

_path = fullPath;
_access = access;
_share = share;

_fileHandle = FileStreamHelpers.OpenHandle(fullPath, mode, access, share, options);

Expand All @@ -77,7 +82,25 @@ internal WindowsFileStreamStrategy(string path, FileMode mode, FileAccess access

public sealed override bool CanWrite => !_fileHandle.IsClosed && (_access & FileAccess.Write) != 0;

public unsafe sealed override long Length => FileStreamHelpers.GetFileLength(_fileHandle, _path);
public unsafe sealed override long Length => _share > FileShare.Read ?
FileStreamHelpers.GetFileLength(_fileHandle, _path) :
_length ??= FileStreamHelpers.GetFileLength(_fileHandle, _path);

protected void UpdateLengthOnChangePosition()
{
// Do not update the cached length if the file can be written somewhere else
// or if the length has not been queried.
if (_share > FileShare.Read || _length is null)
{
Debug.Assert(_length is null);
return;
}

if (_filePosition > _length)
{
_length = _filePosition;
}
}

/// <summary>Gets or sets the position within the current stream</summary>
public override long Position
Expand Down Expand Up @@ -256,6 +279,7 @@ protected unsafe void SetLengthCore(long value)
Debug.Assert(value >= 0, "value >= 0");

FileStreamHelpers.SetLength(_fileHandle, _path, value);
_length = value;

if (_filePosition > value)
{
Expand Down

0 comments on commit 72a4e94

Please sign in to comment.