1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 /************************************************************************* 7 * 8 * File: Pnp.cpp 9 * 10 * Module: UDF File System Driver (Kernel mode execution only) 11 * 12 * Description: 13 * This module implements the Plug and Play routines for UDF called by 14 * the dispatch driver. 15 * 16 *************************************************************************/ 17 18 #include "udffs.h" 19 20 // define the file specific bug-check id 21 #define UDF_BUG_CHECK_ID UDF_FILE_PNP 22 23 24 NTSTATUS 25 UDFPnpQueryRemove ( 26 PtrUDFIrpContext PtrIrpContext, 27 PIRP Irp, 28 PVCB Vcb 29 ); 30 31 NTSTATUS 32 UDFPnpRemove ( 33 PtrUDFIrpContext PtrIrpContext, 34 PIRP Irp, 35 PVCB Vcb 36 ); 37 38 NTSTATUS 39 UDFPnpSurpriseRemove ( 40 PtrUDFIrpContext PtrIrpContext, 41 PIRP Irp, 42 PVCB Vcb 43 ); 44 45 NTSTATUS 46 UDFPnpCancelRemove ( 47 PtrUDFIrpContext PtrIrpContext, 48 PIRP Irp, 49 PVCB Vcb 50 ); 51 52 NTSTATUS 53 NTAPI 54 UDFPnpCompletionRoutine ( 55 IN PDEVICE_OBJECT DeviceObject, 56 IN PIRP Irp, 57 IN PVOID Contxt 58 ); 59 60 NTSTATUS 61 UDFCommonPnp ( 62 PtrUDFIrpContext PtrIrpContext, 63 IN PIRP Irp 64 ); 65 66 /* 67 This routine implements the FSD part of PnP operations 68 69 Arguments: 70 71 VolumeDeviceObject - Supplies the volume device object where the 72 file exists 73 Irp - Supplies the Irp being processed 74 75 Return Value: 76 77 NTSTATUS - The FSD status for the IRP 78 79 */ 80 NTSTATUS 81 UDFPnp ( 82 IN PDEVICE_OBJECT DeviceObject, 83 IN PIRP Irp 84 ) 85 { 86 NTSTATUS RC; 87 PtrUDFIrpContext PtrIrpContext = NULL; 88 BOOLEAN AreWeTopLevel; 89 90 UDFPrint(("UDFPnp\n")); 91 ASSERT(FALSE); 92 93 FsRtlEnterFileSystem(); 94 ASSERT(DeviceObject); 95 ASSERT(Irp); 96 97 // set the top level context 98 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 99 100 _SEH2_TRY { 101 // We expect there to never be a fileobject, in which case we will always 102 // wait. Since at the moment we don't have any concept of pending Pnp 103 // operations, this is a bit nitpicky. 104 105 // get an IRP context structure and issue the request 106 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 107 if(PtrIrpContext) { 108 RC = UDFCommonPnp(PtrIrpContext, Irp); 109 } else { 110 RC = STATUS_INSUFFICIENT_RESOURCES; 111 Irp->IoStatus.Status = RC; 112 Irp->IoStatus.Information = 0; 113 // complete the IRP 114 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 115 } 116 117 } _SEH2_EXCEPT(UDFExceptionFilter( PtrIrpContext, _SEH2_GetExceptionInformation() )) { 118 119 RC = UDFExceptionHandler(PtrIrpContext, Irp); 120 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 121 } _SEH2_END; 122 123 if (AreWeTopLevel) { 124 IoSetTopLevelIrp(NULL); 125 } 126 127 FsRtlExitFileSystem(); 128 129 return RC; 130 } 131 132 /* 133 This is the common routine for doing PnP operations called 134 by both the fsd and fsp threads 135 136 Arguments: 137 138 Irp - Supplies the Irp to process 139 140 Return Value: 141 142 NTSTATUS - The return status for the operation 143 */ 144 NTSTATUS 145 UDFCommonPnp ( 146 PtrUDFIrpContext PtrIrpContext, 147 IN PIRP Irp 148 ) 149 { 150 NTSTATUS RC; 151 PIO_STACK_LOCATION IrpSp; 152 PVCB Vcb; 153 UDFPrint(("UDFCommonPnp\n")); 154 155 _SEH2_TRY { 156 // Get the current Irp stack location. 157 IrpSp = IoGetCurrentIrpStackLocation(Irp); 158 159 // Make sure this device object really is big enough to be a volume device 160 // object. If it isn't, we need to get out before we try to reference some 161 // field that takes us past the end of an ordinary device object. 162 Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); 163 164 if (Vcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) { 165 // We were called with something we don't understand. 166 if(Irp->Flags & IRP_INPUT_OPERATION) { 167 Irp->IoStatus.Information = 0; 168 } 169 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 170 171 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 172 try_return (RC = STATUS_INVALID_PARAMETER); 173 } 174 175 // Force everything to wait. 176 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK; 177 178 // Case on the minor code. 179 switch ( IrpSp->MinorFunction ) { 180 181 case IRP_MN_QUERY_REMOVE_DEVICE: 182 RC = UDFPnpQueryRemove( PtrIrpContext, Irp, Vcb ); 183 break; 184 185 case IRP_MN_SURPRISE_REMOVAL: 186 RC = UDFPnpSurpriseRemove( PtrIrpContext, Irp, Vcb ); 187 break; 188 189 case IRP_MN_REMOVE_DEVICE: 190 RC = UDFPnpRemove( PtrIrpContext, Irp, Vcb ); 191 break; 192 193 /* case IRP_MN_CANCEL_REMOVE_DEVICE: 194 RC = UDFPnpCancelRemove( PtrIrpContext, Irp, Vcb ); 195 break;*/ 196 197 default: 198 UDFPrint(("UDFCommonPnp: pass through\n")); 199 // Just pass the IRP on. As we do not need to be in the 200 // way on return, ellide ourselves out of the stack. 201 IoSkipCurrentIrpStackLocation( Irp ); 202 RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); 203 ASSERT(RC != STATUS_PENDING); 204 205 break; 206 } 207 208 try_exit: NOTHING; 209 210 } _SEH2_FINALLY { 211 UDFReleaseIrpContext(PtrIrpContext); 212 } _SEH2_END; 213 214 return RC; 215 } 216 217 218 /* 219 Routine Description: 220 This routine handles the PnP query remove operation. The filesystem 221 is responsible for answering whether there are any reasons it sees 222 that the volume can not go away (and the device removed). Initiation 223 of the dismount begins when we answer yes to this question. 224 225 Query will be followed by a Cancel or Remove. 226 227 Arguments: 228 Irp - Supplies the Irp to process 229 Vcb - Supplies the volume being queried. 230 231 Return Value: 232 NTSTATUS - The return status for the operation 233 */ 234 NTSTATUS 235 UDFPnpQueryRemove( 236 PtrUDFIrpContext PtrIrpContext, 237 PIRP Irp, 238 PVCB Vcb 239 ) 240 { 241 NTSTATUS RC; 242 KEVENT Event; 243 BOOLEAN VcbDeleted = FALSE; 244 BOOLEAN GlobalHeld = FALSE; 245 BOOLEAN VcbAcquired = FALSE; 246 PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; 247 248 // Having said yes to a QUERY, any communication with the 249 // underlying storage stack is undefined (and may block) 250 // until the bounding CANCEL or REMOVE is sent. 251 252 _SEH2_TRY { 253 254 // Acquire the global resource so that we can try to vaporize 255 // the volume, and the vcb resource itself. 256 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); 257 GlobalHeld = TRUE; 258 259 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) 260 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); 261 #ifdef UDF_DELAYED_CLOSE 262 UDFCloseAllDelayed(Vcb); 263 #endif //UDF_DELAYED_CLOSE 264 265 UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); 266 VcbAcquired = TRUE; 267 268 Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); 269 // With the volume held locked, note that we must finalize as much 270 // as possible right now. 271 UDFDoDismountSequence(Vcb, Buf, FALSE); 272 273 // disable Eject Request Waiter if any 274 UDFReleaseResource( &(Vcb->VCBResource) ); 275 VcbAcquired = FALSE; 276 UDFStopEjectWaiter(Vcb); 277 UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); 278 VcbAcquired = TRUE; 279 280 // We need to pass this down before starting the dismount, which 281 // could disconnect us immediately from the stack. 282 283 // Get the next stack location, and copy over the stack location 284 IoCopyCurrentIrpStackLocationToNext( Irp ); 285 286 // Set up the completion routine 287 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 288 IoSetCompletionRoutine( Irp, 289 UDFPnpCompletionRoutine, 290 &Event, 291 TRUE, 292 TRUE, 293 TRUE ); 294 // Send the request and wait. 295 RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); 296 297 if (RC == STATUS_PENDING) { 298 KeWaitForSingleObject( &Event, 299 Executive, 300 KernelMode, 301 FALSE, 302 NULL ); 303 304 RC = Irp->IoStatus.Status; 305 } 306 307 // Now if no one below us failed already, initiate the dismount 308 // on this volume, make it go away. PnP needs to see our internal 309 // streams close and drop their references to the target device. 310 311 // Since we were able to lock the volume, we are guaranteed to 312 // move this volume into dismount state and disconnect it from 313 // the underlying storage stack. The force on our part is actually 314 // unnecesary, though complete. 315 316 // What is not strictly guaranteed, though, is that the closes 317 // for the metadata streams take effect synchronously underneath 318 // of this call. This would leave references on the target device 319 // even though we are disconnected! 320 if (NT_SUCCESS( RC )) { 321 VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, TRUE ); 322 ASSERT( VcbDeleted ); 323 } 324 325 // Release the Vcb if it could still remain. 326 327 // Note: if everything else succeeded and the Vcb is persistent because the 328 // internal streams did not vaporize, we really need to pend this IRP off on 329 // the side until the dismount is completed. I can't think of a reasonable 330 // case (in UDF) where this would actually happen, though it might still need 331 // to be implemented. 332 // 333 // The reason this is the case is that handles/fileobjects place a reference 334 // on the device objects they overly. In the filesystem case, these references 335 // are on our target devices. PnP correcly thinks that if references remain 336 // on the device objects in the stack that someone has a handle, and that this 337 // counts as a reason to not succeed the query - even though every interrogated 338 // driver thinks that it is OK. 339 ASSERT( !(NT_SUCCESS( RC ) && !VcbDeleted )); 340 341 } _SEH2_FINALLY { 342 343 if (!VcbDeleted && VcbAcquired) { 344 UDFReleaseResource( &(Vcb->VCBResource) ); 345 } 346 347 if (GlobalHeld) { 348 UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); 349 } 350 351 if (!_SEH2_AbnormalTermination()) { 352 Irp->IoStatus.Status = RC; 353 // Free up the Irp Context 354 UDFReleaseIrpContext(PtrIrpContext); 355 // complete the IRP 356 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 357 } 358 } _SEH2_END; 359 360 return RC; 361 } // end UDFPnpQueryRemove() 362 363 364 /* 365 Routine Description: 366 This routine handles the PnP remove operation. This is our notification 367 that the underlying storage device for the volume we have is gone, and 368 an excellent indication that the volume will never reappear. The filesystem 369 is responsible for initiation or completion of the dismount. 370 371 Arguments: 372 Irp - Supplies the Irp to process 373 Vcb - Supplies the volume being removed. 374 375 Return Value: 376 NTSTATUS - The return status for the operation 377 378 --*/ 379 NTSTATUS 380 UDFPnpRemove ( 381 PtrUDFIrpContext PtrIrpContext, 382 PIRP Irp, 383 PVCB Vcb 384 ) 385 { 386 NTSTATUS RC; 387 KEVENT Event; 388 BOOLEAN VcbDeleted; 389 BOOLEAN VcbAcquired; 390 PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; 391 392 // REMOVE - a storage device is now gone. We either got 393 // QUERY'd and said yes OR got a SURPRISE OR a storage 394 // stack failed to spin back up from a sleep/stop state 395 // (the only case in which this will be the first warning). 396 // 397 // Note that it is entirely unlikely that we will be around 398 // for a REMOVE in the first two cases, as we try to intiate 399 // dismount. 400 401 // Acquire the global resource so that we can try to vaporize 402 // the volume, and the vcb resource itself. 403 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); 404 405 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) 406 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); 407 #ifdef UDF_DELAYED_CLOSE 408 UDFCloseAllDelayed(Vcb); 409 #endif //UDF_DELAYED_CLOSE 410 411 UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); 412 VcbAcquired = TRUE; 413 414 // The device will be going away. Remove our lock (benign 415 // if we never had it). 416 if((Vcb->Vpb->Flags & VPB_LOCKED) || 417 (Vcb->VolumeLockPID != (ULONG)-1) ) { 418 Vcb->Vpb->Flags &= ~VPB_LOCKED; 419 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; 420 Vcb->VolumeLockFileObject = NULL; 421 Vcb->VolumeLockPID = -1; 422 RC = STATUS_SUCCESS; 423 } 424 425 // We need to pass this down before starting the dismount, which 426 // could disconnect us immediately from the stack. 427 428 // Get the next stack location, and copy over the stack location 429 IoCopyCurrentIrpStackLocationToNext( Irp ); 430 431 // Set up the completion routine 432 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 433 IoSetCompletionRoutine( Irp, 434 UDFPnpCompletionRoutine, 435 &Event, 436 TRUE, 437 TRUE, 438 TRUE ); 439 440 // Send the request and wait. 441 RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); 442 443 if (RC == STATUS_PENDING) { 444 445 KeWaitForSingleObject( &Event, 446 Executive, 447 KernelMode, 448 FALSE, 449 NULL ); 450 451 RC = Irp->IoStatus.Status; 452 } 453 454 _SEH2_TRY { 455 456 // Knock as many files down for this volume as we can. 457 458 // Now make our dismount happen. This may not vaporize the 459 // Vcb, of course, since there could be any number of handles 460 // outstanding if we were not preceeded by a QUERY. 461 // 462 // PnP will take care of disconnecting this stack if we 463 // couldn't get off of it immediately. 464 Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; 465 Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); 466 if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 467 UDFDoDismountSequence(Vcb, Buf, FALSE); 468 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; 469 Vcb->WriteSecurity = FALSE; 470 // disable Eject Request Waiter if any 471 UDFReleaseResource( &(Vcb->VCBResource) ); 472 VcbAcquired = FALSE; 473 474 UDFStopEjectWaiter(Vcb); 475 476 VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, FALSE ); 477 478 try_exit: NOTHING; 479 480 } _SEH2_FINALLY { 481 // Release the Vcb if it could still remain. 482 if (!VcbDeleted && VcbAcquired) { 483 UDFReleaseResource(&(Vcb->VCBResource)); 484 } 485 UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); 486 487 if(Buf) 488 MyFreePool__(Buf); 489 490 if (!_SEH2_AbnormalTermination()) { 491 Irp->IoStatus.Status = RC; 492 // Free up the Irp Context 493 UDFReleaseIrpContext(PtrIrpContext); 494 // complete the IRP 495 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 496 } 497 } _SEH2_END; 498 499 return RC; 500 } 501 502 503 NTSTATUS 504 UDFPnpSurpriseRemove ( 505 PtrUDFIrpContext PtrIrpContext, 506 PIRP Irp, 507 PVCB Vcb 508 ) 509 510 /*++ 511 512 Routine Description: 513 514 This routine handles the PnP surprise remove operation. This is another 515 type of notification that the underlying storage device for the volume we 516 have is gone, and is excellent indication that the volume will never reappear. 517 The filesystem is responsible for initiation or completion the dismount. 518 519 For the most part, only "real" drivers care about the distinction of a 520 surprise remove, which is a result of our noticing that a user (usually) 521 physically reached into the machine and pulled something out. 522 523 Surprise will be followed by a Remove when all references have been shut down. 524 525 Arguments: 526 527 Irp - Supplies the Irp to process 528 529 Vcb - Supplies the volume being removed. 530 531 Return Value: 532 533 NTSTATUS - The return status for the operation 534 535 --*/ 536 537 { 538 NTSTATUS RC; 539 KEVENT Event; 540 BOOLEAN VcbDeleted; 541 BOOLEAN VcbAcquired; 542 PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; 543 544 // SURPRISE - a device was physically yanked away without 545 // any warning. This means external forces. 546 547 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); 548 549 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) 550 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); 551 #ifdef UDF_DELAYED_CLOSE 552 UDFCloseAllDelayed(Vcb); 553 #endif //UDF_DELAYED_CLOSE 554 555 UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); 556 VcbAcquired = TRUE; 557 558 // We need to pass this down before starting the dismount, which 559 // could disconnect us immediately from the stack. 560 561 // Get the next stack location, and copy over the stack location 562 IoCopyCurrentIrpStackLocationToNext( Irp ); 563 564 // Set up the completion routine 565 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 566 IoSetCompletionRoutine( Irp, 567 UDFPnpCompletionRoutine, 568 &Event, 569 TRUE, 570 TRUE, 571 TRUE ); 572 573 // Send the request and wait. 574 RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); 575 576 if (RC == STATUS_PENDING) { 577 578 KeWaitForSingleObject( &Event, 579 Executive, 580 KernelMode, 581 FALSE, 582 NULL ); 583 584 RC = Irp->IoStatus.Status; 585 } 586 587 _SEH2_TRY { 588 // Knock as many files down for this volume as we can. 589 Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; 590 Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); 591 if(!Buf) { 592 VcbAcquired = FALSE; 593 VcbDeleted = FALSE; 594 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 595 } 596 597 UDFDoDismountSequence(Vcb, Buf, FALSE); 598 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; 599 Vcb->WriteSecurity = FALSE; 600 601 UDFReleaseResource(&(Vcb->VCBResource)); 602 VcbAcquired = FALSE; 603 604 UDFStopEjectWaiter(Vcb); 605 606 // Now make our dismount happen. This may not vaporize the 607 // Vcb, of course, since there could be any number of handles 608 // outstanding since this is an out of band notification. 609 VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, FALSE ); 610 611 try_exit: NOTHING; 612 613 } _SEH2_FINALLY { 614 615 // Release the Vcb if it could still remain. 616 if (!VcbDeleted && VcbAcquired) { 617 UDFReleaseResource(&(Vcb->VCBResource)); 618 } 619 UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); 620 621 if(Buf) 622 MyFreePool__(Buf); 623 624 if (!_SEH2_AbnormalTermination()) { 625 Irp->IoStatus.Status = RC; 626 // Free up the Irp Context 627 UDFReleaseIrpContext(PtrIrpContext); 628 // complete the IRP 629 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 630 } 631 } _SEH2_END; 632 633 return RC; 634 } 635 636 /* 637 NTSTATUS 638 UDFPnpCancelRemove ( 639 PtrUDFIrpContext PtrIrpContext, 640 PIRP Irp, 641 PVCB Vcb 642 ) 643 644 */ 645 /*++ 646 647 Routine Description: 648 649 This routine handles the PnP cancel remove operation. This is our 650 notification that a previously proposed remove (query) was eventually 651 vetoed by a component. The filesystem is responsible for cleaning up 652 and getting ready for more IO. 653 654 Arguments: 655 656 Irp - Supplies the Irp to process 657 658 Vcb - Supplies the volume being removed. 659 660 Return Value: 661 662 NTSTATUS - The return status for the operation 663 664 --*/ 665 666 /*{ 667 NTSTATUS RC; 668 669 // CANCEL - a previous QUERY has been rescinded as a result 670 // of someone vetoing. Since PnP cannot figure out who may 671 // have gotten the QUERY (think about it: stacked drivers), 672 // we must expect to deal with getting a CANCEL without having 673 // seen the QUERY. 674 // 675 // For UDF, this is quite easy. In fact, we can't get a 676 // CANCEL if the underlying drivers succeeded the QUERY since 677 // we disconnect the Vpb on our dismount initiation. This is 678 // actually pretty important because if PnP could get to us 679 // after the disconnect we'd be thoroughly unsynchronized 680 // with respect to the Vcb getting torn apart - merely referencing 681 // the volume device object is insufficient to keep us intact. 682 683 UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); 684 685 // Unlock the volume. This is benign if we never had seen 686 // a QUERY. 687 if(Vcb->Vpb->Flags & VPB_LOCKED) { 688 Vcb->Vpb->Flags &= ~VPB_LOCKED; 689 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; 690 Vcb->VolumeLockFileObject = NULL; 691 RC = STATUS_SUCCESS; 692 } else { 693 RC = STATUS_NOT_LOCKED; 694 } 695 696 try { 697 698 // We must re-enable allocation support if we got through 699 // the first stages of a QUERY_REMOVE; i.e., we decided we 700 // could place a lock on the volume. 701 if (NT_SUCCESS( RC )) { 702 FatSetupAllocationSupport( PtrIrpContext, Vcb ); 703 } 704 705 } finally { 706 UDFReleaseResource(&(Vcb->VCBResource)); 707 } 708 709 // Send the request. The underlying driver will complete the 710 // IRP. Since we don't need to be in the way, simply ellide 711 // ourselves out of the IRP stack. 712 IoSkipCurrentIrpStackLocation( Irp ); 713 714 RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); 715 716 // if (!AbnormalTermination()) { 717 Irp->IoStatus.Status = RC; 718 // Free up the Irp Context 719 UDFReleaseIrpContext(PtrIrpContext); 720 // complete the IRP 721 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 722 // } 723 724 return RC; 725 } */ 726 727 728 // Local support routine 729 NTSTATUS 730 NTAPI 731 UDFPnpCompletionRoutine ( 732 IN PDEVICE_OBJECT DeviceObject, 733 IN PIRP Irp, 734 IN PVOID Contxt 735 ) 736 { 737 PKEVENT Event = (PKEVENT) Contxt; 738 739 KeSetEvent( Event, 0, FALSE ); 740 741 return STATUS_MORE_PROCESSING_REQUIRED; 742 743 UNREFERENCED_PARAMETER( DeviceObject ); 744 UNREFERENCED_PARAMETER( Contxt ); 745 } 746 747 748