sys: cached read/write testing

This commit is contained in:
Bill Zissimopoulos 2016-03-11 14:44:17 -08:00
parent 3f98d1cb01
commit 151247f1e6
8 changed files with 97 additions and 43 deletions

View File

@ -197,7 +197,6 @@ typedef struct
UINT64 Offset; UINT64 Offset;
UINT32 Length; UINT32 Length;
UINT32 Key; UINT32 Key;
UINT32 Constrained:1; /* write's beyond EOF are NOP's (file size remains same) */
} Write; } Write;
struct struct
{ {

View File

@ -70,7 +70,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo); PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo);
NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*Write)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length, BOOLEAN Constrained, PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length, BOOLEAN WriteToEndOfFile,
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo); PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo);
NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*GetFileInfo)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,

View File

@ -446,7 +446,7 @@ FSP_API NTSTATUS FspFileSystemOpWrite(FSP_FILE_SYSTEM *FileSystem,
(PVOID)Request->Req.Write.Address, (PVOID)Request->Req.Write.Address,
Request->Req.Write.Offset, Request->Req.Write.Offset,
Request->Req.Write.Length, Request->Req.Write.Length,
Request->Req.Write.Constrained, (UINT64)-1LL == Request->Req.Write.Offset,
&BytesTransferred, &BytesTransferred,
&FileInfo); &FileInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))

View File

