reactos/ntoskrnl/io/iomgr/iofunc.c
Pierre Schweitzer a3c58ca76f
[NTOSKRNL] Implement the support for reserve IRP in IO
The reserve IRP is an IRP which is allocated on system boot and kept during
the whole system life. Its purpose is to allow page reads in case of
low-memory situations where the system doesn't have enough memory left
to allocate an IRP to read from the page file (would be catastrophic situation).
2018-02-24 14:52:04 +01:00

4203 lines
138 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/iomgr/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)
* Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#include <ioevent.h>
#define NDEBUG
#include <debug.h>
#include "internal/io_i.h"
volatile LONG IoPageReadIrpAllocationFailure = 0;
volatile LONG IoPageReadNonPagefileIrpAllocationFailure = 0;
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
IopCleanupAfterException(IN PFILE_OBJECT FileObject,
IN PIRP Irp OPTIONAL,
IN PKEVENT Event OPTIONAL,
IN PKEVENT LocalEvent OPTIONAL)
{
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject);
if (Irp)
{
/* 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 */
_SEH2_TRY
{
*IoStatusBlock = *KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
FinalStatus = _SEH2_GetExceptionCode();
}
_SEH2_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 = NULL;
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) != 0,
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;
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;
POOL_TYPE PoolType;
PAGED_CODE();
IOTRACE(IO_CTL_DEBUG, "Handle: %p. 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)
{
_SEH2_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;
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* 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);
}
/* If this is a device I/O, try to do it with FastIO path */
if (IsDevIoCtl)
{
PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
/* Check whether FSD is FastIO aware and provide an appropriate routine */
if (FastIoDispatch != NULL && FastIoDispatch->FastIoDeviceControl != NULL)
{
IO_STATUS_BLOCK KernelIosb;
/* If we have an output buffer coming from usermode */
if (PreviousMode != KernelMode && OutputBuffer != NULL)
{
/* Probe it according to its usage */
_SEH2_TRY
{
if (AccessType == METHOD_IN_DIRECT)
{
ProbeForRead(OutputBuffer, OutputBufferLength, sizeof(CHAR));
}
else if (AccessType == METHOD_OUT_DIRECT)
{
ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(CHAR));
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Cleanup after exception and return */
IopCleanupAfterException(FileObject, NULL, EventObject, NULL);
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* If we are dismounting a volume, increase the dismount count */
if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
{
InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
}
/* Call the FSD */
if (FastIoDispatch->FastIoDeviceControl(FileObject,
TRUE,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
IoControlCode,
&KernelIosb,
DeviceObject))
{
IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
/* Write the IOSB back */
_SEH2_TRY
{
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
KernelIosb.Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Backup our complete context in case it exists */
if (FileObject->CompletionContext)
{
CompletionInfo = *(FileObject->CompletionContext);
}
/* If we had an event, signal it */
if (Event)
{
KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
ObDereferenceObject(EventObject);
}
/* If FO was locked, unlock it */
if (LockedForSynch)
{
IopUnlockFileObject(FileObject);
}
/* Set completion if required */
if (CompletionInfo.Port != NULL && UserApcContext != NULL)
{
if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
CompletionInfo.Key,
UserApcContext,
KernelIosb.Status,
KernelIosb.Information,
TRUE)))
{
KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
/* We're done with FastIO! */
ObDereferenceObject(FileObject);
return KernelIosb.Status;
}
}
}
/* Clear the event */
KeClearEvent(&FileObject->Event);
/* Allocate IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, 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; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
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;
PoolType = IsDevIoCtl ? NonPagedPoolCacheAligned : NonPagedPool;
/* Handle the Methods */
switch (AccessType)
{
/* Buffered I/O */
case METHOD_BUFFERED:
/* Enter SEH for allocations */
_SEH2_TRY
{
/* Select the right Buffer Length */
BufferLength = (InputBufferLength > OutputBufferLength) ?
InputBufferLength : OutputBufferLength;
/* Make sure there is one */
if (BufferLength)
{
/* Allocate the System Buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithQuotaTag(PoolType,
BufferLength,
TAG_SYS_BUF);
/* Check if we got a buffer */
if (InputBuffer)
{
/* Copy into the System Buffer */
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
InputBuffer,
InputBufferLength);
}
/* Write the flags */
Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
/* Save the Buffer */
Irp->UserBuffer = OutputBuffer;
}
else
{
/* Clear the Flags and Buffer */
Irp->UserBuffer = NULL;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Cleanup after exception and return */
IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
break;
/* Direct I/O */
case METHOD_IN_DIRECT:
case METHOD_OUT_DIRECT:
/* Enter SEH */
_SEH2_TRY
{
/* Check if we got an input buffer */
if ((InputBufferLength) && (InputBuffer))
{
/* Allocate the System Buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithQuotaTag(PoolType,
InputBufferLength,
TAG_SYS_BUF);
/* Copy into the System Buffer */
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
InputBuffer,
InputBufferLength);
/* Write the flags */
Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
}
/* Check if we got an output buffer */
if (OutputBuffer)
{
/* Allocate the System Buffer */
Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
OutputBufferLength,
FALSE,
FALSE,
Irp);
if (!Irp->MdlAddress)
{
/* Raise exception we'll catch */
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
}
/* Do the probe */
MmProbeAndLockPages(Irp->MdlAddress,
PreviousMode,
(AccessType == METHOD_IN_DIRECT) ?
IoReadAccess : IoWriteAccess);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Cleanup after exception and return */
IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
break;
case METHOD_NEITHER:
/* Just save the Buffer */
Irp->UserBuffer = OutputBuffer;
StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
}
/* Use deferred completion for FS I/O */
if (!IsDevIoCtl)
{
Irp->Flags |= IRP_DEFER_IO_COMPLETION;
}
/* If we are dismounting a volume, increaase the dismount count */
if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
{
InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
}
/* Perform the call */
return IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
!IsDevIoCtl,
PreviousMode,
LockedForSynch,
IopOtherTransfer);
}
NTSTATUS
NTAPI
IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
IN ULONG InformationClass,
IN ULONG Length,
OUT PVOID Information,
OUT PULONG ReturnedLength,
IN BOOLEAN File)
{
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION StackPtr;
BOOLEAN LocalEvent = FALSE;
KEVENT Event;
NTSTATUS Status;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
FileObject, InformationClass, File);
/* Reference the object */
ObReferenceObject(FileObject);
/* Check if this is a file that was opened for Synch I/O */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
/* Use File Object event */
KeClearEvent(&FileObject->Event);
}
else
{
/* Use local event */
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Get the Device Object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->RequestorMode = KernelMode;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->UserIosb = &IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? &Event : NULL;
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->Flags |= IRP_BUFFERED_IO;
Irp->AssociatedIrp.SystemBuffer = Information;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
/* Set the Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = File ? IRP_MJ_QUERY_INFORMATION:
IRP_MJ_QUERY_VOLUME_INFORMATION;
StackPtr->FileObject = FileObject;
/* Check which type this is */
if (File)
{
/* Set Parameters */
StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
StackPtr->Parameters.QueryFile.Length = Length;
}
else
{
/* Set Parameters */
StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
StackPtr->Parameters.QueryVolume.Length = Length;
}
/* Queue the IRP */
IopQueueIrpToThread(Irp);
/* Call the Driver */
Status = IoCallDriver(DeviceObject, Irp);
/* Check if this was synch I/O */
if (!LocalEvent)
{
/* Check if the request is pending */
if (Status == STATUS_PENDING)
{
/* Wait on the file object */
Status = KeWaitForSingleObject(&FileObject->Event,
Executive,
KernelMode,
(FileObject->Flags &
FO_ALERTABLE_IO) != 0,
NULL);
if (Status == STATUS_ALERTED)
{
/* Abort the operation */
IopAbortInterruptedIrp(&FileObject->Event, Irp);
}
/* Get the final status */
Status = FileObject->FinalStatus;
}
/* Release the file lock */
IopUnlockFileObject(FileObject);
}
else if (Status == STATUS_PENDING)
{
/* Wait on the local event and get the final status */
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
/* Return the Length and Status. ReturnedLength is NOT optional */
*ReturnedLength = (ULONG)IoStatusBlock.Information;
return Status;
}
NTSTATUS
NTAPI
IopGetFileInformation(IN PFILE_OBJECT FileObject,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInfoClass,
OUT PVOID Buffer,
OUT PULONG ReturnedLength)
{
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
PIO_STACK_LOCATION Stack;
PDEVICE_OBJECT DeviceObject;
IO_STATUS_BLOCK IoStatusBlock;
PAGED_CODE();
/* Allocate an IRP */
ObReferenceObject(FileObject);
DeviceObject = IoGetRelatedDeviceObject(FileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (Irp == NULL)
{
ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Init event */
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
/* Setup the IRP */
Irp->UserIosb = &IoStatusBlock;
Irp->UserEvent = &Event;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->RequestorMode = KernelMode;
Irp->AssociatedIrp.SystemBuffer = Buffer;
Irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO | IRP_OB_QUERY_NAME;
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Stack = IoGetNextIrpStackLocation(Irp);
Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
Stack->FileObject = FileObject;
Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
Stack->Parameters.QueryFile.Length = Length;
/* Queue the IRP */
IopQueueIrpToThread(Irp);
/* Call the driver */
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
*ReturnedLength = IoStatusBlock.Information;
return Status;
}
NTSTATUS
NTAPI
IopGetBasicInformationFile(IN PFILE_OBJECT FileObject,
OUT PFILE_BASIC_INFORMATION BasicInfo)
{
ULONG ReturnedLength;
PDEVICE_OBJECT DeviceObject;
IO_STATUS_BLOCK IoStatusBlock;
PAGED_CODE();
/* Try to do it the fast way if possible */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
BasicInfo,
&IoStatusBlock,
DeviceObject))
{
return IoStatusBlock.Status;
}
/* In case it failed, fall back to IRP-based method */
return IopGetFileInformation(FileObject, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, BasicInfo, &ReturnedLength);
}
NTSTATUS
NTAPI
IopOpenLinkOrRenameTarget(OUT PHANDLE Handle,
IN PIRP Irp,
IN PFILE_RENAME_INFORMATION RenameInfo,
IN PFILE_OBJECT FileObject)
{
NTSTATUS Status;
HANDLE TargetHandle;
UNICODE_STRING FileName;
PIO_STACK_LOCATION Stack;
PFILE_OBJECT TargetFileObject;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION BasicInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_HANDLE_INFORMATION HandleInformation;
ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
PAGED_CODE();
/* First, establish whether our target is a directory */
if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
{
Status = IopGetBasicInformationFile(FileObject, &BasicInfo);
if (!NT_SUCCESS(Status))
{
return Status;
}
if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
DesiredAccess = FILE_ADD_SUBDIRECTORY;
}
}
/* Setup the string to the target */
FileName.Buffer = RenameInfo->FileName;
FileName.Length = RenameInfo->FileNameLength;
FileName.MaximumLength = RenameInfo->FileNameLength;
InitializeObjectAttributes(&ObjectAttributes,
&FileName,
(FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE) | OBJ_KERNEL_HANDLE,
RenameInfo->RootDirectory,
NULL);
/* And open its parent directory */
if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
{
ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
#if 0
/* Commented out - we don't support FO extension yet
* FIXME: Corrected last arg when it's supported
*/
Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle,
DesiredAccess | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0,
CreateFileTypeNone,
NULL,
IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING,
FileObject->DeviceObject);
#else
ASSERT(FALSE);
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
#endif
}
else
{
Status = IoCreateFile(&TargetHandle,
DesiredAccess | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0,
CreateFileTypeNone,
NULL,
IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING);
}
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Once open, continue only if:
* Target exists and we're allowed to overwrite it
*/
Stack = IoGetNextIrpStackLocation(Irp);
if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
!RenameInfo->ReplaceIfExists &&
IoStatusBlock.Information == FILE_EXISTS)
{
ObCloseHandle(TargetHandle, KernelMode);
return STATUS_OBJECT_NAME_COLLISION;
}
/* Now, we'll get the associated device of the target, to check for same device location
* So, get the FO first
*/
Status = ObReferenceObjectByHandle(TargetHandle,
FILE_WRITE_DATA,
IoFileObjectType,
KernelMode,
(PVOID *)&TargetFileObject,
&HandleInformation);
if (!NT_SUCCESS(Status))
{
ObCloseHandle(TargetHandle, KernelMode);
return Status;
}
/* We can dereference, we have the handle */
ObDereferenceObject(TargetFileObject);
/* If we're not on the same device, error out **/
if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
{
ObCloseHandle(TargetHandle, KernelMode);
return STATUS_NOT_SAME_DEVICE;
}
/* Return parent directory file object and handle */
Stack->Parameters.SetFile.FileObject = TargetFileObject;
*Handle = TargetHandle;
return STATUS_SUCCESS;
}
static
ULONG
IopGetFileMode(IN PFILE_OBJECT FileObject)
{
ULONG Mode = 0;
if (FileObject->Flags & FO_WRITE_THROUGH)
Mode |= FILE_WRITE_THROUGH;
if (FileObject->Flags & FO_SEQUENTIAL_ONLY)
Mode |= FILE_SEQUENTIAL_ONLY;
if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
Mode |= FILE_NO_INTERMEDIATE_BUFFERING;
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
if (FileObject->Flags & FO_ALERTABLE_IO)
Mode |= FILE_SYNCHRONOUS_IO_ALERT;
else
Mode |= FILE_SYNCHRONOUS_IO_NONALERT;
}
if (FileObject->Flags & FO_DELETE_ON_CLOSE)
Mode |= FILE_DELETE_ON_CLOSE;
return Mode;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
IoSynchronousPageWrite(IN PFILE_OBJECT FileObject,
IN PMDL Mdl,
IN PLARGE_INTEGER Offset,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK StatusBlock)
{
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PDEVICE_OBJECT DeviceObject;
IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
FileObject, Mdl, Offset);
/* Is the write originating from Cc? */
if (FileObject->SectionObjectPointer != NULL &&
FileObject->SectionObjectPointer->SharedCacheMap != NULL)
{
++CcDataFlushes;
CcDataPages += BYTES_TO_PAGES(MmGetMdlByteCount(Mdl));
}
/* Get the Device Object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Allocate IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
/* Get the Stack */
StackPtr = IoGetNextIrpStackLocation(Irp);
/* Create the IRP Settings */
Irp->MdlAddress = Mdl;
Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
Irp->UserIosb = StatusBlock;
Irp->UserEvent = Event;
Irp->RequestorMode = KernelMode;
Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
/* Set the Stack Settings */
StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
StackPtr->Parameters.Write.ByteOffset = *Offset;
StackPtr->MajorFunction = IRP_MJ_WRITE;
StackPtr->FileObject = FileObject;
/* Call the Driver */
return IoCallDriver(DeviceObject, Irp);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoPageRead(IN PFILE_OBJECT FileObject,
IN PMDL Mdl,
IN PLARGE_INTEGER Offset,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK StatusBlock)
{
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PDEVICE_OBJECT DeviceObject;
IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
FileObject, Mdl, Offset);
/* Get the Device Object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Allocate IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
/* If allocation failed, try to see whether we can use
* the reserve IRP
*/
if (Irp == NULL)
{
/* We will use it only for paging file */
if (MmIsFileObjectAPagingFile(FileObject))
{
InterlockedExchangeAdd(&IoPageReadIrpAllocationFailure, 1);
Irp = IopAllocateReserveIrp(DeviceObject->StackSize);
}
else
{
InterlockedExchangeAdd(&IoPageReadNonPagefileIrpAllocationFailure, 1);
}
/* If allocation failed (not a paging file or too big stack size)
* Fail for real
*/
if (Irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
}
/* Get the Stack */
StackPtr = IoGetNextIrpStackLocation(Irp);
/* Create the IRP Settings */
Irp->MdlAddress = Mdl;
Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
Irp->UserIosb = StatusBlock;
Irp->UserEvent = Event;
Irp->RequestorMode = KernelMode;
Irp->Flags = IRP_PAGING_IO |
IRP_NOCACHE |
IRP_SYNCHRONOUS_PAGING_IO |
IRP_INPUT_OPERATION;
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
/* Set the Stack Settings */
StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
StackPtr->Parameters.Read.ByteOffset = *Offset;
StackPtr->MajorFunction = IRP_MJ_READ;
StackPtr->FileObject = FileObject;
/* Call the Driver */
return IoCallDriver(DeviceObject, Irp);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoQueryFileInformation(IN PFILE_OBJECT FileObject,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN ULONG Length,
OUT PVOID FileInformation,
OUT PULONG ReturnedLength)
{
/* Call the shared routine */
return IopQueryDeviceInformation(FileObject,
FileInformationClass,
Length,
FileInformation,
ReturnedLength,
TRUE);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoQueryVolumeInformation(IN PFILE_OBJECT FileObject,
IN FS_INFORMATION_CLASS FsInformationClass,
IN ULONG Length,
OUT PVOID FsInformation,
OUT PULONG ReturnedLength)
{
/* Call the shared routine */
return IopQueryDeviceInformation(FileObject,
FsInformationClass,
Length,
FsInformation,
ReturnedLength,
FALSE);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoSetInformation(IN PFILE_OBJECT FileObject,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN ULONG Length,
IN PVOID FileInformation)
{
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION StackPtr;
BOOLEAN LocalEvent = FALSE;
KEVENT Event;
NTSTATUS Status;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n",
FileObject, FileInformationClass, Length);
/* Reference the object */
ObReferenceObject(FileObject);
/* Check if this is a file that was opened for Synch I/O */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
/* Use File Object event */
KeClearEvent(&FileObject->Event);
}
else
{
/* Use local event */
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Get the Device Object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->RequestorMode = KernelMode;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->UserIosb = &IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? &Event : NULL;
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->Flags |= IRP_BUFFERED_IO;
Irp->AssociatedIrp.SystemBuffer = FileInformation;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
/* Set the Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
StackPtr->FileObject = FileObject;
/* Set Parameters */
StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
StackPtr->Parameters.SetFile.Length = Length;
/* Queue the IRP */
IopQueueIrpToThread(Irp);
/* Call the Driver */
Status = IoCallDriver(DeviceObject, Irp);
/* Check if this was synch I/O */
if (!LocalEvent)
{
/* Check if the request is pending */
if (Status == STATUS_PENDING)
{
/* Wait on the file object */
Status = KeWaitForSingleObject(&FileObject->Event,
Executive,
KernelMode,
(FileObject->Flags &
FO_ALERTABLE_IO) != 0,
NULL);
if (Status == STATUS_ALERTED)
{
/* Abort the operation */
IopAbortInterruptedIrp(&FileObject->Event, Irp);
}
/* Get the final status */
Status = FileObject->FinalStatus;
}
/* Release the file lock */
IopUnlockFileObject(FileObject);
}
else if (Status == STATUS_PENDING)
{
/* Wait on the local event and get the final status */
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
/* Return the status */
return Status;
}
/* NATIVE SERVICES ***********************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
NtDeviceIoControlFile(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)
{
/* Call the Generic Function */
return IopDeviceFsIoControl(DeviceHandle,
Event,
UserApcRoutine,
UserApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
TRUE);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtFsControlFile(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)
{
/* Call the Generic Function */
return IopDeviceFsIoControl(DeviceHandle,
Event,
UserApcRoutine,
UserApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
FALSE);
}
NTSTATUS
NTAPI
NtFlushBuffersFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock)
{
PFILE_OBJECT FileObject;
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
NTSTATUS Status;
PDEVICE_OBJECT DeviceObject;
PKEVENT Event = NULL;
BOOLEAN LocalEvent = FALSE;
OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
IO_STATUS_BLOCK KernelIosb;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
if (PreviousMode != KernelMode)
{
/* Protect probes */
_SEH2_TRY
{
/* Probe the I/O Status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Get the File Object */
Status = ObReferenceObjectByHandle(FileHandle,
0,
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
&ObjectHandleInfo);
if (!NT_SUCCESS(Status)) return Status;
/*
* Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
* granted. However, if this is a named pipe, make sure we don't ask for
* FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
* access right!
*/
if (!(ObjectHandleInfo.GrantedAccess &
((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
FILE_WRITE_DATA)))
{
/* We failed */
ObDereferenceObject(FileObject);
return STATUS_ACCESS_DENIED;
}
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
}
else
{
/* Use local event */
Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
if (!Event)
{
/* We failed */
ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Get the Device Object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Clear the event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
/* Set up the IRP */
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? Event : NULL;
Irp->RequestorMode = PreviousMode;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
/* Set up Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
StackPtr->FileObject = FileObject;
/* Call the Driver */
Status = IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
FALSE,
PreviousMode,
!LocalEvent,
IopOtherTransfer);
/* Check if this was async I/O */
if (LocalEvent)
{
/* It was, finalize this request */
Status = IopFinalizeAsynchronousIo(Status,
Event,
Irp,
PreviousMode,
&KernelIosb,
IoStatusBlock);
}
/* Return the Status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
IN HANDLE EventHandle OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG BufferSize,
IN ULONG CompletionFilter,
IN BOOLEAN WatchTree)
{
PIRP Irp;
PKEVENT Event = NULL;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION IoStack;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
BOOLEAN LockedForSync = FALSE;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Check if we're called from user mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O STatus block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the buffer */
if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Check if CompletionFilter is valid */
if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK))
{
return STATUS_INVALID_PARAMETER;
}
}
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
FILE_LIST_DIRECTORY,
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Check if we have an event handle */
if (EventHandle)
{
/* Reference it */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID *)&Event,
NULL);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
return Status;
}
KeClearEvent(Event);
}
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
LockedForSync = TRUE;
}
/* Clear File Object event */
KeClearEvent(&FileObject->Event);
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
/* Set up the IRP */
Irp->RequestorMode = PreviousMode;
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = Event;
Irp->UserBuffer = Buffer;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
/* Set up Stack Data */
IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
IoStack->FileObject = FileObject;
/* Set parameters */
IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
IoStack->Parameters.NotifyDirectory.Length = BufferSize;
if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
/* Perform the call */
return IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
FALSE,
PreviousMode,
LockedForSync,
IopOtherTransfer);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtLockFile(IN HANDLE FileHandle,
IN HANDLE EventHandle OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER ByteOffset,
IN PLARGE_INTEGER Length,
IN ULONG Key,
IN BOOLEAN FailImmediately,
IN BOOLEAN ExclusiveLock)
{
PFILE_OBJECT FileObject;
PLARGE_INTEGER LocalLength = NULL;
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PDEVICE_OBJECT DeviceObject;
PKEVENT Event = NULL;
BOOLEAN LockedForSync = FALSE;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
LARGE_INTEGER CapturedByteOffset, CapturedLength;
NTSTATUS Status;
OBJECT_HANDLE_INFORMATION HandleInformation;
PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
CapturedLength.QuadPart = 0;
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
0,
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
&HandleInformation);
if (!NT_SUCCESS(Status)) return Status;
/* Check if we're called from user mode */
if (PreviousMode != KernelMode)
{
/* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
if (!(HandleInformation.GrantedAccess &
(FILE_WRITE_DATA | FILE_READ_DATA)))
{
ObDereferenceObject(FileObject);
return STATUS_ACCESS_DENIED;
}
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O STatus block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe and capture the large integers */
CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
CapturedLength = ProbeForReadLargeInteger(Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Dereference the object and return exception code */
ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
/* Otherwise, capture them directly */
CapturedByteOffset = *ByteOffset;
CapturedLength = *Length;
}
/* Check if we have an event handle */
if (EventHandle)
{
/* Reference it */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID *)&Event,
NULL);
if (Status != STATUS_SUCCESS) return Status;
KeClearEvent(Event);
}
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Try to do it the FastIO way if possible */
FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL)
{
IO_STATUS_BLOCK KernelIosb;
if (FastIoDispatch->FastIoLock(FileObject,
&CapturedByteOffset,
&CapturedLength,
PsGetCurrentProcess(),
Key,
FailImmediately,
ExclusiveLock,
&KernelIosb,
DeviceObject))
{
/* Write the IOSB back */
_SEH2_TRY
{
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
KernelIosb.Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* If we had an event, signal it */
if (EventHandle)
{
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
ObDereferenceObject(Event);
}
/* Set completion if required */
if (FileObject->CompletionContext != NULL && ApcContext != NULL)
{
if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
FileObject->CompletionContext->Key,
ApcContext,
KernelIosb.Status,
KernelIosb.Information,
TRUE)))
{
KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
FileObject->LockOperation = TRUE;
/* We're done with FastIO! */
ObDereferenceObject(FileObject);
return KernelIosb.Status;
}
}
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
LockedForSync = TRUE;
}
/* Clear File Object event */
KeClearEvent(&FileObject->Event);
FileObject->LockOperation = TRUE;
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
/* Set up the IRP */
Irp->RequestorMode = PreviousMode;
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = Event;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
/* Set up Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
StackPtr->MinorFunction = IRP_MN_LOCK;
StackPtr->FileObject = FileObject;
/* Allocate local buffer */
LocalLength = ExAllocatePoolWithTag(NonPagedPool,
sizeof(LARGE_INTEGER),
TAG_LOCK);
if (!LocalLength)
{
/* Allocating failed, clean up and return failure */
IopCleanupAfterException(FileObject, Irp, Event, NULL);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Set the length */
*LocalLength = CapturedLength;
Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
StackPtr->Parameters.LockControl.Length = LocalLength;
/* Set Parameters */
StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
StackPtr->Parameters.LockControl.Key = Key;
/* Set Flags */
if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
/* Perform the call */
return IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
FALSE,
PreviousMode,
LockedForSync,
IopOtherTransfer);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtQueryDirectoryFile(IN HANDLE FileHandle,
IN HANDLE EventHandle OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan)
{
PIRP Irp;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PIO_STACK_LOCATION StackPtr;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
BOOLEAN LockedForSynch = FALSE;
PKEVENT Event = NULL;
volatile PVOID AuxBuffer = NULL;
PMDL Mdl;
UNICODE_STRING CapturedFileName;
PUNICODE_STRING SearchPattern;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Check if we came from user mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O Status Block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the file information */
ProbeForWrite(FileInformation, Length, sizeof(ULONG));
/* Check if we have a file name */
if (FileName)
{
/* Capture it */
CapturedFileName = ProbeForReadUnicodeString(FileName);
if (CapturedFileName.Length)
{
/* Probe its buffer */
ProbeForRead(CapturedFileName.Buffer,
CapturedFileName.Length,
1);
}
/* Allocate the auxiliary buffer */
AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
CapturedFileName.Length +
sizeof(UNICODE_STRING),
TAG_SYSB);
RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
sizeof(UNICODE_STRING)),
CapturedFileName.Buffer,
CapturedFileName.Length);
/* Setup the search pattern */
SearchPattern = (PUNICODE_STRING)AuxBuffer;
SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
sizeof(UNICODE_STRING));
SearchPattern->Length = CapturedFileName.Length;
SearchPattern->MaximumLength = CapturedFileName.Length;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Free buffer and return the exception code */
if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
FILE_LIST_DIRECTORY,
IoFileObjectType,
PreviousMode,
(PVOID *)&FileObject,
NULL);
if (!NT_SUCCESS(Status))
{
/* Fail */
if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
return Status;
}
/* Are there two associated completion routines? */
if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
{
ObDereferenceObject(FileObject);
if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
return STATUS_INVALID_PARAMETER;
}
/* Check if we have an even handle */
if (EventHandle)
{
/* Get its pointer */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID *)&Event,
NULL);
if (!NT_SUCCESS(Status))
{
/* Fail */
if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
ObDereferenceObject(FileObject);
return Status;
}
/* Clear it */
KeClearEvent(Event);
}
/* 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;
}
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
/* Set up the IRP */
Irp->RequestorMode = PreviousMode;
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = Event;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
Irp->MdlAddress = NULL;
Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
Irp->AssociatedIrp.SystemBuffer = NULL;
/* Check if this is buffered I/O */
if (DeviceObject->Flags & DO_BUFFERED_IO)
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
if (!Irp->AssociatedIrp.SystemBuffer)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, Event, NULL);
if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
/* Return the exception code */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Set the buffer and flags */
Irp->UserBuffer = FileInformation;
Irp->Flags = (IRP_BUFFERED_IO |
IRP_DEALLOCATE_BUFFER |
IRP_INPUT_OPERATION);
}
else if (DeviceObject->Flags & DO_DIRECT_IO)
{
_SEH2_TRY
{
/* Allocate an MDL */
Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, Event, NULL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
/* No allocation flags, and use the buffer directly */
Irp->UserBuffer = FileInformation;
}
/* Set up Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->FileObject = FileObject;
StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
/* Set Parameters */
StackPtr->Parameters.QueryDirectory.FileInformationClass =
FileInformationClass;
StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
StackPtr->Parameters.QueryDirectory.FileIndex = 0;
StackPtr->Parameters.QueryDirectory.Length = Length;
StackPtr->Flags = 0;
if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
/* Set deferred I/O */
Irp->Flags |= IRP_DEFER_IO_COMPLETION;
/* Perform the call */
return IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
TRUE,
PreviousMode,
LockedForSynch,
IopOtherTransfer);
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtQueryEaFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN BOOLEAN ReturnSingleEntry,
IN PVOID EaList OPTIONAL,
IN ULONG EaListLength,
IN PULONG EaIndex OPTIONAL,
IN BOOLEAN RestartScan)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtQueryInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass)
{
OBJECT_HANDLE_INFORMATION HandleInformation;
PFILE_OBJECT FileObject;
NTSTATUS Status;
PIRP Irp;
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION StackPtr;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PKEVENT Event = NULL;
BOOLEAN LocalEvent = FALSE;
PKNORMAL_ROUTINE NormalRoutine;
PVOID NormalContext;
KIRQL OldIrql;
IO_STATUS_BLOCK KernelIosb;
BOOLEAN CallDriver = TRUE;
PFILE_ACCESS_INFORMATION AccessBuffer;
PFILE_MODE_INFORMATION ModeBuffer;
PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
PFILE_ALL_INFORMATION AllBuffer;
PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Check if we're called from user mode */
if (PreviousMode != KernelMode)
{
/* Validate the information class */
if ((FileInformationClass >= FileMaximumInformation) ||
!(IopQueryOperationLength[FileInformationClass]))
{
/* Invalid class */
return STATUS_INVALID_INFO_CLASS;
}
/* Validate the length */
if (Length < IopQueryOperationLength[FileInformationClass])
{
/* Invalid length */
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O Status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the information */
ProbeForWrite(FileInformation, Length, sizeof(ULONG));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
#if DBG
else
{
/* Validate the information class */
if ((FileInformationClass >= FileMaximumInformation) ||
!(IopQueryOperationLength[FileInformationClass]))
{
/* Invalid class */
return STATUS_INVALID_INFO_CLASS;
}
/* Validate the length */
if (Length < IopQueryOperationLength[FileInformationClass])
{
/* Invalid length */
return STATUS_INFO_LENGTH_MISMATCH;
}
}
#endif
/* Reference the Handle */
Status = ObReferenceObjectByHandle(FileHandle,
IopQueryOperationAccess
[FileInformationClass],
IoFileObjectType,
PreviousMode,
(PVOID *)&FileObject,
&HandleInformation);
if (!NT_SUCCESS(Status)) return Status;
/* Check if this is a direct open or not */
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
{
/* Get the device object */
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
}
else
{
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
/* Check if this is a file that was opened for Synch I/O */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
/* Check if the caller just wants the position */
if (FileInformationClass == FilePositionInformation)
{
/* Protect write in SEH */
_SEH2_TRY
{
/* Write the offset */
((PFILE_POSITION_INFORMATION)FileInformation)->
CurrentByteOffset = FileObject->CurrentByteOffset;
/* Fill out the I/O Status Block */
IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
Status = IoStatusBlock->Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Release the file lock, dereference the file and return */
IopUnlockFileObject(FileObject);
ObDereferenceObject(FileObject);
return Status;
}
}
else
{
/* Use local event */
Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
if (!Event)
{
ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Check if FastIO is possible for the two available information classes */
FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
if (FastIoDispatch != NULL &&
((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
(FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
{
BOOLEAN Success = FALSE;
if (FileInformationClass == FileBasicInformation)
{
Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
FileInformation,
&KernelIosb,
DeviceObject);
}
else
{
Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
FileInformation,
&KernelIosb,
DeviceObject);
}
/* If call succeed */
if (Success)
{
/* Write the IOSB back */
_SEH2_TRY
{
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
KernelIosb.Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Free the event if we had one */
if (LocalEvent)
{
ExFreePoolWithTag(Event, TAG_IO);
}
/* If FO was locked, unlock it */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
IopUnlockFileObject(FileObject);
}
/* We're done with FastIO! */
ObDereferenceObject(FileObject);
return KernelIosb.Status;
}
}
/* Clear the File Object event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = PreviousMode;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? Event : NULL;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->MdlAddress = NULL;
Irp->UserBuffer = FileInformation;
/* Set the Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
StackPtr->FileObject = FileObject;
/* Enter SEH */
_SEH2_TRY
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, NULL, Event);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Set the flags */
Irp->Flags |= (IRP_BUFFERED_IO |
IRP_DEALLOCATE_BUFFER |
IRP_INPUT_OPERATION |
IRP_DEFER_IO_COMPLETION);
/* Set the Parameters */
StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
StackPtr->Parameters.QueryFile.Length = Length;
/* Queue the IRP */
IopQueueIrpToThread(Irp);
/* Update operation counts */
IopUpdateOperationCount(IopOtherTransfer);
/* Fill in file information before calling the driver.
See 'File System Internals' page 485.*/
if (FileInformationClass == FileAccessInformation)
{
AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
CallDriver = FALSE;
}
else if (FileInformationClass == FileModeInformation)
{
ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
ModeBuffer->Mode = IopGetFileMode(FileObject);
Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
CallDriver = FALSE;
}
else if (FileInformationClass == FileAlignmentInformation)
{
AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
CallDriver = FALSE;
}
else if (FileInformationClass == FileAllInformation)
{
AllBuffer = Irp->AssociatedIrp.SystemBuffer;
AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
sizeof(FILE_MODE_INFORMATION) +
sizeof(FILE_ALIGNMENT_INFORMATION);
}
/* Call the Driver */
if (CallDriver)
{
Status = IoCallDriver(DeviceObject, Irp);
}
else
{
Status = STATUS_SUCCESS;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
if (Status == STATUS_PENDING)
{
/* Check if this was async I/O */
if (LocalEvent)
{
/* Then to a non-alertable wait */
Status = KeWaitForSingleObject(Event,
Executive,
PreviousMode,
FALSE,
NULL);
if (Status == STATUS_USER_APC)
{
/* Abort the request */
IopAbortInterruptedIrp(Event, Irp);
}
/* Set the final status */
Status = KernelIosb.Status;
/* Enter SEH to write the IOSB back */
_SEH2_TRY
{
/* Write it back to the caller */
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Free the event */
ExFreePoolWithTag(Event, TAG_IO);
}
else
{
/* Wait for the IRP */
Status = KeWaitForSingleObject(&FileObject->Event,
Executive,
PreviousMode,
(FileObject->Flags &
FO_ALERTABLE_IO) != 0,
NULL);
if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
{
/* Abort the request */
IopAbortInterruptedIrp(&FileObject->Event, Irp);
}
/* Set the final status */
Status = FileObject->FinalStatus;
/* Release the file lock */
IopUnlockFileObject(FileObject);
}
}
else
{
/* Free the event if we had one */
if (LocalEvent)
{
/* Clear it in the IRP for completion */
Irp->UserEvent = NULL;
ExFreePoolWithTag(Event, TAG_IO);
}
/* Set the caller IOSB */
Irp->UserIosb = IoStatusBlock;
/* The IRP wasn't completed, complete it ourselves */
KeRaiseIrql(APC_LEVEL, &OldIrql);
IopCompleteRequest(&Irp->Tail.Apc,
&NormalRoutine,
&NormalContext,
(PVOID*)&FileObject,
&NormalContext);
KeLowerIrql(OldIrql);
/* Release the file object if we had locked it*/
if (!LocalEvent) IopUnlockFileObject(FileObject);
}
/* Return the Status */
return Status;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtQueryQuotaInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN BOOLEAN ReturnSingleEntry,
IN PVOID SidList OPTIONAL,
IN ULONG SidListLength,
IN PSID StartSid OPTIONAL,
IN BOOLEAN RestartScan)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
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;
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;
PFAST_IO_DISPATCH FastIoDispatch;
IO_STATUS_BLOCK KernelIosb;
BOOLEAN Success;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Validate User-Mode Buffers */
if (PreviousMode != KernelMode)
{
_SEH2_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);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
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);
}
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* 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 available */
if (!(ByteOffset) ||
((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
(CapturedByteOffset.u.HighPart == -1)))
{
/* Use the Current Byte Offset instead */
CapturedByteOffset = FileObject->CurrentByteOffset;
}
/* If the file is cached, try fast I/O */
if (FileObject->PrivateCacheMap)
{
/* Perform fast read */
FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
Success = FastIoDispatch->FastIoRead(FileObject,
&CapturedByteOffset,
Length,
TRUE,
CapturedKey,
Buffer,
&KernelIosb,
DeviceObject);
/* Only accept the result if we got a straightforward status */
if (Success &&
(KernelIosb.Status == STATUS_SUCCESS ||
KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
KernelIosb.Status == STATUS_END_OF_FILE))
{
/* Fast path -- update transfer & operation counts */
IopUpdateOperationCount(IopReadTransfer);
IopUpdateTransferCount(IopReadTransfer,
(ULONG)KernelIosb.Information);
/* Enter SEH to write the IOSB back */
_SEH2_TRY
{
/* Write it back to the caller */
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* The caller's IOSB was invalid, so fail */
if (EventObject) ObDereferenceObject(EventObject);
IopUnlockFileObject(FileObject);
ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Signal the completion event */
if (EventObject)
{
KeSetEvent(EventObject, 0, FALSE);
ObDereferenceObject(EventObject);
}
/* Clean up */
IopUnlockFileObject(FileObject);
ObDereferenceObject(FileObject);
return KernelIosb.Status;
}
}
/* Remember 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;
}
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = PreviousMode;
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 */
_SEH2_TRY
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* 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)
{
_SEH2_TRY
{
/* Allocate an MDL */
Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
if (!Mdl)
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* 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);
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtReadFileScatter(IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
IN PVOID UserApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK UserIoStatusBlock,
IN FILE_SEGMENT_ELEMENT BufferDescription [],
IN ULONG BufferLength,
IN PLARGE_INTEGER ByteOffset,
IN PULONG Key OPTIONAL)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtSetEaFile(IN HANDLE FileHandle,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID EaBuffer,
IN ULONG EaBufferSize)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtSetInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass)
{
PFILE_OBJECT FileObject;
NTSTATUS Status;
PIRP Irp;
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION StackPtr;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PKEVENT Event = NULL;
BOOLEAN LocalEvent = FALSE;
PKNORMAL_ROUTINE NormalRoutine;
PVOID NormalContext;
KIRQL OldIrql;
IO_STATUS_BLOCK KernelIosb;
PVOID Queue;
PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
PIO_COMPLETION_CONTEXT Context;
PFILE_RENAME_INFORMATION RenameInfo;
HANDLE TargetHandle = NULL;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Check if we're called from user mode */
if (PreviousMode != KernelMode)
{
/* Validate the information class */
if ((FileInformationClass >= FileMaximumInformation) ||
!(IopSetOperationLength[FileInformationClass]))
{
/* Invalid class */
return STATUS_INVALID_INFO_CLASS;
}
/* Validate the length */
if (Length < IopSetOperationLength[FileInformationClass])
{
/* Invalid length */
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O Status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the information */
ProbeForRead(FileInformation,
Length,
(Length == sizeof(BOOLEAN)) ?
sizeof(BOOLEAN) : sizeof(ULONG));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
/* Validate the information class */
if ((FileInformationClass >= FileMaximumInformation) ||
!(IopSetOperationLength[FileInformationClass]))
{
/* Invalid class */
return STATUS_INVALID_INFO_CLASS;
}
/* Validate the length */
if (Length < IopSetOperationLength[FileInformationClass])
{
/* Invalid length */
return STATUS_INFO_LENGTH_MISMATCH;
}
}
/* Reference the Handle */
Status = ObReferenceObjectByHandle(FileHandle,
IopSetOperationAccess
[FileInformationClass],
IoFileObjectType,
PreviousMode,
(PVOID *)&FileObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Check if this is a direct open or not */
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
{
/* Get the device object */
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
}
else
{
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
DPRINT("Will call: %p\n", DeviceObject);
DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
/* Check if this is a file that was opened for Synch I/O */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
/* Check if the caller just wants the position */
if (FileInformationClass == FilePositionInformation)
{
/* Protect write in SEH */
_SEH2_TRY
{
/* Write the offset */
FileObject->CurrentByteOffset =
((PFILE_POSITION_INFORMATION)FileInformation)->
CurrentByteOffset;
/* Fill out the I/O Status Block */
IoStatusBlock->Information = 0;
Status = IoStatusBlock->Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Update transfer count */
IopUpdateTransferCount(IopOtherTransfer, Length);
/* Release the file lock, dereference the file and return */
IopUnlockFileObject(FileObject);
ObDereferenceObject(FileObject);
return Status;
}
}
else
{
/* Use local event */
Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
if (!Event)
{
ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Clear the File Object event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = PreviousMode;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? Event : NULL;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->MdlAddress = NULL;
Irp->UserBuffer = FileInformation;
/* Set the Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
StackPtr->FileObject = FileObject;
/* Enter SEH */
_SEH2_TRY
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
/* Copy the data into it */
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
FileInformation,
Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, NULL, Event);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Set the flags */
Irp->Flags |= (IRP_BUFFERED_IO |
IRP_DEALLOCATE_BUFFER |
IRP_DEFER_IO_COMPLETION);
/* Set the Parameters */
StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
StackPtr->Parameters.SetFile.Length = Length;
/* Queue the IRP */
IopQueueIrpToThread(Irp);
/* Update operation counts */
IopUpdateOperationCount(IopOtherTransfer);
/* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
/* Handle IO Completion Port quickly */
if (FileInformationClass == FileCompletionInformation)
{
/* Check if the file object already has a completion port */
if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
(FileObject->CompletionContext))
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
else
{
/* Reference the Port */
CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
Status = ObReferenceObjectByHandle(CompletionInfo->Port,
IO_COMPLETION_MODIFY_STATE,
IoCompletionType,
PreviousMode,
(PVOID*)&Queue,
NULL);
if (NT_SUCCESS(Status))
{
/* Allocate the Context */
Context = ExAllocatePoolWithTag(PagedPool,
sizeof(IO_COMPLETION_CONTEXT),
IOC_TAG);
if (Context)
{
/* Set the Data */
Context->Key = CompletionInfo->Key;
Context->Port = Queue;
if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
CompletionContext,
Context,
NULL))
{
/*
* Someone else set the completion port in the
* meanwhile, so dereference the port and fail.
*/
ExFreePoolWithTag(Context, IOC_TAG);
ObDereferenceObject(Queue);
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
/* Dereference the Port now */
ObDereferenceObject(Queue);
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
/* Set the IRP Status */
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
}
else if (FileInformationClass == FileRenameInformation ||
FileInformationClass == FileLinkInformation ||
FileInformationClass == FileMoveClusterInformation)
{
/* Get associated information */
RenameInfo = Irp->AssociatedIrp.SystemBuffer;
/* Only rename if:
* -> We have a name
* -> In unicode
* -> sizes are valid
*/
if (RenameInfo->FileNameLength != 0 &&
!(RenameInfo->FileNameLength & 1) &&
(Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
{
/* Properly set information received */
if (FileInformationClass == FileMoveClusterInformation)
{
StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
}
else
{
StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
}
/* If we got fully path OR relative target, attempt a parent directory open */
if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
{
Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Status = Status;
}
else
{
/* Call the Driver */
Status = IoCallDriver(DeviceObject, Irp);
}
}
else
{
/* Call the Driver */
Status = IoCallDriver(DeviceObject, Irp);
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Status = Status;
}
}
else
{
/* Call the Driver */
Status = IoCallDriver(DeviceObject, Irp);
}
/* Check if we're waiting for the IRP to complete */
if (Status == STATUS_PENDING)
{
/* Check if this was async I/O */
if (LocalEvent)
{
/* Then to a non-alertable wait */
Status = KeWaitForSingleObject(Event,
Executive,
PreviousMode,
FALSE,
NULL);
if (Status == STATUS_USER_APC)
{
/* Abort the request */
IopAbortInterruptedIrp(Event, Irp);
}
/* Set the final status */
Status = KernelIosb.Status;
/* Enter SEH to write the IOSB back */
_SEH2_TRY
{
/* Write it back to the caller */
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Free the event */
ExFreePoolWithTag(Event, TAG_IO);
}
else
{
/* Wait for the IRP */
Status = KeWaitForSingleObject(&FileObject->Event,
Executive,
PreviousMode,
(FileObject->Flags &
FO_ALERTABLE_IO) != 0,
NULL);
if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
{
/* Abort the request */
IopAbortInterruptedIrp(&FileObject->Event, Irp);
}
/* Set the final status */
Status = FileObject->FinalStatus;
/* Release the file lock */
IopUnlockFileObject(FileObject);
}
}
else
{
/* Free the event if we had one */
if (LocalEvent)
{
/* Clear it in the IRP for completion */
Irp->UserEvent = NULL;
ExFreePoolWithTag(Event, TAG_IO);
}
/* Set the caller IOSB */
Irp->UserIosb = IoStatusBlock;
/* The IRP wasn't completed, complete it ourselves */
KeRaiseIrql(APC_LEVEL, &OldIrql);
IopCompleteRequest(&Irp->Tail.Apc,
&NormalRoutine,
&NormalContext,
(PVOID*)&FileObject,
&NormalContext);
KeLowerIrql(OldIrql);
/* Release the file object if we had locked it*/
if (!LocalEvent) IopUnlockFileObject(FileObject);
}
if (TargetHandle != NULL)
{
ObCloseHandle(TargetHandle, KernelMode);
}
/* Return the Status */
return Status;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtSetQuotaInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID Buffer,
IN ULONG BufferLength)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtUnlockFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER ByteOffset,
IN PLARGE_INTEGER Length,
IN ULONG Key OPTIONAL)
{
PFILE_OBJECT FileObject;
PLARGE_INTEGER LocalLength = NULL;
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PDEVICE_OBJECT DeviceObject;
PKEVENT Event = NULL;
BOOLEAN LocalEvent = FALSE;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
LARGE_INTEGER CapturedByteOffset, CapturedLength;
NTSTATUS Status;
OBJECT_HANDLE_INFORMATION HandleInformation;
IO_STATUS_BLOCK KernelIosb;
PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
CapturedLength.QuadPart = 0;
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
0,
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
&HandleInformation);
if (!NT_SUCCESS(Status)) return Status;
/* Check if we're called from user mode */
if (PreviousMode != KernelMode)
{
/* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
if (!(HandleInformation.GrantedAccess &
(FILE_WRITE_DATA | FILE_READ_DATA)))
{
ObDereferenceObject(FileObject);
return STATUS_ACCESS_DENIED;
}
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O Status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe and capture the large integers */
CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
CapturedLength = ProbeForReadLargeInteger(Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Dereference the object and return exception code */
ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
/* Otherwise, capture them directly */
CapturedByteOffset = *ByteOffset;
CapturedLength = *Length;
}
/* Check if this is a direct open or not */
if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
{
DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
}
else
{
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
/* Try to do it the FastIO way if possible */
FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
{
if (FastIoDispatch->FastIoUnlockSingle(FileObject,
&CapturedByteOffset,
&CapturedLength,
PsGetCurrentProcess(),
Key,
&KernelIosb,
DeviceObject))
{
/* Write the IOSB back */
_SEH2_TRY
{
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
KernelIosb.Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* We're done with FastIO! */
ObDereferenceObject(FileObject);
return KernelIosb.Status;
}
}
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
}
else
{
/* Use local event */
Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
if (!Event)
{
ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Clear File Object event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
/* Set up the IRP */
Irp->RequestorMode = PreviousMode;
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? Event : NULL;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
/* Set up Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
StackPtr->FileObject = FileObject;
/* Enter SEH */
_SEH2_TRY
{
/* Allocate a buffer */
LocalLength = ExAllocatePoolWithTag(NonPagedPool,
sizeof(LARGE_INTEGER),
TAG_LOCK);
/* Set the length */
*LocalLength = CapturedLength;
Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
StackPtr->Parameters.LockControl.Length = LocalLength;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, NULL, Event);
if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Set Parameters */
StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
StackPtr->Parameters.LockControl.Key = Key;
/* Call the Driver */
Status = IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
FALSE,
PreviousMode,
!LocalEvent,
IopOtherTransfer);
/* Check if this was async I/O */
if (LocalEvent)
{
/* It was, finalize this request */
Status = IopFinalizeAsynchronousIo(Status,
Event,
Irp,
PreviousMode,
&KernelIosb,
IoStatusBlock);
}
/* Return status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtWriteFile(IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL)
{
NTSTATUS Status;
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;
OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
PFAST_IO_DISPATCH FastIoDispatch;
IO_STATUS_BLOCK KernelIosb;
BOOLEAN Success;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Get File Object for write */
Status = ObReferenceFileObjectForWrite(FileHandle,
PreviousMode,
&FileObject,
&ObjectHandleInfo);
if (!NT_SUCCESS(Status)) return Status;
/* Validate User-Mode Buffers */
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
/* Probe the status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the read buffer */
ProbeForRead(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);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Release the file object and return the exception code */
ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
/* Kernel mode: capture directly */
if (ByteOffset) CapturedByteOffset = *ByteOffset;
if (Key) CapturedKey = *Key;
}
/* Check if this is an append operation */
if ((ObjectHandleInfo.GrantedAccess &
(FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
{
/* Give the drivers something to understand */
CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
CapturedByteOffset.u.HighPart = -1;
}
/* 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);
}
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* 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 available */
if (!(ByteOffset) ||
((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
(CapturedByteOffset.u.HighPart == -1)))
{
/* Use the Current Byte Offset instead */
CapturedByteOffset = FileObject->CurrentByteOffset;
}
/* If the file is cached, try fast I/O */
if (FileObject->PrivateCacheMap)
{
/* Perform fast write */
FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
Success = FastIoDispatch->FastIoWrite(FileObject,
&CapturedByteOffset,
Length,
TRUE,
CapturedKey,
Buffer,
&KernelIosb,
DeviceObject);
/* Only accept the result if it was successful */
if (Success &&
KernelIosb.Status == STATUS_SUCCESS)
{
/* Fast path -- update transfer & operation counts */
IopUpdateOperationCount(IopWriteTransfer);
IopUpdateTransferCount(IopWriteTransfer,
(ULONG)KernelIosb.Information);
/* Enter SEH to write the IOSB back */
_SEH2_TRY
{
/* Write it back to the caller */
*IoStatusBlock = KernelIosb;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* The caller's IOSB was invalid, so fail */
if (EventObject) ObDereferenceObject(EventObject);
IopUnlockFileObject(FileObject);
ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Signal the completion event */
if (EventObject)
{
KeSetEvent(EventObject, 0, FALSE);
ObDereferenceObject(EventObject);
}
/* Clean up */
IopUnlockFileObject(FileObject);
ObDereferenceObject(FileObject);
return KernelIosb.Status;
}
}
/* Remember 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;
}
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = PreviousMode;
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_WRITE;
StackPtr->FileObject = FileObject;
StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
SL_WRITE_THROUGH : 0;
StackPtr->Parameters.Write.Key = CapturedKey;
StackPtr->Parameters.Write.Length = Length;
StackPtr->Parameters.Write.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 */
_SEH2_TRY
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
/* Copy the data into it */
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Set the flags */
Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
}
else
{
/* Not writing anything */
Irp->Flags = IRP_BUFFERED_IO;
}
}
else if (DeviceObject->Flags & DO_DIRECT_IO)
{
/* Check if we have a buffer length */
if (Length)
{
_SEH2_TRY
{
/* Allocate an MDL */
Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
if (!Mdl)
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* 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_WRITE_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,
IopWriteTransfer);
}
NTSTATUS
NTAPI
NtWriteFileGather(IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
IN PVOID UserApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK UserIoStatusBlock,
IN FILE_SEGMENT_ELEMENT BufferDescription [],
IN ULONG BufferLength,
IN PLARGE_INTEGER ByteOffset,
IN PULONG Key OPTIONAL)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtQueryVolumeInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FsInformation,
IN ULONG Length,
IN FS_INFORMATION_CLASS FsInformationClass)
{
PFILE_OBJECT FileObject;
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PDEVICE_OBJECT DeviceObject;
PKEVENT Event = NULL;
BOOLEAN LocalEvent = FALSE;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
NTSTATUS Status;
IO_STATUS_BLOCK KernelIosb;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Check if we're called from user mode */
if (PreviousMode != KernelMode)
{
/* Validate the information class */
if ((FsInformationClass >= FileFsMaximumInformation) ||
!(IopQueryFsOperationLength[FsInformationClass]))
{
/* Invalid class */
return STATUS_INVALID_INFO_CLASS;
}
/* Validate the length */
if (Length < IopQueryFsOperationLength[FsInformationClass])
{
/* Invalid length */
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O Status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the information */
ProbeForWrite(FsInformation, Length, sizeof(ULONG));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
IopQueryFsOperationAccess
[FsInformationClass],
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
}
else
{
/* Use local event */
Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
if (!Event)
{
ObDereferenceObject(FileObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Clear File Object event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
/* Set up the IRP */
Irp->RequestorMode = PreviousMode;
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? Event : NULL;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->UserBuffer = FsInformation;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->MdlAddress = NULL;
/* Set up Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
StackPtr->FileObject = FileObject;
/* Enter SEH */
_SEH2_TRY
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, NULL, Event);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Set the flags for this buffered + deferred I/O */
Irp->Flags |= (IRP_BUFFERED_IO |
IRP_DEALLOCATE_BUFFER |
IRP_INPUT_OPERATION |
IRP_DEFER_IO_COMPLETION);
/* Set Parameters */
StackPtr->Parameters.QueryVolume.Length = Length;
StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
/* Call the Driver */
Status = IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
TRUE,
PreviousMode,
!LocalEvent,
IopOtherTransfer);
/* Check if this was async I/O */
if (LocalEvent)
{
/* It was, finalize this request */
Status = IopFinalizeAsynchronousIo(Status,
Event,
Irp,
PreviousMode,
&KernelIosb,
IoStatusBlock);
}
/* Return status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtSetVolumeInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FsInformation,
IN ULONG Length,
IN FS_INFORMATION_CLASS FsInformationClass)
{
PFILE_OBJECT FileObject;
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
PKEVENT Event = NULL;
BOOLEAN LocalEvent = FALSE;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
NTSTATUS Status;
IO_STATUS_BLOCK KernelIosb;
TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
/* Check if we're called from user mode */
if (PreviousMode != KernelMode)
{
/* Validate the information class */
if ((FsInformationClass >= FileFsMaximumInformation) ||
!(IopSetFsOperationLength[FsInformationClass]))
{
/* Invalid class */
return STATUS_INVALID_INFO_CLASS;
}
/* Validate the length */
if (Length < IopSetFsOperationLength[FsInformationClass])
{
/* Invalid length */
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Enter SEH for probing */
_SEH2_TRY
{
/* Probe the I/O Status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the information */
ProbeForRead(FsInformation, Length, sizeof(ULONG));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Get File Object */
Status = ObReferenceObjectByHandle(FileHandle,
IopSetFsOperationAccess
[FsInformationClass],
IoFileObjectType,
PreviousMode,
(PVOID*)&FileObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Get target device for notification */
Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
}
else
{
/* Use local event */
Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
if (!Event)
{
ObDereferenceObject(FileObject);
if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Event, SynchronizationEvent, FALSE);
LocalEvent = TRUE;
}
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Clear File Object event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp)
{
if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
return IopCleanupFailedIrp(FileObject, NULL, Event);
}
/* Set up the IRP */
Irp->RequestorMode = PreviousMode;
Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
Irp->UserEvent = (LocalEvent) ? Event : NULL;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
Irp->UserBuffer = FsInformation;
Irp->AssociatedIrp.SystemBuffer = NULL;
Irp->MdlAddress = NULL;
/* Set up Stack Data */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
StackPtr->FileObject = FileObject;
/* Enter SEH */
_SEH2_TRY
{
/* Allocate a buffer */
Irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
/* Copy the data into it */
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Allocating failed, clean up and return the exception code */
IopCleanupAfterException(FileObject, Irp, NULL, Event);
if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Set the flags for this buffered + deferred I/O */
Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
/* Set Parameters */
StackPtr->Parameters.SetVolume.Length = Length;
StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
/* Call the Driver */
Status = IopPerformSynchronousRequest(DeviceObject,
Irp,
FileObject,
FALSE,
PreviousMode,
!LocalEvent,
IopOtherTransfer);
/* Check if this was async I/O */
if (LocalEvent)
{
/* It was, finalize this request */
Status = IopFinalizeAsynchronousIo(Status,
Event,
Irp,
PreviousMode,
&KernelIosb,
IoStatusBlock);
}
if (TargetDeviceObject && NT_SUCCESS(Status))
{
/* Time to report change */
NotificationStructure.Version = 1;
NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
NotificationStructure.FileObject = NULL;
NotificationStructure.NameBufferOffset = - 1;
Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
}
/* Return status */
return Status;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}