diff options
Diffstat (limited to 'filesys/fastfat/devctrl.c')
| -rw-r--r-- | filesys/fastfat/devctrl.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/filesys/fastfat/devctrl.c b/filesys/fastfat/devctrl.c new file mode 100644 index 00000000..25e574af --- /dev/null +++ b/filesys/fastfat/devctrl.c @@ -0,0 +1,412 @@ +/*++ + +Copyright (c) 1989-2000 Microsoft Corporation + +Module Name: + + DevCtrl.c + +Abstract: + + This module implements the File System Device Control routines for Fat + called by the dispatch driver. + + +--*/ + +#include "FatProcs.h" + +// +// The local debug trace level +// + +#define Dbg (DEBUG_TRACE_DEVCTRL) + +// +// Local procedure prototypes +// + +// +// Tell prefast this is an IO_COMPLETION_ROUTINE +// +IO_COMPLETION_ROUTINE FatDeviceControlCompletionRoutine; + +NTSTATUS +FatDeviceControlCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FatCommonDeviceControl) +#pragma alloc_text(PAGE, FatFsdDeviceControl) +#endif + + +_Function_class_(IRP_MJ_DEVICE_CONTROL) +_Function_class_(DRIVER_DISPATCH) +NTSTATUS +FatFsdDeviceControl ( + _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, + _Inout_ PIRP Irp + ) + +/*++ + +Routine Description: + + This routine implements the FSD part of Device control operations + +Arguments: + + VolumeDeviceObject - Supplies the volume device object where the + file exists + + Irp - Supplies the Irp being processed + +Return Value: + + NTSTATUS - The FSD status for the IRP + +--*/ + +{ + NTSTATUS Status; + PIRP_CONTEXT IrpContext = NULL; + + BOOLEAN TopLevel; + + PAGED_CODE(); + + DebugTrace(+1, Dbg, "FatFsdDeviceControl\n", 0); + + FsRtlEnterFileSystem(); + + TopLevel = FatIsIrpTopLevel( Irp ); + + try { + + IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp )); + + Status = FatCommonDeviceControl( IrpContext, Irp ); + + } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { + + // + // We had some trouble trying to perform the requested + // operation, so we'll abort the I/O request with + // the error status that we get back from the + // execption code + // + + Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); + } + + if (TopLevel) { IoSetTopLevelIrp( NULL ); } + + FsRtlExitFileSystem(); + + // + // And return to our caller + // + + DebugTrace(-1, Dbg, "FatFsdDeviceControl -> %08lx\n", Status); + + UNREFERENCED_PARAMETER( VolumeDeviceObject ); + + return Status; +} + + +_Requires_lock_held_(_Global_critical_region_) +NTSTATUS +FatCommonDeviceControl ( + IN PIRP_CONTEXT IrpContext, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This is the common routine for doing Device control operations called + by both the fsd and fsp threads + +Arguments: + + Irp - Supplies the Irp to process + + InFsp - Indicates if this is the fsp thread or someother thread + +Return Value: + + NTSTATUS - The return status for the operation + +--*/ + +{ + NTSTATUS Status; + PIO_STACK_LOCATION IrpSp; + KEVENT WaitEvent; + PVOID CompletionContext = NULL; + + PVCB Vcb; + PFCB Fcb; + PCCB Ccb; + + PAGED_CODE(); + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0); + DebugTrace( 0, Dbg, "Irp = %p\n", Irp); + DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction); + + // + // Decode the file object, the only type of opens we accept are + // user volume opens. + // + + if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { + + FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); + + DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + + // + // A few IOCTLs actually require some intervention on our part + // + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + + case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES: + + // + // This is sent by the Volume Snapshot driver (Lovelace). + // We flush the volume, and hold all file resources + // to make sure that nothing more gets dirty. Then we wait + // for the IRP to complete or cancel. + // + + SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); + FatAcquireExclusiveVolume( IrpContext, Vcb ); + + FatFlushAndCleanVolume( IrpContext, + Irp, + Vcb, + FlushWithoutPurge ); + + KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE ); + CompletionContext = &WaitEvent; + + // + // Get the next stack location, and copy over the stack location + // + + IoCopyCurrentIrpStackLocationToNext( Irp ); + + // + // Set up the completion routine + // + + IoSetCompletionRoutine( Irp, + FatDeviceControlCompletionRoutine, + CompletionContext, + TRUE, + TRUE, + TRUE ); + break; + + case IOCTL_DISK_COPY_DATA: + + // + // We cannot allow this IOCTL to be sent unless the volume is locked, + // since this IOCTL allows direct writing of data to the volume. + // We do allow kernel callers to force access via a flag. A handle that + // issued a dismount can send this IOCTL as well. + // + + if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) && + !FlagOn( IrpSp->Flags, SL_FORCE_DIRECT_WRITE ) && + !FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) { + + FatCompleteRequest( IrpContext, + Irp, + STATUS_ACCESS_DENIED ); + + DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_ACCESS_DENIED); + return STATUS_ACCESS_DENIED; + } + + break; + + case IOCTL_SCSI_PASS_THROUGH: + case IOCTL_SCSI_PASS_THROUGH_DIRECT: + case IOCTL_SCSI_PASS_THROUGH_EX: + case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX: + + // + // If someone is issuing a format unit command underneath us, then make + // sure we mark the device as needing verification when they close their + // handle. + // + + if ((!FlagOn( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ) || + !FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) && + (Irp->AssociatedIrp.SystemBuffer != NULL)) { + + PCDB Cdb = NULL; + + // + // If this is a 32 bit application running on 64 bit then thunk the + // input structures to grab the Cdb. + // + +#if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) + if (IoIs32bitProcess(Irp)) { + + if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || + (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { + + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32 )) { + + Cdb = (PCDB)((PSCSI_PASS_THROUGH32)(Irp->AssociatedIrp.SystemBuffer))->Cdb; + } + } else { + + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32_EX )) { + + Cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; + } + } + + } else { +#endif + if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || + (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { + + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH )) { + + Cdb = (PCDB)((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb; + } + } else { + + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH_EX )) { + + Cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; + } + } + +#if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) + } +#endif + + if ((Cdb != NULL) && (Cdb->AsByte[0] == SCSIOP_FORMAT_UNIT)) { + + SetFlag( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT ); + SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ); + } + } + + // + // Fall through as we do not need to know the outcome of this operation. + // + + default: + + // + // FAT doesn't need to see this on the way back, so skip ourselves. + // + + IoSkipCurrentIrpStackLocation( Irp ); + break; + } + + // + // Send the request. + // + + Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); + + if (Status == STATUS_PENDING && CompletionContext) { + + KeWaitForSingleObject( &WaitEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + Status = Irp->IoStatus.Status; + } + + // + // If we had a context, the IRP remains for us and we will complete it. + // Handle it appropriately. + // + + if (CompletionContext) { + + // + // Release all the resources that we held because of a + // VOLSNAP_FLUSH_AND_HOLD. + // + + NT_ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES ); + + FatReleaseVolume( IrpContext, Vcb ); + + // + // If we had no context, the IRP will complete asynchronously. + // + + } else { + + Irp = NULL; + } + + FatCompleteRequest( IrpContext, Irp, Status ); + + DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", Status); + + return Status; +} + + +// +// Local support routine +// + +NTSTATUS +FatDeviceControlCompletionRoutine( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt + ) + +{ + PKEVENT Event = (PKEVENT) Contxt; + + // + // If there is an event, this is a synch request. Signal and + // let I/O know this isn't done yet. + // + + if (Event) { + + KeSetEvent( Event, 0, FALSE ); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + UNREFERENCED_PARAMETER( DeviceObject ); + UNREFERENCED_PARAMETER( Irp ); + + return STATUS_SUCCESS; +} + |