@ -174,7 +174,10 @@ BOOLEAN FspAcquireForLazyWrite(
ASSERT(0 == IoGetTopLevelIrp()); ASSERT(0 == IoGetTopLevelIrp());
Result = FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, Wait); Result = FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, Wait);
if (Result) if (Result)
{
FileNode->LazyWriteThread = PsGetCurrentThread();
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
}
FSP_LEAVE_BOOL("Context=%p, Wait=%d", Context, Wait); FSP_LEAVE_BOOL("Context=%p, Wait=%d", Context, Wait);
} }
@ -192,6 +195,7 @@ VOID FspReleaseFromLazyWrite(
ASSERT((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP == IoGetTopLevelIrp()); ASSERT((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP == IoGetTopLevelIrp());
IoSetTopLevelIrp(0); IoSetTopLevelIrp(0);
FileNode->LazyWriteThread = 0;
FspFileNodeRelease(FileNode, Full); FspFileNodeRelease(FileNode, Full);
FSP_LEAVE_VOID("Context=%p", Context); FSP_LEAVE_VOID("Context=%p", Context);

View File

@ -793,6 +793,7 @@ typedef struct
UINT64 Security; UINT64 Security;
ULONG SecurityChangeNumber; ULONG SecurityChangeNumber;
BOOLEAN TruncateOnClose; BOOLEAN TruncateOnClose;
PVOID LazyWriteThread;
/* read-only after creation (and insertion in the ContextTable) */ /* read-only after creation (and insertion in the ContextTable) */
PDEVICE_OBJECT FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject;
UINT64 UserContext; UINT64 UserContext;

View File

@ -88,6 +88,9 @@ static NTSTATUS FspFsvolReadCached(
{ {
PAGED_CODE(); PAGED_CODE();
/* assert: must be top-level IRP */
ASSERT(0 == FspIrpTopFlags(Irp));
NTSTATUS Result; NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_NODE *FileNode = FileObject->FsContext;
@ -151,6 +154,11 @@ static NTSTATUS FspFsvolReadCached(
Result = FspCcCopyRead(FileObject, &ReadOffset, ReadLength, CanWait, Buffer, Result = FspCcCopyRead(FileObject, &ReadOffset, ReadLength, CanWait, Buffer,
&Irp->IoStatus); &Irp->IoStatus);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Main);
return Result;
}
if (STATUS_PENDING == Result) if (STATUS_PENDING == Result)
{ {
FspFileNodeRelease(FileNode, Main); FspFileNodeRelease(FileNode, Main);
@ -184,6 +192,9 @@ static NTSTATUS FspFsvolReadNonCached(
{ {
PAGED_CODE(); PAGED_CODE();
/* assert: either a top-level IRP or Paging I/O */
ASSERT(0 == FspIrpTopFlags(Irp) || FlagOn(Irp->Flags, IRP_PAGING_IO));
NTSTATUS Result; NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_NODE *FileNode = FileObject->FsContext;
@ -191,6 +202,7 @@ static NTSTATUS FspFsvolReadNonCached(
LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset; LARGE_INTEGER ReadOffset = IrpSp->Parameters.Read.ByteOffset;
ULONG ReadLength = IrpSp->Parameters.Read.Length; ULONG ReadLength = IrpSp->Parameters.Read.Length;
ULONG ReadKey = IrpSp->Parameters.Read.Key; ULONG ReadKey = IrpSp->Parameters.Read.Key;
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_REQ *Request; FSP_FSCTL_TRANSACT_REQ *Request;
ASSERT(FileNode == FileDesc->FileNode); ASSERT(FileNode == FileDesc->FileNode);
@ -199,6 +211,12 @@ static NTSTATUS FspFsvolReadNonCached(
if (FlagOn(IrpSp->MinorFunction, IRP_MN_MDL)) if (FlagOn(IrpSp->MinorFunction, IRP_MN_MDL))
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
/* if this is a recursive read (cache) see if we can optimize it away! */
if (FlagOn(FspIrpTopFlags(Irp), FspFileNodeAcquireMain) && /* if TopLevelIrp has acquired Main */
FspFileNodeTryGetFileInfo(FileNode, &FileInfo) && /* and the cached FileSize is valid */
(UINT64)ReadOffset.QuadPart >= FileInfo.FileSize) /* and the ReadOffset is past EOF */
return STATUS_END_OF_FILE;
/* probe and lock the user buffer */ /* probe and lock the user buffer */
if (0 == Irp->MdlAddress) if (0 == Irp->MdlAddress)
{ {
@ -306,18 +324,19 @@ NTSTATUS FspFsvolReadComplete(
if (0 != SafeMdl) if (0 != SafeMdl)
FspSafeMdlCopyBack(SafeMdl); FspSafeMdlCopyBack(SafeMdl);
if (!PagingIo) /* if we are top-level */
if (0 == FspIrpTopFlags(Irp))
{ {
if (FspFsctlTransactReadKind == Request->Kind) if (FspFsctlTransactReadKind == Request->Kind)
{ {
InfoChangeNumber = FileNode->InfoChangeNumber; InfoChangeNumber = FileNode->InfoChangeNumber;
FspIopResetRequest(Request, 0);
Request->Kind = FspFsctlTransactReservedKind; Request->Kind = FspFsctlTransactReservedKind;
FspIopResetRequest(Request, 0);
FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)InfoChangeNumber; FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)InfoChangeNumber;
} }
else else
InfoChangeNumber = (ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestInfoChangeNumber); InfoChangeNumber =
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestInfoChangeNumber);
Success = DEBUGTEST(90, TRUE) && FspFileNodeTryAcquireExclusive(FileNode, Main); Success = DEBUGTEST(90, TRUE) && FspFileNodeTryAcquireExclusive(FileNode, Main);
if (!Success) if (!Success)
@ -326,18 +345,22 @@ NTSTATUS FspFsvolReadComplete(
FSP_RETURN(); FSP_RETURN();
} }
/* update file info */
FspFileNodeTrySetFileInfo(FileNode, FileObject, &Response->Rsp.Read.FileInfo, FspFileNodeTrySetFileInfo(FileNode, FileObject, &Response->Rsp.Read.FileInfo,
InfoChangeNumber); InfoChangeNumber);
/* update the current file offset if synchronous I/O (and not paging I/O) */ /* update the current file offset if synchronous I/O (and not paging I/O) */
if (SynchronousIo) if (SynchronousIo && !PagingIo)
FileObject->CurrentByteOffset.QuadPart = FileObject->CurrentByteOffset.QuadPart =
ReadOffset.QuadPart + Response->IoStatus.Information; ReadOffset.QuadPart + Response->IoStatus.Information;
FspFileNodeRelease(FileNode, Main); FspFileNodeRelease(FileNode, Main);
} }
else else
{
ASSERT(PagingIo);
FspIopResetRequest(Request, 0); FspIopResetRequest(Request, 0);
}
Irp->IoStatus.Information = Response->IoStatus.Information; Irp->IoStatus.Information = Response->IoStatus.Information;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;

View File

@ -88,6 +88,9 @@ static NTSTATUS FspFsvolWriteCached(
{ {
PAGED_CODE(); PAGED_CODE();
/* assert: must be top-level IRP */
ASSERT(0 == FspIrpTopFlags(Irp));
NTSTATUS Result; NTSTATUS Result;
BOOLEAN Retrying = 0 != FspIrpRequest(Irp); BOOLEAN Retrying = 0 != FspIrpRequest(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT FileObject = IrpSp->FileObject;
@ -104,6 +107,7 @@ static NTSTATUS FspFsvolWriteCached(
FSP_FSCTL_FILE_INFO FileInfo; FSP_FSCTL_FILE_INFO FileInfo;
CC_FILE_SIZES FileSizes; CC_FILE_SIZES FileSizes;
UINT64 WriteEndOffset; UINT64 WriteEndOffset;
BOOLEAN ExtendingFile;
BOOLEAN Success; BOOLEAN Success;
/* should we defer the write? */ /* should we defer the write? */
@ -132,22 +136,19 @@ static NTSTATUS FspFsvolWriteCached(
ASSERT(FspTimeoutInfinity32 == ASSERT(FspTimeoutInfinity32 ==
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout); FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout);
FspFileNodeGetFileInfo(FileNode, &FileInfo); FspFileNodeGetFileInfo(FileNode, &FileInfo);
FileSizes.AllocationSize.QuadPart = FileInfo.AllocationSize;
FileSizes.FileSize.QuadPart = FileInfo.FileSize;
FileSizes.ValidDataLength.QuadPart = MAXLONGLONG;
WriteEndOffset = WriteToEndOfFile ? WriteEndOffset = WriteToEndOfFile ?
FileInfo.FileSize + WriteLength : WriteOffset.QuadPart + WriteLength; FileInfo.FileSize + WriteLength : WriteOffset.QuadPart + WriteLength;
if (FileInfo.FileSize < WriteEndOffset) ExtendingFile = FileInfo.FileSize < WriteEndOffset;
if (ExtendingFile)
{ {
/* file is being extended */ FileInfo.FileSize = WriteEndOffset;
FileSizes.FileSize.QuadPart = WriteEndOffset; if (FileInfo.FileSize > FileInfo.AllocationSize)
if (FileSizes.FileSize.QuadPart > FileSizes.AllocationSize.QuadPart)
{ {
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
FspFsvolDeviceExtension(FsvolDeviceObject); FspFsvolDeviceExtension(FsvolDeviceObject);
UINT64 AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize * UINT64 AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize *
FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit; FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit;
FileSizes.AllocationSize.QuadPart = (FileSizes.FileSize.QuadPart + AllocationUnit - 1) FileInfo.AllocationSize = (FileInfo.FileSize + AllocationUnit - 1)
/ AllocationUnit * AllocationUnit; / AllocationUnit * AllocationUnit;
} }
} }
@ -155,6 +156,10 @@ static NTSTATUS FspFsvolWriteCached(
/* initialize cache if not already initialized! */ /* initialize cache if not already initialized! */
if (0 == FileObject->PrivateCacheMap) if (0 == FileObject->PrivateCacheMap)
{ {
FileSizes.AllocationSize.QuadPart = FileInfo.AllocationSize;
FileSizes.FileSize.QuadPart = FileInfo.FileSize;
FileSizes.ValidDataLength.QuadPart = MAXLONGLONG;
Result = FspCcInitializeCacheMap(FileObject, &FileSizes, FALSE, Result = FspCcInitializeCacheMap(FileObject, &FileSizes, FALSE,
&FspCacheManagerCallbacks, FileNode); &FspCacheManagerCallbacks, FileNode);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -163,8 +168,12 @@ static NTSTATUS FspFsvolWriteCached(
return Result; return Result;
} }
} }
else if (FileInfo.FileSize < WriteEndOffset) else if (ExtendingFile)
{ {
FileSizes.AllocationSize.QuadPart = FileInfo.AllocationSize;
FileSizes.FileSize.QuadPart = FileInfo.FileSize;
FileSizes.ValidDataLength.QuadPart = MAXLONGLONG;
/* file is being extended */ /* file is being extended */
Result = FspCcSetFileSizes(FileObject, &FileSizes); Result = FspCcSetFileSizes(FileObject, &FileSizes);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -188,6 +197,11 @@ static NTSTATUS FspFsvolWriteCached(
} }
Result = FspCcCopyWrite(FileObject, &WriteOffset, WriteLength, CanWait, Buffer); Result = FspCcCopyWrite(FileObject, &WriteOffset, WriteLength, CanWait, Buffer);
if (!NT_SUCCESS(Result))
{
FspFileNodeRelease(FileNode, Main);
return Result;
}
if (STATUS_PENDING == Result) if (STATUS_PENDING == Result)
{ {
FspFileNodeRelease(FileNode, Main); FspFileNodeRelease(FileNode, Main);
@ -213,6 +227,9 @@ static NTSTATUS FspFsvolWriteCached(
if (SynchronousIo) if (SynchronousIo)
FileObject->CurrentByteOffset.QuadPart = WriteEndOffset; FileObject->CurrentByteOffset.QuadPart = WriteEndOffset;
if (ExtendingFile)
FspFileNodeSetFileInfo(FileNode, 0, &FileInfo);
FspFileNodeRelease(FileNode, Main); FspFileNodeRelease(FileNode, Main);
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -228,6 +245,9 @@ static NTSTATUS FspFsvolWriteNonCached(
{ {
PAGED_CODE(); PAGED_CODE();
/* assert: either a top-level IRP or Paging I/O */
ASSERT(0 == FspIrpTopFlags(Irp) || FlagOn(Irp->Flags, IRP_PAGING_IO));
NTSTATUS Result; NTSTATUS Result;
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_NODE *FileNode = FileObject->FsContext;
@ -238,6 +258,7 @@ static NTSTATUS FspFsvolWriteNonCached(
BOOLEAN WriteToEndOfFile = BOOLEAN WriteToEndOfFile =
FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart;
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_REQ *Request; FSP_FSCTL_TRANSACT_REQ *Request;
ASSERT(FileNode == FileDesc->FileNode); ASSERT(FileNode == FileDesc->FileNode);
@ -254,6 +275,23 @@ static NTSTATUS FspFsvolWriteNonCached(
if (FspIoqStopped(FspFsvolDeviceExtension(FsvolDeviceObject)->Ioq)) if (FspIoqStopped(FspFsvolDeviceExtension(FsvolDeviceObject)->Ioq))
return FspFsvolDeviceStoppedStatus(FsvolDeviceObject); return FspFsvolDeviceStoppedStatus(FsvolDeviceObject);
/* if we are called by the lazy writer we must constrain writes */
if (FlagOn(FspIrpTopFlags(Irp), FspFileNodeAcquireMain) && /* if TopLevelIrp has acquired Main */
FileNode->LazyWriteThread == PsGetCurrentThread()) /* and this is a lazy writer thread */
{
ASSERT(PagingIo);
ASSERT(FspTimeoutInfinity32 ==
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout);
FspFileNodeGetFileInfo(FileNode, &FileInfo);
if ((UINT64)WriteOffset.QuadPart >= FileInfo.FileSize)
return STATUS_SUCCESS;
if (WriteLength > (ULONG)(FileInfo.FileSize - WriteOffset.QuadPart))
WriteLength = (ULONG)(FileInfo.FileSize - WriteOffset.QuadPart);
}
/* probe and lock the user buffer */ /* probe and lock the user buffer */
if (0 == Irp->MdlAddress) if (0 == Irp->MdlAddress)
{ {
@ -274,7 +312,6 @@ static NTSTATUS FspFsvolWriteNonCached(
Request->Req.Write.Offset = WriteOffset.QuadPart; Request->Req.Write.Offset = WriteOffset.QuadPart;
Request->Req.Write.Length = WriteLength; Request->Req.Write.Length = WriteLength;
Request->Req.Write.Key = WriteKey; Request->Req.Write.Key = WriteKey;
Request->Req.Write.Constrained = PagingIo;
return FSP_STATUS_IOQ_POST; return FSP_STATUS_IOQ_POST;
} }
@ -386,19 +423,25 @@ NTSTATUS FspFsvolWriteComplete(
BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
if (!PagingIo) /* if we are top-level */
if (0 == FspIrpTopFlags(Irp))
{ {
/* update file info */ /* update file info */
FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Write.FileInfo); FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Write.FileInfo);
/* update the current file offset if synchronous I/O (and not paging I/O) */ /* update the current file offset if synchronous I/O (and not paging I/O) */
if (SynchronousIo) if (SynchronousIo && !PagingIo)
FileObject->CurrentByteOffset.QuadPart = WriteToEndOfFile ? FileObject->CurrentByteOffset.QuadPart = WriteToEndOfFile ?
Response->Rsp.Write.FileInfo.FileSize : Response->Rsp.Write.FileInfo.FileSize :
WriteOffset.QuadPart + Response->IoStatus.Information; WriteOffset.QuadPart + Response->IoStatus.Information;
}
FspIopResetRequest(Request, 0); FspIopResetRequest(Request, 0);
}
else
{
ASSERT(PagingIo);
FspIopResetRequest(Request, 0);
}
Irp->IoStatus.Information = Response->IoStatus.Information; Irp->IoStatus.Information = Response->IoStatus.Information;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;

View File

@ -438,33 +438,17 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,
PVOID FileNode0, PVOID Buffer, UINT64 Offset, ULONG Length, BOOLEAN Constrained, PVOID FileNode0, PVOID Buffer, UINT64 Offset, ULONG Length, BOOLEAN WriteToEndOfFile,
PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo) PULONG PBytesTransferred, FSP_FSCTL_FILE_INFO *FileInfo)
{ {
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0; MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
UINT64 EndOffset; UINT64 EndOffset;
if ((UINT64)-1LL == Offset) if (WriteToEndOfFile)
Offset = FileNode->FileInfo.FileSize; Offset = FileNode->FileInfo.FileSize;
EndOffset = Offset + Length;
if (Constrained) if (EndOffset > FileNode->FileInfo.FileSize)
{ SetFileSize(FileSystem, Request, FileNode, EndOffset, FileInfo);
if (Offset >= FileNode->FileInfo.FileSize)
{
*PBytesTransferred = 0;
return STATUS_SUCCESS;
}
EndOffset = Offset + Length;
if (EndOffset > FileNode->FileInfo.FileSize)
EndOffset = FileNode->FileInfo.FileSize;
}
else
{
EndOffset = Offset + Length;
if (EndOffset > FileNode->FileInfo.FileSize)
SetFileSize(FileSystem, Request, FileNode, EndOffset, FileInfo);
}
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, EndOffset - Offset); memcpy((PUINT8)FileNode->FileData + Offset, Buffer, EndOffset - Offset);