/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/io/iofunc.c
+ * 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 *****************************************************************/
VOID
NTAPI
IopCleanupAfterException(IN PFILE_OBJECT FileObject,
- IN PIRP Irp,
+ 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);
- /* Check if we had a buffer */
- if (Irp->AssociatedIrp.SystemBuffer)
+ if (Irp)
{
- /* Free it */
- ExFreePool(Irp->AssociatedIrp.SystemBuffer);
- }
+ /* 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 mdl */
+ if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
- /* Free the IRP */
- IoFreeIrp(Irp);
+ /* Free the IRP */
+ IoFreeIrp(Irp);
+ }
/* Check if we had a file lock */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
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);
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, Event, NULL);
+ if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Setup the IRP */
Irp->UserIosb = IoStatusBlock;
StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
OutputBufferLength;
+ PoolType = IsDevIoCtl ? NonPagedPoolCacheAligned : NonPagedPool;
+
/* Handle the Methods */
switch (AccessType)
{
{
/* Allocate the System Buffer */
Irp->AssociatedIrp.SystemBuffer =
- ExAllocatePoolWithTag(NonPagedPool,
+ ExAllocatePoolWithTag(PoolType,
BufferLength,
TAG_SYS_BUF);
{
/* Allocate the System Buffer */
Irp->AssociatedIrp.SystemBuffer =
- ExAllocatePoolWithTag(NonPagedPool,
+ ExAllocatePoolWithTag(PoolType,
InputBufferLength,
TAG_SYS_BUF);
}
/* Use deferred completion for FS I/O */
- Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
+ 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,
/* Check if this was synch I/O */
if (!LocalEvent)
{
- /* Check if the requet is pending */
+ /* Check if the request is pending */
if (Status == STATUS_PENDING)
{
/* Wait on the file object */
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 **********************************************************/
/*
/* Check if this was synch I/O */
if (!LocalEvent)
{
- /* Check if the requet is pending */
+ /* Check if the request is pending */
if (Status == STATUS_PENDING)
{
/* Wait on the file object */
LARGE_INTEGER CapturedByteOffset, CapturedLength;
NTSTATUS Status;
OBJECT_HANDLE_INFORMATION HandleInformation;
+ PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
CapturedLength.QuadPart = 0;
/* 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)
{
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)
{
if (!NT_SUCCESS(Status))
{
/* Fail */
+ if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
ObDereferenceObject(FileObject);
return Status;
}
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);
}
_SEH2_END;
}
+#if DBG
else
{
/* Validate the information class */
return STATUS_INFO_LENGTH_MISMATCH;
}
}
+#endif
/* Reference the Handle */
Status = ObReferenceObjectByHandle(FileHandle,
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);
/* 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 */
- Status = IoCallDriver(DeviceObject, Irp);
+ 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 */
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);
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 avilable */
+ /* Check if we don't have a byte offset available */
if (!(ByteOffset) ||
((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
(CapturedByteOffset.u.HighPart == -1)))
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;
}
return STATUS_INVALID_PARAMETER;
}
- /* Get the device object */
- DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+ if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
{
/* 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)
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);
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)
{
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 */
if (!LocalEvent) IopUnlockFileObject(FileObject);
}
+ if (TargetHandle != NULL)
+ {
+ ObCloseHandle(TargetHandle, KernelMode);
+ }
+
/* Return the Status */
return Status;
}
NTSTATUS Status;
OBJECT_HANDLE_INFORMATION HandleInformation;
IO_STATUS_BLOCK KernelIosb;
+ PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
CapturedLength.QuadPart = 0;
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)
{
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 */
- Status = ObReferenceObjectByHandle(FileHandle,
- 0,
- IoFileObjectType,
- PreviousMode,
- (PVOID*)&FileObject,
- &ObjectHandleInfo);
+ /* Get File Object for write */
+ Status = ObReferenceFileObjectForWrite(FileHandle,
+ PreviousMode,
+ &FileObject,
+ &ObjectHandleInfo);
if (!NT_SUCCESS(Status)) return Status;
/* Validate User-Mode Buffers */
{
_SEH2_TRY
{
- /*
- * Check if the handle has either FILE_WRITE_DATA or
- * FILE_APPEND_DATA 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);
- _SEH2_YIELD(return STATUS_ACCESS_DENIED);
- }
-
/* Probe the status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Return the exception code */
+ /* Release the file object and return the exception code */
+ ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
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 avilable */
+ /* Check if we don't have a byte offset available */
if (!(ByteOffset) ||
((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
(CapturedByteOffset.u.HighPart == -1)))
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;
}
return STATUS_INVALID_PARAMETER;
}
- /* Get the device object */
- DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+ if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
{
/* 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)