/* * COPYRIGHT: See COPYRIGHT.TXT * PROJECT: Ext2 File System Driver for WinNT/2K/XP * FILE: devctl.c * PROGRAMMER: Matt Wu * HOMEPAGE: http://www.ext2fsd.com * UPDATE HISTORY: */ /* INCLUDES *****************************************************************/ #include "ext2fs.h" /* GLOBALS ***************************************************************/ extern PEXT2_GLOBAL Ext2Global; /* DEFINITIONS *************************************************************/ NTSTATUS Ext2DeviceControlCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, Ext2DeviceControl) #pragma alloc_text(PAGE, Ext2DeviceControlNormal) #pragma alloc_text(PAGE, Ext2ProcessVolumeProperty) #pragma alloc_text(PAGE, Ext2ProcessUserProperty) #pragma alloc_text(PAGE, Ext2ProcessGlobalProperty) #pragma alloc_text(PAGE, Ex2ProcessUserPerfStat) #pragma alloc_text(PAGE, Ex2ProcessMountPoint) #if EXT2_UNLOAD #pragma alloc_text(PAGE, Ext2PrepareToUnload) #endif #endif NTSTATUS Ext2DeviceControlCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } return STATUS_SUCCESS; } NTSTATUS Ext2DeviceControlNormal (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; BOOLEAN CompleteRequest = TRUE; NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb; PIRP Irp; PIO_STACK_LOCATION IrpSp; PIO_STACK_LOCATION NextIrpSp; PDEVICE_OBJECT TargetDeviceObject; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); CompleteRequest = TRUE; DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext; if (!((Vcb) && (Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB)))) { Status = STATUS_INVALID_PARAMETER; __leave; } TargetDeviceObject = Vcb->TargetDeviceObject; // // Pass on the IOCTL to the driver below // CompleteRequest = FALSE; NextIrpSp = IoGetNextIrpStackLocation( Irp ); *NextIrpSp = *IrpSp; IoSetCompletionRoutine( Irp, Ext2DeviceControlCompletion, NULL, FALSE, TRUE, TRUE ); Status = IoCallDriver(TargetDeviceObject, Irp); } __finally { if (!IrpContext->ExceptionInProgress) { if (IrpContext) { if (!CompleteRequest) { IrpContext->Irp = NULL; } Ext2CompleteIrpContext(IrpContext, Status); } } } return Status; } #if EXT2_UNLOAD NTSTATUS Ext2PrepareToUnload (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; BOOLEAN GlobalDataResourceAcquired = FALSE; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } ExAcquireResourceExclusiveLite( &Ext2Global->Resource, TRUE ); GlobalDataResourceAcquired = TRUE; if (FlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) { DEBUG(DL_ERR, ( "Ext2PrepareUnload: Already ready to unload.\n")); Status = STATUS_ACCESS_DENIED; __leave; } { PEXT2_VCB Vcb; PLIST_ENTRY ListEntry; ListEntry = Ext2Global->VcbList.Flink; while (ListEntry != &(Ext2Global->VcbList)) { Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next); ListEntry = ListEntry->Flink; if (Vcb && (!Vcb->ReferenceCount) && IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { Ext2RemoveVcb(Vcb); Ext2ClearVpbFlag(Vcb->Vpb, VPB_MOUNTED); Ext2DestroyVcb(Vcb); } } } if (!IsListEmpty(&(Ext2Global->VcbList))) { DEBUG(DL_ERR, ( "Ext2PrepareUnload: Mounted volumes exists.\n")); Status = STATUS_ACCESS_DENIED; __leave; } IoUnregisterFileSystem(Ext2Global->DiskdevObject); IoUnregisterFileSystem(Ext2Global->CdromdevObject); Ext2Global->DriverObject->DriverUnload = DriverUnload; SetLongFlag(Ext2Global->Flags ,EXT2_UNLOAD_PENDING); Status = STATUS_SUCCESS; DEBUG(DL_INF, ( "Ext2PrepareToUnload: Driver is ready to unload.\n")); } __finally { if (GlobalDataResourceAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); } if (!IrpContext->ExceptionInProgress) { Ext2CompleteIrpContext(IrpContext, Status); } } return Status; } #endif extern CHAR gVersion[]; extern CHAR gTime[]; extern CHAR gDate[]; NTSTATUS Ext2ProcessGlobalProperty( IN PDEVICE_OBJECT DeviceObject, IN PEXT2_VOLUME_PROPERTY3 Property3, IN ULONG Length ) { PEXT2_VOLUME_PROPERTY3 Property2 = (PVOID)Property3; PEXT2_VOLUME_PROPERTY Property = (PVOID)Property3; struct nls_table * PageTable = NULL; NTSTATUS Status = STATUS_SUCCESS; BOOLEAN GlobalDataResourceAcquired = FALSE; __try { if (Length < 8 || !IsFlagOn(Property->Flags, EXT2_FLAG_VP_SET_GLOBAL)) { Status = STATUS_INVALID_PARAMETER; __leave; } /* query Ext2Fsd's version and built date/time*/ if (Property->Command == APP_CMD_QUERY_VERSION) { PEXT2_VOLUME_PROPERTY_VERSION PVPV = (PEXT2_VOLUME_PROPERTY_VERSION) Property; if (Length < sizeof(EXT2_VOLUME_PROPERTY_VERSION)) { Status = STATUS_INVALID_PARAMETER; __leave; } RtlZeroMemory(&PVPV->Date[0], 0x20); RtlZeroMemory(&PVPV->Time[0], 0x20); RtlZeroMemory(&PVPV->Version[0],0x1C); strncpy(&PVPV->Version[0], gVersion, 0x1B); strncpy(&PVPV->Date[0], gDate, 0x1F); strncpy(&PVPV->Time[0], gTime, 0x1F); __leave; } /* must be property query/set commands */ if (Property->Command == APP_CMD_SET_PROPERTY) { if (Length < sizeof(EXT2_VOLUME_PROPERTY)) { Status = STATUS_INVALID_PARAMETER; __leave; } } else if (Property->Command == APP_CMD_SET_PROPERTY2) { if (Length < sizeof(EXT2_VOLUME_PROPERTY2)) { Status = STATUS_INVALID_PARAMETER; __leave; } } else if (Property->Command == APP_CMD_SET_PROPERTY3) { if (Length < sizeof(EXT2_VOLUME_PROPERTY3)) { Status = STATUS_INVALID_PARAMETER; __leave; } } else { Status = STATUS_INVALID_PARAMETER; __leave; } ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE); GlobalDataResourceAcquired = TRUE; switch (Property->Command) { case APP_CMD_SET_PROPERTY3: if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) { if (Property3->AutoMount) SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); else ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); } case APP_CMD_SET_PROPERTY2: RtlZeroMemory(Ext2Global->sHidingPrefix, HIDINGPAT_LEN); if ((Ext2Global->bHidingPrefix = Property2->bHidingPrefix)) { RtlCopyMemory( Ext2Global->sHidingPrefix, Property2->sHidingPrefix, HIDINGPAT_LEN - 1); } RtlZeroMemory(Ext2Global->sHidingSuffix, HIDINGPAT_LEN); if ((Ext2Global->bHidingSuffix = Property2->bHidingSuffix)) { RtlCopyMemory( Ext2Global->sHidingSuffix, Property2->sHidingSuffix, HIDINGPAT_LEN - 1); } case APP_CMD_SET_PROPERTY: if (Property->bReadonly) { ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); } else { SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); if (Property->bExt3Writable) { SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); } else { ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); } } PageTable = load_nls(Property->Codepage); if (PageTable) { memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN); Ext2Global->Codepage.PageTable = PageTable; } break; default: break; } } __finally { if (GlobalDataResourceAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); } } return Status; } NTSTATUS Ext2ProcessVolumeProperty( IN PEXT2_VCB Vcb, IN PEXT2_VOLUME_PROPERTY3 Property3, IN ULONG Length ) { struct nls_table * PageTable = NULL; PEXT2_VOLUME_PROPERTY2 Property2 = (PVOID)Property3; PEXT2_VOLUME_PROPERTY Property = (PVOID)Property3; NTSTATUS Status = STATUS_SUCCESS; BOOLEAN VcbResourceAcquired = FALSE; __try { ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); VcbResourceAcquired = TRUE; if (Property->Command == APP_CMD_SET_PROPERTY || Property->Command == APP_CMD_QUERY_PROPERTY) { if (Length < sizeof(EXT2_VOLUME_PROPERTY)) { Status = STATUS_INVALID_PARAMETER; __leave; } } else if (Property->Command == APP_CMD_SET_PROPERTY2 || Property->Command == APP_CMD_QUERY_PROPERTY2) { if (Length < sizeof(EXT2_VOLUME_PROPERTY2)) { Status = STATUS_INVALID_PARAMETER; __leave; } } else if (Property->Command == APP_CMD_SET_PROPERTY3 || Property->Command == APP_CMD_QUERY_PROPERTY3) { if (Length < sizeof(EXT2_VOLUME_PROPERTY3)) { Status = STATUS_INVALID_PARAMETER; __leave; } } switch (Property->Command) { case APP_CMD_SET_PROPERTY3: if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) { if (Property3->AutoMount) SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); else ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); } if (Property3->Flags2 & EXT2_VPROP3_USERIDS) { SetFlag(Vcb->Flags, VCB_USER_IDS); Vcb->uid = Property3->uid; Vcb->gid = Property3->gid; if (Property3->EIDS) { Vcb->euid = Property3->euid; Vcb->egid = Property3->egid; SetFlag(Vcb->Flags, VCB_USER_EIDS); } else { Vcb->euid = Vcb->egid = 0; ClearFlag(Vcb->Flags, VCB_USER_EIDS); } } else { ClearFlag(Vcb->Flags, VCB_USER_IDS); ClearFlag(Vcb->Flags, VCB_USER_EIDS); Vcb->uid = Vcb->gid = 0; Vcb->euid = Vcb->egid = 0; } case APP_CMD_SET_PROPERTY2: RtlZeroMemory(Vcb->sHidingPrefix, HIDINGPAT_LEN); if (Vcb->bHidingPrefix = Property2->bHidingPrefix) { RtlCopyMemory( Vcb->sHidingPrefix, Property2->sHidingPrefix, HIDINGPAT_LEN - 1); } RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN); if (Vcb->bHidingSuffix = Property2->bHidingSuffix) { RtlCopyMemory( Vcb->sHidingSuffix, Property2->sHidingSuffix, HIDINGPAT_LEN - 1); } Vcb->DrvLetter = Property2->DrvLetter; case APP_CMD_SET_PROPERTY: if (Property->bReadonly) { if (IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) { Ext2FlushFiles(NULL, Vcb, FALSE); Ext2FlushVolume(NULL, Vcb, FALSE); } SetLongFlag(Vcb->Flags, VCB_READ_ONLY); } else { if (Property->bExt3Writable) { SetLongFlag(Vcb->Flags, VCB_FORCE_WRITING); } if (!Vcb->IsExt3fs) { ClearLongFlag(Vcb->Flags, VCB_READ_ONLY); } else if (!Property->bExt3Writable) { SetLongFlag(Vcb->Flags, VCB_READ_ONLY); } else if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) { ClearLongFlag(Vcb->Flags, VCB_READ_ONLY); Ext2RecoverJournal(NULL, Vcb); if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) { SetLongFlag(Vcb->Flags, VCB_READ_ONLY); } else { ClearLongFlag(Vcb->Flags, VCB_READ_ONLY); } } else { ClearLongFlag(Vcb->Flags, VCB_READ_ONLY); } } PageTable = load_nls(Property->Codepage); memcpy(Vcb->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN); Vcb->Codepage.PageTable = PageTable; if (Vcb->Codepage.PageTable) { Ext2InitializeLabel(Vcb, Vcb->SuperBlock); } break; case APP_CMD_QUERY_PROPERTY3: if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) { SetFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT); Property3->AutoMount = TRUE; } else { ClearFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT); Property3->AutoMount = FALSE; } if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) { SetFlag(Property3->Flags2, EXT2_VPROP3_USERIDS); Property3->uid = Vcb->uid; Property3->gid = Vcb->gid; if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) { Property3->EIDS = TRUE; Property3->euid = Vcb->euid; Property3->egid = Vcb->egid; } else { Property3->EIDS = FALSE; } } else { ClearFlag(Property3->Flags2, EXT2_VPROP3_USERIDS); } case APP_CMD_QUERY_PROPERTY2: RtlCopyMemory(Property2->UUID, Vcb->SuperBlock->s_uuid, 16); Property2->DrvLetter = Vcb->DrvLetter; if (Property2->bHidingPrefix = Vcb->bHidingPrefix) { RtlCopyMemory( Property2->sHidingPrefix, Vcb->sHidingPrefix, HIDINGPAT_LEN); } else { RtlZeroMemory( Property2->sHidingPrefix, HIDINGPAT_LEN); } if (Property2->bHidingSuffix = Vcb->bHidingSuffix) { RtlCopyMemory( Property2->sHidingSuffix, Vcb->sHidingSuffix, HIDINGPAT_LEN); } else { RtlZeroMemory( Property2->sHidingSuffix, HIDINGPAT_LEN); } case APP_CMD_QUERY_PROPERTY: Property->bExt2 = TRUE; Property->bExt3 = Vcb->IsExt3fs; Property->bReadonly = IsFlagOn(Vcb->Flags, VCB_READ_ONLY); if (!Property->bReadonly && Vcb->IsExt3fs) { Property->bExt3Writable = TRUE; } else { Property->bExt3Writable = FALSE; } RtlZeroMemory(Property->Codepage, CODEPAGE_MAXLEN); if (Vcb->Codepage.PageTable) { strncpy(Property->Codepage, Vcb->Codepage.PageTable->charset, CODEPAGE_MAXLEN); } else { strncpy(Property->Codepage, "default", CODEPAGE_MAXLEN); } break; default: Status = STATUS_INVALID_PARAMETER; break; } } __finally { if (VcbResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } } return Status; } NTSTATUS Ext2ProcessUserProperty( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VOLUME_PROPERTY3 Property, IN ULONG Length ) { NTSTATUS Status = STATUS_SUCCESS; PEXT2_VCB Vcb = NULL; PDEVICE_OBJECT DeviceObject = NULL; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); if (Property->Magic != EXT2_VOLUME_PROPERTY_MAGIC) { Status = STATUS_INVALID_PARAMETER; __leave; } DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { Status = Ext2ProcessGlobalProperty(DeviceObject, Property, Length); } else { Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; if (!((Vcb) && (Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB)))) { Status = STATUS_INVALID_PARAMETER; __leave; } Status = Ext2ProcessVolumeProperty(Vcb, Property, Length); } if (NT_SUCCESS(Status)) { IrpContext->Irp->IoStatus.Information = Length; } } __finally { if (!IrpContext->ExceptionInProgress) { Ext2CompleteIrpContext(IrpContext, Status); } } return Status; } NTSTATUS Ex2ProcessUserPerfStat( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_QUERY_PERFSTAT QueryPerf, IN ULONG Length ) { PEXT2_VCB Vcb = NULL; PDEVICE_OBJECT DeviceObject = NULL; BOOLEAN GlobalDataResourceAcquired = FALSE; NTSTATUS Status = STATUS_SUCCESS; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { if (QueryPerf->Magic != EXT2_QUERY_PERFSTAT_MAGIC) { Status = STATUS_INVALID_PARAMETER; __leave; } if (QueryPerf->Command != IOCTL_APP_QUERY_PERFSTAT) { Status = STATUS_INVALID_PARAMETER; __leave; } if (Length != EXT2_QUERY_PERFSTAT_SZV1 && Length != EXT2_QUERY_PERFSTAT_SZV2) { Status = STATUS_INVALID_PARAMETER; __leave; } ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE); GlobalDataResourceAcquired = TRUE; if (Length == EXT2_QUERY_PERFSTAT_SZV2) { QueryPerf->Flags = EXT2_QUERY_PERFSTAT_VER2; QueryPerf->PerfStatV2 = Ext2Global->PerfStat; } else { memcpy(&QueryPerf->PerfStatV1.Irps[0], &Ext2Global->PerfStat.Irps[0], FIELD_OFFSET(EXT2_PERF_STATISTICS_V1, Unit)); memcpy(&QueryPerf->PerfStatV1.Unit, &Ext2Global->PerfStat.Unit, sizeof(EXT2_STAT_ARRAY_V1)); memcpy(&QueryPerf->PerfStatV1.Current, &Ext2Global->PerfStat.Current, sizeof(EXT2_STAT_ARRAY_V1)); memcpy(&QueryPerf->PerfStatV1.Size, &Ext2Global->PerfStat.Size, sizeof(EXT2_STAT_ARRAY_V1)); memcpy(&QueryPerf->PerfStatV1.Total, &Ext2Global->PerfStat.Total, sizeof(EXT2_STAT_ARRAY_V1)); } } else { Status = STATUS_INVALID_PARAMETER; __leave; } if (NT_SUCCESS(Status)) { IrpContext->Irp->IoStatus.Information = Length; } } __finally { if (GlobalDataResourceAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); } if (!IrpContext->ExceptionInProgress) { Ext2CompleteIrpContext(IrpContext, Status); } } return Status; } NTSTATUS Ex2ProcessMountPoint( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_MOUNT_POINT MountPoint, IN ULONG Length ) { UNICODE_STRING Link; UNICODE_STRING Target; WCHAR Buffer[] = L"\\DosDevices\\Global\\Z:"; NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT DeviceObject = NULL; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (!IsExt2FsDevice(DeviceObject)) { status = STATUS_INVALID_PARAMETER; __leave; } if (Length != sizeof(EXT2_MOUNT_POINT) || MountPoint->Magic != EXT2_APP_MOUNTPOINT_MAGIC) { status = STATUS_INVALID_PARAMETER; __leave; } RtlInitUnicodeString(&Link, Buffer); Buffer[12] = MountPoint->Link[0]; switch (MountPoint->Command) { case APP_CMD_ADD_DOS_SYMLINK: RtlInitUnicodeString(&Target, &MountPoint->Name[0]); status = IoCreateSymbolicLink(&Link, &Target); break; case APP_CMD_DEL_DOS_SYMLINK: status = IoDeleteSymbolicLink(&Link); break; default: status = STATUS_INVALID_PARAMETER; } } __finally { if (!IrpContext->ExceptionInProgress) { Ext2CompleteIrpContext(IrpContext, status); } } return status; } NTSTATUS Ext2DeviceControl (IN PEXT2_IRP_CONTEXT IrpContext) { PIRP Irp; PIO_STACK_LOCATION irpSp; ULONG code; ULONG length; NTSTATUS Status; ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); Irp = IrpContext->Irp; irpSp = IoGetCurrentIrpStackLocation(Irp); code = irpSp->Parameters.DeviceIoControl.IoControlCode; length = irpSp->Parameters.DeviceIoControl.OutputBufferLength; switch (code) { case IOCTL_APP_VOLUME_PROPERTY: Status = Ext2ProcessUserProperty( IrpContext, Irp->AssociatedIrp.SystemBuffer, length ); break; case IOCTL_APP_QUERY_PERFSTAT: Status = Ex2ProcessUserPerfStat( IrpContext, Irp->AssociatedIrp.SystemBuffer, length ); break; case IOCTL_APP_MOUNT_POINT: Status = Ex2ProcessMountPoint( IrpContext, Irp->AssociatedIrp.SystemBuffer, length ); break; #if EXT2_UNLOAD case IOCTL_PREPARE_TO_UNLOAD: Status = Ext2PrepareToUnload(IrpContext); break; #endif default: Status = Ext2DeviceControlNormal(IrpContext); } return Status; }