[UDFS]
[reactos.git] / reactos / drivers / filesystems / udfs / pnp.cpp
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 \f
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) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
592 UDFDoDismountSequence(Vcb, Buf, FALSE);
593 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
594 Vcb->WriteSecurity = FALSE;
595
596 UDFReleaseResource(&(Vcb->VCBResource));
597 VcbAcquired = FALSE;
598
599 UDFStopEjectWaiter(Vcb);
600
601 // Now make our dismount happen. This may not vaporize the
602 // Vcb, of course, since there could be any number of handles
603 // outstanding since this is an out of band notification.
604 VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, FALSE );
605
606 try_exit: NOTHING;
607
608 } _SEH2_FINALLY {
609
610 // Release the Vcb if it could still remain.
611 if (!VcbDeleted && VcbAcquired) {
612 UDFReleaseResource(&(Vcb->VCBResource));
613 }
614 UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
615
616 if(Buf)
617 MyFreePool__(Buf);
618
619 if (!_SEH2_AbnormalTermination()) {
620 Irp->IoStatus.Status = RC;
621 // Free up the Irp Context
622 UDFReleaseIrpContext(PtrIrpContext);
623 // complete the IRP
624 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
625 }
626 } _SEH2_END;
627
628 return RC;
629 }
630
631 /*
632 NTSTATUS
633 UDFPnpCancelRemove (
634 PtrUDFIrpContext PtrIrpContext,
635 PIRP Irp,
636 PVCB Vcb
637 )
638
639 */
640 /*++
641
642 Routine Description:
643
644 This routine handles the PnP cancel remove operation. This is our
645 notification that a previously proposed remove (query) was eventually
646 vetoed by a component. The filesystem is responsible for cleaning up
647 and getting ready for more IO.
648
649 Arguments:
650
651 Irp - Supplies the Irp to process
652
653 Vcb - Supplies the volume being removed.
654
655 Return Value:
656
657 NTSTATUS - The return status for the operation
658
659 --*/
660
661 /*{
662 NTSTATUS RC;
663
664 // CANCEL - a previous QUERY has been rescinded as a result
665 // of someone vetoing. Since PnP cannot figure out who may
666 // have gotten the QUERY (think about it: stacked drivers),
667 // we must expect to deal with getting a CANCEL without having
668 // seen the QUERY.
669 //
670 // For UDF, this is quite easy. In fact, we can't get a
671 // CANCEL if the underlying drivers succeeded the QUERY since
672 // we disconnect the Vpb on our dismount initiation. This is
673 // actually pretty important because if PnP could get to us
674 // after the disconnect we'd be thoroughly unsynchronized
675 // with respect to the Vcb getting torn apart - merely referencing
676 // the volume device object is insufficient to keep us intact.
677
678 UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);
679
680 // Unlock the volume. This is benign if we never had seen
681 // a QUERY.
682 if(Vcb->Vpb->Flags & VPB_LOCKED) {
683 Vcb->Vpb->Flags &= ~VPB_LOCKED;
684 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
685 Vcb->VolumeLockFileObject = NULL;
686 RC = STATUS_SUCCESS;
687 } else {
688 RC = STATUS_NOT_LOCKED;
689 }
690
691 try {
692
693 // We must re-enable allocation support if we got through
694 // the first stages of a QUERY_REMOVE; i.e., we decided we
695 // could place a lock on the volume.
696 if (NT_SUCCESS( RC )) {
697 FatSetupAllocationSupport( PtrIrpContext, Vcb );
698 }
699
700 } finally {
701 UDFReleaseResource(&(Vcb->VCBResource));
702 }
703
704 // Send the request. The underlying driver will complete the
705 // IRP. Since we don't need to be in the way, simply ellide
706 // ourselves out of the IRP stack.
707 IoSkipCurrentIrpStackLocation( Irp );
708
709 RC = IoCallDriver(Vcb->TargetDeviceObject, Irp);
710
711 // if (!AbnormalTermination()) {
712 Irp->IoStatus.Status = RC;
713 // Free up the Irp Context
714 UDFReleaseIrpContext(PtrIrpContext);
715 // complete the IRP
716 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
717 // }
718
719 return RC;
720 } */
721
722 \f
723 // Local support routine
724 NTSTATUS
725 NTAPI
726 UDFPnpCompletionRoutine (
727 IN PDEVICE_OBJECT DeviceObject,
728 IN PIRP Irp,
729 IN PVOID Contxt
730 )
731 {
732 PKEVENT Event = (PKEVENT) Contxt;
733
734 KeSetEvent( Event, 0, FALSE );
735
736 return STATUS_MORE_PROCESSING_REQUIRED;
737
738 UNREFERENCED_PARAMETER( DeviceObject );
739 UNREFERENCED_PARAMETER( Contxt );
740 }
741
742