3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File System Device Control routines for Fat
12 called by the dispatch driver.
20 // The local debug trace level
23 #define Dbg (DEBUG_TRACE_DEVCTRL)
26 // Local procedure prototypes
30 // Tell prefast this is an IO_COMPLETION_ROUTINE
32 IO_COMPLETION_ROUTINE FatDeviceControlCompletionRoutine
;
36 FatDeviceControlCompletionRoutine(
37 IN PDEVICE_OBJECT DeviceObject
,
43 #pragma alloc_text(PAGE, FatCommonDeviceControl)
44 #pragma alloc_text(PAGE, FatFsdDeviceControl)
48 _Function_class_(IRP_MJ_DEVICE_CONTROL
)
49 _Function_class_(DRIVER_DISPATCH
)
53 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject
,
61 This routine implements the FSD part of Device control operations
65 VolumeDeviceObject - Supplies the volume device object where the
68 Irp - Supplies the Irp being processed
72 NTSTATUS - The FSD status for the IRP
78 PIRP_CONTEXT IrpContext
= NULL
;
84 DebugTrace(+1, Dbg
, "FatFsdDeviceControl\n", 0);
86 FsRtlEnterFileSystem();
88 TopLevel
= FatIsIrpTopLevel( Irp
);
92 IrpContext
= FatCreateIrpContext( Irp
, CanFsdWait( Irp
));
94 Status
= FatCommonDeviceControl( IrpContext
, Irp
);
96 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
99 // We had some trouble trying to perform the requested
100 // operation, so we'll abort the I/O request with
101 // the error status that we get back from the
105 Status
= FatProcessException( IrpContext
, Irp
, _SEH2_GetExceptionCode() );
108 if (TopLevel
) { IoSetTopLevelIrp( NULL
); }
110 FsRtlExitFileSystem();
113 // And return to our caller
116 DebugTrace(-1, Dbg
, "FatFsdDeviceControl -> %08lx\n", Status
);
118 UNREFERENCED_PARAMETER( VolumeDeviceObject
);
124 _Requires_lock_held_(_Global_critical_region_
)
126 FatCommonDeviceControl (
127 IN PIRP_CONTEXT IrpContext
,
135 This is the common routine for doing Device control operations called
136 by both the fsd and fsp threads
140 Irp - Supplies the Irp to process
142 InFsp - Indicates if this is the fsp thread or someother thread
146 NTSTATUS - The return status for the operation
152 PIO_STACK_LOCATION IrpSp
;
154 PVOID CompletionContext
= NULL
;
163 // Get a pointer to the current Irp stack location
166 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
168 DebugTrace(+1, Dbg
, "FatCommonDeviceControl\n", 0);
169 DebugTrace( 0, Dbg
, "Irp = %p\n", Irp
);
170 DebugTrace( 0, Dbg
, "MinorFunction = %08lx\n", IrpSp
->MinorFunction
);
173 // Decode the file object, the only type of opens we accept are
174 // user volume opens.
177 if (FatDecodeFileObject( IrpSp
->FileObject
, &Vcb
, &Fcb
, &Ccb
) != UserVolumeOpen
) {
179 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
181 DebugTrace(-1, Dbg
, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER
);
182 return STATUS_INVALID_PARAMETER
;
186 // A few IOCTLs actually require some intervention on our part
189 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
) {
191 case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES
:
194 // This is sent by the Volume Snapshot driver (Lovelace).
195 // We flush the volume, and hold all file resources
196 // to make sure that nothing more gets dirty. Then we wait
197 // for the IRP to complete or cancel.
200 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
201 FatAcquireExclusiveVolume( IrpContext
, Vcb
);
203 FatFlushAndCleanVolume( IrpContext
,
208 KeInitializeEvent( &WaitEvent
, NotificationEvent
, FALSE
);
209 CompletionContext
= &WaitEvent
;
212 // Get the next stack location, and copy over the stack location
215 IoCopyCurrentIrpStackLocationToNext( Irp
);
218 // Set up the completion routine
221 IoSetCompletionRoutine( Irp
,
222 FatDeviceControlCompletionRoutine
,
229 case IOCTL_DISK_COPY_DATA
:
232 // We cannot allow this IOCTL to be sent unless the volume is locked,
233 // since this IOCTL allows direct writing of data to the volume.
234 // We do allow kernel callers to force access via a flag. A handle that
235 // issued a dismount can send this IOCTL as well.
238 if (!FlagOn( Vcb
->VcbState
, VCB_STATE_FLAG_LOCKED
) &&
239 !FlagOn( IrpSp
->Flags
, SL_FORCE_DIRECT_WRITE
) &&
240 !FlagOn( Ccb
->Flags
, CCB_FLAG_COMPLETE_DISMOUNT
)) {
242 FatCompleteRequest( IrpContext
,
244 STATUS_ACCESS_DENIED
);
246 DebugTrace(-1, Dbg
, "FatCommonDeviceControl -> %08lx\n", STATUS_ACCESS_DENIED
);
247 return STATUS_ACCESS_DENIED
;
252 case IOCTL_SCSI_PASS_THROUGH
:
253 case IOCTL_SCSI_PASS_THROUGH_DIRECT
:
254 case IOCTL_SCSI_PASS_THROUGH_EX
:
255 case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX
:
258 // If someone is issuing a format unit command underneath us, then make
259 // sure we mark the device as needing verification when they close their
263 if ((!FlagOn( IrpSp
->FileObject
->Flags
, FO_FILE_MODIFIED
) ||
264 !FlagOn( Ccb
->Flags
, CCB_FLAG_SENT_FORMAT_UNIT
)) &&
265 (Irp
->AssociatedIrp
.SystemBuffer
!= NULL
)) {
270 // If this is a 32 bit application running on 64 bit then thunk the
271 // input structures to grab the Cdb.
274 #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED)
275 if (IoIs32bitProcess(Irp
)) {
277 if ( (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
) ||
278 (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
)) {
280 if (IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
>= sizeof( SCSI_PASS_THROUGH32
)) {
282 Cdb
= (PCDB
)((PSCSI_PASS_THROUGH32
)(Irp
->AssociatedIrp
.SystemBuffer
))->Cdb
;
286 if (IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
>= sizeof( SCSI_PASS_THROUGH32_EX
)) {
288 Cdb
= (PCDB
)((PSCSI_PASS_THROUGH32_EX
)(Irp
->AssociatedIrp
.SystemBuffer
))->Cdb
;
294 if ( (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
) ||
295 (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
)) {
297 if (IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
>= sizeof( SCSI_PASS_THROUGH
)) {
299 Cdb
= (PCDB
)((PSCSI_PASS_THROUGH
)(Irp
->AssociatedIrp
.SystemBuffer
))->Cdb
;
303 if (IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
>= sizeof( SCSI_PASS_THROUGH_EX
)) {
305 Cdb
= (PCDB
)((PSCSI_PASS_THROUGH_EX
)(Irp
->AssociatedIrp
.SystemBuffer
))->Cdb
;
309 #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED)
313 if ((Cdb
!= NULL
) && (Cdb
->AsByte
[0] == SCSIOP_FORMAT_UNIT
)) {
315 SetFlag( Ccb
->Flags
, CCB_FLAG_SENT_FORMAT_UNIT
);
316 SetFlag( IrpSp
->FileObject
->Flags
, FO_FILE_MODIFIED
);
321 // Fall through as we do not need to know the outcome of this operation.
327 // FAT doesn't need to see this on the way back, so skip ourselves.
330 IoSkipCurrentIrpStackLocation( Irp
);
338 Status
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
340 if (Status
== STATUS_PENDING
&& CompletionContext
) {
342 KeWaitForSingleObject( &WaitEvent
,
348 Status
= Irp
->IoStatus
.Status
;
352 // If we had a context, the IRP remains for us and we will complete it.
353 // Handle it appropriately.
356 if (CompletionContext
) {
359 // Release all the resources that we held because of a
360 // VOLSNAP_FLUSH_AND_HOLD.
363 NT_ASSERT( IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES
);
365 FatReleaseVolume( IrpContext
, Vcb
);
368 // If we had no context, the IRP will complete asynchronously.
376 FatCompleteRequest( IrpContext
, Irp
, Status
);
378 DebugTrace(-1, Dbg
, "FatCommonDeviceControl -> %08lx\n", Status
);
385 // Local support routine
390 FatDeviceControlCompletionRoutine(
391 _In_ PDEVICE_OBJECT DeviceObject
,
393 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
397 PKEVENT Event
= (PKEVENT
) Contxt
;
400 // If there is an event, this is a synch request. Signal and
401 // let I/O know this isn't done yet.
406 KeSetEvent( Event
, 0, FALSE
);
407 return STATUS_MORE_PROCESSING_REQUIRED
;
410 UNREFERENCED_PARAMETER( DeviceObject
);
411 UNREFERENCED_PARAMETER( Irp
);
413 return STATUS_SUCCESS
;