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  Module Name: FsCntrl.cpp
9 
10  Abstract:
11 
12     Contains code to handle the "File System IOCTL" dispatch entry point.
13 
14  Environment:
15 
16     Kernel mode only
17 
18 */
19 
20 #include            "udffs.h"
21 
22 // define the file specific bug-check id
23 #define         UDF_BUG_CHECK_ID    UDF_FILE_FS_CONTROL
24 
25 NTSTATUS UDFBlankMount(IN PVCB Vcb);
26 
27 PDIR_INDEX_HDR UDFDirIndexAlloc(IN uint_di i);
28 
29 /*
30  Function: UDFFSControl()
31 
32  Description:
33     The I/O Manager will invoke this routine to handle a File System
34     Control request (this is IRP_MJ_FILE_SYSTEM_CONTROL dispatch point)
35 
36 */
37 NTSTATUS
38 NTAPI
39 UDFFSControl(
40     PDEVICE_OBJECT      DeviceObject,      // the logical volume device object
41     PIRP                Irp                // I/O Request Packet
42     )
43 {
44     NTSTATUS            RC = STATUS_SUCCESS;
45     PtrUDFIrpContext    PtrIrpContext;
46     BOOLEAN             AreWeTopLevel = FALSE;
47 
48     UDFPrint(("\nUDFFSControl: \n\n"));
49 
50     FsRtlEnterFileSystem();
51     ASSERT(DeviceObject);
52     ASSERT(Irp);
53 
54     // set the top level context
55     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
56 
57     _SEH2_TRY {
58 
59         // get an IRP context structure and issue the request
60         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
61         if(PtrIrpContext) {
62             RC = UDFCommonFSControl(PtrIrpContext, Irp);
63         } else {
64             RC = STATUS_INSUFFICIENT_RESOURCES;
65             Irp->IoStatus.Status = RC;
66             Irp->IoStatus.Information = 0;
67             // complete the IRP
68             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
69         }
70 
71     } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
72 
73         UDFPrintErr(("UDFFSControl: exception ***"));
74         RC = UDFExceptionHandler(PtrIrpContext, Irp);
75 
76         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
77     } _SEH2_END;
78 
79     if(AreWeTopLevel) {
80         IoSetTopLevelIrp(NULL);
81     }
82 
83     FsRtlExitFileSystem();
84 
85     return(RC);
86 } // end UDFFSControl()
87 
88 /*
89  Function: UDFCommonFSControl()
90 
91  Description:
92     The actual work is performed here.
93 
94  Expected Interrupt Level (for execution) :
95   IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
96     to be deferred to a worker thread context)
97 
98  Return Value: STATUS_SUCCESS/Error
99 */
100 
101 NTSTATUS
102 NTAPI
103 UDFCommonFSControl(
104     PtrUDFIrpContext    PtrIrpContext,
105     PIRP                Irp                // I/O Request Packet
106     )
107 {
108     NTSTATUS                RC = STATUS_UNRECOGNIZED_VOLUME;
109     PIO_STACK_LOCATION      IrpSp = NULL;
110 //    PDEVICE_OBJECT          PtrTargetDeviceObject = NULL;
111 
112     UDFPrint(("\nUDFCommonFSControl\n\n"));
113 //    BrutePoint();
114 
115     _SEH2_TRY {
116 
117         IrpSp = IoGetCurrentIrpStackLocation(Irp);
118         ASSERT(IrpSp);
119 
120         switch ((IrpSp)->MinorFunction)
121         {
122         case IRP_MN_USER_FS_REQUEST:
123             UDFPrint(("  UDFFSControl: UserFsReq request ....\n"));
124 
125             RC = UDFUserFsCtrlRequest(PtrIrpContext,Irp);
126             break;
127         case IRP_MN_MOUNT_VOLUME:
128 
129             UDFPrint(("  UDFFSControl: MOUNT_VOLUME request ....\n"));
130 
131             RC = UDFMountVolume(PtrIrpContext,Irp);
132             break;
133         case IRP_MN_VERIFY_VOLUME:
134 
135             UDFPrint(("  UDFFSControl: VERIFY_VOLUME request ....\n"));
136 
137             RC = UDFVerifyVolume(Irp);
138             break;
139         default:
140             UDFPrintErr(("  UDFFSControl: STATUS_INVALID_DEVICE_REQUEST MinorFunction %x\n", (IrpSp)->MinorFunction));
141             RC = STATUS_INVALID_DEVICE_REQUEST;
142 
143             Irp->IoStatus.Status = RC;
144             Irp->IoStatus.Information = 0;
145             // complete the IRP
146             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
147             break;
148         }
149 
150 //try_exit:   NOTHING;
151     } _SEH2_FINALLY {
152         if (!_SEH2_AbnormalTermination()) {
153             // Free up the Irp Context
154             UDFPrint(("  UDFCommonFSControl: finally\n"));
155             UDFReleaseIrpContext(PtrIrpContext);
156         } else {
157             UDFPrint(("  UDFCommonFSControl: finally after exception ***\n"));
158         }
159     } _SEH2_END;
160 
161     return(RC);
162 } // end UDFCommonFSControl()
163 
164 /*
165 Routine Description:
166     This is the common routine for implementing the user's requests made
167     through NtFsControlFile.
168 
169 Arguments:
170     Irp - Supplies the Irp being processed
171 
172 Return Value:
173     NTSTATUS - The return status for the operation
174 
175 */
176 NTSTATUS
177 NTAPI
178 UDFUserFsCtrlRequest(
179     PtrUDFIrpContext IrpContext,
180     PIRP             Irp
181     )
182 {
183     NTSTATUS RC;
184     PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation( Irp );
185 
186     //  Case on the control code.
187     switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) {
188 
189     case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
190     case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
191     case FSCTL_REQUEST_BATCH_OPLOCK :
192     case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE :
193     case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
194     case FSCTL_OPLOCK_BREAK_NOTIFY :
195     case FSCTL_OPLOCK_BREAK_ACK_NO_2 :
196     case FSCTL_REQUEST_FILTER_OPLOCK :
197 
198         UDFPrint(("UDFUserFsCtrlRequest: OPLOCKS\n"));
199         RC = STATUS_INVALID_DEVICE_REQUEST;
200 
201         Irp->IoStatus.Information = 0;
202         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
203         break;
204 /*
205         RC = UDFOplockRequest( IrpContext, Irp );
206         break;
207 */
208     case FSCTL_INVALIDATE_VOLUMES :
209 
210         RC = UDFInvalidateVolumes( IrpContext, Irp );
211         break;
212 /*
213     case FSCTL_MOVE_FILE:
214 
215     case FSCTL_QUERY_ALLOCATED_RANGES:
216     case FSCTL_SET_ZERO_DATA:
217     case FSCTL_SET_SPARSE:
218 
219     case FSCTL_MARK_VOLUME_DIRTY:
220 
221         RC = UDFDirtyVolume( IrpContext, Irp );
222         break;
223 
224   */
225     case FSCTL_IS_VOLUME_DIRTY:
226 
227         RC = UDFIsVolumeDirty(IrpContext, Irp);
228         break;
229 
230     case FSCTL_ALLOW_EXTENDED_DASD_IO:
231 
232         UDFPrint(("UDFUserFsCtrlRequest: FSCTL_ALLOW_EXTENDED_DASD_IO\n"));
233         // DASD i/o is always permitted
234         // So, no-op this call
235         RC = STATUS_SUCCESS;
236 
237         Irp->IoStatus.Information = 0;
238         Irp->IoStatus.Status = STATUS_SUCCESS;
239         break;
240 
241     case FSCTL_DISMOUNT_VOLUME:
242 
243         RC = UDFDismountVolume( IrpContext, Irp );
244         break;
245 
246     case FSCTL_IS_VOLUME_MOUNTED:
247 
248         RC = UDFIsVolumeMounted( IrpContext, Irp );
249         break;
250 
251     case FSCTL_FILESYSTEM_GET_STATISTICS:
252 
253         RC = UDFGetStatistics( IrpContext, Irp );
254         break;
255 
256     case FSCTL_LOCK_VOLUME:
257 
258         RC = UDFLockVolume( IrpContext, Irp );
259         break;
260 
261     case FSCTL_UNLOCK_VOLUME:
262 
263         RC = UDFUnlockVolume( IrpContext, Irp );
264         break;
265 
266     case FSCTL_IS_PATHNAME_VALID:
267 
268         RC = UDFIsPathnameValid( IrpContext, Irp );
269         break;
270 
271     case FSCTL_GET_VOLUME_BITMAP:
272 
273         UDFPrint(("UDFUserFsCtrlRequest: FSCTL_GET_VOLUME_BITMAP\n"));
274         RC = UDFGetVolumeBitmap( IrpContext, Irp );
275         break;
276 
277     case FSCTL_GET_RETRIEVAL_POINTERS:
278 
279         UDFPrint(("UDFUserFsCtrlRequest: FSCTL_GET_RETRIEVAL_POINTERS\n"));
280         RC = UDFGetRetrievalPointers( IrpContext, Irp, 0 );
281         break;
282 
283 
284     //  We don't support any of the known or unknown requests.
285     default:
286 
287         UDFPrintErr(("UDFUserFsCtrlRequest: STATUS_INVALID_DEVICE_REQUEST for %x\n",
288             IrpSp->Parameters.FileSystemControl.FsControlCode));
289         RC = STATUS_INVALID_DEVICE_REQUEST;
290 
291         Irp->IoStatus.Information = 0;
292         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
293         break;
294     }
295 
296     IoCompleteRequest(Irp,IO_DISK_INCREMENT);
297     return RC;
298 
299 } // end UDFUserFsCtrlRequest()
300 
301 
302 /*
303 Routine Description:
304     This is the common routine for implementing the mount requests
305 
306 Arguments:
307     Irp - Supplies the Irp being processed
308 
309 Return Value:
310     NTSTATUS - The return status for the operation
311 
312 */
313 NTSTATUS
314 NTAPI
315 UDFMountVolume(
316     IN PtrUDFIrpContext PtrIrpContext,
317     IN PIRP Irp
318     )
319 {
320     NTSTATUS                RC;
321     PIO_STACK_LOCATION      IrpSp = IoGetCurrentIrpStackLocation(Irp);
322     PDEVICE_OBJECT          TargetDeviceObject = NULL;
323     PFILTER_DEV_EXTENSION   filterDevExt;
324     PDEVICE_OBJECT          fsDeviceObject;
325     PVPB                    Vpb = IrpSp->Parameters.MountVolume.Vpb;
326     PVCB                    Vcb = NULL;
327 //    PVCB                    OldVcb = NULL;
328     PDEVICE_OBJECT          VolDo = NULL;
329     IO_STATUS_BLOCK         Iosb;
330     ULONG                   MediaChangeCount = 0;
331     ULONG                   Characteristics;
332     DEVICE_TYPE             FsDeviceType;
333     BOOLEAN                 RestoreDoVerify = FALSE;
334     BOOLEAN                 WrongMedia = FALSE;
335     BOOLEAN                 RemovableMedia = TRUE;
336     BOOLEAN                 CompleteIrp = FALSE;
337     ULONG                   Mode;
338     TEST_UNIT_READY_USER_OUT TestUnitReadyBuffer;
339     ULONG                   i;
340     LARGE_INTEGER           delay;
341     BOOLEAN                 VcbAcquired = FALSE;
342     BOOLEAN                 DeviceNotTouched = TRUE;
343     BOOLEAN                 Locked = FALSE;
344     int8*                   ioBuf = NULL;
345 
346     ASSERT(IrpSp);
347     UDFPrint(("\n !!! UDFMountVolume\n"));
348 //    UDFPrint(("Build " VER_STR_PRODUCT "\n\n"));
349 
350     fsDeviceObject = PtrIrpContext->TargetDeviceObject;
351     UDFPrint(("Mount on device object %x\n", fsDeviceObject));
352     filterDevExt = (PFILTER_DEV_EXTENSION)fsDeviceObject->DeviceExtension;
353     if (filterDevExt->NodeIdentifier.NodeType == UDF_NODE_TYPE_FILTER_DEVOBJ &&
354         filterDevExt->NodeIdentifier.NodeSize == sizeof(FILTER_DEV_EXTENSION)) {
355         CompleteIrp = FALSE;
356     } else
357     if (filterDevExt->NodeIdentifier.NodeType == UDF_NODE_TYPE_UDFFS_DEVOBJ &&
358         filterDevExt->NodeIdentifier.NodeSize == sizeof(UDFFS_DEV_EXTENSION)) {
359         CompleteIrp = TRUE;
360     } else {
361         UDFPrintErr(("Invalid node type in FS or FILTER DeviceObject\n"));
362         ASSERT(FALSE);
363     }
364     // Get a pointer to the target physical/virtual device object.
365     TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject;
366 
367     if(((Characteristics = TargetDeviceObject->Characteristics) & FILE_FLOPPY_DISKETTE) ||
368        (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_BEING_UNLOADED) ) {
369         WrongMedia = TRUE;
370     } else {
371         RemovableMedia = (Characteristics & FILE_REMOVABLE_MEDIA) ? TRUE : FALSE;
372         if(TargetDeviceObject->DeviceType != FILE_DEVICE_CD_ROM) {
373             if(UDFGetRegParameter(NULL, REG_MOUNT_ON_CDONLY_NAME, TRUE)) {
374                 WrongMedia = TRUE;
375             }
376         }
377         if(TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) {
378             FsDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
379 #ifdef UDF_HDD_SUPPORT
380         } else
381         if (TargetDeviceObject->DeviceType == FILE_DEVICE_DISK) {
382             if(RemovableMedia) {
383                 if(!UDFGetRegParameter(NULL, REG_MOUNT_ON_ZIP_NAME, FALSE)) {
384                     WrongMedia = TRUE;
385                 }
386             } else {
387                 if(!UDFGetRegParameter(NULL, REG_MOUNT_ON_HDD_NAME, FALSE)) {
388                     WrongMedia = TRUE;
389                 }
390             }
391             FsDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
392 #endif //UDF_HDD_SUPPORT
393         } else {
394             WrongMedia = TRUE;
395         }
396     }
397 
398     // Acquire GlobalDataResource
399     UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
400 
401     _SEH2_TRY {
402 
403         UDFScanForDismountedVcb(PtrIrpContext);
404 
405         if(WrongMedia) try_return(RC = STATUS_UNRECOGNIZED_VOLUME);
406 
407         if(RemovableMedia) {
408             UDFPrint(("UDFMountVolume: removable media\n"));
409             // just remember current MediaChangeCount
410             // or fail if No Media ....
411 
412             // experimental CHECK_VERIFY, for fucking BENQ DVD_DD_1620
413 
414                 // Now we can get device state via GET_EVENT (if supported)
415                 // or still one TEST_UNIT_READY command
416                 RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY,
417                                      TargetDeviceObject,
418                                      NULL,0,
419                                      &MediaChangeCount,sizeof(ULONG),
420                                      FALSE,&Iosb );
421 
422             // Send TEST_UNIT_READY comment
423             // This can spin-up or wake-up the device
424             if(UDFGetRegParameter(NULL, UDF_WAIT_CD_SPINUP, TRUE)) {
425                 delay.QuadPart = -15000000LL; // 1.5 sec
426                 for(i=0; i<UDF_READY_MAX_RETRY; i++) {
427                     // Use device default ready timeout
428                     Mode = 0;
429                     RC = UDFPhSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY,
430                                          TargetDeviceObject,
431                                          &Mode,sizeof(Mode),
432                                          &TestUnitReadyBuffer,sizeof(TEST_UNIT_READY_USER_OUT),
433                                          FALSE,NULL);
434                     UDFPrint(("UDFMountVolume: TEST_UNIT_READY %x\n", RC));
435                     if(!NT_SUCCESS(RC))
436                         break;
437                     if(TestUnitReadyBuffer.SenseKey == SCSI_SENSE_NOT_READY &&
438                        TestUnitReadyBuffer.AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY &&
439                        TestUnitReadyBuffer.AdditionalSenseCodeQualifier == SCSI_SENSEQ_BECOMING_READY) {
440                         UDFPrint(("UDFMountVolume: retry\n"));
441                         KeDelayExecutionThread(KernelMode, FALSE, &delay);
442                         //delay.QuadPart -= 10000000LL; // 1.0 sec
443                     } else {
444                         break;
445                     }
446                 }
447                 if(i) {
448                     UDFPrint(("UDFMountVolume: additional delay 3 sec\n"));
449                     delay.QuadPart = -30000000LL; // 3.0 sec
450                     KeDelayExecutionThread(KernelMode, FALSE, &delay);
451                 }
452             }
453 
454             // Now we can get device state via GET_EVENT (if supported)
455             // or still one TEST_UNIT_READY command
456             RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY,
457                                  TargetDeviceObject,
458                                  NULL,0,
459                                  &MediaChangeCount,sizeof(ULONG),
460                                  FALSE,&Iosb );
461 
462             if(RC == STATUS_IO_DEVICE_ERROR) {
463                 UDFPrint(("UDFMountVolume: retry check verify\n"));
464                 RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY,
465                                      TargetDeviceObject,
466                                      NULL,0,
467                                      &MediaChangeCount,sizeof(ULONG),
468                                      FALSE,&Iosb );
469             }
470 
471             if(!NT_SUCCESS(RC) && (RC != STATUS_VERIFY_REQUIRED))
472                 try_return(RC);
473 
474             //  Be safe about the count in case the driver didn't fill it in
475             if(Iosb.Information != sizeof(ULONG)) {
476                 MediaChangeCount = 0;
477             }
478 
479             if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
480                 // Check if device is busy before locking tray and performing
481                 // further geomentry discovery. This is needed to avoid streaming
482                 // loss during CD-R recording. Note, that some recording tools
483                 // work with device via SPTI bypassing FS/Device driver layers.
484 
485                 ioBuf = (int8*)MyAllocatePool__(NonPagedPool,4096);
486                 if(!ioBuf) {
487                     try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
488                 }
489                 RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY,TargetDeviceObject,
490                     ioBuf,sizeof(DISK_GEOMETRY),
491                     ioBuf,sizeof(DISK_GEOMETRY),
492                     FALSE, NULL );
493 
494                 if(RC == STATUS_DEVICE_NOT_READY) {
495                     // probably, the device is really busy, may be by CD/DVD recording
496                     UserPrint(("  busy (*)\n"));
497                     try_return(RC);
498                 }
499             }
500 
501             // lock media for now
502             if(!WrongMedia) {
503                 ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = TRUE;
504                 RC = UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
505                                      TargetDeviceObject,
506                                      &MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
507                                      NULL,0,
508                                      FALSE,NULL);
509                 Locked = TRUE;
510             }
511 
512         }
513         // Now before we can initialize the Vcb we need to set up the
514         // Get our device object and alignment requirement.
515         // Device extension == VCB
516         UDFPrint(("UDFMountVolume: create device\n"));
517         RC = IoCreateDevice( UDFGlobalData.DriverObject,
518                                  sizeof(VCB),
519                                  NULL,
520                                  FsDeviceType,
521                                  0,
522                                  FALSE,
523                                  &VolDo );
524 
525         if(!NT_SUCCESS(RC)) try_return(RC);
526 
527         // Our alignment requirement is the larger of the processor alignment requirement
528         // already in the volume device object and that in the DeviceObjectWeTalkTo
529         if(TargetDeviceObject->AlignmentRequirement > VolDo->AlignmentRequirement) {
530             VolDo->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
531         }
532 
533         VolDo->Flags &= ~DO_DEVICE_INITIALIZING;
534 
535         // device object field in the VPB to point to our new volume device
536         // object.
537         Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo;
538 
539         // We must initialize the stack size in our device object before
540         // the following reads, because the I/O system has not done it yet.
541         ((PDEVICE_OBJECT)VolDo)->StackSize = (CCHAR) (TargetDeviceObject->StackSize + 1);
542 
543         Vcb = (PVCB)VolDo->DeviceExtension;
544 
545         // Initialize the Vcb.  This routine will raise on an allocation
546         // failure.
547         RC = UDFInitializeVCB(VolDo,TargetDeviceObject,Vpb);
548         if(!NT_SUCCESS(RC)) {
549             Vcb = NULL;
550             try_return(RC);
551         }
552 
553         VolDo = NULL;
554         Vpb = NULL;
555 
556         UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
557         VcbAcquired = TRUE;
558 
559         // Let's reference the Vpb to make sure we are the one to
560         // have the last dereference.
561         Vcb->Vpb->ReferenceCount ++;
562 
563         Vcb->MediaChangeCount = MediaChangeCount;
564         Vcb->FsDeviceType = FsDeviceType;
565 
566         // Clear the verify bit for the start of mount.
567         if(Vcb->Vpb->RealDevice->Flags & DO_VERIFY_VOLUME) {
568             Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
569             RestoreDoVerify = TRUE;
570         }
571 
572         DeviceNotTouched = FALSE;
573         RC = UDFGetDiskInfo(TargetDeviceObject,Vcb);
574         if(!NT_SUCCESS(RC)) try_return(RC);
575 
576         //     ****  Read registry settings  ****
577         UDFReadRegKeys(Vcb, FALSE, FALSE);
578 
579         Vcb->MountPhErrorCount = 0;
580 
581         // Initialize internal cache
582         Mode = WCACHE_MODE_ROM;
583         RC = WCacheInit__(&(Vcb->FastCache),
584                           Vcb->WCacheMaxFrames,
585                           Vcb->WCacheMaxBlocks,
586                           Vcb->WriteBlockSize,
587                           5, Vcb->BlockSizeBits,
588                           Vcb->WCacheBlocksPerFrameSh,
589                           0/*Vcb->FirstLBA*/, Vcb->LastPossibleLBA, Mode,
590                               0/*WCACHE_CACHE_WHOLE_PACKET*/ |
591                               (Vcb->DoNotCompareBeforeWrite ? WCACHE_DO_NOT_COMPARE : 0) |
592                               (Vcb->CacheChainedIo ? WCACHE_CHAINED_IO : 0) |
593                               WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS,  // this will be cleared after mount
594                           Vcb->WCacheFramesToKeepFree,
595 //                          UDFTWrite, UDFTRead,
596                           UDFTWriteVerify, UDFTReadVerify,
597 #ifdef UDF_ASYNC_IO
598                           UDFTWriteAsync, UDFTReadAsync,
599 #else  //UDF_ASYNC_IO
600                           NULL, NULL,
601 #endif //UDF_ASYNC_IO
602                           UDFIsBlockAllocated,
603                           UDFUpdateVAT,
604                           UDFWCacheErrorHandler);
605         if(!NT_SUCCESS(RC)) try_return(RC);
606 
607         RC = UDFVInit(Vcb);
608         if(!NT_SUCCESS(RC)) try_return(RC);
609 
610         UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
611         RC = UDFGetDiskInfoAndVerify(TargetDeviceObject,Vcb);
612         UDFReleaseResource(&(Vcb->BitMapResource1));
613 
614         ASSERT(!Vcb->Modified);
615         WCacheChFlags__(&(Vcb->FastCache),
616                         WCACHE_CACHE_WHOLE_PACKET, // enable cache whole packet
617                         WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS);  // let user retry request on Bad Blocks
618 
619 #ifdef UDF_READ_ONLY_BUILD
620         Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
621         Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY;
622 #endif //UDF_READ_ONLY_BUILD
623 
624         if(!NT_SUCCESS(RC)) {
625             UDFPrint(("UDFMountVolume: try raw mount\n"));
626             if(Vcb->NSRDesc & VRS_ISO9660_FOUND) {
627                 UDFPrint(("UDFMountVolume: block raw mount due to ISO9660 presence\n"));
628                 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
629                 try_return(RC);
630             }
631 try_raw_mount:
632             UDFPrint(("UDFMountVolume: try raw mount (2)\n"));
633             if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
634 
635                 UDFPrint(("UDFMountVolume: trying raw mount...\n"));
636                 Vcb->VolIdent.Length =
637                 (Vcb->VolIdent.MaximumLength = sizeof(UDF_BLANK_VOLUME_LABEL)) - 2;
638                 if(Vcb->VolIdent.Buffer)
639                     MyFreePool__(Vcb->VolIdent.Buffer);
640                 Vcb->VolIdent.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, sizeof(UDF_BLANK_VOLUME_LABEL));
641                 if(!Vcb->VolIdent.Buffer)
642                     try_return(STATUS_INSUFFICIENT_RESOURCES);
643                 RtlCopyMemory(Vcb->VolIdent.Buffer, UDF_BLANK_VOLUME_LABEL, sizeof(UDF_BLANK_VOLUME_LABEL));
644 
645                 RC = UDFBlankMount(Vcb);
646                 if(!NT_SUCCESS(RC)) try_return(RC);
647 
648             } else {
649 //                Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
650                 try_return(RC);
651             }
652         } else {
653             Vcb->MountPhErrorCount = -1;
654 #ifndef UDF_READ_ONLY_BUILD
655             // set cache mode according to media type
656             if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) {
657                 UDFPrint(("UDFMountVolume: writable volume\n"));
658                 if(!Vcb->CDR_Mode) {
659                     if((FsDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
660                        CdrwMediaClassEx_IsRAM(Vcb->MediaClassEx)) {
661                         UDFPrint(("UDFMountVolume: RAM mode\n"));
662                         Mode = WCACHE_MODE_RAM;
663                     } else {
664                         UDFPrint(("UDFMountVolume: RW mode\n"));
665                         Mode = WCACHE_MODE_RW;
666                     }
667 /*                    if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
668                     } else {
669                         Vcb->WriteSecurity = TRUE;
670                     }*/
671                 } else {
672                     UDFPrint(("UDFMountVolume: R mode\n"));
673                     Mode = WCACHE_MODE_R;
674                 }
675                 // we can't record ACL on old format disks
676                 if(!UDFNtAclSupported(Vcb)) {
677                     UDFPrint(("UDFMountVolume: NO ACL and ExtFE support\n"));
678                     Vcb->WriteSecurity = FALSE;
679                     Vcb->UseExtendedFE = FALSE;
680                 }
681             }
682             WCacheSetMode__(&(Vcb->FastCache), Mode);
683 #endif //UDF_READ_ONLY_BUILD
684             // Complete mount operations: create root FCB
685             UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
686             RC = UDFCompleteMount(Vcb);
687             UDFReleaseResource(&(Vcb->BitMapResource1));
688             if(!NT_SUCCESS(RC)) {
689                 // We must have Vcb->VCBOpenCount = 1 for UDFBlankMount()
690                 // Thus, we should not decrement it here
691                 // Also, if we shall not perform BlankMount,
692                 // but simply cleanup and return error, Vcb->VCBOpenCount
693                 // will be decremented during cleanup. Thus anyway it must
694                 // stay 1 unchanged here
695                 //UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
696                 UDFCloseResidual(Vcb);
697                 Vcb->VCBOpenCount = 1;
698                 if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)
699                     Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
700                 goto try_raw_mount;
701             }
702             Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
703         }
704 
705 #ifndef UDF_READ_ONLY_BUILD
706         if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) {
707             RC = UDFStartEjectWaiter(Vcb);
708             if(!NT_SUCCESS(RC)) try_return(RC);
709         } else {
710             UDFPrint(("UDFMountVolume: RO mount\n"));
711             Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
712         }
713 #endif //UDF_READ_ONLY_BUILD
714 
715         Vcb->Vpb->SerialNumber = Vcb->PhSerialNumber;
716         Vcb->Vpb->VolumeLabelLength = Vcb->VolIdent.Length;
717         RtlCopyMemory( Vcb->Vpb->VolumeLabel,
718                        Vcb->VolIdent.Buffer,
719                        Vcb->VolIdent.Length );
720 
721         Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_MOUNTED;
722 
723         UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
724         Vcb->TotalAllocUnits = UDFGetTotalSpace(Vcb);
725         Vcb->FreeAllocUnits = UDFGetFreeSpace(Vcb);
726         // Register shutdown routine
727         if(!Vcb->ShutdownRegistered) {
728             UDFPrint(("UDFMountVolume: Register shutdown routine\n"));
729             IoRegisterShutdownNotification(Vcb->VCBDeviceObject);
730             Vcb->ShutdownRegistered = TRUE;
731         }
732 
733         // unlock media
734         if(RemovableMedia) {
735             if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) {
736                 UDFPrint(("UDFMountVolume: unlock media on RO volume\n"));
737                 ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = FALSE;
738                 UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
739                                      TargetDeviceObject,
740                                      &MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
741                                      NULL,0,
742                                      FALSE,NULL);
743                 if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)
744                     UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
745             }
746         }
747 
748         if (UDFGlobalData.MountEvent)
749         {
750             Vcb->IsVolumeJustMounted = TRUE;
751             KeSetEvent(UDFGlobalData.MountEvent, 0, FALSE);
752         }
753 
754         //  The new mount is complete.
755         UDFReleaseResource( &(Vcb->VCBResource) );
756         VcbAcquired = FALSE;
757         Vcb = NULL;
758 
759         RC = STATUS_SUCCESS;
760 
761 try_exit: NOTHING;
762     } _SEH2_FINALLY {
763 
764         UDFPrint(("UDFMountVolume: RC = %x\n", RC));
765 
766         if(ioBuf) {
767             MyFreePool__(ioBuf);
768         }
769 
770         if(!NT_SUCCESS(RC)) {
771 
772             if(RemovableMedia && Locked) {
773                 UDFPrint(("UDFMountVolume: unlock media\n"));
774                 ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = FALSE;
775                 UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
776                                      TargetDeviceObject,
777                                      &MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
778                                      NULL,0,
779                                      FALSE,NULL);
780             }
781 /*            if((RC != STATUS_DEVICE_NOT_READY) &&
782                (RC != STATUS_NO_MEDIA_IN_DEVICE) ) {*/
783                 // reset driver
784             if(!DeviceNotTouched &&
785                (!Vcb || (Vcb && (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)))) {
786                 UDFPrint(("UDFMountVolume: reset driver\n"));
787                 UDFResetDeviceDriver(Vcb, TargetDeviceObject, TRUE);
788             }
789 
790             if(RC == STATUS_CRC_ERROR || RC == STATUS_FILE_CORRUPT_ERROR) {
791                 UDFPrint(("UDFMountVolume: status -> STATUS_UNRECOGNIZED_VOLUME\n"));
792                 RC = STATUS_UNRECOGNIZED_VOLUME;
793             }
794 
795             // If we didn't complete the mount then cleanup any remaining structures.
796             if(Vpb) {
797                Vpb->DeviceObject = NULL;
798             }
799 
800             if(Vcb) {
801                 // Restore the verify bit.
802                 if(RestoreDoVerify) {
803                     Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
804                 }
805                 // Make sure there is no Vcb since it could go away
806                 if(Vcb->VCBOpenCount)
807                     UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
808                 // This procedure will also delete the volume device object
809                 if(UDFDismountVcb( Vcb, VcbAcquired )) {
810                     UDFReleaseResource( &(Vcb->VCBResource) );
811                 }
812             } else if(VolDo) {
813                 IoDeleteDevice( VolDo );
814             }
815         }
816         // Release the global resource.
817         UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
818 
819         if (CompleteIrp || NT_SUCCESS(RC)) {
820             if(!_SEH2_AbnormalTermination()) {
821                 // Set mount event
822 
823                 UDFPrint(("UDFMountVolume: complete req RC %x\n", RC));
824                 UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_MOUNT);
825                 // Complete the IRP.
826                 Irp->IoStatus.Status = RC;
827                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
828             }
829         } else {
830             // Pass Irp to lower driver (CDFS)
831 
832             // Get this driver out of the driver stack and get to the next driver as
833             // quickly as possible.
834             Irp->CurrentLocation++;
835             Irp->Tail.Overlay.CurrentStackLocation++;
836 
837             // Now call the appropriate file system driver with the request.
838             RC = IoCallDriver( filterDevExt->lowerFSDeviceObject, Irp );
839 
840         }
841 
842     } _SEH2_END;
843 
844     UDFPrint(("UDFMountVolume: final RC = %x\n", RC));
845     return RC;
846 
847 } // end UDFMountVolume()
848 
849 NTSTATUS
850 UDFStartEjectWaiter(
851     IN PVCB    Vcb
852     )
853 {
854 //    NTSTATUS RC;
855     PREVENT_MEDIA_REMOVAL_USER_IN Buff;
856     UDFPrint(("UDFStartEjectWaiter:\n"));
857 
858     if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) {
859         UDFPrint(("  UDF_VCB_FLAGS_MEDIA_READ_ONLY\n"));
860     }
861     if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) {
862         UDFPrint(("  UDF_VCB_FLAGS_MEDIA_LOCKED\n"));
863     }
864     UDFPrint(("  EjectWaiter=%x\n", Vcb->EjectWaiter));
865     if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) &&
866        /*!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) &&*/
867        !(Vcb->EjectWaiter)) {
868 
869         UDFPrint(("UDFStartEjectWaiter: check driver\n"));
870         if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) &&
871             (Vcb->FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)) {
872             // we don't know how to write without our device driver
873             Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
874             UDFPrint(("  not our driver, ignore\n"));
875             return STATUS_SUCCESS;
876         }
877         UDFPrint(("UDFStartEjectWaiter: check removable\n"));
878         if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) {
879             // prevent media removal
880             UDFPrint(("UDFStartEjectWaiter: lock media\n"));
881             Buff.PreventMediaRemoval = TRUE;
882             UDFTSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
883                            Vcb,
884                            &Buff,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
885                            NULL,0,
886                            FALSE,NULL );
887             Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_LOCKED;
888         }
889         UDFPrint(("UDFStartEjectWaiter: prepare to start\n"));
890         // initialize Eject Request waiter
891         Vcb->EjectWaiter = (PUDFEjectWaitContext)MyAllocatePool__(NonPagedPool, sizeof(UDFEjectWaitContext));
892         if(!(Vcb->EjectWaiter)) return STATUS_INSUFFICIENT_RESOURCES;
893         KeInitializeEvent(&(Vcb->WaiterStopped), NotificationEvent, FALSE);
894         Vcb->EjectWaiter->Vcb = Vcb;
895         Vcb->EjectWaiter->SoftEjectReq = FALSE;
896         KeInitializeEvent(&(Vcb->EjectWaiter->StopReq), NotificationEvent, FALSE);
897 //        Vcb->EjectWaiter->StopReq = FALSE;
898         Vcb->EjectWaiter->WaiterStopped = &(Vcb->WaiterStopped);
899         // This can occure after unexpected media loss, when EjectRequestWaiter
900         // terminates automatically
901         ASSERT(!(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT));
902         Vcb->VCBFlags |= UDF_VCB_FLAGS_STOP_WAITER_EVENT;
903         ExInitializeWorkItem(&(Vcb->EjectWaiter->EjectReqWorkQueueItem), UDFEjectReqWaiter, Vcb->EjectWaiter);
904         UDFPrint(("UDFStartEjectWaiter: create thread\n"));
905         ExQueueWorkItem(&(Vcb->EjectWaiter->EjectReqWorkQueueItem), DelayedWorkQueue);
906     } else {
907         UDFPrint(("  ignore\n"));
908     }
909     return STATUS_SUCCESS;
910 } // end UDFStartEjectWaiter()
911 
912 NTSTATUS
913 UDFCompleteMount(
914     IN PVCB    Vcb
915     )
916 {
917     NTSTATUS                    RC;// = STATUS_SUCCESS;
918     PtrUDFNTRequiredFCB         NtReqFcb = NULL;
919     PFSRTL_COMMON_FCB_HEADER    PtrCommonFCBHeader = NULL;
920     UNICODE_STRING              LocalPath;
921     PtrUDFObjectName            RootName;
922     PtrUDFFCB                   RootFcb;
923 
924     UDFPrint(("UDFCompleteMount:\n"));
925     Vcb->ZBuffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, max(Vcb->LBlockSize, PAGE_SIZE), 'zNWD');
926     if(!Vcb->ZBuffer) return STATUS_INSUFFICIENT_RESOURCES;
927     RtlZeroMemory(Vcb->ZBuffer, Vcb->LBlockSize);
928 
929     UDFPrint(("UDFCompleteMount: alloc Root FCB\n"));
930     // Create the root index and reference it in the Vcb.
931     RootFcb =
932     Vcb->RootDirFCB = UDFAllocateFCB();
933     if(!RootFcb) return STATUS_INSUFFICIENT_RESOURCES;
934 
935     UDFPrint(("UDFCompleteMount: alloc Root ObjName\n"));
936     // Allocate and set root FCB unique name
937     RootName = UDFAllocateObjectName();
938     if(!RootName) {
939         UDFCleanUpFCB(RootFcb);
940         Vcb->RootDirFCB = NULL;
941         return STATUS_INSUFFICIENT_RESOURCES;
942     }
943     RC = MyInitUnicodeString(&(RootName->ObjectName),UDF_ROOTDIR_NAME);
944     if(!NT_SUCCESS(RC))
945         goto insuf_res_1;
946 
947     RootFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO));
948     if(!RootFcb->FileInfo) {
949         RC = STATUS_INSUFFICIENT_RESOURCES;
950 insuf_res_1:
951         MyFreePool__(RootName->ObjectName.Buffer);
952         UDFReleaseObjectName(RootName);
953         UDFCleanUpFCB(RootFcb);
954         Vcb->RootDirFCB = NULL;
955         return RC;
956     }
957     UDFPrint(("UDFCompleteMount: open Root Dir\n"));
958     // Open Root Directory
959     RC = UDFOpenRootFile__( Vcb, &(Vcb->RootLbAddr), RootFcb->FileInfo );
960     if(!NT_SUCCESS(RC)) {
961 insuf_res_2:
962         UDFCleanUpFile__(Vcb, RootFcb->FileInfo);
963         MyFreePool__(RootFcb->FileInfo);
964         goto insuf_res_1;
965     }
966     RootFcb->FileInfo->Fcb = RootFcb;
967 
968     if(!(RootFcb->NTRequiredFCB = RootFcb->FileInfo->Dloc->CommonFcb)) {
969         UDFPrint(("UDFCompleteMount: alloc Root ObjName (2)\n"));
970         if(!(RootFcb->NTRequiredFCB =
971                     (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))) ) ) {
972             RC = STATUS_INSUFFICIENT_RESOURCES;
973             goto insuf_res_2;
974         }
975         RtlZeroMemory(RootFcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
976         RootFcb->FileInfo->Dloc->CommonFcb = RootFcb->NTRequiredFCB;
977     }
978     UDFPrint(("UDFCompleteMount: init FCB\n"));
979     RC = UDFInitializeFCB(RootFcb,Vcb,RootName,UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY,NULL);
980     if(!NT_SUCCESS(RC)) {
981         // if we get here, no resources are inited
982         RootFcb->OpenHandleCount =
983         RootFcb->ReferenceCount  =
984         RootFcb->NTRequiredFCB->CommonRefCount = 0;
985 
986         UDFCleanUpFile__(Vcb, RootFcb->FileInfo);
987         MyFreePool__(RootFcb->FileInfo);
988         MyFreePool__(RootFcb->NTRequiredFCB);
989         UDFCleanUpFCB(RootFcb);
990         Vcb->RootDirFCB = NULL;
991         return RC;
992     }
993 
994     // this is a part of UDF_RESIDUAL_REFERENCE
995     UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
996     RootFcb->OpenHandleCount =
997     RootFcb->ReferenceCount  =
998     RootFcb->NTRequiredFCB->CommonRefCount = 1;
999 
1000     UDFGetFileXTime(RootFcb->FileInfo,
1001                   &(RootFcb->NTRequiredFCB->CreationTime.QuadPart),
1002                   &(RootFcb->NTRequiredFCB->LastAccessTime.QuadPart),
1003                   &(RootFcb->NTRequiredFCB->ChangeTime.QuadPart),
1004                   &(RootFcb->NTRequiredFCB->LastWriteTime.QuadPart) );
1005 
1006     if(Vcb->SysStreamLbAddr.logicalBlockNum) {
1007         Vcb->SysSDirFileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO));
1008         if(!Vcb->SysSDirFileInfo) {
1009             RC = STATUS_INSUFFICIENT_RESOURCES;
1010             goto unwind_1;
1011         }
1012         // Open System SDir Directory
1013         RC = UDFOpenRootFile__( Vcb, &(Vcb->SysStreamLbAddr), Vcb->SysSDirFileInfo );
1014         if(!NT_SUCCESS(RC)) {
1015             UDFCleanUpFile__(Vcb, Vcb->SysSDirFileInfo);
1016             MyFreePool__(Vcb->SysSDirFileInfo);
1017             Vcb->SysSDirFileInfo = NULL;
1018             goto unwind_1;
1019         } else {
1020             Vcb->SysSDirFileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY;
1021         }
1022     }
1023 
1024     // Open Unallocatable space stream
1025     // Generally, it should be placed in SystemStreamDirectory, but some
1026     // stupid apps think that RootDirectory is much better place.... :((
1027     RC = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE);
1028     if(NT_SUCCESS(RC)) {
1029         RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL);
1030         MyFreePool__(LocalPath.Buffer);
1031     }
1032     if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
1033 
1034 //unwind_2:
1035         UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo);
1036         Vcb->NonAllocFileInfo = NULL;
1037         // this was a part of UDF_RESIDUAL_REFERENCE
1038         UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
1039 unwind_1:
1040 
1041         // UDFCloseResidual() will clean up everything
1042 
1043         return RC;
1044     }
1045 
1046     /* process Non-allocatable */
1047     if(NT_SUCCESS(RC)) {
1048         UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used
1049         UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
1050     } else {
1051         /* try to read Non-allocatable from alternate locations */
1052         RC = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE_2);
1053         if(!NT_SUCCESS(RC)) {
1054             goto unwind_1;
1055         }
1056         RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL);
1057         MyFreePool__(LocalPath.Buffer);
1058         if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
1059             goto unwind_1;
1060         }
1061         if(NT_SUCCESS(RC)) {
1062             UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used
1063             UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
1064         } else
1065         if(Vcb->SysSDirFileInfo) {
1066             RC = MyInitUnicodeString(&LocalPath, UDF_SN_NON_ALLOCATABLE);
1067             if(!NT_SUCCESS(RC)) {
1068                 goto unwind_1;
1069             }
1070             RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->NonAllocFileInfo), NULL);
1071             MyFreePool__(LocalPath.Buffer);
1072             if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
1073                 goto unwind_1;
1074             }
1075             if(NT_SUCCESS(RC)) {
1076                 UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used
1077 //                    UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
1078             } else {
1079                 RC = STATUS_SUCCESS;
1080             }
1081         } else {
1082             RC = STATUS_SUCCESS;
1083         }
1084     }
1085 
1086     /* Read SN UID mapping */
1087     if(Vcb->SysSDirFileInfo) {
1088         RC = MyInitUnicodeString(&LocalPath, UDF_SN_UID_MAPPING);
1089         if(!NT_SUCCESS(RC))
1090             goto unwind_3;
1091         RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->UniqueIDMapFileInfo), NULL);
1092         MyFreePool__(LocalPath.Buffer);
1093         if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
1094 unwind_3:
1095 //            UDFCloseFile__(Vcb, Vcb->NonAllocFileInfo);
1096 //            UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo);
1097 //            if(Vcb->NonAllocFileInfo)
1098 //                MyFreePool__(Vcb->NonAllocFileInfo);
1099 //            Vcb->NonAllocFileInfo = NULL;
1100             goto unwind_1;
1101         } else {
1102             Vcb->UniqueIDMapFileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY;
1103         }
1104         RC = STATUS_SUCCESS;
1105     }
1106 
1107 #define DWN_MAX_CFG_FILE_SIZE  0x10000
1108 
1109     /* Read DWN config file from disk with disk-specific options */
1110     RC = MyInitUnicodeString(&LocalPath, UDF_CONFIG_STREAM_NAME_W);
1111     if(NT_SUCCESS(RC)) {
1112 
1113         int8* buff;
1114         SIZE_T len;
1115         PUDF_FILE_INFO CfgFileInfo = NULL;
1116 
1117         RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &CfgFileInfo, NULL);
1118         if(OS_SUCCESS(RC)) {
1119 
1120             len = (ULONG)UDFGetFileSize(CfgFileInfo);
1121             if(len && len < DWN_MAX_CFG_FILE_SIZE) {
1122                 buff = (int8*)MyAllocatePool__(NonPagedPool, len);
1123                 if(buff) {
1124                     RC = UDFReadFile__(Vcb, CfgFileInfo, 0, len, FALSE, buff, &len);
1125                     if(OS_SUCCESS(RC)) {
1126                         // parse config
1127                         Vcb->Cfg = (PUCHAR)buff;
1128                         Vcb->CfgLength = len;
1129                         UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE /*cfg*/);
1130                         Vcb->Cfg = NULL;
1131                         Vcb->CfgLength = 0;
1132                         Vcb->CfgVersion = 0;
1133                     }
1134                     MyFreePool__(buff);
1135                 }
1136             }
1137 
1138             UDFCloseFile__(Vcb, CfgFileInfo);
1139         }
1140         if(CfgFileInfo) {
1141             UDFCleanUpFile__(Vcb, CfgFileInfo);
1142         }
1143         MyFreePool__(LocalPath.Buffer);
1144     }
1145     RC = STATUS_SUCCESS;
1146 
1147     // clear Modified flags. It was not real modify, just
1148     // bitmap construction
1149     Vcb->BitmapModified = FALSE;
1150     //Vcb->Modified = FALSE;
1151     UDFPreClrModified(Vcb);
1152     UDFClrModified(Vcb);
1153     // this is a part of UDF_RESIDUAL_REFERENCE
1154     UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
1155 
1156     NtReqFcb = RootFcb->NTRequiredFCB;
1157 
1158     // Start initializing the fields contained in the CommonFCBHeader.
1159     PtrCommonFCBHeader = &(NtReqFcb->CommonFCBHeader);
1160 
1161     // DisAllow fast-IO for now.
1162 //    PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible;
1163     PtrCommonFCBHeader->IsFastIoPossible = FastIoIsPossible;
1164 
1165     // Initialize the MainResource and PagingIoResource pointers in
1166     // the CommonFCBHeader structure to point to the ERESOURCE structures we
1167     // have allocated and already initialized above.
1168 //    PtrCommonFCBHeader->Resource = &(NtReqFcb->MainResource);
1169 //    PtrCommonFCBHeader->PagingIoResource = &(NtReqFcb->PagingIoResource);
1170 
1171     // Initialize the file size values here.
1172     PtrCommonFCBHeader->AllocationSize.QuadPart = 0;
1173     PtrCommonFCBHeader->FileSize.QuadPart = 0;
1174 
1175     // The following will disable ValidDataLength support.
1176 //    PtrCommonFCBHeader->ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFI64;
1177     PtrCommonFCBHeader->ValidDataLength.QuadPart = 0;
1178 
1179     if(!NT_SUCCESS(RC))
1180         return RC;
1181     UDFAssignAcl(Vcb, NULL, RootFcb, NtReqFcb);
1182 /*
1183     Vcb->CDBurnerVolumeValid = true;
1184 
1185     len =
1186     Vcb->CDBurnerVolume.Length = 256;
1187     Vcb->CDBurnerVolume.MaximumLength = 256;
1188     Vcb->CDBurnerVolume.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, 256);
1189     RC = RegTGetStringValue(NULL, REG_CD_BURNER_KEY_NAME, REG_CD_BURNER_VOLUME_NAME, Vcb->CDBurnerVolume.Buffer,
1190         len);
1191     Vcb->CDBurnerVolume.Length = (USHORT)(wcslen(Vcb->CDBurnerVolume.Buffer)*sizeof(WCHAR));
1192 
1193     if(RC != STATUS_OBJECT_NAME_NOT_FOUND && !NT_SUCCESS(RC) )
1194         return RC;
1195 
1196     if (NT_SUCCESS(RC)) {
1197         RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
1198                               REG_CD_BURNER_KEY_NAME, REG_CD_BURNER_VOLUME_NAME,
1199                               REG_SZ,L"",sizeof(L"")+1);
1200 
1201     } else {
1202         Vcb->CDBurnerVolumeValid = false;
1203         RC = STATUS_SUCCESS;
1204     }
1205 */
1206     ASSERT(!Vcb->Modified);
1207 
1208     return RC;
1209 } // end UDFCompleteMount()
1210 
1211 NTSTATUS
1212 UDFBlankMount(
1213     IN PVCB    Vcb
1214     )
1215 {
1216     NTSTATUS                    RC;// = STATUS_SUCCESS;
1217     PtrUDFNTRequiredFCB         NtReqFcb = NULL;
1218     PFSRTL_COMMON_FCB_HEADER    PtrCommonFCBHeader = NULL;
1219     PtrUDFObjectName            RootName;
1220     PtrUDFFCB                   RootFcb;
1221     PDIR_INDEX_HDR hDirNdx;
1222     PDIR_INDEX_ITEM DirNdx;
1223 
1224     // Create the root index and reference it in the Vcb.
1225     RootFcb =
1226     Vcb->RootDirFCB = UDFAllocateFCB();
1227     if(!RootFcb) return STATUS_INSUFFICIENT_RESOURCES;
1228     RtlZeroMemory(RootFcb,sizeof(UDFFCB));
1229 
1230     // Allocate and set root FCB unique name
1231     RootName = UDFAllocateObjectName();
1232     if(!RootName) {
1233 //bl_unwind_2:
1234         UDFCleanUpFCB(RootFcb);
1235         Vcb->RootDirFCB = NULL;
1236         return STATUS_INSUFFICIENT_RESOURCES;
1237     }
1238     RC = MyInitUnicodeString(&(RootName->ObjectName),UDF_ROOTDIR_NAME);
1239     if(!NT_SUCCESS(RC))
1240         goto bl_unwind_1;
1241 
1242     RootFcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_FCB;
1243     RootFcb->NodeIdentifier.NodeSize = sizeof(UDFFCB);
1244 
1245     RootFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO));
1246     if(!RootFcb->FileInfo) {
1247         MyFreePool__(RootName->ObjectName.Buffer);
1248         RC = STATUS_INSUFFICIENT_RESOURCES;
1249 bl_unwind_1:
1250         UDFReleaseObjectName(RootName);
1251         UDFCleanUpFCB(RootFcb);
1252         Vcb->RootDirFCB = NULL;
1253         return RC;
1254     }
1255     RtlZeroMemory(RootFcb->FileInfo, sizeof(UDF_FILE_INFO));
1256     if(!OS_SUCCESS(RC = UDFStoreDloc(Vcb, RootFcb->FileInfo, 1))) {
1257         MyFreePool__(RootFcb->FileInfo);
1258         RootFcb->FileInfo = NULL;
1259         MyFreePool__(RootName->ObjectName.Buffer);
1260         goto  bl_unwind_1;
1261     }
1262     RootFcb->FileInfo->NextLinkedFile =
1263     RootFcb->FileInfo->PrevLinkedFile = RootFcb->FileInfo;
1264 
1265     hDirNdx = UDFDirIndexAlloc(2);
1266     DirNdx = UDFDirIndex(hDirNdx,0);
1267     DirNdx->FileCharacteristics = FILE_DIRECTORY;
1268     DirNdx->FI_Flags = UDF_FI_FLAG_SYS_ATTR;
1269     DirNdx->SysAttr = FILE_ATTRIBUTE_READONLY;
1270     RtlInitUnicodeString(&DirNdx->FName, L".");
1271     DirNdx->FileInfo = RootFcb->FileInfo;
1272     DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL | HASH_KEEP_NAME);
1273 
1274     DirNdx = UDFDirIndex(hDirNdx,1);
1275     DirNdx->FI_Flags = UDF_FI_FLAG_SYS_ATTR;
1276     if(Vcb->ShowBlankCd == 2) {
1277         DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
1278     }
1279     DirNdx->SysAttr = FILE_ATTRIBUTE_READONLY;
1280     RtlInitUnicodeString(&DirNdx->FName, L"Blank.CD");
1281     DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL);
1282 
1283     RootFcb->FileInfo->Dloc->DirIndex = hDirNdx;
1284     RootFcb->FileInfo->Fcb = RootFcb;
1285 
1286     if(!(RootFcb->NTRequiredFCB = RootFcb->FileInfo->Dloc->CommonFcb)) {
1287         if(!(RootFcb->NTRequiredFCB =
1288                     (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))) ) ) {
1289             MyFreePool__(RootName->ObjectName.Buffer);
1290             UDFReleaseObjectName(RootName);
1291             UDFCleanUpFCB(RootFcb);
1292             Vcb->RootDirFCB = NULL;
1293             return STATUS_INSUFFICIENT_RESOURCES;
1294         }
1295         RtlZeroMemory(RootFcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
1296         RootFcb->FileInfo->Dloc->CommonFcb = RootFcb->NTRequiredFCB;
1297     }
1298     RC = UDFInitializeFCB(RootFcb,Vcb,RootName,UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY,NULL);
1299     if(!NT_SUCCESS(RC)) {
1300         // if we get here, no resources are inited
1301         RootFcb->OpenHandleCount =
1302         RootFcb->ReferenceCount  =
1303         RootFcb->NTRequiredFCB->CommonRefCount = 0;
1304 
1305         UDFCleanUpFile__(Vcb, RootFcb->FileInfo);
1306         MyFreePool__(RootFcb->FileInfo);
1307         MyFreePool__(RootFcb->NTRequiredFCB);
1308         UDFCleanUpFCB(RootFcb);
1309         Vcb->RootDirFCB = NULL;
1310         return RC;
1311     }
1312 
1313     // this is a part of UDF_RESIDUAL_REFERENCE
1314     UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
1315     RootFcb->OpenHandleCount =
1316     RootFcb->ReferenceCount  =
1317     RootFcb->NTRequiredFCB->CommonRefCount =
1318     RootFcb->FileInfo->RefCount =
1319     RootFcb->FileInfo->Dloc->LinkRefCount = 1;
1320 
1321     // this is a part of UDF_RESIDUAL_REFERENCE
1322     UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
1323 
1324     NtReqFcb = RootFcb->NTRequiredFCB;
1325 
1326     // Start initializing the fields contained in the CommonFCBHeader.
1327     PtrCommonFCBHeader = &(NtReqFcb->CommonFCBHeader);
1328 
1329     // DisAllow fast-IO for now.
1330     PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible;
1331 
1332     // Initialize the MainResource and PagingIoResource pointers in
1333     // the CommonFCBHeader structure to point to the ERESOURCE structures we
1334     // have allocated and already initialized above.
1335     PtrCommonFCBHeader->Resource = &(NtReqFcb->MainResource);
1336     PtrCommonFCBHeader->PagingIoResource = &(NtReqFcb->PagingIoResource);
1337 
1338     // Initialize the file size values here.
1339     PtrCommonFCBHeader->AllocationSize.QuadPart = 0;
1340     PtrCommonFCBHeader->FileSize.QuadPart = 0;
1341 
1342     // The following will disable ValidDataLength support.
1343     PtrCommonFCBHeader->ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFLL;
1344 
1345     return RC;
1346 } // end UDFBlankMount()
1347 
1348 VOID
1349 UDFCloseResidual(
1350     IN PVCB Vcb
1351     )
1352 {
1353     //  Deinitialize Non-alloc file
1354     if(Vcb->VCBOpenCount)
1355         UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
1356     UDFPrint(("UDFCloseResidual: NonAllocFileInfo %x\n", Vcb->NonAllocFileInfo));
1357     if(Vcb->NonAllocFileInfo) {
1358         UDFCloseFile__(Vcb,Vcb->NonAllocFileInfo);
1359         UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo);
1360         MyFreePool__(Vcb->NonAllocFileInfo);
1361         Vcb->NonAllocFileInfo = NULL;
1362     }
1363     //  Deinitialize Unique ID Mapping
1364     UDFPrint(("UDFCloseResidual: NonAllocFileInfo %x\n", Vcb->NonAllocFileInfo));
1365     if(Vcb->UniqueIDMapFileInfo) {
1366         UDFCloseFile__(Vcb,Vcb->UniqueIDMapFileInfo);
1367         UDFCleanUpFile__(Vcb, Vcb->UniqueIDMapFileInfo);
1368         MyFreePool__(Vcb->UniqueIDMapFileInfo);
1369         Vcb->UniqueIDMapFileInfo = NULL;
1370     }
1371     //  Deinitialize VAT file
1372     UDFPrint(("UDFCloseResidual: VatFileInfo %x\n", Vcb->VatFileInfo));
1373     if(Vcb->VatFileInfo) {
1374         UDFCloseFile__(Vcb,Vcb->VatFileInfo);
1375         UDFCleanUpFile__(Vcb, Vcb->VatFileInfo);
1376         MyFreePool__(Vcb->VatFileInfo);
1377         Vcb->VatFileInfo = NULL;
1378     }
1379     //  System StreamDir
1380     UDFPrint(("UDFCloseResidual: SysSDirFileInfo %x\n", Vcb->SysSDirFileInfo));
1381     if(Vcb->SysSDirFileInfo) {
1382         UDFCloseFile__(Vcb, Vcb->SysSDirFileInfo);
1383         UDFCleanUpFile__(Vcb, Vcb->SysSDirFileInfo);
1384         MyFreePool__(Vcb->SysSDirFileInfo);
1385         Vcb->SysSDirFileInfo = NULL;
1386     }
1387 /*    //  Deinitialize root dir fcb
1388     if(Vcb->RootDirFCB) {
1389         UDFCloseFile__(Vcb,Vcb->RootDirFCB->FileInfo);
1390         UDFCleanUpFile__(Vcb, Vcb->RootDirFCB->FileInfo);
1391         MyFreePool__(Vcb->RootDirFCB->FileInfo);
1392         UDFCleanUpFCB(Vcb->RootDirFCB);
1393         //  Remove root FCB reference in vcb
1394         if(Vcb->VCBOpenCount) Vcb->VCBOpenCount--;
1395     }
1396 
1397     // Deinitialize Non-alloc file
1398     if(Vcb->VCBOpenCount) Vcb->VCBOpenCount--;
1399     if(Vcb->NonAllocFileInfo) {
1400         UDFCloseFile__(Vcb,Vcb->NonAllocFileInfo);
1401         // We must release VCB here !!!!
1402 //        UDFCleanUpFcbChain(Vcb, Vcb->NonAllocFileInfo, 1);
1403         Vcb->NonAllocFileInfo = NULL;
1404     }
1405     // Deinitialize VAT file
1406     if(Vcb->VatFileInfo) {
1407         UDFCloseFile__(Vcb,Vcb->VatFileInfo);
1408         // We must release VCB here !!!!
1409 //        UDFCleanUpFcbChain(Vcb, Vcb->VatFileInfo, 1);
1410         Vcb->VatFileInfo = NULL;
1411     }*/
1412 
1413     // Deinitialize root dir fcb
1414     UDFPrint(("UDFCloseResidual: RootDirFCB %x\n", Vcb->RootDirFCB));
1415     if(Vcb->RootDirFCB) {
1416         UDFCloseFile__(Vcb,Vcb->RootDirFCB->FileInfo);
1417         if(Vcb->RootDirFCB->OpenHandleCount)
1418             Vcb->RootDirFCB->OpenHandleCount--;
1419         UDFCleanUpFcbChain(Vcb, Vcb->RootDirFCB->FileInfo, 1, TRUE);
1420         // Remove root FCB reference in vcb
1421         if(Vcb->VCBOpenCount)
1422             UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
1423         Vcb->RootDirFCB = NULL;
1424     }
1425 } // end UDFCloseResidual()
1426 
1427 VOID
1428 UDFCleanupVCB(
1429     IN PVCB Vcb
1430     )
1431 {
1432     _SEH2_TRY {
1433         UDFReleaseFileIdCache(Vcb);
1434         UDFReleaseDlocList(Vcb);
1435     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1436         BrutePoint();
1437     } _SEH2_END;
1438 
1439     if(Vcb->ShutdownRegistered && Vcb->VCBDeviceObject) {
1440         IoUnregisterShutdownNotification(Vcb->VCBDeviceObject);
1441         Vcb->ShutdownRegistered = FALSE;
1442     }
1443 
1444     MyFreeMemoryAndPointer(Vcb->Partitions);
1445     MyFreeMemoryAndPointer(Vcb->LVid);
1446     MyFreeMemoryAndPointer(Vcb->Vat);
1447     MyFreeMemoryAndPointer(Vcb->SparingTable);
1448 
1449     if(Vcb->FSBM_Bitmap) {
1450         DbgFreePool(Vcb->FSBM_Bitmap);
1451         Vcb->FSBM_Bitmap = NULL;
1452     }
1453     if(Vcb->ZSBM_Bitmap) {
1454         DbgFreePool(Vcb->ZSBM_Bitmap);
1455         Vcb->ZSBM_Bitmap = NULL;
1456     }
1457     if(Vcb->BSBM_Bitmap) {
1458         DbgFreePool(Vcb->BSBM_Bitmap);
1459         Vcb->BSBM_Bitmap = NULL;
1460     }
1461 #ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS
1462     if(Vcb->FSBM_Bitmap_owners) {
1463         DbgFreePool(Vcb->FSBM_Bitmap_owners);
1464         Vcb->FSBM_Bitmap_owners = NULL;
1465     }
1466 #endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS
1467     if(Vcb->FSBM_OldBitmap) {
1468         DbgFreePool(Vcb->FSBM_OldBitmap);
1469         Vcb->FSBM_OldBitmap = NULL;
1470     }
1471 
1472     MyFreeMemoryAndPointer(Vcb->Statistics);
1473     MyFreeMemoryAndPointer(Vcb->NTRequiredFCB);
1474     MyFreeMemoryAndPointer(Vcb->VolIdent.Buffer);
1475     MyFreeMemoryAndPointer(Vcb->TargetDevName.Buffer);
1476 
1477     if(Vcb->ZBuffer) {
1478         DbgFreePool(Vcb->ZBuffer);
1479         Vcb->ZBuffer = NULL;
1480     }
1481 
1482     if(Vcb->fZBuffer) {
1483         DbgFreePool(Vcb->fZBuffer);
1484         Vcb->fZBuffer = NULL;
1485     }
1486 
1487     MyFreeMemoryAndPointer(Vcb->OPCh);
1488     MyFreeMemoryAndPointer(Vcb->WParams);
1489     MyFreeMemoryAndPointer(Vcb->Error);
1490     MyFreeMemoryAndPointer(Vcb->TrackMap);
1491 
1492 } // end UDFCleanupVCB()
1493 
1494 /*
1495 
1496 Routine Description:
1497 
1498     This routine walks through the list of Vcb's looking for any which may
1499     now be deleted.  They may have been left on the list because there were
1500     outstanding references.
1501 
1502 Arguments:
1503 
1504 Return Value:
1505 
1506     None
1507 
1508 */
1509 VOID
1510 UDFScanForDismountedVcb(
1511     IN PtrUDFIrpContext IrpContext
1512     )
1513 {
1514     PVCB Vcb;
1515     PLIST_ENTRY Link;
1516 
1517 
1518     // Walk through all of the Vcb's attached to the global data.
1519     Link = UDFGlobalData.VCBQueue.Flink;
1520 
1521     while (Link != &(UDFGlobalData.VCBQueue)) {
1522 
1523         Vcb = CONTAINING_RECORD( Link, VCB, NextVCB );
1524 
1525         // Move to the next link now since the current Vcb may be deleted.
1526         Link = Link->Flink;
1527 
1528         // If dismount is already underway then check if this Vcb can
1529         // go away.
1530         if((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) ||
1531             ((!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) && (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE))) {
1532 
1533             UDFCheckForDismount( IrpContext, Vcb, FALSE );
1534         }
1535     }
1536 
1537     return;
1538 } // end UDFScanForDismountedVcb()
1539 
1540 /*
1541 Routine Description:
1542     This routine determines if a volume is currently mounted.
1543 
1544 Arguments:
1545     Irp - Supplies the Irp to process
1546 
1547 Return Value:
1548     NTSTATUS - The return status for the operation
1549 
1550 */
1551 NTSTATUS
1552 UDFIsVolumeMounted(
1553     IN PtrUDFIrpContext IrpContext,
1554     IN PIRP Irp
1555     )
1556 {
1557     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
1558 
1559     PtrUDFFCB Fcb;
1560     PtrUDFCCB Ccb;
1561 
1562     UDFPrint(("UDFIsVolumeMounted\n"));
1563 
1564     Ccb = (PtrUDFCCB)IrpSp->FileObject->FsContext2;
1565     if(!Ccb) {
1566         UDFPrintErr(("  !Ccb\n"));
1567         Irp->IoStatus.Information = 0;
1568         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1569         return STATUS_INVALID_PARAMETER;
1570     }
1571     Fcb = Ccb->Fcb;
1572 
1573     if(Fcb &&
1574        !(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) &&
1575        !(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) ) {
1576 
1577         // Disable PopUps, we want to return any error.
1578         IrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS;
1579 
1580         // Verify the Vcb.  This will raise in the error condition.
1581         UDFVerifyVcb( IrpContext, Fcb->Vcb );
1582     }
1583 
1584     Irp->IoStatus.Information = 0;
1585     Irp->IoStatus.Status = STATUS_SUCCESS;
1586 
1587     return STATUS_SUCCESS;
1588 } // end UDFIsVolumeMounted()
1589 
1590 /*
1591     This routine returns the filesystem performance counters from the
1592     appropriate VCB.
1593 
1594 Arguments:
1595     Irp - Supplies the Irp to process
1596 
1597 Return Value:
1598     NTSTATUS - The return status for the operation
1599 */
1600 NTSTATUS
1601 UDFGetStatistics(
1602     IN PtrUDFIrpContext IrpContext,
1603     IN PIRP Irp
1604     )
1605 {
1606     PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
1607     NTSTATUS status;
1608     PVCB Vcb;
1609 
1610     PFILE_SYSTEM_STATISTICS Buffer;
1611     ULONG BufferLength;
1612     ULONG StatsSize;
1613     ULONG BytesToCopy;
1614 
1615     UDFPrint(("UDFGetStatistics\n"));
1616 
1617     // Extract the buffer
1618     BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
1619     //  Get a pointer to the output buffer.
1620     Buffer = (PFILE_SYSTEM_STATISTICS)(Irp->AssociatedIrp.SystemBuffer);
1621 
1622     //  Make sure the buffer is big enough for at least the common part.
1623     if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) {
1624         status = STATUS_BUFFER_TOO_SMALL;
1625         Irp->IoStatus.Information = 0;
1626         goto EO_stat;
1627     }
1628 
1629     //  Now see how many bytes we can copy.
1630     StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors;
1631     if (BufferLength < StatsSize) {
1632         BytesToCopy = BufferLength;
1633         status = STATUS_BUFFER_OVERFLOW;
1634     } else {
1635         BytesToCopy = StatsSize;
1636         status =  STATUS_SUCCESS;
1637     }
1638 
1639     Vcb = (PVCB)(((PDEVICE_OBJECT)IrpSp->DeviceObject)->DeviceExtension);
1640     //  Fill in the output buffer
1641     RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy );
1642     Irp->IoStatus.Information = BytesToCopy;
1643 EO_stat:
1644     Irp->IoStatus.Status = status;
1645 
1646     return status;
1647 } // end UDFGetStatistics()
1648 
1649 
1650 /*
1651     This routine determines if pathname is valid path for UDF Filesystem
1652 
1653 Arguments:
1654     Irp - Supplies the Irp to process
1655 
1656 Return Value:
1657     NTSTATUS - The return status for the operation
1658 */
1659 NTSTATUS
1660 UDFIsPathnameValid(
1661     IN PtrUDFIrpContext IrpContext,
1662     IN PIRP Irp
1663     )
1664 {
1665     PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
1666     NTSTATUS                    RC;
1667     PPATHNAME_BUFFER            PathnameBuffer;
1668     UNICODE_STRING              PathName;
1669     UNICODE_STRING              CurName;
1670     PWCHAR                      TmpBuffer;
1671 
1672     UDFPrint(("UDFIsPathnameValid\n"));
1673 
1674     // Extract the pathname
1675     PathnameBuffer = (PPATHNAME_BUFFER)Irp->AssociatedIrp.SystemBuffer;
1676     PathName.Buffer = PathnameBuffer->Name;
1677     PathName.Length = (USHORT)PathnameBuffer->PathNameLength;
1678 
1679     _SEH2_TRY {
1680         //  Check for an invalid buffer
1681         if (FIELD_OFFSET(PATHNAME_BUFFER, Name[0]) + PathnameBuffer->PathNameLength >
1682             IrpSp->Parameters.FileSystemControl.InputBufferLength) {
1683             try_return( RC = STATUS_INVALID_PARAMETER);
1684         }
1685         while (TRUE) {
1686             // get next path part...
1687             TmpBuffer = PathName.Buffer;
1688             PathName.Buffer = UDFDissectName(PathName.Buffer,&(CurName.Length) );
1689             PathName.Length -= (USHORT)((ULONG_PTR)(PathName.Buffer) - (ULONG_PTR)TmpBuffer);
1690             CurName.Buffer = PathName.Buffer - CurName.Length;
1691             CurName.Length *= sizeof(WCHAR);
1692             CurName.MaximumLength -= CurName.Length;
1693 
1694             if (CurName.Length) {
1695                 // check path fragment size
1696                 if (CurName.Length > UDF_NAME_LEN*sizeof(WCHAR)) {
1697                     try_return(RC = STATUS_OBJECT_NAME_INVALID);
1698                 }
1699                 if (!UDFIsNameValid(&CurName, NULL, NULL)) {
1700                     try_return(RC = STATUS_OBJECT_NAME_INVALID);
1701                 }
1702             } else {
1703                 try_return(RC = STATUS_SUCCESS);
1704             }
1705         }
1706 try_exit:   NOTHING;
1707     } _SEH2_FINALLY {
1708         Irp->IoStatus.Information = 0;
1709         Irp->IoStatus.Status = RC;
1710     } _SEH2_END;
1711 
1712     return RC;
1713 } // end UDFIsPathnameValid()
1714 
1715 /*
1716     This routine performs the lock volume operation.  It is responsible for
1717     either completing of enqueuing the input Irp.
1718 Arguments:
1719     Irp - Supplies the Irp to process
1720 Return Value:
1721     NTSTATUS - The return status for the operation
1722 */
1723 NTSTATUS
1724 UDFLockVolume(
1725     IN PtrUDFIrpContext IrpContext,
1726     IN PIRP             Irp,
1727     IN ULONG            PID
1728     )
1729 {
1730     NTSTATUS RC;
1731 
1732     KIRQL SavedIrql;
1733     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
1734 
1735     PVCB Vcb;
1736     PtrUDFFCB Fcb;
1737     PtrUDFCCB Ccb;
1738     BOOLEAN VcbAcquired = FALSE;
1739 
1740     UDFPrint(("UDFLockVolume: PID %x\n", PID));
1741 
1742     //  Decode the file object, the only type of opens we accept are
1743     //  user volume opens.
1744     Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
1745     if(!Ccb) {
1746         UDFPrintErr(("  !Ccb\n"));
1747         Irp->IoStatus.Information = 0;
1748         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1749         return STATUS_INVALID_PARAMETER;
1750     }
1751     Fcb = Ccb->Fcb;
1752     Vcb = Fcb->Vcb;
1753 
1754     // Check for volume open
1755     if (Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
1756         Irp->IoStatus.Information = 0;
1757         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1758         return STATUS_INVALID_PARAMETER;
1759     }
1760 
1761     UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_LOCK);
1762 
1763     _SEH2_TRY {
1764 
1765         if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
1766             UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
1767 #ifdef UDF_DELAYED_CLOSE
1768         UDFCloseAllDelayed(Vcb);
1769 #endif //UDF_DELAYED_CLOSE
1770 
1771         //  Acquire exclusive access to the Vcb.
1772         UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
1773         VcbAcquired = TRUE;
1774 
1775         //  Verify the Vcb.
1776         UDFVerifyVcb( IrpContext, Vcb );
1777 
1778         //  If the volume is already locked then complete with success if this file
1779         //  object has the volume locked, fail otherwise.
1780 /*        if (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) {
1781 
1782             if (Vcb->VolumeLockFileObject == IrpSp->FileObject) {
1783                 RC = STATUS_SUCCESS;
1784             } else {
1785                 RC = STATUS_ACCESS_DENIED;
1786             }
1787         //  If the open count for the volume is greater than 1 then this request
1788         //  will fail.
1789         } else if (Vcb->VCBOpenCount > UDF_RESIDUAL_REFERENCE+1) {
1790             RC = STATUS_ACCESS_DENIED;
1791         //  We will try to get rid of all of the user references.  If there is only one
1792         //  remaining after the purge then we can allow the volume to be locked.
1793         } else {
1794             // flush system cache
1795             UDFReleaseResource( &(Vcb->VCBResource) );
1796             VcbAcquired = FALSE;
1797         }*/
1798 
1799     } _SEH2_FINALLY {
1800 
1801         //  Release the Vcb.
1802         if(VcbAcquired) {
1803             UDFReleaseResource( &(Vcb->VCBResource) );
1804             VcbAcquired = FALSE;
1805         }
1806     } _SEH2_END;
1807 
1808     UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
1809     VcbAcquired = TRUE;
1810     UDFFlushLogicalVolume(NULL, NULL, Vcb/*, 0*/);
1811     UDFReleaseResource( &(Vcb->VCBResource) );
1812     VcbAcquired = FALSE;
1813     //  Check if the Vcb is already locked, or if the open file count
1814     //  is greater than 1 (which implies that someone else also is
1815     //  currently using the volume, or a file on the volume).
1816     IoAcquireVpbSpinLock( &SavedIrql );
1817 
1818     if (!(Vcb->Vpb->Flags & VPB_LOCKED) &&
1819         (Vcb->VolumeLockPID == (ULONG)-1) &&
1820         (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE+1) &&
1821         (Vcb->Vpb->ReferenceCount == 2)) {
1822 
1823         // Mark volume as locked
1824         if(PID == (ULONG)-1) {
1825             Vcb->Vpb->Flags |= VPB_LOCKED;
1826         }
1827         Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_LOCKED;
1828         Vcb->VolumeLockFileObject = IrpSp->FileObject;
1829         Vcb->VolumeLockPID        = PID;
1830 
1831         RC = STATUS_SUCCESS;
1832 
1833     } else {
1834 
1835         RC = STATUS_ACCESS_DENIED;
1836     }
1837 
1838     IoReleaseVpbSpinLock( SavedIrql );
1839 
1840     if(!NT_SUCCESS(RC)) {
1841         UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED);
1842     }
1843 
1844     //  Complete the request if there haven't been any exceptions.
1845     Irp->IoStatus.Information = 0;
1846     Irp->IoStatus.Status = RC;
1847     return RC;
1848 } // end UDFLockVolume()
1849 
1850 /*
1851     This routine performs the unlock volume operation.  It is responsible for
1852     either completing of enqueuing the input Irp.
1853 Arguments:
1854     Irp - Supplies the Irp to process
1855 Return Value:
1856     NTSTATUS - The return status for the operation
1857 */
1858 NTSTATUS
1859 UDFUnlockVolume(
1860     IN PtrUDFIrpContext IrpContext,
1861     IN PIRP             Irp,
1862     IN ULONG            PID
1863     )
1864 {
1865     NTSTATUS RC = STATUS_INVALID_PARAMETER;
1866 
1867     KIRQL SavedIrql;
1868     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
1869 
1870     PVCB Vcb;
1871     PtrUDFFCB Fcb;
1872     PtrUDFCCB Ccb;
1873 
1874     UDFPrint(("UDFUnlockVolume: PID %x\n", PID));
1875 
1876     //  Decode the file object, the only type of opens we accept are
1877     //  user volume opens.
1878     Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
1879     if(!Ccb) {
1880         UDFPrintErr(("  !Ccb\n"));
1881         Irp->IoStatus.Information = 0;
1882         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1883         return STATUS_INVALID_PARAMETER;
1884     }
1885     Fcb = Ccb->Fcb;
1886     Vcb = Fcb->Vcb;
1887 
1888     // Check for volume open
1889     if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
1890         Irp->IoStatus.Information = 0;
1891         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1892         return STATUS_INVALID_PARAMETER;
1893     }
1894 
1895     //  Acquire exclusive access to the Vcb/Vpb.
1896     IoAcquireVpbSpinLock( &SavedIrql );
1897 
1898     _SEH2_TRY {
1899 
1900         //  We won't check for a valid Vcb for this request.  An unlock will always
1901         //  succeed on a locked volume.
1902         if(Vcb->Vpb->Flags & VPB_LOCKED ||
1903            Vcb->VolumeLockPID == PID) {
1904             Vcb->Vpb->Flags &= ~VPB_LOCKED;
1905             Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
1906             Vcb->VolumeLockFileObject = NULL;
1907             Vcb->VolumeLockPID = -1;
1908             UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_UNLOCK);
1909             RC = STATUS_SUCCESS;
1910         } else {
1911             RC = STATUS_NOT_LOCKED;
1912             RC = STATUS_SUCCESS;
1913             RC = STATUS_VOLUME_DISMOUNTED;
1914         }
1915 
1916     } _SEH2_FINALLY {
1917         ;
1918     } _SEH2_END;
1919 
1920     //  Release all of our resources
1921     IoReleaseVpbSpinLock( SavedIrql );
1922 
1923     //  Complete the request if there haven't been any exceptions.
1924     Irp->IoStatus.Information = 0;
1925     Irp->IoStatus.Status = RC;
1926     return RC;
1927 } // end UDFUnlockVolume()
1928 
1929 
1930 /*
1931     This routine performs the dismount volume operation.  It is responsible for
1932     either completing of enqueuing the input Irp.  We only dismount a volume which
1933     has been locked.  The intent here is that someone has locked the volume (they are the
1934     only remaining handle).  We set the verify bit here and the user will close his handle.
1935     We will dismount a volume with no user's handles in the verify path.
1936 Arguments:
1937     Irp - Supplies the Irp to process
1938 Return Value:
1939     NTSTATUS - The return status for the operation
1940 */
1941 NTSTATUS
1942 UDFDismountVolume(
1943     IN PtrUDFIrpContext IrpContext,
1944     IN PIRP Irp
1945     )
1946 {
1947     NTSTATUS RC;
1948 
1949     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
1950 
1951     PVCB Vcb;
1952     PtrUDFFCB Fcb;
1953     PtrUDFCCB Ccb;
1954     PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
1955     BOOLEAN VcbAcquired = FALSE;
1956 
1957     UDFPrint(("\n ### UDFDismountVolume ###\n\n"));
1958 
1959     //  Decode the file object, the only type of opens we accept are
1960     //  user volume opens.
1961     Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
1962     if(!Ccb) {
1963         UDFPrintErr(("  !Ccb\n"));
1964         Irp->IoStatus.Information = 0;
1965         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1966         return STATUS_INVALID_PARAMETER;
1967     }
1968     Fcb = Ccb->Fcb;
1969     Vcb = Fcb->Vcb;
1970 
1971     // Check for volume open
1972     if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
1973         Irp->IoStatus.Information = 0;
1974         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1975         return STATUS_INVALID_PARAMETER;
1976     }
1977 
1978     UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT);
1979 
1980     if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
1981         UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
1982 #ifdef UDF_DELAYED_CLOSE
1983     UDFCloseAllDelayed(Vcb);
1984 #endif //UDF_DELAYED_CLOSE
1985 
1986     //  Acquire exclusive access to the Vcb.
1987     UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
1988     VcbAcquired = TRUE;
1989 
1990     _SEH2_TRY {
1991 
1992         //  Mark the volume as needs to be verified, but only do it if
1993         //  the vcb is locked by this handle and the volume is currently mounted.
1994 
1995         if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
1996             // disable Eject Request Waiter if any
1997             UDFReleaseResource( &(Vcb->VCBResource) );
1998             VcbAcquired = FALSE;
1999 
2000             UDFStopEjectWaiter(Vcb);
2001             RC = STATUS_SUCCESS;
2002         } else
2003         if(/*!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) ||*/
2004            !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) ||
2005             (Vcb->VCBOpenCount > (UDF_RESIDUAL_REFERENCE+1))) {
2006 
2007             RC = STATUS_NOT_LOCKED;
2008         } else
2009         if((Vcb->VolumeLockFileObject != IrpSp->FileObject)) {
2010 
2011             RC = STATUS_INVALID_PARAMETER;
2012 
2013         } else {
2014 
2015             Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
2016             Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
2017             if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
2018             UDFDoDismountSequence(Vcb, Buf, FALSE);
2019             Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
2020             Vcb->WriteSecurity = FALSE;
2021             // disable Eject Request Waiter if any
2022             UDFReleaseResource( &(Vcb->VCBResource) );
2023             VcbAcquired = FALSE;
2024 
2025             UDFStopEjectWaiter(Vcb);
2026             RC = STATUS_SUCCESS;
2027         }
2028 try_exit: NOTHING;
2029     } _SEH2_FINALLY {
2030         //  Free memory
2031         if(Buf) MyFreePool__(Buf);
2032         //  Release all of our resources
2033         if(VcbAcquired)
2034             UDFReleaseResource( &(Vcb->VCBResource) );
2035     } _SEH2_END;
2036 
2037     if(!NT_SUCCESS(RC)) {
2038         UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT_FAILED);
2039     }
2040 
2041     //  Complete the request if there haven't been any exceptions.
2042     Irp->IoStatus.Information = 0;
2043     Irp->IoStatus.Status = RC;
2044     return RC;
2045 } // end UDFDismountVolume()
2046 
2047 /*
2048 
2049     This routine returns the volume allocation bitmap.
2050 
2051         Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in
2052             through the input buffer.
2053         Output = the VOLUME_BITMAP_BUFFER data structure is returned through
2054             the output buffer.
2055 
2056     We return as much as the user buffer allows starting the specified input
2057     LCN (trucated to a byte).  If there is no input buffer, we start at zero.
2058 
2059 Arguments:
2060 
2061     Irp - Supplies the Irp being processed.
2062 
2063 Return Value:
2064 
2065     NTSTATUS - The return status for the operation.
2066 
2067  */
2068 NTSTATUS
2069 UDFGetVolumeBitmap(
2070     IN PtrUDFIrpContext IrpContext,
2071     IN PIRP Irp
2072     )
2073 {
2074 //    NTSTATUS RC;
2075 
2076     PEXTENDED_IO_STACK_LOCATION IrpSp =
2077         (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
2078 
2079     PVCB Vcb;
2080     PtrUDFFCB Fcb;
2081     PtrUDFCCB Ccb;
2082 
2083     UDFPrint(("UDFGetVolumeBitmap\n"));
2084 
2085     ULONG BytesToCopy;
2086     ULONG TotalClusters;
2087     ULONG DesiredClusters;
2088     ULONG StartingCluster;
2089     ULONG InputBufferLength;
2090     ULONG OutputBufferLength;
2091     LARGE_INTEGER StartingLcn;
2092     PVOLUME_BITMAP_BUFFER OutputBuffer;
2093     ULONG i, lim;
2094     PULONG FSBM;
2095 //    PULONG Dest;
2096     ULONG LSh;
2097 
2098     // Decode the file object, the only type of opens we accept are
2099     // user volume opens.
2100     Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
2101     if(!Ccb) {
2102         UDFPrintErr(("  !Ccb\n"));
2103         Irp->IoStatus.Information = 0;
2104         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2105         return STATUS_INVALID_PARAMETER;
2106     }
2107     Fcb = Ccb->Fcb;
2108     Vcb = Fcb->Vcb;
2109 
2110     InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
2111     OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
2112 
2113     OutputBuffer = (PVOLUME_BITMAP_BUFFER)UDFGetCallersBuffer(IrpContext, Irp);
2114     if(!OutputBuffer)
2115         return STATUS_INVALID_USER_BUFFER;
2116 
2117     // Check for a minimum length on the input and output buffers.
2118     if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) ||
2119         (OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) {
2120 
2121         UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
2122         Irp->IoStatus.Information = 0;
2123         Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
2124         return STATUS_BUFFER_TOO_SMALL;
2125     }
2126 
2127     //  Check if a starting cluster was specified.
2128     TotalClusters = Vcb->FSBM_BitCount;
2129     StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn;
2130 
2131     if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) {
2132 
2133         UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
2134         Irp->IoStatus.Information = 0;
2135         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2136         return STATUS_INVALID_PARAMETER;
2137 
2138     } else {
2139 
2140         StartingCluster = StartingLcn.LowPart & ~7;
2141     }
2142 
2143     OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
2144     DesiredClusters = TotalClusters - StartingCluster;
2145 
2146     if (OutputBufferLength < (DesiredClusters + 7) / 8) {
2147 
2148         BytesToCopy = OutputBufferLength;
2149 //        RC = STATUS_BUFFER_OVERFLOW;
2150 
2151     } else {
2152 
2153         BytesToCopy = (DesiredClusters + 7) / 8;
2154 //        RC = STATUS_SUCCESS;
2155     }
2156 
2157     UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
2158 
2159     _SEH2_TRY {
2160 
2161         //  Fill in the fixed part of the output buffer
2162         OutputBuffer->StartingLcn.QuadPart = StartingCluster;
2163         OutputBuffer->BitmapSize.QuadPart = DesiredClusters;
2164 
2165         RtlZeroMemory( &OutputBuffer->Buffer[0], BytesToCopy );
2166         lim = BytesToCopy * 8;
2167         FSBM = (PULONG)(Vcb->FSBM_Bitmap);
2168         LSh = Vcb->LB2B_Bits;
2169 //        Dest = (PULONG)(&OutputBuffer->Buffer[0]);
2170 
2171         for(i=StartingCluster & ~7; i<lim; i++) {
2172             if(UDFGetFreeBit(FSBM, i<<LSh))
2173                 UDFSetFreeBit(FSBM, i);
2174         }
2175 
2176     } _SEH2_EXCEPT(UDFExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
2177 
2178         BrutePoint();
2179         UDFPrintErr(("UDFGetVolumeBitmap: Exception\n"));
2180 //        UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
2181         BrutePoint();
2182 //        RC = UDFExceptionHandler(IrpContext, Irp);
2183         UDFReleaseResource(&(Vcb->VCBResource));
2184         UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
2185 
2186         Irp->IoStatus.Information = 0;
2187         Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER;
2188         return STATUS_INVALID_USER_BUFFER;
2189     } _SEH2_END;
2190 
2191     UDFReleaseResource(&(Vcb->VCBResource));
2192 
2193     UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
2194     Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) +
2195                                 BytesToCopy;
2196     Irp->IoStatus.Status = STATUS_SUCCESS;
2197 
2198     return STATUS_SUCCESS;
2199 
2200 
2201 } // end UDFGetVolumeBitmap()
2202 
2203 
2204 NTSTATUS
2205 UDFGetRetrievalPointers(
2206     IN PtrUDFIrpContext IrpContext,
2207     IN PIRP  Irp,
2208     IN ULONG Special
2209     )
2210 {
2211     NTSTATUS RC;
2212 
2213     PEXTENDED_IO_STACK_LOCATION IrpSp =
2214         (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
2215 
2216     PVCB Vcb;
2217     PtrUDFFCB Fcb;
2218     PtrUDFCCB Ccb;
2219     PUDF_FILE_INFO FileInfo;
2220 
2221     ULONG InputBufferLength;
2222     ULONG OutputBufferLength;
2223 
2224     PRETRIEVAL_POINTERS_BUFFER OutputBuffer;
2225     PSTARTING_VCN_INPUT_BUFFER InputBuffer;
2226 
2227     LARGE_INTEGER StartingVcn;
2228     int64 AllocationSize;
2229 
2230     PEXTENT_MAP SubMapping = NULL;
2231     ULONG SubExtInfoSz;
2232     ULONG i;
2233     ULONG LBS;
2234     ULONG LBSh;
2235     ULONG L2BSh;
2236 
2237     UDFPrint(("UDFGetRetrievalPointers\n"));
2238 
2239     // Decode the file object, the only type of opens we accept are
2240     // user volume opens.
2241     Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
2242     if(!Ccb) {
2243         UDFPrintErr(("  !Ccb\n"));
2244         Irp->IoStatus.Information = 0;
2245         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2246         return STATUS_INVALID_PARAMETER;
2247     }
2248     Fcb = Ccb->Fcb;
2249     Vcb = Fcb->Vcb;
2250 
2251     //  Get the input and output buffer lengths and pointers.
2252     //  Initialize some variables.
2253     InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
2254     OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
2255 
2256     //OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)UDFGetCallersBuffer( IrpContext, Irp );
2257     if(Special) {
2258         OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->AssociatedIrp.SystemBuffer;
2259     } else {
2260         OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->UserBuffer;
2261     }
2262     InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
2263     if(!InputBuffer) {
2264         InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)OutputBuffer;
2265     }
2266 
2267     _SEH2_TRY {
2268 
2269         Irp->IoStatus.Information = 0;
2270         //  Check for a minimum length on the input and ouput buffers.
2271         if ((InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER)) ||
2272             (OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))) {
2273 
2274             try_return( RC = STATUS_BUFFER_TOO_SMALL );
2275         }
2276 
2277         _SEH2_TRY {
2278 
2279             if (Irp->RequestorMode != KernelMode) {
2280                 ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
2281                               InputBufferLength,
2282                               sizeof(UCHAR) );
2283                 ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
2284             }
2285             StartingVcn = InputBuffer->StartingVcn;
2286 
2287         } _SEH2_EXCEPT(Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH) {
2288 
2289             RC = _SEH2_GetExceptionCode();
2290             RC = FsRtlIsNtstatusExpected(RC) ?
2291                               RC : STATUS_INVALID_USER_BUFFER;
2292             try_return(RC);
2293         } _SEH2_END;
2294 
2295         switch(Special) {
2296         case 0:
2297             FileInfo = Fcb->FileInfo;
2298             break;
2299         case 1:
2300             FileInfo = Vcb->NonAllocFileInfo;
2301             break;
2302         default:
2303             try_return( RC = STATUS_INVALID_PARAMETER );
2304         }
2305 
2306         if(!FileInfo) {
2307             try_return( RC = STATUS_OBJECT_NAME_NOT_FOUND );
2308         }
2309 
2310         AllocationSize = UDFGetFileAllocationSize(Vcb, FileInfo);
2311 
2312         LBS   = Vcb->LBlockSize;
2313         LBSh  = Vcb->LBlockSizeBits;
2314         L2BSh = Vcb->LB2B_Bits;
2315 
2316         if (StartingVcn.HighPart ||
2317             StartingVcn.LowPart >= (ULONG)(AllocationSize >> LBSh)) {
2318 
2319             try_return( RC = STATUS_END_OF_FILE );
2320         }
2321 
2322         SubExtInfoSz = (OutputBufferLength - FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0])) / (sizeof(LARGE_INTEGER)*2);
2323         // re-use AllocationSize as NextVcn
2324         RC = UDFReadFileLocation__(Vcb, FileInfo, StartingVcn.QuadPart << LBSh,
2325                                    &SubMapping, &SubExtInfoSz, &AllocationSize);
2326         if(!NT_SUCCESS(RC))
2327             try_return(RC);
2328 
2329         OutputBuffer->ExtentCount = SubExtInfoSz;
2330         OutputBuffer->StartingVcn = StartingVcn;
2331         for(i=0; i<SubExtInfoSz; i++) {
2332             // assume, that
2333             // for not-allocated extents we have start Lba = -1
2334             // for not-recorded extents start Lba.LowPart contains real Lba, Lba.HighPart = 0x80000000
2335             // for recorded extents Lba.LowPart contains real Lba, Lba.HighPart = 0
2336             if(SubMapping[i].extLocation == LBA_NOT_ALLOCATED) {
2337                 OutputBuffer->Extents[i].Lcn.QuadPart = (int64)(-1);
2338             } else
2339             if(SubMapping[i].extLocation & 0x80000000) {
2340                 OutputBuffer->Extents[i].Lcn.LowPart = (SubMapping[i].extLocation & 0x7fffffff) >> L2BSh;
2341                 OutputBuffer->Extents[i].Lcn.HighPart = 0x80000000;
2342             } else {
2343                 OutputBuffer->Extents[i].Lcn.LowPart = SubMapping[i].extLocation >> L2BSh;
2344                 OutputBuffer->Extents[i].Lcn.HighPart = 0;
2345             }
2346             // alignment for last sector
2347             SubMapping[i].extLength += LBS-1;
2348             StartingVcn.QuadPart += SubMapping[i].extLength   >> LBSh;
2349             OutputBuffer->Extents[i].NextVcn = StartingVcn;
2350         }
2351 
2352         Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]) + i * sizeof(LARGE_INTEGER) * 2;
2353 
2354 try_exit:   NOTHING;
2355     } _SEH2_FINALLY {
2356 
2357         if(SubMapping)
2358             MyFreePool__(SubMapping);
2359         Irp->IoStatus.Status = RC;
2360     } _SEH2_END;
2361 
2362     return RC;
2363 } // end UDFGetRetrievalPointers()
2364 
2365 
2366 NTSTATUS
2367 UDFIsVolumeDirty(
2368     IN PtrUDFIrpContext IrpContext,
2369     IN PIRP Irp
2370     )
2371 {
2372     PULONG VolumeState;
2373     PEXTENDED_IO_STACK_LOCATION IrpSp =
2374         (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
2375 
2376     PVCB Vcb;
2377     PtrUDFFCB Fcb;
2378     PtrUDFCCB Ccb;
2379 
2380     UDFPrint(("UDFIsVolumeDirty\n"));
2381 
2382     Irp->IoStatus.Information = 0;
2383 
2384     if (Irp->AssociatedIrp.SystemBuffer != NULL) {
2385         VolumeState = (PULONG)(Irp->AssociatedIrp.SystemBuffer);
2386     } else if (Irp->MdlAddress != NULL) {
2387         VolumeState = (PULONG)MmGetSystemAddressForMdl(Irp->MdlAddress);
2388     } else {
2389         UDFPrintErr(("  STATUS_INVALID_USER_BUFFER\n"));
2390         Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER;
2391         return STATUS_INVALID_USER_BUFFER;
2392     }
2393 
2394     if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
2395         UDFPrintErr(("  STATUS_BUFFER_TOO_SMALL\n"));
2396         Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
2397         return STATUS_BUFFER_TOO_SMALL;
2398     }
2399 
2400     (*VolumeState) = 0;
2401 
2402     // Decode the file object, the only type of opens we accept are
2403     // user volume opens.
2404     Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
2405     if(!Ccb) {
2406         UDFPrintErr(("  !Ccb\n"));
2407         Irp->IoStatus.Information = 0;
2408         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2409         return STATUS_INVALID_PARAMETER;
2410     }
2411     Fcb = Ccb->Fcb;
2412     Vcb = Fcb->Vcb;
2413 
2414     if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
2415         UDFPrintErr(("  !Volume\n"));
2416         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2417         return STATUS_INVALID_PARAMETER;
2418     }
2419 
2420     if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
2421         UDFPrintErr(("  !Mounted\n"));
2422         Irp->IoStatus.Status = STATUS_VOLUME_DISMOUNTED;
2423         return STATUS_VOLUME_DISMOUNTED;
2424     }
2425 
2426     if(Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) {
2427         UDFPrint(("  Dirty\n"));
2428         (*VolumeState) |= VOLUME_IS_DIRTY;
2429         Irp->IoStatus.Information = sizeof(ULONG);
2430     } else {
2431         UDFPrint(("  Clean\n"));
2432     }
2433     Irp->IoStatus.Status = STATUS_SUCCESS;
2434 
2435     return STATUS_SUCCESS;
2436 
2437 } // end UDFIsVolumeDirty()
2438 
2439 
2440 NTSTATUS
2441 UDFInvalidateVolumes(
2442     IN PtrUDFIrpContext IrpContext,
2443     IN PIRP Irp
2444     )
2445 {
2446     NTSTATUS RC;
2447     PEXTENDED_IO_STACK_LOCATION IrpSp =
2448         (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
2449     PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
2450 
2451     UDFPrint(("UDFInvalidateVolumes\n"));
2452 
2453     KIRQL SavedIrql;
2454 
2455     LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
2456 
2457     HANDLE Handle;
2458 
2459     PVPB NewVpb;
2460     PVCB Vcb;
2461 
2462     PLIST_ENTRY Link;
2463 
2464     PFILE_OBJECT FileToMarkBad;
2465     PDEVICE_OBJECT DeviceToMarkBad;
2466 
2467     Irp->IoStatus.Information = 0;
2468 
2469     //  Check for the correct security access.
2470     //  The caller must have the SeTcbPrivilege.
2471     if (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
2472         IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
2473         IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES &&
2474         !SeSinglePrivilegeCheck( TcbPrivilege, UserMode )) {
2475         UDFPrintErr(("UDFInvalidateVolumes: STATUS_PRIVILEGE_NOT_HELD\n"));
2476         Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD;
2477         return STATUS_PRIVILEGE_NOT_HELD;
2478     }
2479     //  Try to get a pointer to the device object from the handle passed in.
2480     if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) {
2481         UDFPrintErr(("UDFInvalidateVolumes: STATUS_INVALID_PARAMETER\n"));
2482         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2483         return STATUS_INVALID_PARAMETER;
2484     }
2485 
2486     Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer);
2487 
2488     RC = ObReferenceObjectByHandle( Handle,
2489                                     0,
2490                                     *IoFileObjectType,
2491                                     KernelMode,
2492                                     (PVOID*)&FileToMarkBad,
2493                                     NULL );
2494 
2495     if (!NT_SUCCESS(RC)) {
2496         UDFPrintErr(("UDFInvalidateVolumes: can't get handle, RC=%x\n", RC));
2497         Irp->IoStatus.Status = RC;
2498         return RC;
2499     }
2500 
2501     //  We only needed the pointer, not a reference.
2502     ObDereferenceObject( FileToMarkBad );
2503 
2504     //  Grab the DeviceObject from the FileObject.
2505     DeviceToMarkBad = FileToMarkBad->DeviceObject;
2506 
2507     //  Create a new Vpb for this device so that any new opens will mount
2508     //  a new volume.
2509     NewVpb = (PVPB)DbgAllocatePoolWithTag( NonPagedPool, sizeof( VPB ), 'bpvU' );
2510     if(!NewVpb) {
2511         UDFPrintErr(("UDFInvalidateVolumes: STATUS_INSUFFICIENT_RESOURCES\n"));
2512         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2513         return STATUS_INSUFFICIENT_RESOURCES;
2514     }
2515     RtlZeroMemory( NewVpb, sizeof( VPB ) );
2516 
2517     NewVpb->Type = IO_TYPE_VPB;
2518     NewVpb->Size = sizeof( VPB );
2519     NewVpb->RealDevice = DeviceToMarkBad;
2520     NewVpb->Flags = DeviceToMarkBad->Vpb->Flags & VPB_REMOVE_PENDING;
2521 
2522     // Acquire GlobalDataResource
2523     UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
2524 
2525     //  Nothing can go wrong now.
2526     IoAcquireVpbSpinLock( &SavedIrql );
2527     if (DeviceToMarkBad->Vpb->Flags & VPB_MOUNTED) {
2528         DeviceToMarkBad->Vpb = NewVpb;
2529         NewVpb = NULL;
2530     }
2531     ASSERT( DeviceToMarkBad->Vpb->DeviceObject == NULL );
2532     IoReleaseVpbSpinLock( SavedIrql );
2533 
2534     if (NewVpb) {
2535         DbgFreePool( NewVpb );
2536     }
2537 
2538     // Walk through all of the Vcb's attached to the global data.
2539     Link = UDFGlobalData.VCBQueue.Flink;
2540 
2541     //ASSERT(FALSE);
2542 
2543     while (Link != &(UDFGlobalData.VCBQueue)) {
2544         // Get 'next' Vcb
2545         Vcb = CONTAINING_RECORD( Link, VCB, NextVCB );
2546         // Move to the next link now since the current Vcb may be deleted.
2547         Link = Link->Flink;
2548 
2549         // Acquire Vcb resource
2550         UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
2551 
2552         if (Vcb->Vpb->RealDevice == DeviceToMarkBad) {
2553 
2554             if(!Buf) {
2555                 Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)*2);
2556                 if(!Buf) {
2557                     UDFPrintErr(("UDFInvalidateVolumes: STATUS_INSUFFICIENT_RESOURCES (2)\n"));
2558                     UDFReleaseResource(&(Vcb->VCBResource));
2559                     MyFreePool__(NewVpb);
2560                     Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2561                     return STATUS_INSUFFICIENT_RESOURCES;
2562                 }
2563             }
2564 
2565 #ifdef UDF_DELAYED_CLOSE
2566             UDFPrint(("    UDFInvalidateVolumes:     set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n"));
2567             Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
2568             UDFReleaseResource(&(Vcb->VCBResource));
2569 #endif //UDF_DELAYED_CLOSE
2570 
2571             if(Vcb->RootDirFCB && Vcb->RootDirFCB->FileInfo) {
2572                 UDFPrint(("    UDFInvalidateVolumes:     UDFCloseAllSystemDelayedInDir\n"));
2573                 RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
2574                 ASSERT(OS_SUCCESS(RC));
2575             }
2576 #ifdef UDF_DELAYED_CLOSE
2577             UDFPrint(("    UDFInvalidateVolumes:     UDFCloseAllDelayed\n"));
2578             UDFCloseAllDelayed(Vcb);
2579             //ASSERT(OS_SUCCESS(RC));
2580 #endif //UDF_DELAYED_CLOSE
2581 
2582             UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
2583 
2584             UDFDoDismountSequence(Vcb, Buf, FALSE);
2585             UDFReleaseResource(&(Vcb->VCBResource));
2586 
2587             UDFStopEjectWaiter(Vcb);
2588             UDFPrint(("UDFInvalidateVolumes: Vcb %x dismounted\n", Vcb));
2589             break;
2590         } else {
2591             UDFPrint(("UDFInvalidateVolumes: skip Vcb %x\n", Vcb));
2592             UDFReleaseResource(&(Vcb->VCBResource));
2593         }
2594 
2595     }
2596     // Once we have processed all the mounted logical volumes, we can release
2597     // all acquired global resources and leave (in peace :-)
2598     UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
2599 
2600     Irp->IoStatus.Status = STATUS_SUCCESS;
2601 
2602     if(Buf) {
2603         UDFPrint(("UDFInvalidateVolumes: free buffer\n"));
2604         MyFreePool__(Buf);
2605     }
2606 
2607     // drop volume completly
2608     UDFPrint(("UDFInvalidateVolumes: drop volume completly\n"));
2609     UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
2610     UDFScanForDismountedVcb(IrpContext);
2611     UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
2612 
2613     UDFPrint(("UDFInvalidateVolumes: done\n"));
2614     return STATUS_SUCCESS;
2615 
2616 } // end UDFInvalidateVolumes()
2617