/* * 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é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; }