in GVFS/GVFS.Platform.Windows/WindowsFileSystemVirtualizer.cs [884:998]
private void GetFileStreamHandlerAsyncHandler(
CancellationToken cancellationToken,
int commandId,
uint length,
Guid streamGuid,
string sha,
EventMetadata requestMetadata,
string triggeringProcessImageFileName)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
try
{
if (!this.GitObjects.TryCopyBlobContentStream(
sha,
cancellationToken,
GVFSGitObjects.RequestSource.FileStreamCallback,
(stream, blobLength) =>
{
if (blobLength != length)
{
requestMetadata.Add("blobLength", blobLength);
this.Context.Tracer.RelatedError(requestMetadata, $"{nameof(this.GetFileStreamHandlerAsyncHandler)}: Actual file length (blobLength) does not match requested length");
throw new GetFileStreamException(HResult.InternalError);
}
byte[] buffer = new byte[Math.Min(MaxBlobStreamBufferSize, blobLength)];
long remainingData = blobLength;
using (IWriteBuffer targetBuffer = this.virtualizationInstance.CreateWriteBuffer((uint)buffer.Length))
{
while (remainingData > 0)
{
cancellationToken.ThrowIfCancellationRequested();
uint bytesToCopy = (uint)Math.Min(remainingData, targetBuffer.Length);
try
{
targetBuffer.Stream.Seek(0, SeekOrigin.Begin);
StreamCopyBlockTo(stream, targetBuffer.Stream, bytesToCopy, buffer);
}
catch (IOException e)
{
requestMetadata.Add("Exception", e.ToString());
this.Context.Tracer.RelatedError(requestMetadata, "IOException while copying to unmanaged buffer.");
throw new GetFileStreamException("IOException while copying to unmanaged buffer: " + e.Message, (HResult)HResultExtensions.HResultFromNtStatus.FileNotAvailable);
}
long writeOffset = length - remainingData;
HResult writeResult = this.virtualizationInstance.WriteFileData(streamGuid, targetBuffer, (ulong)writeOffset, bytesToCopy);
remainingData -= bytesToCopy;
if (writeResult != HResult.Ok)
{
switch (writeResult)
{
case HResult.Handle:
// HResult.Handle is expected, and occurs when an application closes a file handle before OnGetFileStream
// is complete
break;
default:
{
this.Context.Tracer.RelatedError(requestMetadata, $"{nameof(this.virtualizationInstance.WriteFileData)} failed, error: " + writeResult.ToString("X") + "(" + writeResult.ToString("G") + ")");
}
break;
}
throw new GetFileStreamException(writeResult);
}
}
}
}))
{
this.Context.Tracer.RelatedError(requestMetadata, $"{nameof(this.GetFileStreamHandlerAsyncHandler)}: TryCopyBlobContentStream failed");
this.TryCompleteCommand(commandId, (HResult)HResultExtensions.HResultFromNtStatus.FileNotAvailable);
return;
}
}
catch (OperationCanceledException)
{
requestMetadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(this.GetFileStreamHandlerAsyncHandler)}: Operation cancelled");
this.Context.Tracer.RelatedEvent(
EventLevel.Informational,
nameof(this.GetFileStreamHandlerAsyncHandler) + "_OperationCancelled",
requestMetadata);
return;
}
catch (GetFileStreamException e)
{
this.TryCompleteCommand(commandId, (HResult)e.HResult);
return;
}
catch (Exception e)
{
requestMetadata.Add("Exception", e.ToString());
this.Context.Tracer.RelatedError(requestMetadata, $"{nameof(this.GetFileStreamHandlerAsyncHandler)}: TryCopyBlobContentStream failed");
this.TryCompleteCommand(commandId, (HResult)HResultExtensions.HResultFromNtStatus.FileNotAvailable);
return;
}
this.FileSystemCallbacks.OnPlaceholderFileHydrated(triggeringProcessImageFileName);
this.TryCompleteCommand(commandId, HResult.Ok);
}