Something went wrong. Try again.
Reactos
Something went wrong. Try again.
11 kB · 415 lines
C
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416/*++
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;
NTSTATUSNTAPIFatDeviceControlCompletionRoutine( 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)NTSTATUSNTAPIFatFsdDeviceControl ( _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 );
_SEH2_TRY {
IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ));
Status = FatCommonDeviceControl( IrpContext, Irp );
} _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_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 // exception code //
Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); } _SEH2_END;
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_)NTSTATUSFatCommonDeviceControl ( 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//
NTSTATUSNTAPIFatDeviceControlCompletionRoutine( _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;}