summaryrefslogtreecommitdiff
path: root/filesys/fastfat/devctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'filesys/fastfat/devctrl.c')
-rw-r--r--filesys/fastfat/devctrl.c412
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;
+}
+