mirror of
https://github.com/reactos/reactos.git
synced 2024-09-23 02:56:00 +00:00
2880 lines
82 KiB
C
2880 lines
82 KiB
C
/*
|
|
* COPYRIGHT: See COPYRIGHT.TXT
|
|
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
|
* FILE: fsctl.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, Ext2IsHandleCountZero)
|
|
#pragma alloc_text(PAGE, Ext2LockVcb)
|
|
#pragma alloc_text(PAGE, Ext2LockVolume)
|
|
#pragma alloc_text(PAGE, Ext2UnlockVcb)
|
|
#pragma alloc_text(PAGE, Ext2UnlockVolume)
|
|
#pragma alloc_text(PAGE, Ext2AllowExtendedDasdIo)
|
|
#pragma alloc_text(PAGE, Ext2GetRetrievalPointerBase)
|
|
#pragma alloc_text(PAGE, Ext2QueryExtentMappings)
|
|
#pragma alloc_text(PAGE, Ext2QueryRetrievalPointers)
|
|
#pragma alloc_text(PAGE, Ext2GetRetrievalPointers)
|
|
#pragma alloc_text(PAGE, Ext2UserFsRequest)
|
|
#pragma alloc_text(PAGE, Ext2IsMediaWriteProtected)
|
|
#pragma alloc_text(PAGE, Ext2MountVolume)
|
|
#pragma alloc_text(PAGE, Ext2PurgeVolume)
|
|
#pragma alloc_text(PAGE, Ext2PurgeFile)
|
|
#pragma alloc_text(PAGE, Ext2DismountVolume)
|
|
#pragma alloc_text(PAGE, Ext2IsVolumeMounted)
|
|
#pragma alloc_text(PAGE, Ext2VerifyVolume)
|
|
#pragma alloc_text(PAGE, Ext2FileSystemControl)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
Ext2SetVpbFlag (
|
|
IN PVPB Vpb,
|
|
IN USHORT Flag )
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
IoAcquireVpbSpinLock(&OldIrql);
|
|
Vpb->Flags |= Flag;
|
|
IoReleaseVpbSpinLock(OldIrql);
|
|
}
|
|
|
|
VOID
|
|
Ext2ClearVpbFlag (
|
|
IN PVPB Vpb,
|
|
IN USHORT Flag )
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
IoAcquireVpbSpinLock(&OldIrql);
|
|
Vpb->Flags &= ~Flag;
|
|
IoReleaseVpbSpinLock(OldIrql);
|
|
}
|
|
|
|
BOOLEAN
|
|
Ext2IsHandleCountZero(IN PEXT2_VCB Vcb)
|
|
{
|
|
PEXT2_FCB Fcb;
|
|
PLIST_ENTRY List;
|
|
|
|
for ( List = Vcb->FcbList.Flink;
|
|
List != &Vcb->FcbList;
|
|
List = List->Flink ) {
|
|
|
|
Fcb = CONTAINING_RECORD(List, EXT2_FCB, Next);
|
|
|
|
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
|
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
|
|
|
DEBUG(DL_INF, ( "Ext2IsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n",
|
|
Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer, Fcb->OpenHandleCount));
|
|
|
|
if (Fcb->OpenHandleCount) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2LockVcb (IN PEXT2_VCB Vcb,
|
|
IN PFILE_OBJECT FileObject)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
_SEH2_TRY {
|
|
|
|
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
|
|
DEBUG(DL_INF, ( "Ext2LockVolume: Volume is already locked.\n"));
|
|
Status = STATUS_ACCESS_DENIED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (Vcb->OpenHandleCount > (ULONG)(FileObject ? 1 : 0)) {
|
|
DEBUG(DL_INF, ( "Ext2LockVcb: There are still opened files.\n"));
|
|
|
|
Status = STATUS_ACCESS_DENIED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (!Ext2IsHandleCountZero(Vcb)) {
|
|
DEBUG(DL_INF, ( "Ext2LockVcb: Thare are still opened files.\n"));
|
|
|
|
Status = STATUS_ACCESS_DENIED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
|
|
Ext2SetVpbFlag(Vcb->Vpb, VPB_LOCKED);
|
|
Vcb->LockFile = FileObject;
|
|
|
|
DEBUG(DL_INF, ( "Ext2LockVcb: Volume locked.\n"));
|
|
|
|
} _SEH2_FINALLY {
|
|
// Nothing
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2LockVolume (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PEXT2_VCB Vcb = NULL;
|
|
NTSTATUS Status;
|
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext != NULL);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
//
|
|
// This request is not allowed on the main device object
|
|
//
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
|
|
ASSERT(Vcb != NULL);
|
|
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
|
|
|
|
#if (_WIN32_WINNT >= 0x0500)
|
|
CcWaitForCurrentLazyWriterActivity();
|
|
#endif
|
|
ExAcquireResourceExclusiveLite(
|
|
&Vcb->MainResource,
|
|
TRUE );
|
|
|
|
VcbResourceAcquired = TRUE;
|
|
|
|
/* flush dirty data before locking the volume */
|
|
if (!IsVcbReadOnly(Vcb)) {
|
|
Ext2FlushFiles(IrpContext, Vcb, FALSE);
|
|
Ext2FlushVolume(IrpContext, Vcb, FALSE);
|
|
}
|
|
|
|
Status = Ext2LockVcb(Vcb, IrpSp->FileObject);
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (VcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
}
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2UnlockVcb ( IN PEXT2_VCB Vcb,
|
|
IN PFILE_OBJECT FileObject )
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
_SEH2_TRY {
|
|
|
|
if (FileObject && FileObject->FsContext != Vcb) {
|
|
Status = STATUS_NOT_LOCKED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
|
|
DEBUG(DL_ERR, ( ": Ext2UnlockVcb: Volume is not locked.\n"));
|
|
Status = STATUS_NOT_LOCKED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (Vcb->LockFile == FileObject) {
|
|
ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
|
|
Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
|
|
DEBUG(DL_INF, ( "Ext2UnlockVcb: Volume unlocked.\n"));
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Status = STATUS_NOT_LOCKED;
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
// Nothing
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2UnlockVolume (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
PEXT2_VCB Vcb = NULL;
|
|
NTSTATUS Status;
|
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext != NULL);
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
|
|
|
|
//
|
|
// This request is not allowed on the main device object
|
|
//
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
ASSERT(Vcb != NULL);
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
ExAcquireResourceExclusiveLite(
|
|
&Vcb->MainResource,
|
|
TRUE );
|
|
VcbResourceAcquired = TRUE;
|
|
|
|
Status = Ext2UnlockVcb(Vcb, IrpSp->FileObject);
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (VcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
}
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2InvalidateVolumes ( IN PEXT2_IRP_CONTEXT IrpContext )
|
|
{
|
|
NTSTATUS Status;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
#ifndef __REACTOS__
|
|
PVPB NewVpb = NULL;
|
|
#endif
|
|
HANDLE Handle;
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
ULONG InputLength = 0;
|
|
PFILE_OBJECT FileObject;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
BOOLEAN GlobalResourceAcquired = FALSE;
|
|
|
|
LUID Privilege = {SE_TCB_PRIVILEGE, 0};
|
|
|
|
_SEH2_TRY {
|
|
|
|
Irp = IrpContext->Irp;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (!IsExt2FsDevice(IrpSp->DeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) {
|
|
Status = STATUS_PRIVILEGE_NOT_HELD;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
|
|
#ifndef _GNU_NTIFS_
|
|
InputLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
#else
|
|
InputLength = ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))->
|
|
Parameters.FileSystemControl.InputBufferLength;
|
|
#endif
|
|
|
|
#if defined(_WIN64)
|
|
if (IoIs32bitProcess(Irp)) {
|
|
if (InputLength != sizeof(UINT32)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
|
|
} else
|
|
#endif
|
|
{
|
|
if (InputLength != sizeof(HANDLE)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
|
|
}
|
|
|
|
Status = ObReferenceObjectByHandle( Handle,
|
|
0,
|
|
*IoFileObjectType,
|
|
KernelMode,
|
|
(void **)&FileObject,
|
|
NULL );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
} else {
|
|
DeviceObject = FileObject->DeviceObject;
|
|
ObDereferenceObject(FileObject);
|
|
}
|
|
|
|
ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
|
|
GlobalResourceAcquired = TRUE;
|
|
|
|
ListEntry = Ext2Global->VcbList.Flink;
|
|
while (ListEntry != &Ext2Global->VcbList) {
|
|
|
|
PEXT2_VCB Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh "
|
|
"Blink = %p &Vcb->Next = %p\n",
|
|
Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
|
|
|
|
if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) {
|
|
|
|
DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Got Vcb=%xh Vcb->Vpb=%xh "
|
|
"Blink = %p &Vcb->Next = %p\n",
|
|
Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
|
|
/* dismount the volume */
|
|
Ext2CheckDismount(IrpContext, Vcb, FALSE);
|
|
}
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (GlobalResourceAcquired) {
|
|
ExReleaseResourceLite(&Ext2Global->Resource);
|
|
}
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2AllowExtendedDasdIo(IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PEXT2_VCB Vcb;
|
|
PEXT2_CCB Ccb;
|
|
NTSTATUS status;
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
|
|
|
|
Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext;
|
|
Ccb = (PEXT2_CCB) IrpSp->FileObject->FsContext2;
|
|
|
|
ASSERT(Vcb != NULL);
|
|
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
if (Ccb) {
|
|
SetLongFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO);
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Ext2CompleteIrpContext(IrpContext, status);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Ext2OplockRequest
|
|
*
|
|
* oplock requests handler routine
|
|
*
|
|
* Arguments:
|
|
* IrpContext: the ext2 irp context
|
|
*
|
|
* Return Value:
|
|
* NTSTATUS: The return status for the operation
|
|
*
|
|
*/
|
|
|
|
NTSTATUS
|
|
Ext2OplockRequest (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ULONG FsCtrlCode;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PEXTENDED_IO_STACK_LOCATION EIrpSp;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
|
|
ULONG OplockCount = 0;
|
|
|
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|
BOOLEAN FcbResourceAcquired = FALSE;
|
|
|
|
ASSERT(IrpContext);
|
|
|
|
_SEH2_TRY {
|
|
|
|
Irp = IrpContext->Irp;
|
|
ASSERT(Irp);
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(IrpSp);
|
|
EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
|
|
//
|
|
// This request is not allowed on the main device object
|
|
//
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
|
|
ASSERT(Vcb != NULL);
|
|
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
FileObject = IrpContext->FileObject;
|
|
|
|
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
|
|
|
//
|
|
// This request is not allowed on volumes
|
|
//
|
|
|
|
if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
|
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
|
|
|
if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
|
|
Status = STATUS_FILE_DELETED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
|
if (Ccb == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
|
|
FsCtrlCode = EIrpSp->Parameters.FileSystemControl.FsControlCode;
|
|
|
|
switch (FsCtrlCode) {
|
|
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
|
case FSCTL_REQUEST_BATCH_OPLOCK:
|
|
|
|
VcbResourceAcquired =
|
|
ExAcquireResourceSharedLite(
|
|
&Vcb->MainResource,
|
|
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
|
|
|
|
ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
|
|
|
FcbResourceAcquired =
|
|
ExAcquireResourceExclusiveLite (
|
|
&Fcb->MainResource,
|
|
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
|
|
|
|
if (FsCtrlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
|
|
OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor);
|
|
} else {
|
|
OplockCount = Fcb->OpenHandleCount;
|
|
}
|
|
|
|
break;
|
|
|
|
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
|
case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
|
|
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
|
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
|
|
|
FcbResourceAcquired =
|
|
ExAcquireResourceSharedLite (
|
|
&Fcb->MainResource,
|
|
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Ext2BugCheck(EXT2_BUGCHK_FSCTL, FsCtrlCode, 0, 0);
|
|
}
|
|
|
|
|
|
//
|
|
// Call the FsRtl routine to grant/acknowledge oplock.
|
|
//
|
|
|
|
Status = FsRtlOplockFsctrl( &Fcb->Oplock,
|
|
Irp,
|
|
OplockCount );
|
|
|
|
//
|
|
// Set the flag indicating if Fast I/O is possible
|
|
//
|
|
|
|
Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
|
|
IrpContext->Irp = NULL;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (VcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2IsVolumeDirty (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIRP Irp;
|
|
PEXTENDED_IO_STACK_LOCATION IrpSp;
|
|
PULONG VolumeState;
|
|
|
|
_SEH2_TRY {
|
|
|
|
Irp = IrpContext->Irp;
|
|
IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// Get a pointer to the output buffer. Look at the system buffer field in th
|
|
// irp first. Then the Irp Mdl.
|
|
//
|
|
|
|
if (Irp->AssociatedIrp.SystemBuffer != NULL) {
|
|
|
|
VolumeState = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
} else if (Irp->MdlAddress != NULL) {
|
|
|
|
VolumeState = MmGetSystemAddressForMdl( Irp->MdlAddress );
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_USER_BUFFER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
*VolumeState = 0;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
Ext2CompleteIrpContext(IrpContext, status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2QueryExtentMappings(
|
|
IN PEXT2_IRP_CONTEXT IrpContext,
|
|
IN PEXT2_VCB Vcb,
|
|
IN PEXT2_FCB Fcb,
|
|
IN PLARGE_INTEGER RequestVbn,
|
|
OUT PLARGE_INTEGER * pMappedRuns
|
|
)
|
|
{
|
|
PLARGE_INTEGER MappedRuns = NULL;
|
|
PLARGE_INTEGER PartialRuns = NULL;
|
|
|
|
PEXT2_EXTENT Chain = NULL;
|
|
PEXT2_EXTENT Extent = NULL;
|
|
|
|
LONGLONG Vbn = 0;
|
|
ULONG Length = 0;
|
|
ULONG i = 0;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
_SEH2_TRY {
|
|
|
|
/* now building all the request extents */
|
|
while (Vbn < RequestVbn->QuadPart) {
|
|
|
|
Length = 0x80000000; /* 2g bytes */
|
|
if (RequestVbn->QuadPart < Vbn + Length) {
|
|
Length = (ULONG)(RequestVbn->QuadPart - Vbn);
|
|
}
|
|
|
|
/* build extents for sub-range */
|
|
Extent = NULL;
|
|
Status = Ext2BuildExtents(
|
|
IrpContext,
|
|
Vcb,
|
|
Fcb->Mcb,
|
|
Vbn,
|
|
Length,
|
|
FALSE,
|
|
&Extent);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (Chain) {
|
|
Ext2JointExtents(Chain, Extent);
|
|
} else {
|
|
Chain = Extent;
|
|
}
|
|
|
|
/* allocate extent array */
|
|
PartialRuns = Ext2AllocatePool(
|
|
NonPagedPool,
|
|
(Ext2CountExtents(Chain) + 2) *
|
|
(2 * sizeof(LARGE_INTEGER)),
|
|
'RE2E');
|
|
|
|
if (PartialRuns == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
_SEH2_LEAVE;
|
|
}
|
|
RtlZeroMemory( PartialRuns,
|
|
(Ext2CountExtents(Chain) + 2) *
|
|
(2 * sizeof(LARGE_INTEGER)));
|
|
|
|
if (MappedRuns) {
|
|
RtlMoveMemory(PartialRuns,
|
|
MappedRuns,
|
|
i * 2 * sizeof(LARGE_INTEGER));
|
|
Ext2FreePool(MappedRuns, 'RE2E');
|
|
}
|
|
MappedRuns = PartialRuns;
|
|
|
|
/* walk all the Mcb runs in Extent */
|
|
for (; Extent != NULL; Extent = Extent->Next) {
|
|
MappedRuns[i*2 + 0].QuadPart = Vbn + Extent->Offset;
|
|
MappedRuns[i*2 + 1].QuadPart = Extent->Lba;
|
|
i = i+1;
|
|
}
|
|
|
|
Vbn = Vbn + Length;
|
|
}
|
|
|
|
*pMappedRuns = MappedRuns;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) {
|
|
if (MappedRuns) {
|
|
Ext2FreePool(MappedRuns, 'RE2E');
|
|
}
|
|
*pMappedRuns = NULL;
|
|
}
|
|
|
|
if (Chain) {
|
|
Ext2DestroyExtentChain(Chain);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2QueryRetrievalPointers (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PEXTENDED_IO_STACK_LOCATION EIrpSp;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
|
|
PLARGE_INTEGER RequestVbn;
|
|
PLARGE_INTEGER * pMappedRuns;
|
|
|
|
ULONG InputSize;
|
|
ULONG OutputSize;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
BOOLEAN FcbResourceAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext);
|
|
Irp = IrpContext->Irp;
|
|
ASSERT(Irp);
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
|
|
ASSERT(IrpSp);
|
|
|
|
InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
|
|
DbgBreak();
|
|
|
|
/* This request is not allowed on the main device object */
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
ASSERT(Vcb != NULL);
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
FileObject = IrpContext->FileObject;
|
|
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
|
|
|
/* check Fcb is valid or not */
|
|
if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
|
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
|
if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
|
|
Status = STATUS_FILE_DELETED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
|
if (Ccb == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
|
|
/* Is requstor in kernel and Fcb a paging file ? */
|
|
if (Irp->RequestorMode != KernelMode ||
|
|
!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) ||
|
|
InputSize != sizeof(LARGE_INTEGER) ||
|
|
OutputSize != sizeof(PVOID)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (!ExAcquireResourceExclusiveLite (
|
|
&Fcb->MainResource, Ext2CanIWait())) {
|
|
Status = STATUS_PENDING;
|
|
_SEH2_LEAVE;
|
|
}
|
|
FcbResourceAcquired = TRUE;
|
|
|
|
RequestVbn = EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
pMappedRuns = Irp->UserBuffer;
|
|
|
|
DbgBreak();
|
|
|
|
/* request size beyonds whole file size */
|
|
if (RequestVbn->QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
|
|
Status = STATUS_END_OF_FILE;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Status = Ext2QueryExtentMappings(
|
|
IrpContext,
|
|
Vcb,
|
|
Fcb,
|
|
RequestVbn,
|
|
pMappedRuns
|
|
);
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
} else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2GetRetrievalPointers (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PEXTENDED_IO_STACK_LOCATION EIrpSp;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
|
|
PSTARTING_VCN_INPUT_BUFFER SVIB;
|
|
PRETRIEVAL_POINTERS_BUFFER RPSB;
|
|
|
|
PEXT2_EXTENT Chain = NULL;
|
|
PEXT2_EXTENT Extent = NULL;
|
|
|
|
LONGLONG Vbn = 0;
|
|
ULONG Length = 0;
|
|
ULONG i = 0;
|
|
|
|
ULONG UsedSize = 0;
|
|
ULONG InputSize;
|
|
ULONG OutputSize;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
BOOLEAN FcbResourceAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext);
|
|
Irp = IrpContext->Irp;
|
|
ASSERT(Irp);
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
|
|
ASSERT(IrpSp);
|
|
|
|
InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
|
|
/* This request is not allowed on the main device object */
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
ASSERT(Vcb != NULL);
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
FileObject = IrpContext->FileObject;
|
|
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
|
|
|
/* check Fcb is valid or not */
|
|
if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
|
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
|
|
|
if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
|
|
Status = STATUS_FILE_DELETED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
|
if (Ccb == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
|
|
if (InputSize < sizeof(STARTING_VCN_INPUT_BUFFER) ||
|
|
OutputSize < sizeof(RETRIEVAL_POINTERS_BUFFER) ) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (!ExAcquireResourceExclusiveLite (
|
|
&Fcb->MainResource, Ext2CanIWait())) {
|
|
Status = STATUS_PENDING;
|
|
_SEH2_LEAVE;
|
|
}
|
|
FcbResourceAcquired = TRUE;
|
|
|
|
SVIB = (PSTARTING_VCN_INPUT_BUFFER)
|
|
EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
RPSB = (PRETRIEVAL_POINTERS_BUFFER) Ext2GetUserBuffer(Irp);
|
|
|
|
/* probe user buffer */
|
|
|
|
_SEH2_TRY {
|
|
if (Irp->RequestorMode != KernelMode) {
|
|
ProbeForRead (SVIB, InputSize, sizeof(UCHAR));
|
|
ProbeForWrite(RPSB, OutputSize, sizeof(UCHAR));
|
|
}
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
} _SEH2_END;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
UsedSize = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]);
|
|
|
|
/* request size beyonds whole file size ? */
|
|
DEBUG(DL_DBG, ("Ext2GetRetrievalPointers: Startin from Vbn: %I64xh\n",
|
|
SVIB->StartingVcn.QuadPart));
|
|
Vbn = (SVIB->StartingVcn.QuadPart << BLOCK_BITS);
|
|
if (Vbn >= Fcb->Header.AllocationSize.QuadPart ) {
|
|
Status = STATUS_END_OF_FILE;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* now building all the request extents */
|
|
while (Vbn < Fcb->Header.AllocationSize.QuadPart) {
|
|
|
|
ASSERT(Chain == NULL);
|
|
Length = 0x80000000; /* 2g bytes */
|
|
if (Fcb->Header.AllocationSize.QuadPart < Vbn + Length) {
|
|
Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - Vbn);
|
|
}
|
|
|
|
/* build extents for sub-range */
|
|
Status = Ext2BuildExtents(
|
|
IrpContext,
|
|
Vcb,
|
|
Fcb->Mcb,
|
|
Vbn,
|
|
Length,
|
|
FALSE,
|
|
&Chain);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgBreak();
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* fill user buffer of RETRIEVAL_POINTERS_BUFFER */
|
|
Extent = Chain;
|
|
while (Extent) {
|
|
|
|
DEBUG(DL_MAP, ("Ext2GetRetrievalPointers: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
|
|
&Fcb->Mcb->FullName, i,
|
|
((Vbn + Extent->Offset) >> BLOCK_BITS),
|
|
Extent->Lba));
|
|
|
|
RPSB->Extents[i].Lcn.QuadPart = (Extent->Lba >> BLOCK_BITS);
|
|
RPSB->Extents[i].NextVcn.QuadPart = ((Vbn + Extent->Offset + Extent->Length) >> BLOCK_BITS);
|
|
if (i == 0) {
|
|
RPSB->StartingVcn.QuadPart = ((Vbn + Extent->Offset) >> BLOCK_BITS);
|
|
} else {
|
|
ASSERT(RPSB->Extents[i-1].NextVcn.QuadPart == ((Vbn + Extent->Offset) >> BLOCK_BITS));
|
|
}
|
|
if (UsedSize + sizeof(RETRIEVAL_POINTERS_BUFFER) > OutputSize) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
_SEH2_LEAVE;
|
|
}
|
|
UsedSize += sizeof(LARGE_INTEGER) * 2;
|
|
Irp->IoStatus.Information = (ULONG_PTR)UsedSize;
|
|
RPSB->ExtentCount = ++i;
|
|
Extent = Extent->Next;
|
|
}
|
|
|
|
if (Chain) {
|
|
Ext2DestroyExtentChain(Chain);
|
|
Chain = NULL;
|
|
}
|
|
|
|
Vbn = Vbn + Length;
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
NTSTATUS _s;
|
|
ULONG _i = 0;
|
|
LARGE_INTEGER RequestVbn = Fcb->Header.AllocationSize;
|
|
PLARGE_INTEGER MappedRuns = NULL;
|
|
|
|
_s = Ext2QueryExtentMappings(
|
|
IrpContext,
|
|
Vcb,
|
|
Fcb,
|
|
&RequestVbn,
|
|
&MappedRuns
|
|
);
|
|
if (!NT_SUCCESS(_s) || NULL == MappedRuns) {
|
|
DbgBreak();
|
|
goto exit_to_get_rps;
|
|
}
|
|
|
|
while (MappedRuns[_i*2 + 0].QuadPart != 0 ||
|
|
MappedRuns[_i*2 + 1].QuadPart != 0 ) {
|
|
DEBUG(DL_MAP, ("Ext2QueryExtentMappings: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
|
|
&Fcb->Mcb->FullName, _i,
|
|
MappedRuns[_i*2 + 0].QuadPart,
|
|
MappedRuns[_i*2 + 1].QuadPart));
|
|
_i++;
|
|
}
|
|
|
|
exit_to_get_rps:
|
|
|
|
if (MappedRuns) {
|
|
Ext2FreePool(MappedRuns, 'RE2E');
|
|
}
|
|
}
|
|
#endif
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (Chain) {
|
|
Ext2DestroyExtentChain(Chain);
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
} else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2GetRetrievalPointerBase (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PEXTENDED_IO_STACK_LOCATION EIrpSp;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
|
|
PLARGE_INTEGER FileAreaOffset;
|
|
|
|
ULONG OutputSize;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
BOOLEAN FcbResourceAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext);
|
|
Irp = IrpContext->Irp;
|
|
ASSERT(Irp);
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
|
|
ASSERT(IrpSp);
|
|
|
|
OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
|
|
/* This request is not allowed on the main device object */
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
ASSERT(Vcb != NULL);
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
FileObject = IrpContext->FileObject;
|
|
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
|
|
|
/* check Fcb is valid or not */
|
|
if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
|
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
|
|
|
if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
|
|
Status = STATUS_FILE_DELETED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
|
if (Ccb == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
|
|
if (OutputSize < sizeof(LARGE_INTEGER)) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (!ExAcquireResourceExclusiveLite (
|
|
&Fcb->MainResource, Ext2CanIWait())) {
|
|
Status = STATUS_PENDING;
|
|
_SEH2_LEAVE;
|
|
}
|
|
FcbResourceAcquired = TRUE;
|
|
|
|
FileAreaOffset = (PLARGE_INTEGER) Ext2GetUserBuffer(Irp);
|
|
|
|
/* probe user buffer */
|
|
|
|
_SEH2_TRY {
|
|
if (Irp->RequestorMode != KernelMode) {
|
|
ProbeForWrite(FileAreaOffset, OutputSize, sizeof(UCHAR));
|
|
}
|
|
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
} _SEH2_END;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
DEBUG(DL_DBG, ("Ext2GetRetrievalPointerBase: FileAreaOffset is 0.\n"));
|
|
|
|
FileAreaOffset->QuadPart = 0; // sector offset to the first allocatable unit on the filesystem
|
|
|
|
Irp->IoStatus.Information = sizeof(LARGE_INTEGER);
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
} else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2InspectReparseData(
|
|
IN PREPARSE_DATA_BUFFER RDB,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (!RDB) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto out;
|
|
}
|
|
|
|
if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
goto out;
|
|
}
|
|
|
|
if (InputBufferLength < RDB->ReparseDataLength) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
goto out;
|
|
}
|
|
|
|
if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
goto out;
|
|
}
|
|
|
|
if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
|
|
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
|
|
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
|
|
> (PUCHAR)RDB + InputBufferLength ) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
goto out;
|
|
}
|
|
|
|
if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
|
|
+ RDB->SymbolicLinkReparseBuffer.PrintNameOffset
|
|
+ RDB->SymbolicLinkReparseBuffer.PrintNameLength
|
|
> (PUCHAR)RDB + InputBufferLength) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
goto out;
|
|
}
|
|
|
|
if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
|
|
{
|
|
ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
|
|
REPARSE_DATA_BUFFER_HEADER_SIZE);
|
|
RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
|
RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
|
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
|
|
PathBufferLength * sizeof(WCHAR);
|
|
RDB->Reserved = 0;
|
|
RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
|
|
RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
|
|
RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
|
|
RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
|
|
RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
|
|
RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2ReadSymlink (
|
|
IN PEXT2_IRP_CONTEXT IrpContext,
|
|
IN PEXT2_VCB Vcb,
|
|
IN PEXT2_MCB Mcb,
|
|
IN PVOID Buffer,
|
|
IN ULONG Size,
|
|
OUT PULONG BytesRead
|
|
)
|
|
{
|
|
return Ext2ReadInode ( IrpContext,
|
|
Vcb,
|
|
Mcb,
|
|
0,
|
|
Buffer,
|
|
Size,
|
|
FALSE,
|
|
BytesRead);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PEXTENDED_IO_STACK_LOCATION EIrpSp;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
PEXT2_MCB Mcb = NULL;
|
|
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
BOOLEAN MainResourceAcquired = FALSE;
|
|
|
|
PVOID OutputBuffer;
|
|
ULONG OutputBufferLength;
|
|
ULONG BytesRead = 0;
|
|
|
|
PREPARSE_DATA_BUFFER RDB;
|
|
|
|
UNICODE_STRING UniName;
|
|
OEM_STRING OemName;
|
|
|
|
PCHAR OemNameBuffer = NULL;
|
|
int OemNameLength = 0, i;
|
|
|
|
Ccb = IrpContext->Ccb;
|
|
ASSERT(Ccb != NULL);
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
Mcb = IrpContext->Fcb->Mcb;
|
|
Irp = IrpContext->Irp;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
_SEH2_TRY {
|
|
|
|
if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
|
|
!IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
|
|
Status = STATUS_NOT_A_REPARSE_POINT;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
|
|
OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
|
|
if (!RDB) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
OemNameLength = (ULONG)Mcb->Inode.i_size;
|
|
if (OemNameLength > USHRT_MAX) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
OemName.Length = (USHORT)OemNameLength;
|
|
OemName.MaximumLength = OemNameLength + 1;
|
|
OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
|
|
OemName.MaximumLength,
|
|
'NL2E');
|
|
if (!OemNameBuffer) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Status = Ext2ReadSymlink(IrpContext,
|
|
Vcb,
|
|
Mcb,
|
|
OemNameBuffer,
|
|
OemNameLength,
|
|
&BytesRead
|
|
);
|
|
OemName.Buffer[OemName.Length] = '\0';
|
|
for (i = 0;i < OemName.Length;i++) {
|
|
if (OemName.Buffer[i] == '/') {
|
|
OemName.Buffer[i] = '\\';
|
|
}
|
|
}
|
|
|
|
if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
|
|
UniName.Length = USHRT_MAX;
|
|
} else {
|
|
UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
|
|
}
|
|
UniName.MaximumLength = UniName.Length;
|
|
UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
|
|
Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
|
|
if (UniName.MaximumLength < 2*UniName.Length) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Ext2InitializeReparseData(RDB, UniName.Length);
|
|
UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
|
|
/*
|
|
(PWCHAR)((PUCHAR)&
|
|
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
|
|
*/
|
|
Ext2OEMToUnicode(Vcb, &UniName, &OemName);
|
|
RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
|
|
RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
|
|
UniName.Buffer, UniName.Length);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (OemNameBuffer) {
|
|
Ext2FreePool(OemNameBuffer, 'NL2E');
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
} else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2WriteSymlink (
|
|
IN PEXT2_IRP_CONTEXT IrpContext,
|
|
IN PEXT2_VCB Vcb,
|
|
IN PEXT2_MCB Mcb,
|
|
IN PVOID Buffer,
|
|
IN ULONG Size,
|
|
OUT PULONG BytesWritten
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
|
|
|
|
if (Size >= EXT2_LINKLEN_IN_INODE) {
|
|
|
|
/* initialize inode i_block[] */
|
|
if (0 == Mcb->Inode.i_blocks) {
|
|
memset(Data, 0, EXT2_LINKLEN_IN_INODE);
|
|
ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
|
|
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
|
}
|
|
|
|
Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
|
|
0, Buffer, Size,
|
|
FALSE, BytesWritten);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto out;
|
|
}
|
|
|
|
} else {
|
|
|
|
/* free inode blocks before writing in line */
|
|
if (Mcb->Inode.i_blocks) {
|
|
LARGE_INTEGER Zero = {0, 0};
|
|
Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
|
|
}
|
|
|
|
ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
|
|
memset(Data, 0, EXT2_LINKLEN_IN_INODE);
|
|
RtlCopyMemory(Data, Buffer, Size);
|
|
}
|
|
|
|
Mcb->Inode.i_size = Size;
|
|
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
|
|
|
if (BytesWritten) {
|
|
*BytesWritten = Size;
|
|
}
|
|
|
|
out:
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
PEXT2_MCB Mcb = NULL;
|
|
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
PVOID InputBuffer;
|
|
ULONG InputBufferLength;
|
|
ULONG BytesWritten = 0;
|
|
|
|
PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
|
|
PEXT2_MCB ParentMcb = NULL;
|
|
|
|
PREPARSE_DATA_BUFFER RDB;
|
|
|
|
UNICODE_STRING UniName;
|
|
OEM_STRING OemName;
|
|
|
|
PCHAR OemNameBuffer = NULL;
|
|
int OemNameLength = 0, i;
|
|
|
|
BOOLEAN MainResourceAcquired = FALSE;
|
|
BOOLEAN FcbLockAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
Ccb = IrpContext->Ccb;
|
|
ASSERT(Ccb != NULL);
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
Fcb = IrpContext->Fcb;
|
|
Mcb = Fcb->Mcb;
|
|
Irp = IrpContext->Irp;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
|
|
FcbLockAcquired = TRUE;
|
|
|
|
ParentMcb = Mcb->Parent;
|
|
ParentDcb = ParentMcb->Fcb;
|
|
if (ParentDcb == NULL) {
|
|
ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
|
|
}
|
|
if (ParentDcb) {
|
|
Ext2ReferXcb(&ParentDcb->ReferenceCount);
|
|
}
|
|
|
|
if (!Mcb)
|
|
_SEH2_LEAVE;
|
|
|
|
if (FcbLockAcquired) {
|
|
ExReleaseResourceLite(&Vcb->FcbLock);
|
|
FcbLockAcquired = FALSE;
|
|
}
|
|
|
|
if (!ExAcquireResourceSharedLite(
|
|
&Fcb->MainResource,
|
|
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
|
|
Status = STATUS_PENDING;
|
|
_SEH2_LEAVE;
|
|
}
|
|
MainResourceAcquired = TRUE;
|
|
|
|
InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
|
|
Status = Ext2InspectReparseData(RDB, InputBufferLength);
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
|
UniName.MaximumLength = UniName.Length;
|
|
UniName.Buffer =
|
|
(PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
|
|
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
|
|
|
|
OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
|
|
if (OemNameLength > USHRT_MAX) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
_SEH2_LEAVE;
|
|
}
|
|
OemName.Length = (USHORT)OemNameLength;
|
|
OemName.MaximumLength = OemNameLength + 1;
|
|
OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
|
|
OemName.MaximumLength,
|
|
'NL2E');
|
|
if (!OemNameBuffer) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
|
|
OemName.Buffer[OemName.Length] = '\0';
|
|
for (i = 0;i < OemName.Length;i++) {
|
|
if (OemName.Buffer[i] == '\\') {
|
|
OemName.Buffer[i] = '/';
|
|
}
|
|
}
|
|
|
|
/* free all data blocks of the inode (to be set as symlink) */
|
|
{
|
|
LARGE_INTEGER zero = {0};
|
|
Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero);
|
|
}
|
|
|
|
/* decrease dir count of group desc and vcb stat */
|
|
if (S_ISDIR(Mcb->Inode.i_mode)) {
|
|
|
|
ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP;
|
|
Ext2UpdateGroupDirStat(IrpContext, Vcb, group);
|
|
|
|
/* drop extra reference for dir inode */
|
|
ext3_dec_count(&Mcb->Inode);
|
|
}
|
|
|
|
/* overwrite inode mode as type SYMLINK */
|
|
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
|
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
|
|
|
|
Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
|
|
OemNameLength, &BytesWritten);
|
|
if (NT_SUCCESS(Status)) {
|
|
Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb,
|
|
S_IFLNK | S_IRWXUGO);
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (FcbLockAcquired) {
|
|
ExReleaseResourceLite(&Vcb->FcbLock);
|
|
FcbLockAcquired = FALSE;
|
|
}
|
|
|
|
if (MainResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (OemNameBuffer) {
|
|
Ext2FreePool(OemNameBuffer, 'NL2E');
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Ext2NotifyReportChange(
|
|
IrpContext,
|
|
Vcb,
|
|
Mcb,
|
|
FILE_NOTIFY_CHANGE_ATTRIBUTES,
|
|
FILE_ACTION_MODIFIED );
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
} else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
|
|
if (ParentDcb) {
|
|
Ext2ReleaseFcb(ParentDcb);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2TruncateSymlink(
|
|
PEXT2_IRP_CONTEXT IrpContext,
|
|
PEXT2_VCB Vcb,
|
|
PEXT2_MCB Mcb,
|
|
ULONG Size
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PUCHAR data = (PUCHAR)&Mcb->Inode.i_block;
|
|
ULONG len = (ULONG)Mcb->Inode.i_size;
|
|
LARGE_INTEGER NewSize;
|
|
|
|
if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
|
|
|
|
RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
|
|
Mcb->Inode.i_size = Size;
|
|
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
|
|
|
} else {
|
|
NewSize.QuadPart = Size;
|
|
status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
return status;
|
|
}
|
|
|
|
|
|
/* FIXME: We can only handle one reparse point right now. */
|
|
NTSTATUS
|
|
Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PIRP Irp = NULL;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
PEXT2_MCB Mcb = NULL;
|
|
|
|
PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
|
|
PEXT2_MCB ParentMcb = NULL;
|
|
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
BOOLEAN FcbLockAcquired = FALSE;
|
|
BOOLEAN MainResourceAcquired = FALSE;
|
|
|
|
|
|
_SEH2_TRY {
|
|
|
|
Ccb = IrpContext->Ccb;
|
|
ASSERT(Ccb != NULL);
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
Mcb = IrpContext->Fcb->Mcb;
|
|
Irp = IrpContext->Irp;
|
|
|
|
ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
|
|
FcbLockAcquired = TRUE;
|
|
|
|
ParentMcb = Mcb->Parent;
|
|
ParentDcb = ParentMcb->Fcb;
|
|
if (ParentDcb == NULL) {
|
|
ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
|
|
}
|
|
if (ParentDcb) {
|
|
Ext2ReferXcb(&ParentDcb->ReferenceCount);
|
|
}
|
|
|
|
if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
|
|
!IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
|
|
Status = STATUS_NOT_A_REPARSE_POINT;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Fcb = Ext2AllocateFcb (Vcb, Mcb);
|
|
if (Fcb) {
|
|
Ext2ReferXcb(&Fcb->ReferenceCount);
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (FcbLockAcquired) {
|
|
ExReleaseResourceLite(&Vcb->FcbLock);
|
|
FcbLockAcquired = FALSE;
|
|
}
|
|
|
|
if (!ExAcquireResourceSharedLite(
|
|
&Fcb->MainResource,
|
|
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
|
|
Status = STATUS_PENDING;
|
|
_SEH2_LEAVE;
|
|
}
|
|
MainResourceAcquired = TRUE;
|
|
|
|
Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* inode is to be removed */
|
|
SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (FcbLockAcquired) {
|
|
ExReleaseResourceLite(&Vcb->FcbLock);
|
|
}
|
|
|
|
if (MainResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Ext2NotifyReportChange(
|
|
IrpContext,
|
|
Vcb,
|
|
Mcb,
|
|
FILE_NOTIFY_CHANGE_ATTRIBUTES,
|
|
FILE_ACTION_MODIFIED );
|
|
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
} else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
|
|
if (ParentDcb) {
|
|
Ext2ReleaseFcb(ParentDcb);
|
|
}
|
|
|
|
if (Fcb) {
|
|
Ext2ReleaseFcb(Fcb);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStackLocation;
|
|
ULONG FsControlCode;
|
|
NTSTATUS Status;
|
|
|
|
ASSERT(IrpContext);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
Irp = IrpContext->Irp;
|
|
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
#ifndef _GNU_NTIFS_
|
|
FsControlCode =
|
|
IoStackLocation->Parameters.FileSystemControl.FsControlCode;
|
|
#else
|
|
FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)
|
|
IoStackLocation)->Parameters.FileSystemControl.FsControlCode;
|
|
#endif
|
|
|
|
switch (FsControlCode) {
|
|
|
|
case FSCTL_GET_REPARSE_POINT:
|
|
Status = Ext2GetReparsePoint(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_SET_REPARSE_POINT:
|
|
Status = Ext2SetReparsePoint(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_DELETE_REPARSE_POINT:
|
|
Status = Ext2DeleteReparsePoint(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_LOCK_VOLUME:
|
|
Status = Ext2LockVolume(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_UNLOCK_VOLUME:
|
|
Status = Ext2UnlockVolume(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_DISMOUNT_VOLUME:
|
|
Status = Ext2DismountVolume(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_IS_VOLUME_MOUNTED:
|
|
Status = Ext2IsVolumeMounted(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_INVALIDATE_VOLUMES:
|
|
Status = Ext2InvalidateVolumes(IrpContext);
|
|
break;
|
|
|
|
#if (_WIN32_WINNT >= 0x0500)
|
|
case FSCTL_ALLOW_EXTENDED_DASD_IO:
|
|
Status = Ext2AllowExtendedDasdIo(IrpContext);
|
|
break;
|
|
#endif //(_WIN32_WINNT >= 0x0500)
|
|
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
|
case FSCTL_REQUEST_BATCH_OPLOCK:
|
|
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
|
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
|
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
|
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
|
|
|
Status = Ext2OplockRequest(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_IS_VOLUME_DIRTY:
|
|
Status = Ext2IsVolumeDirty(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_QUERY_RETRIEVAL_POINTERS:
|
|
Status = Ext2QueryRetrievalPointers(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_GET_RETRIEVAL_POINTERS:
|
|
Status = Ext2GetRetrievalPointers(IrpContext);
|
|
break;
|
|
|
|
case FSCTL_GET_RETRIEVAL_POINTER_BASE:
|
|
Status = Ext2GetRetrievalPointerBase(IrpContext);
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
Ext2IsMediaWriteProtected (
|
|
IN PEXT2_IRP_CONTEXT IrpContext,
|
|
IN PDEVICE_OBJECT TargetDevice
|
|
)
|
|
{
|
|
PIRP Irp;
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
|
|
TargetDevice,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
FALSE,
|
|
&Event,
|
|
&IoStatus );
|
|
|
|
if (Irp == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
|
|
|
|
Status = IoCallDriver(TargetDevice, Irp);
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
|
|
(VOID) KeWaitForSingleObject( &Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PLARGE_INTEGER)NULL );
|
|
|
|
Status = IoStatus.Status;
|
|
}
|
|
|
|
return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PDEVICE_OBJECT MainDeviceObject;
|
|
BOOLEAN GlobalDataResourceAcquired = FALSE;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStackLocation;
|
|
PDEVICE_OBJECT TargetDeviceObject;
|
|
NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
|
|
PDEVICE_OBJECT VolumeDeviceObject = NULL;
|
|
PEXT2_VCB Vcb = NULL, OldVcb = NULL;
|
|
PVPB OldVpb = NULL, Vpb = NULL;
|
|
PEXT2_SUPER_BLOCK Ext2Sb = NULL;
|
|
ULONG dwBytes;
|
|
DISK_GEOMETRY DiskGeometry;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext != NULL);
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
MainDeviceObject = IrpContext->DeviceObject;
|
|
|
|
//
|
|
// Make sure we can wait.
|
|
//
|
|
|
|
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
|
|
|
//
|
|
// This request is only allowed on the main device object
|
|
//
|
|
if (!IsExt2FsDevice(MainDeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
|
|
Status = STATUS_UNRECOGNIZED_VOLUME;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
#if 0
|
|
if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) &&
|
|
*((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') {
|
|
} else {
|
|
Status = STATUS_UNRECOGNIZED_VOLUME;
|
|
_SEH2_LEAVE;
|
|
}
|
|
#endif
|
|
|
|
Irp = IrpContext->Irp;
|
|
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
|
TargetDeviceObject =
|
|
IoStackLocation->Parameters.MountVolume.DeviceObject;
|
|
|
|
dwBytes = sizeof(DISK_GEOMETRY);
|
|
Status = Ext2DiskIoControl(
|
|
TargetDeviceObject,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
&DiskGeometry,
|
|
&dwBytes );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Status = IoCreateDevice(
|
|
MainDeviceObject->DriverObject,
|
|
sizeof(EXT2_VCB),
|
|
NULL,
|
|
FILE_DEVICE_DISK_FILE_SYSTEM,
|
|
0,
|
|
FALSE,
|
|
&VolumeDeviceObject );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
|
|
|
|
#ifdef _PNP_POWER_
|
|
/* don't care about power management requests */
|
|
VolumeDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
|
|
#endif
|
|
|
|
VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
|
|
ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
|
|
|
|
/*
|
|
These are for buffer-address alignment requirements.
|
|
Never do this check, unless you want fail user requests :)
|
|
|
|
if (TargetDeviceObject->AlignmentRequirement >
|
|
VolumeDeviceObject->AlignmentRequirement) {
|
|
|
|
VolumeDeviceObject->AlignmentRequirement =
|
|
TargetDeviceObject->AlignmentRequirement;
|
|
}
|
|
|
|
if (DiskGeometry.BytesPerSector - 1 >
|
|
VolumeDeviceObject->AlignmentRequirement) {
|
|
VolumeDeviceObject->AlignmentRequirement =
|
|
DiskGeometry.BytesPerSector - 1;
|
|
TargetDeviceObject->AlignmentRequirement =
|
|
DiskGeometry.BytesPerSector - 1;
|
|
}
|
|
*/
|
|
(IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
|
|
VolumeDeviceObject;
|
|
Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
|
|
|
|
Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
|
|
|
|
RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
|
|
Vcb->Identifier.Type = EXT2VCB;
|
|
Vcb->Identifier.Size = sizeof(EXT2_VCB);
|
|
Vcb->TargetDeviceObject = TargetDeviceObject;
|
|
Vcb->DiskGeometry = DiskGeometry;
|
|
InitializeListHead(&Vcb->Next);
|
|
|
|
Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
|
|
if (!NT_SUCCESS(Status)) {
|
|
Vcb = NULL;
|
|
Status = STATUS_UNRECOGNIZED_VOLUME;
|
|
_SEH2_LEAVE;
|
|
}
|
|
ASSERT (NULL != Ext2Sb);
|
|
|
|
/* check Linux Ext2/Ext3 volume magic */
|
|
if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
|
|
DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
|
|
} else {
|
|
Status = STATUS_UNRECOGNIZED_VOLUME;
|
|
Vcb = NULL;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
|
|
|
|
/* initialize Vcb structure */
|
|
Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
|
|
TargetDeviceObject,
|
|
VolumeDeviceObject, Vpb);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
PLIST_ENTRY List;
|
|
|
|
ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
|
|
GlobalDataResourceAcquired = TRUE;
|
|
|
|
for (List = Ext2Global->VcbList.Flink;
|
|
List != &Ext2Global->VcbList;
|
|
List = List->Flink) {
|
|
|
|
OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
|
|
OldVpb = OldVcb->Vpb;
|
|
|
|
/* in case we are already in the queue, should not happen */
|
|
if (OldVpb == Vpb) {
|
|
continue;
|
|
}
|
|
|
|
if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
|
|
(!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
|
|
(OldVpb->RealDevice == TargetDeviceObject) &&
|
|
(OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
|
|
(RtlEqualMemory(&OldVpb->VolumeLabel[0],
|
|
&Vpb->VolumeLabel[0],
|
|
Vpb->VolumeLabelLength)) &&
|
|
(RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
|
|
&Vcb->SuperBlock->s_uuid[0], 16)) ) {
|
|
ClearFlag(OldVcb->Flags, VCB_MOUNTED);
|
|
}
|
|
}
|
|
|
|
SetLongFlag(Vcb->Flags, VCB_MOUNTED);
|
|
SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
|
|
Ext2InsertVcb(Vcb);
|
|
Vcb = NULL;
|
|
Vpb = NULL;
|
|
ObDereferenceObject(TargetDeviceObject);
|
|
|
|
} else {
|
|
|
|
Vcb = NULL;
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (GlobalDataResourceAcquired) {
|
|
ExReleaseResourceLite(&Ext2Global->Resource);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if ( Vpb != NULL ) {
|
|
Vpb->DeviceObject = NULL;
|
|
}
|
|
}
|
|
|
|
if (Vcb) {
|
|
Ext2DestroyVcb(Vcb);
|
|
} else {
|
|
if (Ext2Sb) {
|
|
Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
|
|
}
|
|
if (VolumeDeviceObject) {
|
|
IoDeleteDevice(VolumeDeviceObject);
|
|
DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
|
|
IN PEXT2_VCB Vcb )
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
BOOLEAN bVerify = FALSE;
|
|
ULONG ChangeCount = 0;
|
|
ULONG dwBytes;
|
|
|
|
PIRP Irp;
|
|
PEXTENDED_IO_STACK_LOCATION IrpSp;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext != NULL);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
Irp = IrpContext->Irp;
|
|
IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
|
|
|
|
if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
|
|
IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
|
|
|
|
dwBytes = sizeof(ULONG);
|
|
Status = Ext2DiskIoControl(
|
|
Vcb->TargetDeviceObject,
|
|
IOCTL_DISK_CHECK_VERIFY,
|
|
NULL,
|
|
0,
|
|
&ChangeCount,
|
|
&dwBytes );
|
|
|
|
if ( STATUS_VERIFY_REQUIRED == Status ||
|
|
STATUS_DEVICE_NOT_READY == Status ||
|
|
STATUS_NO_MEDIA_IN_DEVICE == Status ||
|
|
(NT_SUCCESS(Status) &&
|
|
(ChangeCount != Vcb->ChangeCount))) {
|
|
|
|
KIRQL Irql;
|
|
|
|
IoAcquireVpbSpinLock(&Irql);
|
|
if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
|
|
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
|
|
}
|
|
IoReleaseVpbSpinLock(Irql);
|
|
|
|
} else {
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
Ext2NormalizeAndRaiseStatus(IrpContext, Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
|
|
IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
|
|
Ext2NormalizeAndRaiseStatus ( IrpContext,
|
|
STATUS_VERIFY_REQUIRED );
|
|
}
|
|
|
|
if (IsMounted(Vcb)) {
|
|
|
|
if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
|
|
(IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
|
|
(IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
|
|
(IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
|
|
(IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
|
|
(IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
|
|
IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
|
|
IrpSp->Parameters.FileSystemControl.FsControlCode ==
|
|
FSCTL_MARK_VOLUME_DIRTY)) {
|
|
|
|
if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
|
|
|
|
KIRQL Irql;
|
|
|
|
IoAcquireVpbSpinLock(&Irql);
|
|
if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
|
|
SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
|
|
}
|
|
IoReleaseVpbSpinLock(Irql);
|
|
|
|
IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
|
|
|
|
Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
} _SEH2_END;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
PEXT2_SUPER_BLOCK ext2_sb = NULL;
|
|
PEXT2_VCB Vcb = NULL;
|
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|
PIRP Irp;
|
|
ULONG ChangeCount = 0;
|
|
ULONG dwBytes;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext != NULL);
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
//
|
|
// This request is not allowed on the main device object
|
|
//
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
ASSERT(Vcb != NULL);
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
VcbResourceAcquired =
|
|
ExAcquireResourceExclusiveLite(
|
|
&Vcb->MainResource,
|
|
TRUE );
|
|
|
|
if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
|
|
Status = STATUS_SUCCESS;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (!IsMounted(Vcb)) {
|
|
Status = STATUS_WRONG_VOLUME;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
dwBytes = sizeof(ULONG);
|
|
Status = Ext2DiskIoControl(
|
|
Vcb->TargetDeviceObject,
|
|
IOCTL_DISK_CHECK_VERIFY,
|
|
NULL,
|
|
0,
|
|
&ChangeCount,
|
|
&dwBytes );
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
Status = STATUS_WRONG_VOLUME;
|
|
_SEH2_LEAVE;
|
|
} else {
|
|
Vcb->ChangeCount = ChangeCount;
|
|
}
|
|
|
|
Irp = IrpContext->Irp;
|
|
|
|
Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT(NULL != ext2_sb);
|
|
if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
|
|
(memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
|
|
(memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
|
|
|
|
ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
|
|
|
|
if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
|
|
SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
|
|
} else {
|
|
ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
|
|
}
|
|
|
|
DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
|
|
|
|
} else {
|
|
|
|
Status = STATUS_WRONG_VOLUME;
|
|
Ext2PurgeVolume(Vcb, FALSE);
|
|
|
|
SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
|
|
ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
|
|
|
|
DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (ext2_sb)
|
|
Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
|
|
|
|
if (VcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
}
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PEXT2_VCB Vcb = 0;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
ASSERT(IrpContext);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
Ext2VerifyVcb (IrpContext, Vcb);
|
|
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
PEXT2_VCB Vcb = NULL;
|
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext != NULL);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
|
|
//
|
|
// This request is not allowed on the main device object
|
|
//
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
|
|
ASSERT(Vcb != NULL);
|
|
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
ASSERT(IsMounted(Vcb));
|
|
|
|
ExAcquireResourceExclusiveLite(
|
|
&Vcb->MainResource,
|
|
TRUE );
|
|
|
|
VcbResourceAcquired = TRUE;
|
|
|
|
if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
|
|
Status = STATUS_VOLUME_DISMOUNTED;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Ext2FlushFiles(IrpContext, Vcb, FALSE);
|
|
Ext2FlushVolume(IrpContext, Vcb, FALSE);
|
|
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
VcbResourceAcquired = FALSE;
|
|
|
|
Ext2PurgeVolume(Vcb, TRUE);
|
|
Ext2CheckDismount(IrpContext, Vcb, TRUE);
|
|
|
|
DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (VcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
}
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
Ext2CheckDismount (
|
|
IN PEXT2_IRP_CONTEXT IrpContext,
|
|
IN PEXT2_VCB Vcb,
|
|
IN BOOLEAN bForce )
|
|
{
|
|
KIRQL Irql;
|
|
PVPB Vpb = Vcb->Vpb, NewVpb = NULL;
|
|
BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
|
|
ULONG UnCleanCount = 0;
|
|
|
|
NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
|
|
if (NewVpb == NULL) {
|
|
DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
|
|
return FALSE;
|
|
}
|
|
DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
|
|
INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
|
|
memset(NewVpb, '_', VPB_SIZE);
|
|
RtlZeroMemory(NewVpb, sizeof(VPB));
|
|
|
|
ExAcquireResourceExclusiveLite(
|
|
&Ext2Global->Resource, TRUE );
|
|
|
|
ExAcquireResourceExclusiveLite(
|
|
&Vcb->MainResource, TRUE );
|
|
|
|
if (IrpContext &&
|
|
IrpContext->MajorFunction == IRP_MJ_CREATE &&
|
|
IrpContext->RealDevice == Vcb->RealDevice) {
|
|
UnCleanCount = 2;
|
|
} else {
|
|
UnCleanCount = 1;
|
|
}
|
|
|
|
IoAcquireVpbSpinLock (&Irql);
|
|
|
|
DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
|
|
Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
|
|
|
|
if (Vpb->ReferenceCount <= UnCleanCount) {
|
|
|
|
if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
|
|
|
|
ClearFlag(Vpb->Flags, VPB_MOUNTED);
|
|
ClearFlag(Vpb->Flags, VPB_LOCKED);
|
|
|
|
if ((Vcb->RealDevice != Vpb->RealDevice) &&
|
|
(Vcb->RealDevice->Vpb == Vpb)) {
|
|
SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
|
|
SetFlag(Vpb->Flags, VPB_PERSISTENT );
|
|
}
|
|
|
|
Ext2RemoveVcb(Vcb);
|
|
SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
|
|
}
|
|
|
|
if (Vpb->ReferenceCount) {
|
|
bTearDown = TRUE;
|
|
} else {
|
|
bDeleted = TRUE;
|
|
Vpb->DeviceObject = NULL;
|
|
}
|
|
|
|
DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
|
|
Vpb, bDeleted, bTearDown));
|
|
|
|
|
|
} else if (bForce) {
|
|
|
|
DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
|
|
NewVpb, Vcb->Vpb, Vpb->RealDevice));
|
|
|
|
/* keep vpb president and later we'll free it */
|
|
SetFlag(Vpb->Flags, VPB_PERSISTENT);
|
|
|
|
Vcb->Vpb2 = Vcb->Vpb;
|
|
NewVpb->Type = IO_TYPE_VPB;
|
|
NewVpb->Size = sizeof(VPB);
|
|
NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
|
|
NewVpb->RealDevice = Vpb->RealDevice;
|
|
NewVpb->RealDevice->Vpb = NewVpb;
|
|
NewVpb = NULL;
|
|
ClearFlag(Vpb->Flags, VPB_MOUNTED);
|
|
SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
|
|
ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
|
|
}
|
|
|
|
IoReleaseVpbSpinLock(Irql);
|
|
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
ExReleaseResourceLite(&Ext2Global->Resource);
|
|
|
|
if (bTearDown) {
|
|
DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
|
|
Ext2TearDownStream(Vcb);
|
|
}
|
|
|
|
if (bDeleted) {
|
|
DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
|
|
Ext2DestroyVcb(Vcb);
|
|
}
|
|
|
|
if (NewVpb != NULL) {
|
|
DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
|
|
ExFreePoolWithTag(NewVpb, TAG_VPB);
|
|
DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
|
|
}
|
|
|
|
return bDeleted;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2PurgeVolume (IN PEXT2_VCB Vcb,
|
|
IN BOOLEAN FlushBeforePurge )
|
|
{
|
|
PEXT2_FCB Fcb;
|
|
LIST_ENTRY List, *Next;
|
|
|
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|
BOOLEAN FcbResourceAcquired = FALSE;
|
|
BOOLEAN gdResourceAcquired = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(Vcb != NULL);
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
|
|
VcbResourceAcquired = TRUE;
|
|
|
|
if (IsVcbReadOnly(Vcb)) {
|
|
FlushBeforePurge = FALSE;
|
|
}
|
|
|
|
InitializeListHead(&List);
|
|
|
|
ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
|
|
FcbResourceAcquired = TRUE;
|
|
|
|
while (!IsListEmpty(&Vcb->FcbList)) {
|
|
|
|
Next = RemoveHeadList(&Vcb->FcbList);
|
|
Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
|
|
|
|
DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n",
|
|
&Fcb->Mcb->FullName, Fcb->ReferenceCount));
|
|
InsertTailList(&List, &Fcb->Next);
|
|
}
|
|
|
|
while (!IsListEmpty(&List)) {
|
|
|
|
Next = RemoveHeadList(&List);
|
|
Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
|
|
|
|
if (ExAcquireResourceExclusiveLite(
|
|
&Fcb->MainResource,
|
|
TRUE )) {
|
|
|
|
Ext2PurgeFile(Fcb, FlushBeforePurge);
|
|
|
|
if (Fcb->ReferenceCount <= 1) {
|
|
Fcb->TsDrop.QuadPart = 0;
|
|
InsertHeadList(&Vcb->FcbList, &Fcb->Next);
|
|
} else {
|
|
InsertTailList(&Vcb->FcbList, &Fcb->Next);
|
|
}
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
}
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->FcbLock);
|
|
FcbResourceAcquired = FALSE;
|
|
}
|
|
|
|
/* acquire bd lock to avoid bh creation */
|
|
ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
|
|
gdResourceAcquired = TRUE;
|
|
|
|
/* discard buffer_headers for group_desc */
|
|
Ext2DropBH(Vcb);
|
|
|
|
if (FlushBeforePurge) {
|
|
ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
|
|
ExReleaseResourceLite(&Vcb->PagingIoResource);
|
|
|
|
CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
|
|
}
|
|
|
|
if (Vcb->SectionObject.ImageSectionObject) {
|
|
MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
|
|
}
|
|
|
|
if (Vcb->SectionObject.DataSectionObject) {
|
|
CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
|
|
}
|
|
|
|
DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (gdResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
|
|
}
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->FcbLock);
|
|
}
|
|
|
|
if (VcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2PurgeFile ( IN PEXT2_FCB Fcb,
|
|
IN BOOLEAN FlushBeforePurge )
|
|
{
|
|
IO_STATUS_BLOCK IoStatus;
|
|
|
|
ASSERT(Fcb != NULL);
|
|
|
|
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
|
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
|
|
|
|
|
if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
|
|
DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
|
|
&Fcb->Mcb->FullName));
|
|
ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
|
|
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
|
CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
|
|
ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
|
}
|
|
|
|
if (Fcb->SectionObject.ImageSectionObject) {
|
|
DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
|
|
&Fcb->Mcb->FullName));
|
|
MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
|
|
}
|
|
|
|
if (Fcb->SectionObject.DataSectionObject) {
|
|
DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
|
|
&Fcb->Mcb->FullName));
|
|
CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ASSERT(IrpContext);
|
|
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
switch (IrpContext->MinorFunction) {
|
|
|
|
case IRP_MN_USER_FS_REQUEST:
|
|
Status = Ext2UserFsRequest(IrpContext);
|
|
break;
|
|
|
|
case IRP_MN_MOUNT_VOLUME:
|
|
Status = Ext2MountVolume(IrpContext);
|
|
break;
|
|
|
|
case IRP_MN_VERIFY_VOLUME:
|
|
Status = Ext2VerifyVolume(IrpContext);
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|