2.1.ReactOS系统NtReadFile函数的实现。
NTSTATUS
NTAPI
NtReadFile(IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
PFILE_OBJECT FileObject;
PIRP Irp;
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION StackPtr;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PKEVENT EventObject = NULL;
LARGE_INTEGER CapturedByteOffset;
ULONG CapturedKey = 0;
BOOLEAN Synchronous = FALSE;
PMDL Mdl;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Validate User-Mode Buffers */
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
/* Probe the status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the read buffer */
ProbeForWrite(Buffer, Length, 1);
/* Check if we got a byte offset */
if (ByteOffset)
{
/* Capture and probe it */
CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
}
/* Capture and probe the key */
if (Key) CapturedKey = ProbeForReadUlong(Key);
}
_SEH_HANDLE
{
/* Get the exception code */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
/* Check for probe failure */
if (!NT_SUCCESS(Status)) return Status;
}
else
{
/* Kernel mode: capture directly */
if (ByteOffset) CapturedByteOffset = *ByteOffset;
if (Key) CapturedKey = *Key;
}
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
FILE_READ_DATA,
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Check for event */
if (Event)
{
/* Reference it */
Status = ObReferenceObjectByHandle(Event,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&EventObject,
NULL);
if (!NT_SUCCESS(Status))
{
/* Fail */
ObDereferenceObject(FileObject);
return Status;
}
/* Otherwise reset the event */
KeClearEvent(EventObject);
}
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock the file object */
IopLockFileObject(FileObject);
/* Check if we don't have a byte offset avilable */
if (!(ByteOffset) ||
((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
(CapturedByteOffset.u.HighPart == -1)))
{
/* Use the Current Byte Offset instead */
CapturedByteOffset = FileObject->CurrentByteOffset;
}
/* Rememer we are sync */
Synchronous = TRUE;
}
else if (!(ByteOffset) &&
!(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
{
/* Otherwise, this was async I/O without a byte offset, so fail */
if (EventObject) ObDereferenceObject(EventObject);
ObDereferenceObject(FileObject);
return STATUS_INVALID_PARAMETER;
}
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = KernelMode;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = EventObject;
Irp->PendingReturned = FALSE;
Irp->Cancel = FALSE;
Irp->CancelRoutine = NULL;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->MdlAddress = NULL;
/* Set the Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_READ;
StackPtr->FileObject = FileObject;
StackPtr->Parameters.Read.Key = CapturedKey;
StackPtr->Parameters.Read.Length = Length;
StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
/* Check if this is buffered I/O */
if (DeviceObject->Flags & DO_BUFFERED_IO)
{
/* Check if we have a buffer length */
if (Length)
{
/* Enter SEH */
_SEH_TRY
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
}
_SEH_HANDLE
{
/* Allocating failed, clean up */
IopCleanupAfterException(FileObject, Irp, NULL, Event);
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status)) return Status;
/* Set the buffer and flags */
Irp->UserBuffer = Buffer;
Irp->Flags = (IRP_BUFFERED_IO |
IRP_DEALLOCATE_BUFFER |
IRP_INPUT_OPERATION);
}
else
{
/* Not reading anything */
Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
}
}
else if (DeviceObject->Flags & DO_DIRECT_IO)
{
/* Check if we have a buffer length */
if (Length)
{
/* Allocate an MDL */
Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
}
/* No allocation flags */
Irp->Flags = 0;
}
else
{
/* No allocation flags, and use the buffer directly */
Irp->Flags = 0;
Irp->UserBuffer = Buffer;
}
/* Now set the deferred read flags */
Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
#if 0
/* FIXME: VFAT SUCKS */
if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
#endif
/* Perform the call */
return IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
TRUE,
PreviousMode,
Synchronous,
IopReadTransfer);
}