📄 iofunc.c
字号:
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/iofunc.c
* PURPOSE: Generic I/O Functions that build IRPs for various operations
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Gunnar Dalsnes
* Filip Navara (navaraf@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#include "internal/io_i.h"
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
IopCleanupAfterException(IN PFILE_OBJECT FileObject,
IN PIRP Irp,
IN PKEVENT Event OPTIONAL,
IN PKEVENT LocalEvent OPTIONAL)
{
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject);
/* Check if we had a buffer */
if (Irp->AssociatedIrp.SystemBuffer)
{
/* Free it */
ExFreePool(Irp->AssociatedIrp.SystemBuffer);
}
/* Free the mdl */
if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
/* Free the IRP */
IoFreeIrp(Irp);
/* Check if we had a file lock */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Release it */
IopUnlockFileObject(FileObject);
}
/* Check if we had an event */
if (Event) ObDereferenceObject(Event);
/* Check if we had a local event */
if (LocalEvent) ExFreePool(LocalEvent);
/* Derefenrce the FO */
ObDereferenceObject(FileObject);
}
NTSTATUS
NTAPI
IopFinalizeAsynchronousIo(IN NTSTATUS SynchStatus,
IN PKEVENT Event,
IN PIRP Irp,
IN KPROCESSOR_MODE PreviousMode,
IN PIO_STATUS_BLOCK KernelIosb,
OUT PIO_STATUS_BLOCK IoStatusBlock)
{
NTSTATUS FinalStatus = SynchStatus;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "IRP: %p. Status: %lx \n", Irp, SynchStatus);
/* Make sure the IRP was completed, but returned pending */
if (FinalStatus == STATUS_PENDING)
{
/* Wait for the IRP */
FinalStatus = KeWaitForSingleObject(Event,
Executive,
PreviousMode,
FALSE,
NULL);
if (FinalStatus == STATUS_USER_APC)
{
/* Abort the request */
IopAbortInterruptedIrp(Event, Irp);
}
/* Set the final status */
FinalStatus = KernelIosb->Status;
}
/* Wrap potential user-mode write in SEH */
_SEH_TRY
{
*IoStatusBlock = *KernelIosb;
}
_SEH_HANDLE
{
/* Get the exception code */
FinalStatus = _SEH_GetExceptionCode();
}
_SEH_END;
/* Free the event and return status */
ExFreePool(Event);
return FinalStatus;
}
NTSTATUS
NTAPI
IopPerformSynchronousRequest(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN BOOLEAN Deferred,
IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN SynchIo,
IN IOP_TRANSFER_TYPE TransferType)
{
NTSTATUS Status;
PKNORMAL_ROUTINE NormalRoutine;
PVOID NormalContext;
KIRQL OldIrql;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "IRP: %p. DO: %p. FO: %p \n",
Irp, DeviceObject, FileObject);
/* Queue the IRP */
IopQueueIrpToThread(Irp);
/* Update operation counts */
IopUpdateOperationCount(TransferType);
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
/* Check if we're optimizing this case */
if (Deferred)
{
/* We are! Check if the IRP wasn't completed */
if (Status != STATUS_PENDING)
{
/* Complete it ourselves */
ASSERT(!Irp->PendingReturned);
KeRaiseIrql(APC_LEVEL, &OldIrql);
IopCompleteRequest(&Irp->Tail.Apc,
&NormalRoutine,
&NormalContext,
(PVOID*)&FileObject,
&NormalContext);
KeLowerIrql(OldIrql);
}
}
/* Check if this was synch I/O */
if (SynchIo)
{
/* Make sure the IRP was completed, but returned pending */
if (Status == STATUS_PENDING)
{
/* Wait for the IRP */
Status = KeWaitForSingleObject(&FileObject->Event,
Executive,
PreviousMode,
(FileObject->Flags &
FO_ALERTABLE_IO),
NULL);
if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
{
/* Abort the request */
IopAbortInterruptedIrp(&FileObject->Event, Irp);
}
/* Set the final status */
Status = FileObject->FinalStatus;
}
/* Release the file lock */
IopUnlockFileObject(FileObject);
}
/* Return status */
return Status;
}
NTSTATUS
NTAPI
IopDeviceFsIoControl(IN HANDLE DeviceHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
IN PVOID UserApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG IoControlCode,
IN PVOID InputBuffer,
IN ULONG InputBufferLength OPTIONAL,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength OPTIONAL,
IN BOOLEAN IsDevIoCtl)
{
NTSTATUS Status = STATUS_SUCCESS;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PKEVENT EventObject = NULL;
BOOLEAN LockedForSynch = FALSE;
ULONG AccessType;
OBJECT_HANDLE_INFORMATION HandleInformation;
ACCESS_MASK DesiredAccess;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
ULONG BufferLength;
IOTRACE(IO_CTL_DEBUG, "Handle: %lx. CTL: %lx. Type: %lx \n",
DeviceHandle, IoControlCode, IsDevIoCtl);
/* Get the access type */
AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode);
/* Check if we came from user mode */
if (PreviousMode != KernelMode)
{
_SEH_TRY
{
/* Probe the status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Check if this is buffered I/O */
if (AccessType == METHOD_BUFFERED)
{
/* Check if we have an output buffer */
if (OutputBuffer)
{
/* Probe the output buffer */
ProbeForWrite(OutputBuffer,
OutputBufferLength,
sizeof(CHAR));
}
else
{
/* Make sure the caller can't fake this as we depend on this */
OutputBufferLength = 0;
}
}
/* Check if we we have an input buffer I/O */
if (AccessType != METHOD_NEITHER)
{
/* Check if we have an input buffer */
if (InputBuffer)
{
/* Probe the input buffer */
ProbeForRead(InputBuffer, InputBufferLength, sizeof(CHAR));
}
else
{
/* Make sure the caller can't fake this as we depend on this */
InputBufferLength = 0;
}
}
}
_SEH_HANDLE
{
/* Get the exception code */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status)) return Status;
}
/* Don't check for access rights right now, KernelMode can do anything */
Status = ObReferenceObjectByHandle(DeviceHandle,
0,
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
&HandleInformation);
if (!NT_SUCCESS(Status)) return Status;
/* Can't use an I/O completion port and an APC in the same time */
if ((FileObject->CompletionContext) && (UserApcRoutine))
{
/* Fail */
ObDereferenceObject(FileObject);
return STATUS_INVALID_PARAMETER;
}
/* Check if we from user mode */
if (PreviousMode != KernelMode)
{
/* Get the access mask */
DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
/* Check if we can open it */
if ((DesiredAccess != FILE_ANY_ACCESS) &&
(HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
{
/* Dereference the file object and fail */
ObDereferenceObject(FileObject);
return STATUS_ACCESS_DENIED;
}
}
/* Check for an event */
if (Event)
{
/* Reference it */
Status = ObReferenceObjectByHandle(Event,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&EventObject,
NULL);
if (!NT_SUCCESS(Status))
{
/* Dereference the file object and fail */
ObDereferenceObject(FileObject);
return Status;
}
/* Clear it */
KeClearEvent(EventObject);
}
/* Check if this is a file that was opened for Synch I/O */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
/* Remember to unlock later */
LockedForSynch = TRUE;
}
/* Check if this is a direct open or not */
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
{
/* It's a direct open, get the attached device */
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
}
else
{
/* Otherwise get the related device */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
/* Clear the event */
KeClearEvent(&FileObject->Event);
/* Allocate IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
/* Setup the IRP */
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = EventObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
Irp->Cancel = FALSE;
Irp->CancelRoutine = NULL;
Irp->PendingReturned = FALSE;
Irp->RequestorMode = PreviousMode;
Irp->MdlAddress = NULL;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->Flags = 0;
Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
/* Set stack location settings */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->FileObject = FileObject;
StackPtr->MajorFunction = IsDevIoCtl ?
IRP_MJ_DEVICE_CONTROL :
IRP_MJ_FILE_SYSTEM_CONTROL;
StackPtr->MinorFunction = 0;
StackPtr->Control = 0;
StackPtr->Flags = 0;
StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
/* Set the IOCTL Data */
StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
OutputBufferLength;
/* Handle the Methods */
switch (AccessType)
{
/* Buffered I/O */
case METHOD_BUFFERED:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -