mirror of
https://github.com/reactos/reactos.git
synced 2025-04-20 12:29:56 +00:00
1267 lines
34 KiB
C
1267 lines
34 KiB
C
![]() |
/*
|
|||
|
* COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
|
|||
|
* PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
|
|||
|
* FILE: fsctl.c
|
|||
|
* PURPOSE:
|
|||
|
* PROGRAMMER: Mark Piper, Matt Wu, Bo Brant<EFBFBD>n.
|
|||
|
* HOMEPAGE:
|
|||
|
* UPDATE HISTORY:
|
|||
|
*/
|
|||
|
|
|||
|
/* INCLUDES *****************************************************************/
|
|||
|
|
|||
|
#include "rfsd.h"
|
|||
|
|
|||
|
/* GLOBALS ***************************************************************/
|
|||
|
|
|||
|
extern PRFSD_GLOBAL RfsdGlobal;
|
|||
|
|
|||
|
/* DEFINITIONS *************************************************************/
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
RfsdIsMediaWriteProtected (
|
|||
|
IN PRFSD_IRP_CONTEXT IrpContext,
|
|||
|
IN PDEVICE_OBJECT TargetDevice);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
//#pragma alloc_text(PAGE, RfsdSetVpbFlag)
|
|||
|
//#pragma alloc_text(PAGE, RfsdClearVpbFlag)
|
|||
|
#pragma alloc_text(PAGE, RfsdIsHandleCountZero)
|
|||
|
#pragma alloc_text(PAGE, RfsdLockVcb)
|
|||
|
#pragma alloc_text(PAGE, RfsdLockVolume)
|
|||
|
#pragma alloc_text(PAGE, RfsdUnlockVcb)
|
|||
|
#pragma alloc_text(PAGE, RfsdUnlockVolume)
|
|||
|
#pragma alloc_text(PAGE, RfsdAllowExtendedDasdIo)
|
|||
|
#pragma alloc_text(PAGE, RfsdUserFsRequest)
|
|||
|
#pragma alloc_text(PAGE, RfsdIsMediaWriteProtected)
|
|||
|
#pragma alloc_text(PAGE, RfsdMountVolume)
|
|||
|
#pragma alloc_text(PAGE, RfsdCheckDismount)
|
|||
|
#pragma alloc_text(PAGE, RfsdPurgeVolume)
|
|||
|
#pragma alloc_text(PAGE, RfsdPurgeFile)
|
|||
|
#pragma alloc_text(PAGE, RfsdDismountVolume)
|
|||
|
#pragma alloc_text(PAGE, RfsdIsVolumeMounted)
|
|||
|
#pragma alloc_text(PAGE, RfsdVerifyVolume)
|
|||
|
#pragma alloc_text(PAGE, RfsdFileSystemControl)
|
|||
|
#endif
|
|||
|
|
|||
|
VOID
|
|||
|
RfsdSetVpbFlag (
|
|||
|
IN PVPB Vpb,
|
|||
|
IN USHORT Flag )
|
|||
|
{
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
IoAcquireVpbSpinLock(&OldIrql);
|
|||
|
|
|||
|
Vpb->Flags |= Flag;
|
|||
|
|
|||
|
IoReleaseVpbSpinLock(OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
RfsdClearVpbFlag (
|
|||
|
IN PVPB Vpb,
|
|||
|
IN USHORT Flag )
|
|||
|
{
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
IoAcquireVpbSpinLock(&OldIrql);
|
|||
|
|
|||
|
Vpb->Flags &= ~Flag;
|
|||
|
|
|||
|
IoReleaseVpbSpinLock(OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
RfsdIsHandleCountZero(IN PRFSD_VCB Vcb)
|
|||
|
{
|
|||
|
PRFSD_FCB Fcb;
|
|||
|
PLIST_ENTRY List;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
for( List = Vcb->FcbList.Flink;
|
|||
|
List != &Vcb->FcbList;
|
|||
|
List = List->Flink ) {
|
|||
|
|
|||
|
Fcb = CONTAINING_RECORD(List, RFSD_FCB, Next);
|
|||
|
|
|||
|
ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
|
|||
|
(Fcb->Identifier.Size == sizeof(RFSD_FCB)));
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdIsHandleCountZero: Key:%x,%xh File:%S OpenHandleCount=%xh\n",
|
|||
|
Fcb->RfsdMcb->Key.k_dir_id, Fcb->RfsdMcb->Key.k_objectid, Fcb->RfsdMcb->ShortName.Buffer, Fcb->OpenHandleCount));
|
|||
|
|
|||
|
if (Fcb->OpenHandleCount) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RfsdLockVcb (IN PRFSD_VCB Vcb,
|
|||
|
IN PFILE_OBJECT FileObject)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
|
|||
|
RfsdPrint((DBG_INFO, "RfsdLockVolume: Volume is already locked.\n"));
|
|||
|
|
|||
|
Status = STATUS_ACCESS_DENIED;
|
|||
|
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (Vcb->OpenFileHandleCount > (ULONG)(FileObject ? 1 : 0)) {
|
|||
|
RfsdPrint((DBG_INFO, "RfsdLockVcb: There are still opened files.\n"));
|
|||
|
|
|||
|
Status = STATUS_ACCESS_DENIED;
|
|||
|
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (!RfsdIsHandleCountZero(Vcb)) {
|
|||
|
RfsdPrint((DBG_INFO, "RfsdLockVcb: Thare are still opened files.\n"));
|
|||
|
|
|||
|
Status = STATUS_ACCESS_DENIED;
|
|||
|
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
SetFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
|
|||
|
|
|||
|
RfsdSetVpbFlag(Vcb->Vpb, VPB_LOCKED);
|
|||
|
|
|||
|
Vcb->LockFile = FileObject;
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdLockVcb: Volume locked.\n"));
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
// Nothing
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdLockVolume (IN PRFSD_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PRFSD_VCB Vcb = 0;
|
|||
|
NTSTATUS Status;
|
|||
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
ASSERT(IrpContext != NULL);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
|
|||
|
|
|||
|
DeviceObject = IrpContext->DeviceObject;
|
|||
|
|
|||
|
Status = STATUS_UNSUCCESSFUL;
|
|||
|
|
|||
|
//
|
|||
|
// This request is not allowed on the main device object
|
|||
|
//
|
|||
|
if (DeviceObject == RfsdGlobal->DeviceObject) {
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
ASSERT(Vcb != NULL);
|
|||
|
|
|||
|
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
|
|||
|
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
|
|||
|
|
|||
|
ASSERT(IsMounted(Vcb));
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
|
|||
|
|
|||
|
#if (_WIN32_WINNT >= 0x0500)
|
|||
|
CcWaitForCurrentLazyWriterActivity();
|
|||
|
#endif
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
TRUE );
|
|||
|
|
|||
|
VcbResourceAcquired = TRUE;
|
|||
|
|
|||
|
Status = RfsdLockVcb(Vcb, IrpSp->FileObject);
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if (VcbResourceAcquired) {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
ExGetCurrentResourceThread()
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (!IrpContext->ExceptionInProgress) {
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RfsdUnlockVcb ( IN PRFSD_VCB Vcb,
|
|||
|
IN PFILE_OBJECT FileObject )
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
if (FileObject && FileObject->FsContext != Vcb) {
|
|||
|
|
|||
|
Status = STATUS_NOT_LOCKED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
|
|||
|
RfsdPrint((DBG_ERROR, ": RfsdUnlockVcb: Volume is not locked.\n"));
|
|||
|
Status = STATUS_NOT_LOCKED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (Vcb->LockFile == FileObject) {
|
|||
|
|
|||
|
ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
|
|||
|
|
|||
|
RfsdClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdUnlockVcb: Volume unlocked.\n"));
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
Status = STATUS_NOT_LOCKED;
|
|||
|
}
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
// Nothing
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdUnlockVolume (
|
|||
|
IN PRFSD_IRP_CONTEXT IrpContext
|
|||
|
)
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
NTSTATUS Status;
|
|||
|
PRFSD_VCB Vcb = 0;
|
|||
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
ASSERT(IrpContext != NULL);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
|
|||
|
|
|||
|
DeviceObject = IrpContext->DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// This request is not allowed on the main device object
|
|||
|
//
|
|||
|
if (DeviceObject == RfsdGlobal->DeviceObject) {
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
ASSERT(Vcb != NULL);
|
|||
|
|
|||
|
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
|
|||
|
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
|
|||
|
|
|||
|
ASSERT(IsMounted(Vcb));
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
TRUE );
|
|||
|
|
|||
|
VcbResourceAcquired = TRUE;
|
|||
|
|
|||
|
Status = RfsdUnlockVcb(Vcb, IrpSp->FileObject);
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if (VcbResourceAcquired) {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
ExGetCurrentResourceThread()
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (!IrpContext->ExceptionInProgress) {
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdInvalidateVolumes ( IN PRFSD_IRP_CONTEXT IrpContext )
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
|
|||
|
HANDLE Handle;
|
|||
|
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
BOOLEAN GlobalResourceAcquired = FALSE;
|
|||
|
|
|||
|
LUID Privilege = {SE_TCB_PRIVILEGE, 0};
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
Irp = IrpContext->Irp;
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) {
|
|||
|
Status = STATUS_PRIVILEGE_NOT_HELD;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (
|
|||
|
#ifndef _GNU_NTIFS_
|
|||
|
IrpSp->Parameters.FileSystemControl.InputBufferLength
|
|||
|
#else
|
|||
|
((PEXTENDED_IO_STACK_LOCATION)(IrpSp))->
|
|||
|
Parameters.FileSystemControl.InputBufferLength
|
|||
|
#endif
|
|||
|
!= 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 {
|
|||
|
ObDereferenceObject(FileObject);
|
|||
|
DeviceObject = FileObject->DeviceObject;
|
|||
|
}
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: FileObject=%xh ...\n", FileObject));
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&RfsdGlobal->Resource,
|
|||
|
TRUE );
|
|||
|
|
|||
|
GlobalResourceAcquired = TRUE;
|
|||
|
|
|||
|
ListEntry = RfsdGlobal->VcbList.Flink;
|
|||
|
|
|||
|
while (ListEntry != &RfsdGlobal->VcbList) {
|
|||
|
|
|||
|
PRFSD_VCB Vcb;
|
|||
|
|
|||
|
Vcb = CONTAINING_RECORD(ListEntry, RFSD_VCB, Next);
|
|||
|
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh...\n", Vcb, Vcb->Vpb));
|
|||
|
if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject))
|
|||
|
{
|
|||
|
ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
|
|||
|
RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: RfsdPurgeVolume...\n"));
|
|||
|
RfsdPurgeVolume(Vcb, FALSE);
|
|||
|
ClearFlag(Vcb->Flags, VCB_MOUNTED);
|
|||
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|||
|
|
|||
|
//
|
|||
|
// Vcb is still attached on the list ......
|
|||
|
//
|
|||
|
|
|||
|
if (ListEntry->Blink == &Vcb->Next)
|
|||
|
{
|
|||
|
RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: RfsdCheckDismount...\n"));
|
|||
|
RfsdCheckDismount(IrpContext, Vcb, FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if (GlobalResourceAcquired) {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&RfsdGlobal->Resource,
|
|||
|
ExGetCurrentResourceThread() );
|
|||
|
}
|
|||
|
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RfsdAllowExtendedDasdIo(IN PRFSD_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PRFSD_VCB Vcb;
|
|||
|
PRFSD_CCB Ccb;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
|
|||
|
|
|||
|
Vcb = (PRFSD_VCB) IrpSp->FileObject->FsContext;
|
|||
|
Ccb = (PRFSD_CCB) IrpSp->FileObject->FsContext2;
|
|||
|
|
|||
|
ASSERT(Vcb != NULL);
|
|||
|
|
|||
|
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
|
|||
|
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
|
|||
|
|
|||
|
ASSERT(IsMounted(Vcb));
|
|||
|
|
|||
|
if (Ccb) {
|
|||
|
SetFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO);
|
|||
|
|
|||
|
RfsdCompleteIrpContext(IrpContext, STATUS_SUCCESS);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdUserFsRequest (IN PRFSD_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION IoStackLocation;
|
|||
|
ULONG FsControlCode;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(IrpContext);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_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_LOCK_VOLUME:
|
|||
|
Status = RfsdLockVolume(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
case FSCTL_UNLOCK_VOLUME:
|
|||
|
Status = RfsdUnlockVolume(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
case FSCTL_DISMOUNT_VOLUME:
|
|||
|
Status = RfsdDismountVolume(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
case FSCTL_IS_VOLUME_MOUNTED:
|
|||
|
Status = RfsdIsVolumeMounted(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
case FSCTL_INVALIDATE_VOLUMES:
|
|||
|
Status = RfsdInvalidateVolumes(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
#if (_WIN32_WINNT >= 0x0500)
|
|||
|
case FSCTL_ALLOW_EXTENDED_DASD_IO:
|
|||
|
Status = RfsdAllowExtendedDasdIo(IrpContext);
|
|||
|
break;
|
|||
|
#endif //(_WIN32_WINNT >= 0x0500)
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
RfsdPrint((DBG_ERROR, "RfsdUserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
|
|||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
RfsdIsMediaWriteProtected (
|
|||
|
IN PRFSD_IRP_CONTEXT IrpContext,
|
|||
|
IN PDEVICE_OBJECT TargetDevice
|
|||
|
)
|
|||
|
{
|
|||
|
PIRP Irp;
|
|||
|
KEVENT Event;
|
|||
|
NTSTATUS Status;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdMountVolume (IN PRFSD_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;
|
|||
|
PRFSD_VCB Vcb;
|
|||
|
PRFSD_SUPER_BLOCK RfsdSb = NULL;
|
|||
|
ULONG dwBytes;
|
|||
|
DISK_GEOMETRY DiskGeometry;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
|
|||
|
ASSERT(IrpContext != NULL);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_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 (MainDeviceObject != RfsdGlobal->DeviceObject) {
|
|||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&(RfsdGlobal->Resource),
|
|||
|
TRUE );
|
|||
|
|
|||
|
GlobalDataResourceAcquired = TRUE;
|
|||
|
|
|||
|
if (FlagOn(RfsdGlobal->Flags, RFSD_UNLOAD_PENDING)) {
|
|||
|
Status = STATUS_UNRECOGNIZED_VOLUME;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Irp = IrpContext->Irp;
|
|||
|
|
|||
|
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
TargetDeviceObject =
|
|||
|
IoStackLocation->Parameters.MountVolume.DeviceObject;
|
|||
|
|
|||
|
dwBytes = sizeof(DISK_GEOMETRY);
|
|||
|
Status = RfsdDiskIoControl(
|
|||
|
TargetDeviceObject,
|
|||
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&DiskGeometry,
|
|||
|
&dwBytes );
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Status = IoCreateDevice(
|
|||
|
MainDeviceObject->DriverObject,
|
|||
|
sizeof(RFSD_VCB),
|
|||
|
NULL,
|
|||
|
FILE_DEVICE_DISK_FILE_SYSTEM,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&VolumeDeviceObject );
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
|
|||
|
|
|||
|
if (TargetDeviceObject->AlignmentRequirement >
|
|||
|
VolumeDeviceObject->AlignmentRequirement) {
|
|||
|
|
|||
|
VolumeDeviceObject->AlignmentRequirement =
|
|||
|
TargetDeviceObject->AlignmentRequirement;
|
|||
|
}
|
|||
|
|
|||
|
(IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
|
|||
|
VolumeDeviceObject;
|
|||
|
|
|||
|
Vcb = (PRFSD_VCB) VolumeDeviceObject->DeviceExtension;
|
|||
|
|
|||
|
RtlZeroMemory(Vcb, sizeof(RFSD_VCB));
|
|||
|
|
|||
|
Vcb->Identifier.Type = RFSDVCB;
|
|||
|
Vcb->Identifier.Size = sizeof(RFSD_VCB);
|
|||
|
|
|||
|
Vcb->TargetDeviceObject = TargetDeviceObject;
|
|||
|
Vcb->DiskGeometry = DiskGeometry;
|
|||
|
|
|||
|
RfsdSb = RfsdLoadSuper(Vcb, FALSE);
|
|||
|
|
|||
|
if (RfsdSb) {
|
|||
|
if ( SuperblockContainsMagicKey(RfsdSb) ) {
|
|||
|
RfsdPrint((DBG_INFO, "Volume of ReiserFS rfsd file system is found.\n"));
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
Status = STATUS_UNRECOGNIZED_VOLUME;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Vcb->BlockSize = RfsdSb->s_blocksize; // NOTE: FFS also does this here, since LoadGroup is not called in the non-ext2 drivers
|
|||
|
Vcb->GroupDesc = NULL; // NOTE: GroupDesc is not used for ReiserFS. Setting it to NULL will keep other code from barfing.
|
|||
|
// Vcb->SectorBits = RFSDLog(SECTOR_SIZE); // NOTE: SectorBits are unused for ReiserFS
|
|||
|
|
|||
|
Status = RfsdInitializeVcb(IrpContext, Vcb, RfsdSb, TargetDeviceObject,
|
|||
|
VolumeDeviceObject, IoStackLocation->Parameters.MountVolume.Vpb);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
if (RfsdIsMediaWriteProtected(IrpContext, TargetDeviceObject)) {
|
|||
|
SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
|
|||
|
} else {
|
|||
|
ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
|
|||
|
}
|
|||
|
|
|||
|
SetFlag(Vcb->Flags, VCB_MOUNTED);
|
|||
|
|
|||
|
RfsdInsertVcb(Vcb);
|
|||
|
|
|||
|
ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
|
|||
|
}
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if (GlobalDataResourceAcquired) {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&RfsdGlobal->Resource,
|
|||
|
ExGetCurrentResourceThread() );
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
if (RfsdSb) {
|
|||
|
ExFreePool(RfsdSb);
|
|||
|
}
|
|||
|
|
|||
|
if (VolumeDeviceObject) {
|
|||
|
IoDeleteDevice(VolumeDeviceObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!IrpContext->ExceptionInProgress) {
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
|
|||
|
}
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdVerifyVolume (IN PRFSD_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
PRFSD_SUPER_BLOCK rfsd_sb = NULL;
|
|||
|
PRFSD_VCB Vcb = 0;
|
|||
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|||
|
BOOLEAN GlobalResourceAcquired = FALSE;
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION IoStackLocation;
|
|||
|
ULONG ChangeCount;
|
|||
|
ULONG dwReturn;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
ASSERT(IrpContext != NULL);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
|
|||
|
|
|||
|
DeviceObject = IrpContext->DeviceObject;
|
|||
|
//
|
|||
|
// This request is not allowed on the main device object
|
|||
|
//
|
|||
|
if (DeviceObject == RfsdGlobal->DeviceObject) {
|
|||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&RfsdGlobal->Resource,
|
|||
|
TRUE );
|
|||
|
|
|||
|
GlobalResourceAcquired = TRUE;
|
|||
|
|
|||
|
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
ASSERT(Vcb != NULL);
|
|||
|
|
|||
|
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
|
|||
|
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
TRUE );
|
|||
|
|
|||
|
VcbResourceAcquired = TRUE;
|
|||
|
|
|||
|
if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (!IsMounted(Vcb)) {
|
|||
|
Status = STATUS_WRONG_VOLUME;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
dwReturn = sizeof(ULONG);
|
|||
|
Status = RfsdDiskIoControl(
|
|||
|
Vcb->TargetDeviceObject,
|
|||
|
IOCTL_DISK_CHECK_VERIFY,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&ChangeCount,
|
|||
|
&dwReturn );
|
|||
|
|
|||
|
if (ChangeCount != Vcb->ChangeCount) {
|
|||
|
Status = STATUS_WRONG_VOLUME;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Irp = IrpContext->Irp;
|
|||
|
|
|||
|
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
rfsd_sb = RfsdLoadSuper(Vcb, TRUE);
|
|||
|
|
|||
|
// FUTURE: use the volume name and uuid from the extended superblock to make this happen.
|
|||
|
// NOTE: The magic check will have to use the same thing as mount did!
|
|||
|
if ((rfsd_sb != NULL) /*&& (rfsd_sb->s_magic == RFSD_SUPER_MAGIC) &&
|
|||
|
(memcmp(rfsd_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
|
|||
|
(memcmp(rfsd_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)*/) {
|
|||
|
ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
|
|||
|
|
|||
|
if (RfsdIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
|
|||
|
SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
|
|||
|
} else {
|
|||
|
ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
|
|||
|
}
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdVerifyVolume: Volume verify succeeded.\n"));
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
Status = STATUS_WRONG_VOLUME;
|
|||
|
|
|||
|
RfsdPurgeVolume(Vcb, FALSE);
|
|||
|
|
|||
|
SetFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
|
|||
|
|
|||
|
ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdVerifyVolume: Volume verify failed.\n"));
|
|||
|
}
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if (rfsd_sb)
|
|||
|
ExFreePool(rfsd_sb);
|
|||
|
|
|||
|
if (VcbResourceAcquired) {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
ExGetCurrentResourceThread()
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (GlobalResourceAcquired) {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&RfsdGlobal->Resource,
|
|||
|
ExGetCurrentResourceThread() );
|
|||
|
}
|
|||
|
|
|||
|
if (!IrpContext->ExceptionInProgress) {
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdIsVolumeMounted (IN PRFSD_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(IrpContext);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
|
|||
|
|
|||
|
return RfsdVerifyVolume(IrpContext);
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdDismountVolume (IN PRFSD_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
PRFSD_VCB Vcb = 0;
|
|||
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
ASSERT(IrpContext != NULL);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
|
|||
|
|
|||
|
DeviceObject = IrpContext->DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// This request is not allowed on the main device object
|
|||
|
//
|
|||
|
if (DeviceObject == RfsdGlobal->DeviceObject) {
|
|||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
ASSERT(Vcb != NULL);
|
|||
|
|
|||
|
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
|
|||
|
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
|
|||
|
|
|||
|
ASSERT(IsMounted(Vcb));
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
TRUE );
|
|||
|
|
|||
|
VcbResourceAcquired = TRUE;
|
|||
|
|
|||
|
if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
|
|||
|
Status = STATUS_VOLUME_DISMOUNTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
|
|||
|
RfsdPrint((DBG_ERROR, "RfsdDismount: Volume is not locked.\n"));
|
|||
|
|
|||
|
Status = STATUS_ACCESS_DENIED;
|
|||
|
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
*/
|
|||
|
#if DISABLED
|
|||
|
RfsdFlushFiles(Vcb, FALSE);
|
|||
|
|
|||
|
RfsdFlushVolume(Vcb, FALSE);
|
|||
|
|
|||
|
RfsdPurgeVolume(Vcb, TRUE);
|
|||
|
#endif
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
ExGetCurrentResourceThread() );
|
|||
|
|
|||
|
VcbResourceAcquired = FALSE;
|
|||
|
|
|||
|
RfsdCheckDismount(IrpContext, Vcb, TRUE);
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdDismount: Volume dismount pending.\n"));
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if (VcbResourceAcquired) {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
ExGetCurrentResourceThread()
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (!IrpContext->ExceptionInProgress) {
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
BOOLEAN
|
|||
|
RfsdCheckDismount (
|
|||
|
IN PRFSD_IRP_CONTEXT IrpContext,
|
|||
|
IN PRFSD_VCB Vcb,
|
|||
|
IN BOOLEAN bForce )
|
|||
|
{
|
|||
|
KIRQL Irql;
|
|||
|
PVPB Vpb = Vcb->Vpb;
|
|||
|
BOOLEAN bDeleted = FALSE;
|
|||
|
ULONG UnCleanCount = 0;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&RfsdGlobal->Resource, TRUE );
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&Vcb->MainResource, TRUE );
|
|||
|
|
|||
|
if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
|
|||
|
(IrpContext->RealDevice == Vcb->RealDevice)) {
|
|||
|
UnCleanCount = 3;
|
|||
|
} else {
|
|||
|
UnCleanCount = 2;
|
|||
|
}
|
|||
|
|
|||
|
IoAcquireVpbSpinLock (&Irql);
|
|||
|
|
|||
|
if ((Vpb->ReferenceCount == UnCleanCount) || bForce) {
|
|||
|
|
|||
|
if ((Vpb->ReferenceCount != UnCleanCount) && bForce) {
|
|||
|
KdPrint(("RfsdCheckDismount: force dismount ...\n"));
|
|||
|
}
|
|||
|
|
|||
|
ClearFlag( Vpb->Flags, VPB_MOUNTED );
|
|||
|
ClearFlag( Vpb->Flags, VPB_LOCKED );
|
|||
|
|
|||
|
#ifdef _MSC_VER
|
|||
|
#pragma prefast( suppress: 28175, "allowed in file system drivers" )
|
|||
|
#endif
|
|||
|
if ((Vcb->RealDevice != Vpb->RealDevice) &&
|
|||
|
(Vcb->RealDevice->Vpb == Vpb)) {
|
|||
|
SetFlag( Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING );
|
|||
|
SetFlag( Vpb->Flags, VPB_PERSISTENT );
|
|||
|
}
|
|||
|
|
|||
|
RfsdRemoveVcb(Vcb);
|
|||
|
|
|||
|
ClearFlag(Vpb->Flags, VPB_MOUNTED);
|
|||
|
SetFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
|
|||
|
|
|||
|
Vpb->DeviceObject = NULL;
|
|||
|
|
|||
|
bDeleted = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
IoReleaseVpbSpinLock(Irql);
|
|||
|
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
ExGetCurrentResourceThread() );
|
|||
|
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&RfsdGlobal->Resource,
|
|||
|
ExGetCurrentResourceThread() );
|
|||
|
|
|||
|
if (bDeleted) {
|
|||
|
KdPrint(("RfsdCheckDismount: now free the vcb ...\n"));
|
|||
|
RfsdFreeVcb(Vcb);
|
|||
|
}
|
|||
|
|
|||
|
return bDeleted;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdPurgeVolume (IN PRFSD_VCB Vcb,
|
|||
|
IN BOOLEAN FlushBeforePurge )
|
|||
|
{
|
|||
|
PRFSD_FCB Fcb;
|
|||
|
LIST_ENTRY FcbList;
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PFCB_LIST_ENTRY FcbListEntry;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
ASSERT(Vcb != NULL);
|
|||
|
|
|||
|
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
|
|||
|
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
|
|||
|
|
|||
|
if ( IsFlagOn(Vcb->Flags, VCB_READ_ONLY) ||
|
|||
|
IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
|
|||
|
FlushBeforePurge = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
FcbListEntry= NULL;
|
|||
|
InitializeListHead(&FcbList);
|
|||
|
|
|||
|
for (ListEntry = Vcb->FcbList.Flink;
|
|||
|
ListEntry != &Vcb->FcbList;
|
|||
|
ListEntry = ListEntry->Flink ) {
|
|||
|
|
|||
|
Fcb = CONTAINING_RECORD(ListEntry, RFSD_FCB, Next);
|
|||
|
|
|||
|
Fcb->ReferenceCount++;
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdPurgeVolume: %s refercount=%xh\n", Fcb->AnsiFileName.Buffer, Fcb->ReferenceCount));
|
|||
|
|
|||
|
FcbListEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FCB_LIST_ENTRY), RFSD_POOL_TAG);
|
|||
|
|
|||
|
if (FcbListEntry) {
|
|||
|
|
|||
|
FcbListEntry->Fcb = Fcb;
|
|||
|
|
|||
|
InsertTailList(&FcbList, &FcbListEntry->Next);
|
|||
|
} else {
|
|||
|
RfsdPrint((DBG_ERROR, "RfsdPurgeVolume: Error allocating FcbListEntry ...\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty(&FcbList)) {
|
|||
|
|
|||
|
ListEntry = RemoveHeadList(&FcbList);
|
|||
|
|
|||
|
FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next);
|
|||
|
|
|||
|
Fcb = FcbListEntry->Fcb;
|
|||
|
|
|||
|
if (ExAcquireResourceExclusiveLite(
|
|||
|
&Fcb->MainResource,
|
|||
|
TRUE )) {
|
|||
|
|
|||
|
RfsdPurgeFile(Fcb, FlushBeforePurge);
|
|||
|
|
|||
|
if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) {
|
|||
|
RemoveEntryList(&Fcb->Next);
|
|||
|
RfsdFreeFcb(Fcb);
|
|||
|
} else {
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Fcb->MainResource,
|
|||
|
ExGetCurrentResourceThread());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(FcbListEntry);
|
|||
|
}
|
|||
|
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdPurgeVolume: Volume flushed and purged.\n"));
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
// Nothing
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdPurgeFile ( IN PRFSD_FCB Fcb,
|
|||
|
IN BOOLEAN FlushBeforePurge )
|
|||
|
{
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(Fcb != NULL);
|
|||
|
|
|||
|
ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
|
|||
|
(Fcb->Identifier.Size == sizeof(RFSD_FCB)));
|
|||
|
|
|||
|
|
|||
|
if( !IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY) && FlushBeforePurge &&
|
|||
|
!IsFlagOn(Fcb->Vcb->Flags, VCB_WRITE_PROTECTED)) {
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdPurgeFile: CcFlushCache on %s.\n",
|
|||
|
Fcb->AnsiFileName.Buffer));
|
|||
|
|
|||
|
ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
|
|||
|
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
|||
|
|
|||
|
CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
|
|||
|
|
|||
|
ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
|||
|
}
|
|||
|
|
|||
|
if (Fcb->SectionObject.ImageSectionObject) {
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdPurgeFile: MmFlushImageSection on %s.\n",
|
|||
|
Fcb->AnsiFileName.Buffer));
|
|||
|
|
|||
|
MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
|
|||
|
}
|
|||
|
|
|||
|
if (Fcb->SectionObject.DataSectionObject) {
|
|||
|
|
|||
|
RfsdPrint((DBG_INFO, "RfsdPurgeFile: CcPurgeCacheSection on %s.\n",
|
|||
|
Fcb->AnsiFileName.Buffer));
|
|||
|
|
|||
|
CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
RfsdFileSystemControl (IN PRFSD_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(IrpContext);
|
|||
|
|
|||
|
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
|
|||
|
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
|
|||
|
|
|||
|
switch (IrpContext->MinorFunction) {
|
|||
|
|
|||
|
case IRP_MN_USER_FS_REQUEST:
|
|||
|
Status = RfsdUserFsRequest(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
case IRP_MN_MOUNT_VOLUME:
|
|||
|
Status = RfsdMountVolume(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
case IRP_MN_VERIFY_VOLUME:
|
|||
|
Status = RfsdVerifyVolume(IrpContext);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
RfsdPrint((DBG_ERROR, "RfsdFilsSystemControl: Invalid Device Request.\n"));
|
|||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
RfsdCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|