1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 DevCtrl.c 8 9 Abstract: 10 11 This module implements the File System Device Control routines for Fat 12 called by the dispatch driver. 13 14 15 --*/ 16 17 #include "fatprocs.h" 18 19 // 20 // The local debug trace level 21 // 22 23 #define Dbg (DEBUG_TRACE_DEVCTRL) 24 25 // 26 // Local procedure prototypes 27 // 28 29 // 30 // Tell prefast this is an IO_COMPLETION_ROUTINE 31 // 32 IO_COMPLETION_ROUTINE FatDeviceControlCompletionRoutine; 33 34 NTSTATUS 35 NTAPI 36 FatDeviceControlCompletionRoutine( 37 IN PDEVICE_OBJECT DeviceObject, 38 IN PIRP Irp, 39 IN PVOID Contxt 40 ); 41 42 #ifdef ALLOC_PRAGMA 43 #pragma alloc_text(PAGE, FatCommonDeviceControl) 44 #pragma alloc_text(PAGE, FatFsdDeviceControl) 45 #endif 46 47 48 _Function_class_(IRP_MJ_DEVICE_CONTROL) 49 _Function_class_(DRIVER_DISPATCH) 50 NTSTATUS 51 NTAPI 52 FatFsdDeviceControl ( 53 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, 54 _Inout_ PIRP Irp 55 ) 56 57 /*++ 58 59 Routine Description: 60 61 This routine implements the FSD part of Device control operations 62 63 Arguments: 64 65 VolumeDeviceObject - Supplies the volume device object where the 66 file exists 67 68 Irp - Supplies the Irp being processed 69 70 Return Value: 71 72 NTSTATUS - The FSD status for the IRP 73 74 --*/ 75 76 { 77 NTSTATUS Status; 78 PIRP_CONTEXT IrpContext = NULL; 79 80 BOOLEAN TopLevel; 81 82 PAGED_CODE(); 83 84 DebugTrace(+1, Dbg, "FatFsdDeviceControl\n", 0); 85 86 FsRtlEnterFileSystem(); 87 88 TopLevel = FatIsIrpTopLevel( Irp ); 89 90 _SEH2_TRY { 91 92 IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp )); 93 94 Status = FatCommonDeviceControl( IrpContext, Irp ); 95 96 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 97 98 // 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 102 // exception code 103 // 104 105 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 106 } _SEH2_END; 107 108 if (TopLevel) { IoSetTopLevelIrp( NULL ); } 109 110 FsRtlExitFileSystem(); 111 112 // 113 // And return to our caller 114 // 115 116 DebugTrace(-1, Dbg, "FatFsdDeviceControl -> %08lx\n", Status); 117 118 UNREFERENCED_PARAMETER( VolumeDeviceObject ); 119 120 return Status; 121 } 122 123 124 _Requires_lock_held_(_Global_critical_region_) 125 NTSTATUS 126 FatCommonDeviceControl ( 127 IN PIRP_CONTEXT IrpContext, 128 IN PIRP Irp 129 ) 130 131 /*++ 132 133 Routine Description: 134 135 This is the common routine for doing Device control operations called 136 by both the fsd and fsp threads 137 138 Arguments: 139 140 Irp - Supplies the Irp to process 141 142 InFsp - Indicates if this is the fsp thread or someother thread 143 144 Return Value: 145 146 NTSTATUS - The return status for the operation 147 148 --*/ 149 150 { 151 NTSTATUS Status; 152 PIO_STACK_LOCATION IrpSp; 153 KEVENT WaitEvent; 154 PVOID CompletionContext = NULL; 155 156 PVCB Vcb; 157 PFCB Fcb; 158 PCCB Ccb; 159 160 PAGED_CODE(); 161 162 // 163 // Get a pointer to the current Irp stack location 164 // 165 166 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 167 168 DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0); 169 DebugTrace( 0, Dbg, "Irp = %p\n", Irp); 170 DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction); 171 172 // 173 // Decode the file object, the only type of opens we accept are 174 // user volume opens. 175 // 176 177 if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { 178 179 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 180 181 DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER); 182 return STATUS_INVALID_PARAMETER; 183 } 184 185 // 186 // A few IOCTLs actually require some intervention on our part 187 // 188 189 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { 190 191 case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES: 192 193 // 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. 198 // 199 200 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 201 FatAcquireExclusiveVolume( IrpContext, Vcb ); 202 203 FatFlushAndCleanVolume( IrpContext, 204 Irp, 205 Vcb, 206 FlushWithoutPurge ); 207 208 KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE ); 209 CompletionContext = &WaitEvent; 210 211 // 212 // Get the next stack location, and copy over the stack location 213 // 214 215 IoCopyCurrentIrpStackLocationToNext( Irp ); 216 217 // 218 // Set up the completion routine 219 // 220 221 IoSetCompletionRoutine( Irp, 222 FatDeviceControlCompletionRoutine, 223 CompletionContext, 224 TRUE, 225 TRUE, 226 TRUE ); 227 break; 228 229 case IOCTL_DISK_COPY_DATA: 230 231 // 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. 236 // 237 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 )) { 241 242 FatCompleteRequest( IrpContext, 243 Irp, 244 STATUS_ACCESS_DENIED ); 245 246 DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_ACCESS_DENIED); 247 return STATUS_ACCESS_DENIED; 248 } 249 250 break; 251 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: 256 257 // 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 260 // handle. 261 // 262 263 if ((!FlagOn( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ) || 264 !FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) && 265 (Irp->AssociatedIrp.SystemBuffer != NULL)) { 266 267 PCDB Cdb = NULL; 268 269 // 270 // If this is a 32 bit application running on 64 bit then thunk the 271 // input structures to grab the Cdb. 272 // 273 274 #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) 275 if (IoIs32bitProcess(Irp)) { 276 277 if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || 278 (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { 279 280 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32 )) { 281 282 Cdb = (PCDB)((PSCSI_PASS_THROUGH32)(Irp->AssociatedIrp.SystemBuffer))->Cdb; 283 } 284 } else { 285 286 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32_EX )) { 287 288 Cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; 289 } 290 } 291 292 } else { 293 #endif 294 if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || 295 (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { 296 297 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH )) { 298 299 Cdb = (PCDB)((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb; 300 } 301 } else { 302 303 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH_EX )) { 304 305 Cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; 306 } 307 } 308 309 #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) 310 } 311 #endif 312 313 if ((Cdb != NULL) && (Cdb->AsByte[0] == SCSIOP_FORMAT_UNIT)) { 314 315 SetFlag( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT ); 316 SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ); 317 } 318 } 319 320 // 321 // Fall through as we do not need to know the outcome of this operation. 322 // 323 324 default: 325 326 // 327 // FAT doesn't need to see this on the way back, so skip ourselves. 328 // 329 330 IoSkipCurrentIrpStackLocation( Irp ); 331 break; 332 } 333 334 // 335 // Send the request. 336 // 337 338 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); 339 340 if (Status == STATUS_PENDING && CompletionContext) { 341 342 KeWaitForSingleObject( &WaitEvent, 343 Executive, 344 KernelMode, 345 FALSE, 346 NULL ); 347 348 Status = Irp->IoStatus.Status; 349 } 350 351 // 352 // If we had a context, the IRP remains for us and we will complete it. 353 // Handle it appropriately. 354 // 355 356 if (CompletionContext) { 357 358 // 359 // Release all the resources that we held because of a 360 // VOLSNAP_FLUSH_AND_HOLD. 361 // 362 363 NT_ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES ); 364 365 FatReleaseVolume( IrpContext, Vcb ); 366 367 // 368 // If we had no context, the IRP will complete asynchronously. 369 // 370 371 } else { 372 373 Irp = NULL; 374 } 375 376 FatCompleteRequest( IrpContext, Irp, Status ); 377 378 DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", Status); 379 380 return Status; 381 } 382 383 384 // 385 // Local support routine 386 // 387 388 NTSTATUS 389 NTAPI 390 FatDeviceControlCompletionRoutine( 391 _In_ PDEVICE_OBJECT DeviceObject, 392 _In_ PIRP Irp, 393 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt 394 ) 395 396 { 397 PKEVENT Event = (PKEVENT) Contxt; 398 399 // 400 // If there is an event, this is a synch request. Signal and 401 // let I/O know this isn't done yet. 402 // 403 404 if (Event) { 405 406 KeSetEvent( Event, 0, FALSE ); 407 return STATUS_MORE_PROCESSING_REQUIRED; 408 } 409 410 UNREFERENCED_PARAMETER( DeviceObject ); 411 UNREFERENCED_PARAMETER( Irp ); 412 413 return STATUS_SUCCESS; 414 } 415 416