72640e7d50da03a67f0249f70ab65de65591bd4b
[reactos.git] / reactos / drivers / filesystems / udfs / fscntrl.cpp
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7
8 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 KdPrint(("\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 KdPrint(("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 KdPrint(("\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 KdPrint((" UDFFSControl: UserFsReq request ....\n"));
124
125 RC = UDFUserFsCtrlRequest(PtrIrpContext,Irp);
126 break;
127 case IRP_MN_MOUNT_VOLUME:
128
129 KdPrint((" UDFFSControl: MOUNT_VOLUME request ....\n"));
130
131 RC = UDFMountVolume(PtrIrpContext,Irp);
132 break;
133 case IRP_MN_VERIFY_VOLUME:
134
135 KdPrint((" UDFFSControl: VERIFY_VOLUME request ....\n"));
136
137 RC = UDFVerifyVolume(Irp);
138 break;
139 default:
140 KdPrint((" 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 KdPrint((" UDFCommonFSControl: finally\n"));
155 UDFReleaseIrpContext(PtrIrpContext);
156 } else {
157 KdPrint((" 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 KdPrint(("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 KdPrint(("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 KdPrint(("UDFUserFsCtrlRequest: FSCTL_GET_VOLUME_BITMAP\n"));
274 RC = UDFGetVolumeBitmap( IrpContext, Irp );
275 break;
276
277 case FSCTL_GET_RETRIEVAL_POINTERS:
278
279 KdPrint(("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 KdPrint(("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 KdPrint(("\n !!! UDFMountVolume\n"));
348 // KdPrint(("Build " VER_STR_PRODUCT "\n\n"));
349
350 fsDeviceObject = PtrIrpContext->TargetDeviceObject;
351 KdPrint(("Mount on device object %x\n"));
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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("UDFMountVolume: try raw mount\n"));
626 if(Vcb->NSRDesc & VRS_ISO9660_FOUND) {
627 KdPrint(("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 KdPrint(("UDFMountVolume: try raw mount (2)\n"));
633 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
634
635 KdPrint(("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 KdPrint(("UDFMountVolume: writable volume\n"));
658 if(!Vcb->CDR_Mode) {
659 if((FsDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
660 CdrwMediaClassEx_IsRAM(Vcb->MediaClassEx)) {
661 KdPrint(("UDFMountVolume: RAM mode\n"));
662 Mode = WCACHE_MODE_RAM;
663 } else {
664 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("UDFMountVolume: reset driver\n"));
787 UDFResetDeviceDriver(Vcb, TargetDeviceObject, TRUE);
788 }
789
790 if(RC == STATUS_CRC_ERROR || RC == STATUS_FILE_CORRUPT_ERROR) {
791 KdPrint(("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 KdPrint(("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 return IoCallDriver( filterDevExt->lowerFSDeviceObject, Irp );
839
840 }
841
842 } _SEH2_END;
843
844 KdPrint(("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 KdPrint(("UDFStartEjectWaiter:\n"));
857
858 if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) {
859 KdPrint((" UDF_VCB_FLAGS_MEDIA_READ_ONLY\n"));
860 }
861 if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) {
862 KdPrint((" UDF_VCB_FLAGS_MEDIA_LOCKED\n"));
863 }
864 KdPrint((" 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 KdPrint(("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 KdPrint((" not our driver, ignore\n"));
875 return STATUS_SUCCESS;
876 }
877 KdPrint(("UDFStartEjectWaiter: check removable\n"));
878 if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) {
879 // prevent media removal
880 KdPrint(("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 KdPrint(("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), (PWORKER_THREAD_ROUTINE)UDFEjectReqWaiter, Vcb->EjectWaiter);
904 KdPrint(("UDFStartEjectWaiter: create thread\n"));
905 ExQueueWorkItem(&(Vcb->EjectWaiter->EjectReqWorkQueueItem), DelayedWorkQueue);
906 } else {
907 KdPrint((" 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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 uint32 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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("UDFIsVolumeMounted\n"));
1563
1564 Ccb = (PtrUDFCCB)IrpSp->FileObject->FsContext2;
1565 if(!Ccb) {
1566 KdPrint((" !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 KdPrint(("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 KdPrint(("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)(PathName.Buffer) - (ULONG)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 KdPrint(("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 KdPrint((" !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 KdPrint(("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 KdPrint((" !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 KdPrint(("\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 KdPrint((" !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 KdPrint(("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 KdPrint((" !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 KdPrint(("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 KdPrint(("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 KdPrint((" !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 KdPrint(("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 KdPrint((" 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 KdPrint((" 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 KdPrint((" !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 KdPrint((" !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 KdPrint((" !Mounted\n"));
2422 Irp->IoStatus.Status = STATUS_VOLUME_DISMOUNTED;
2423 return STATUS_VOLUME_DISMOUNTED;
2424 }
2425
2426 if(Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) {
2427 KdPrint((" Dirty\n"));
2428 (*VolumeState) |= VOLUME_IS_DIRTY;
2429 Irp->IoStatus.Information = sizeof(ULONG);
2430 } else {
2431 KdPrint((" 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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint((" 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 KdPrint((" UDFInvalidateVolumes: UDFCloseAllSystemDelayedInDir\n"));
2573 RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
2574 ASSERT(OS_SUCCESS(RC));
2575 }
2576 #ifdef UDF_DELAYED_CLOSE
2577 KdPrint((" 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 KdPrint(("UDFInvalidateVolumes: Vcb %x dismounted\n", Vcb));
2589 break;
2590 } else {
2591 KdPrint(("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 KdPrint(("UDFInvalidateVolumes: free buffer\n"));
2604 MyFreePool__(Buf);
2605 }
2606
2607 // drop volume completly
2608 KdPrint(("UDFInvalidateVolumes: drop volume completly\n"));
2609 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
2610 UDFScanForDismountedVcb(IrpContext);
2611 UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
2612
2613 KdPrint(("UDFInvalidateVolumes: done\n"));
2614 return STATUS_SUCCESS;
2615
2616 } // end UDFInvalidateVolumes()