mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 02:37:06 +00:00
355 lines
8.8 KiB
C
355 lines
8.8 KiB
C
/*
|
|
* COPYRIGHT: See COPYRIGHT.TXT
|
|
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
|
* FILE: dispatch.c
|
|
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
|
* HOMEPAGE: http://www.ext2fsd.com
|
|
* UPDATE HISTORY:
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "ext2fs.h"
|
|
|
|
/* GLOBALS ***************************************************************/
|
|
|
|
extern PEXT2_GLOBAL Ext2Global;
|
|
|
|
/* DEFINITIONS *************************************************************/
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, Ext2QueueRequest)
|
|
#pragma alloc_text(PAGE, Ext2DeQueueRequest)
|
|
#endif
|
|
|
|
/*
|
|
* Ext2OplockComplete
|
|
*
|
|
* callback routine of FsRtlCheckOplock when an oplock break has
|
|
* completed, allowing an Irp to resume execution.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Context: the IrpContext to be queued
|
|
* Irp: the I/O request packet
|
|
*
|
|
* Return Value:
|
|
* N/A
|
|
*/
|
|
|
|
VOID NTAPI
|
|
Ext2OplockComplete (
|
|
IN PVOID Context,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
//
|
|
// Check on the return value in the Irp.
|
|
//
|
|
|
|
if (Irp->IoStatus.Status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// queue the Irp context in the workqueue.
|
|
//
|
|
|
|
Ext2QueueRequest((PEXT2_IRP_CONTEXT)Context);
|
|
|
|
} else {
|
|
|
|
//
|
|
// complete the request in case of failure
|
|
//
|
|
|
|
Ext2CompleteIrpContext( (PEXT2_IRP_CONTEXT) Context,
|
|
Irp->IoStatus.Status );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Ext2LockIrp
|
|
*
|
|
* performs buffer locking if we need pend the process of the Irp
|
|
*
|
|
* Arguments:
|
|
* Context: the irp context
|
|
* Irp: the I/O request packet.
|
|
*
|
|
* Return Value:
|
|
* N/A
|
|
*/
|
|
|
|
VOID NTAPI
|
|
Ext2LockIrp (
|
|
IN PVOID Context,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PEXT2_IRP_CONTEXT IrpContext;
|
|
|
|
if (Irp == NULL) {
|
|
return;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
|
|
|
if ( IrpContext->MajorFunction == IRP_MJ_READ ||
|
|
IrpContext->MajorFunction == IRP_MJ_WRITE ) {
|
|
|
|
//
|
|
// lock the user's buffer to MDL, if the I/O is bufferred
|
|
//
|
|
|
|
if (!IsFlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
|
|
|
|
Ext2LockUserBuffer( Irp, IrpSp->Parameters.Write.Length,
|
|
(IrpContext->MajorFunction == IRP_MJ_READ) ?
|
|
IoWriteAccess : IoReadAccess );
|
|
}
|
|
|
|
} else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL
|
|
&& IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
|
|
|
|
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryDirectory.Length;
|
|
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
|
|
|
} else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {
|
|
|
|
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryEa.Length;
|
|
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
|
|
|
} else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {
|
|
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.SetEa.Length;
|
|
Ext2LockUserBuffer(Irp, Length, IoReadAccess);
|
|
|
|
} else if ( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
|
|
(IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) ) {
|
|
PEXTENDED_IO_STACK_LOCATION EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
|
|
if ( (EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) ||
|
|
(EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS) ||
|
|
(EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTER_BASE) ) {
|
|
ULONG Length = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
|
}
|
|
}
|
|
|
|
// Mark the request as pending status
|
|
|
|
IoMarkIrpPending( Irp );
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2QueueRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
ASSERT(IrpContext);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
/* set the flags of "can wait" and "queued" */
|
|
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
|
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
|
|
|
|
/* make sure the buffer is kept valid in system context */
|
|
Ext2LockIrp(IrpContext, IrpContext->Irp);
|
|
|
|
/* initialize workite*/
|
|
ExInitializeWorkItem(
|
|
&IrpContext->WorkQueueItem,
|
|
Ext2DeQueueRequest,
|
|
IrpContext );
|
|
|
|
/* dispatch it */
|
|
ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
VOID NTAPI
|
|
Ext2DeQueueRequest (IN PVOID Context)
|
|
{
|
|
PEXT2_IRP_CONTEXT IrpContext;
|
|
|
|
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
|
|
|
ASSERT(IrpContext);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
_SEH2_TRY {
|
|
|
|
_SEH2_TRY {
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
if (!IrpContext->IsTopLevel) {
|
|
IoSetTopLevelIrp((PIRP) FSRTL_FSP_TOP_LEVEL_IRP);
|
|
}
|
|
|
|
Ext2DispatchRequest(IrpContext);
|
|
|
|
} _SEH2_EXCEPT (Ext2ExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
|
|
|
|
Ext2ExceptionHandler(IrpContext);
|
|
} _SEH2_END;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
IoSetTopLevelIrp(NULL);
|
|
|
|
FsRtlExitFileSystem();
|
|
} _SEH2_END;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2DispatchRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
ASSERT(IrpContext);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
switch (IrpContext->MajorFunction) {
|
|
|
|
case IRP_MJ_CREATE:
|
|
return Ext2Create(IrpContext);
|
|
|
|
case IRP_MJ_CLOSE:
|
|
return Ext2Close(IrpContext);
|
|
|
|
case IRP_MJ_READ:
|
|
return Ext2Read(IrpContext);
|
|
|
|
case IRP_MJ_WRITE:
|
|
return Ext2Write(IrpContext);
|
|
|
|
case IRP_MJ_FLUSH_BUFFERS:
|
|
return Ext2Flush(IrpContext);
|
|
|
|
case IRP_MJ_QUERY_INFORMATION:
|
|
return Ext2QueryFileInformation(IrpContext);
|
|
|
|
case IRP_MJ_SET_INFORMATION:
|
|
return Ext2SetFileInformation(IrpContext);
|
|
|
|
case IRP_MJ_QUERY_VOLUME_INFORMATION:
|
|
return Ext2QueryVolumeInformation(IrpContext);
|
|
|
|
case IRP_MJ_SET_VOLUME_INFORMATION:
|
|
return Ext2SetVolumeInformation(IrpContext);
|
|
|
|
case IRP_MJ_DIRECTORY_CONTROL:
|
|
return Ext2DirectoryControl(IrpContext);
|
|
|
|
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
|
return Ext2FileSystemControl(IrpContext);
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
return Ext2DeviceControl(IrpContext);
|
|
|
|
case IRP_MJ_LOCK_CONTROL:
|
|
return Ext2LockControl(IrpContext);
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
return Ext2Cleanup(IrpContext);
|
|
|
|
case IRP_MJ_SHUTDOWN:
|
|
return Ext2ShutDown(IrpContext);
|
|
|
|
case IRP_MJ_QUERY_EA:
|
|
return Ext2QueryEa(IrpContext);
|
|
|
|
case IRP_MJ_SET_EA:
|
|
return Ext2SetEa(IrpContext);
|
|
|
|
#if (_WIN32_WINNT >= 0x0500)
|
|
case IRP_MJ_PNP:
|
|
return Ext2Pnp(IrpContext);
|
|
#endif //(_WIN32_WINNT >= 0x0500)
|
|
default:
|
|
DEBUG(DL_ERR, ( "Ext2DispatchRequest: Unexpected major function: %xh\n",
|
|
IrpContext->MajorFunction));
|
|
|
|
Ext2CompleteIrpContext(IrpContext, STATUS_DRIVER_INTERNAL_ERROR);
|
|
|
|
return STATUS_DRIVER_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
Ext2BuildRequest (PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
BOOLEAN AtIrqlPassiveLevel = FALSE;
|
|
BOOLEAN IsTopLevelIrp = FALSE;
|
|
PEXT2_IRP_CONTEXT IrpContext = NULL;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
_SEH2_TRY {
|
|
|
|
_SEH2_TRY {
|
|
|
|
#if EXT2_DEBUG
|
|
Ext2DbgPrintCall(DeviceObject, Irp);
|
|
#endif
|
|
|
|
AtIrqlPassiveLevel = (KeGetCurrentIrql() == PASSIVE_LEVEL);
|
|
|
|
if (AtIrqlPassiveLevel) {
|
|
FsRtlEnterFileSystem();
|
|
}
|
|
|
|
if (!IoGetTopLevelIrp()) {
|
|
IsTopLevelIrp = TRUE;
|
|
IoSetTopLevelIrp(Irp);
|
|
}
|
|
|
|
IrpContext = Ext2AllocateIrpContext(DeviceObject, Irp);
|
|
|
|
if (!IrpContext) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
Ext2CompleteRequest(Irp, TRUE, IO_NO_INCREMENT);
|
|
|
|
} else {
|
|
|
|
if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
|
|
!AtIrqlPassiveLevel) {
|
|
|
|
DbgBreak();
|
|
}
|
|
|
|
Status = Ext2DispatchRequest(IrpContext);
|
|
}
|
|
} _SEH2_EXCEPT (Ext2ExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
|
|
|
|
Status = Ext2ExceptionHandler(IrpContext);
|
|
} _SEH2_END;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (IsTopLevelIrp) {
|
|
IoSetTopLevelIrp(NULL);
|
|
}
|
|
|
|
if (AtIrqlPassiveLevel) {
|
|
FsRtlExitFileSystem();
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|