1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
8 Module Name: VerfySup.cpp
12 This module implements the UDF verification routines.
22 // define the file specific bug-check id
23 #define UDF_BUG_CHECK_ID UDF_FILE_VERIFY_FS_CONTROL
27 This routine checks that the current Vcb is valid and currently mounted
28 on the device. It will raise on an error condition.
29 We check whether the volume needs verification and the current state
33 Vcb - This is the volume to verify.
38 IN PtrUDFIrpContext IrpContext
,
42 NTSTATUS RC
= STATUS_SUCCESS
;
44 ULONG MediaChangeCount
= 0;
46 BOOLEAN UnsafeIoctl
= (Vcb
->VCBFlags
& UDF_VCB_FLAGS_UNSAFE_IOCTL
) ? TRUE
: FALSE
;
48 UDFPrint(("UDFVerifyVCB: Modified=%d\n", Vcb
->Modified
));
49 // Fail immediately if the volume is in the progress of being dismounted
50 // or has been marked invalid.
51 if (Vcb
->VCBFlags
& UDF_VCB_FLAGS_BEING_DISMOUNTED
) {
52 return STATUS_FILE_INVALID
;
55 // If the media is removable and the verify volume flag in the
56 // device object is not set then we want to ping the device
57 // to see if it needs to be verified
58 if ( (Vcb
->VCBFlags
& UDF_VCB_FLAGS_REMOVABLE_MEDIA
) &&
59 !(Vcb
->Vpb
->RealDevice
->Flags
& DO_VERIFY_VOLUME
) &&
60 (!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_MEDIA_LOCKED
) || UnsafeIoctl
) ) {
61 UDFPrint(("UDFVerifyVCB: UnsafeIoctl=%d, locked=%d\n", UnsafeIoctl
, (Vcb
->VCBFlags
& UDF_VCB_FLAGS_MEDIA_LOCKED
) ? 0 : 1));
62 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_UNSAFE_IOCTL
;
63 RC
= UDFTSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY
,
66 &MediaChangeCount
,sizeof(ULONG
),
69 // Be safe about the count in case the driver didn't fill it in
70 if (Iosb
.Information
!= sizeof(ULONG
)) MediaChangeCount
= 0;
71 UDFPrint((" MediaChangeCount %d -> %d\n", Vcb
->MediaChangeCount
, MediaChangeCount
));
73 // If the volume is now an empty device, or we have receieved a
74 // bare STATUS_VERIFY_REQUIRED (various hardware conditions such
75 // as bus resets, etc., will trigger this in the drivers), or the
76 // media change count has moved since we last inspected the device,
77 // then mark the volume to be verified.
79 if ( (RC
== STATUS_VERIFY_REQUIRED
) ||
80 (UDFIsRawDevice(RC
) && (Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) ||
81 (NT_SUCCESS(RC
) && (Vcb
->MediaChangeCount
!= MediaChangeCount
)) ||
84 UDFPrint((" set DO_VERIFY_VOLUME\n"));
85 Vcb
->Vpb
->RealDevice
->Flags
|= DO_VERIFY_VOLUME
;
87 // If the volume is not mounted and we got a media change count,
88 // update the Vcb so we do not trigger a verify again at this
89 // count value. If the verify->mount path detects that the media
90 // has actually changed and this Vcb is valid again, this will have
91 // done nothing. We are already synchronized since the caller has
93 if (!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) &&
95 Vcb
->MediaChangeCount
= MediaChangeCount
;
98 } else if (!NT_SUCCESS(RC
)) {
99 // Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
100 UDFPrint((" UDFNormalizeAndRaiseStatus(%x)\n", RC
));
101 UDFNormalizeAndRaiseStatus(IrpContext
,RC
);
106 UDFPrint(("UDFVerifyVCB: Modified=%d\n", Vcb
->Modified
));
107 // The Vcb may be mounted but the underlying real device may need to be verified.
108 // If it does then we'll set the Iosb in the irp to be our real device
109 if (Vcb
->Vpb
->RealDevice
->Flags
& DO_VERIFY_VOLUME
) {
111 UDFPrint((" DO_VERIFY_VOLUME -> IoSetHardErrorOrVerifyDevice()\n"));
112 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
,
113 Vcb
->Vpb
->RealDevice
);
115 RC
= STATUS_VERIFY_REQUIRED
;
116 UDFPrint((" UDFRaiseStatus()\n"));
117 UDFRaiseStatus(IrpContext
, RC
);
121 UDFPrint(("UDFVerifyVCB: Modified=%d\n", Vcb
->Modified
));
122 if (!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) {
123 UDFPrint((" !UDF_VCB_FLAGS_VOLUME_MOUNTED -> IoSetHardErrorOrVerifyDevice()\n"));
124 Vcb
->Vpb
->RealDevice
->Flags
|= DO_VERIFY_VOLUME
;
125 IoSetHardErrorOrVerifyDevice( IrpContext
->Irp
, Vcb
->Vpb
->RealDevice
);
126 RC
= STATUS_WRONG_VOLUME
;
127 UDFPrint((" UDFRaiseStatus()\n"));
128 UDFRaiseStatus(IrpContext
, RC
);
129 // UDFRaiseStatus(IrpContext, STATUS_UNRECOGNIZED_VOLUME);
132 if ((Vcb
->VCBFlags
& UDF_VCB_FLAGS_BEING_DISMOUNTED
)) {
133 UDFPrint((" UDF_VCB_FLAGS_BEING_DISMOUNTED\n"));
134 RC
= STATUS_FILE_INVALID
;
135 UDFRaiseStatus( IrpContext
, RC
);
138 UDFPrint(("UDFVerifyVcb: RC = %x\n", RC
));
141 } // end UDFVerifyVcb()
146 This routine performs the verify volume operation. It is responsible for
147 either completing of enqueuing the input Irp.
150 Irp - Supplies the Irp to process
154 NTSTATUS - The return status for the operation
162 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
163 PVPB Vpb
= IrpSp
->Parameters
.VerifyVolume
.Vpb
;
164 PVCB Vcb
= (PVCB
)IrpSp
->Parameters
.VerifyVolume
.DeviceObject
->DeviceExtension
;
166 IO_STATUS_BLOCK Iosb
;
167 ULONG MediaChangeCount
= 0;
170 BOOLEAN UnsafeIoctl
= (Vcb
->VCBFlags
& UDF_VCB_FLAGS_UNSAFE_IOCTL
) ? TRUE
: FALSE
;
172 // Update the real device in the IrpContext from the Vpb. There was no available
173 // file object when the IrpContext was created.
174 // IrpContext->RealDevice = Vpb->RealDevice;
175 UDFPrint(("UDFVerifyVolume:\n"));
177 // Acquire shared global access, the termination handler for the
178 // following try statement will free the access.
180 UDFAcquireResourceShared(&(UDFGlobalData
.GlobalDataResource
),TRUE
);
181 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
),TRUE
);
185 UDFPrint(("UDFVerifyVolume: Modified=%d\n", Vcb
->Modified
));
186 // Check if the real device still needs to be verified. If it doesn't
187 // then obviously someone beat us here and already did the work
188 // so complete the verify irp with success. Otherwise reenable
189 // the real device and get to work.
190 if( !(Vpb
->RealDevice
->Flags
& DO_VERIFY_VOLUME
) &&
191 ((Vcb
->VCBFlags
& UDF_VCB_FLAGS_MEDIA_LOCKED
) && !UnsafeIoctl
) ) {
192 UDFPrint(("UDFVerifyVolume: STATUS_SUCCESS (1)\n"));
193 try_return(RC
= STATUS_SUCCESS
);
195 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_UNSAFE_IOCTL
;
196 // Verify that there is a disk here.
197 RC
= UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY
,
198 Vcb
->TargetDeviceObject
,
200 &MediaChangeCount
,sizeof(ULONG
),
203 if(!NT_SUCCESS( RC
)) {
204 // If we will allow a raw mount then return WRONG_VOLUME to
205 // allow the volume to be mounted by raw.
206 if(FlagOn( IrpSp
->Flags
, SL_ALLOW_RAW_MOUNT
)) {
207 UDFPrint(("UDFVerifyVolume: STATUS_WRONG_VOLUME (1)\n"));
208 RC
= STATUS_WRONG_VOLUME
;
211 if(UDFIsRawDevice(RC
)) {
212 UDFPrint(("UDFVerifyVolume: STATUS_WRONG_VOLUME (2)\n"));
213 RC
= STATUS_WRONG_VOLUME
;
218 if(Iosb
.Information
!= sizeof(ULONG
)) {
219 // Be safe about the count in case the driver didn't fill it in
220 MediaChangeCount
= 0;
223 UDFPrint(("UDFVerifyVolume: Modified=%d\n", Vcb
->Modified
));
224 UDFPrint(("UDFVerifyVolume: MediaChangeCount=%x, Vcb->MediaChangeCount=%x, UnsafeIoctl=%x\n",
225 MediaChangeCount
, Vcb
->MediaChangeCount
, UnsafeIoctl
));
226 // Verify that the device actually saw a change. If the driver does not
227 // support the MCC, then we must verify the volume in any case.
228 if(MediaChangeCount
== 0 ||
229 (Vcb
->MediaChangeCount
!= MediaChangeCount
) ||
232 UDFPrint(("UDFVerifyVolume: compare\n"));
234 NewVcb
= (PVCB
)MyAllocatePool__(NonPagedPool
,sizeof(VCB
));
236 try_return(RC
=STATUS_INSUFFICIENT_RESOURCES
);
237 RtlZeroMemory(NewVcb
,sizeof(VCB
));
239 NewVcb
->TargetDeviceObject
= Vcb
->TargetDeviceObject
;
242 // Set the removable media flag based on the real device's
244 if(Vpb
->RealDevice
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
245 UDFSetFlag( NewVcb
->VCBFlags
, UDF_VCB_FLAGS_REMOVABLE_MEDIA
);
248 RC
= UDFGetDiskInfo(NewVcb
->TargetDeviceObject
,NewVcb
);
249 if(!NT_SUCCESS(RC
)) try_return(RC
);
250 // Prevent modification attempts durring Verify
251 NewVcb
->VCBFlags
|= UDF_VCB_FLAGS_VOLUME_READ_ONLY
|
252 UDF_VCB_FLAGS_MEDIA_READ_ONLY
;
253 // Compare physical parameters (phase 1)
254 UDFPrint(("UDFVerifyVolume: Modified=%d\n", Vcb
->Modified
));
255 RC
= UDFCompareVcb(Vcb
,NewVcb
, TRUE
);
256 if(!NT_SUCCESS(RC
)) try_return(RC
);
258 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) &&
259 Vcb
->MountPhErrorCount
> MOUNT_ERR_THRESHOLD
) {
260 UDFPrint(("UDFVerifyVolume: it was very BAD volume. Do not perform Logical check\n"));
261 goto skip_logical_check
;
263 // Initialize internal cache
264 // in *** READ ONLY *** mode
265 Mode
= WCACHE_MODE_ROM
;
267 RC
= WCacheInit__(&(NewVcb
->FastCache
),
268 UDFGlobalData
.WCacheMaxFrames
,
269 UDFGlobalData
.WCacheMaxBlocks
,
270 NewVcb
->WriteBlockSize
,
271 5, NewVcb
->BlockSizeBits
,
272 UDFGlobalData
.WCacheBlocksPerFrameSh
,
273 0/*NewVcb->FirstLBA*/, NewVcb
->LastPossibleLBA
, Mode
,
274 /*WCACHE_CACHE_WHOLE_PACKET*/ 0 |
275 (Vcb
->DoNotCompareBeforeWrite
? WCACHE_DO_NOT_COMPARE
: 0) |
276 WCACHE_MARK_BAD_BLOCKS
| WCACHE_RO_BAD_BLOCKS
, // speed up mount on bad disks
277 UDFGlobalData
.WCacheFramesToKeepFree
,
280 UDFTWriteAsync
, UDFTReadAsync
,
283 #endif //UDF_ASYNC_IO
284 UDFIsBlockAllocated
, UDFUpdateVAT
,
285 UDFWCacheErrorHandler
);
286 if(!NT_SUCCESS(RC
)) try_return(RC
);
288 UDFPrint(("UDFVerifyVolume: Modified=%d\n", Vcb
->Modified
));
289 RC
= UDFGetDiskInfoAndVerify(NewVcb
->TargetDeviceObject
,NewVcb
);
290 UDFPrint((" NewVcb->NSRDesc=%x\n", NewVcb
->NSRDesc
));
291 if(!NT_SUCCESS(RC
)) {
292 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) &&
293 (NewVcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) &&
294 !(NewVcb
->NSRDesc
& VRS_ISO9660_FOUND
)) {
295 UDFPrint(("UDFVerifyVolume: both are RAW -> remount\n", Vcb
->Modified
));
297 goto skip_logical_check
;
299 if(RC
== STATUS_UNRECOGNIZED_VOLUME
) {
300 try_return(RC
= STATUS_WRONG_VOLUME
);
305 WCacheChFlags__(&(Vcb
->FastCache
),
306 WCACHE_CACHE_WHOLE_PACKET
, // enable cache whole packet
307 WCACHE_MARK_BAD_BLOCKS
| WCACHE_RO_BAD_BLOCKS
); // let user retry request on Bad Blocks
309 NewVcb
->VCBFlags
|= UDF_VCB_FLAGS_VOLUME_MOUNTED
;
310 // Compare logical parameters (phase 2)
311 UDFPrint(("UDFVerifyVolume: Modified=%d\n", Vcb
->Modified
));
312 RC
= UDFCompareVcb(Vcb
,NewVcb
, FALSE
);
313 if(!NT_SUCCESS(RC
)) try_return(RC
);
314 // We have unitialized WCache, so it is better to
315 // force MOUNT_VOLUME call
316 if(!WCacheIsInitialized__(&(Vcb
->FastCache
)))
317 try_return(RC
= STATUS_WRONG_VOLUME
);
323 UDFPrint(("UDFVerifyVolume: compared\n"));
324 UDFPrint(("UDFVerifyVolume: Modified=%d\n", Vcb
->Modified
));
325 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_LOCKED
)) {
326 UDFPrint(("UDFVerifyVolume: set UDF_VCB_FLAGS_VOLUME_MOUNTED\n"));
327 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_VOLUME_MOUNTED
;
328 Vcb
->SoftEjectReq
= FALSE
;
330 UDFClearFlag( Vpb
->RealDevice
->Flags
, DO_VERIFY_VOLUME
);
336 // Update the media change count to note that we have verified the volume
338 Vcb
->MediaChangeCount
= MediaChangeCount
;
340 // If we got the wrong volume, mark the Vcb as not mounted.
341 if(RC
== STATUS_WRONG_VOLUME
) {
342 UDFPrint(("UDFVerifyVolume: clear UDF_VCB_FLAGS_VOLUME_MOUNTED\n"));
343 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_MOUNTED
;
344 Vcb
->WriteSecurity
= FALSE
;
345 // ASSERT(!(Vcb->EjectWaiter));
346 if(Vcb
->EjectWaiter
) {
347 UDFReleaseResource(&(Vcb
->VCBResource
));
348 UDFStopEjectWaiter(Vcb
);
349 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
),TRUE
);
353 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)){
354 BOOLEAN CacheInitialized
= FALSE
;
355 UDFPrint((" !!! VerifyVolume - QUICK REMOUNT !!!\n"));
356 // Initialize internal cache
357 CacheInitialized
= WCacheIsInitialized__(&(Vcb
->FastCache
));
358 if(!CacheInitialized
) {
359 Mode
= WCACHE_MODE_ROM
;
360 RC
= WCacheInit__(&(Vcb
->FastCache
),
361 Vcb
->WCacheMaxFrames
,
362 Vcb
->WCacheMaxBlocks
,
364 5, Vcb
->BlockSizeBits
,
365 Vcb
->WCacheBlocksPerFrameSh
,
366 0/*Vcb->FirstLBA*/, Vcb
->LastPossibleLBA
, Mode
,
367 /*WCACHE_CACHE_WHOLE_PACKET*/ 0 |
368 (Vcb
->DoNotCompareBeforeWrite
? WCACHE_DO_NOT_COMPARE
: 0) |
369 (Vcb
->CacheChainedIo
? WCACHE_CHAINED_IO
: 0),
370 Vcb
->WCacheFramesToKeepFree
,
371 // UDFTWrite, UDFTRead,
372 UDFTWriteVerify
, UDFTReadVerify
,
374 UDFTWriteAsync
, UDFTReadAsync
,
377 #endif //UDF_ASYNC_IO
378 UDFIsBlockAllocated
, UDFUpdateVAT
,
379 UDFWCacheErrorHandler
);
382 if(!Vcb
->VerifyCtx
.VInited
) {
388 if(!CacheInitialized
) {
389 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_MEDIA_READ_ONLY
)) {
391 if((Vcb
->TargetDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
392 CdrwMediaClassEx_IsRAM(Vcb
->MediaClassEx
)) {
393 UDFPrint(("UDFMountVolume: RAM mode\n"));
394 Mode
= WCACHE_MODE_RAM
;
396 UDFPrint(("UDFMountVolume: RW mode\n"));
397 Mode
= WCACHE_MODE_RW
;
399 /* if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
401 Vcb->WriteSecurity = TRUE;
404 Mode
= WCACHE_MODE_R
;
407 WCacheSetMode__(&(Vcb
->FastCache
), Mode
);
409 WCacheChFlags__(&(Vcb
->FastCache
),
410 WCACHE_CACHE_WHOLE_PACKET
, // enable cache whole packet
411 WCACHE_MARK_BAD_BLOCKS
| WCACHE_RO_BAD_BLOCKS
); // let user retry request on Bad Blocks
413 // we can't record ACL on old format disks
414 if(!UDFNtAclSupported(Vcb
)) {
415 Vcb
->WriteSecurity
= FALSE
;
416 Vcb
->UseExtendedFE
= FALSE
;
418 UDFPrint(("UDFVerifyVolume: try start EjectWaiter\n"));
419 RC
= UDFStartEjectWaiter(Vcb
);
420 if(!NT_SUCCESS(RC
)) {
421 UDFPrint(("UDFVerifyVolume: start EjectWaiter failed\n"));
422 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_MOUNTED
;
423 Vcb
->WriteSecurity
= FALSE
;
429 // Release internal cache
430 UDFPrint(("UDFVerifyVolume: delete NewVcb\n"));
431 WCacheFlushAll__(&(NewVcb
->FastCache
),NewVcb
);
432 WCacheRelease__(&(NewVcb
->FastCache
));
434 ASSERT(!(NewVcb
->EjectWaiter
));
435 // Waiter thread should be already stopped
436 // if MediaChangeCount have changed
437 ASSERT(!(Vcb
->EjectWaiter
));
439 UDFCleanupVCB(NewVcb
);
440 MyFreePool__(NewVcb
);
442 UDFReleaseResource(&(Vcb
->VCBResource
));
443 UDFReleaseResource(&(UDFGlobalData
.GlobalDataResource
));
446 // Complete the request if no exception.
447 Irp
->IoStatus
.Information
= 0;
449 Irp
->IoStatus
.Status
= RC
;
450 IoCompleteRequest(Irp
,IO_DISK_INCREMENT
);
452 UDFPrint(("UDFVerifyVolume: RC = %x\n", RC
));
455 } // end UDFVerifyVolume ()
460 This routines performs an IoVerifyVolume operation and takes the
461 appropriate action. If the verify is successful then we send the originating
462 Irp off to an Ex Worker Thread. This routine is called from the exception handler.
463 No file system resources are held when this routine is called.
467 Irp - The irp to send off after all is well and done.
468 Device - The real device needing verification.
473 IN PtrUDFIrpContext IrpContext
,
475 IN PDEVICE_OBJECT DeviceToVerify
480 NTSTATUS RC
= STATUS_SUCCESS
;
481 PIO_STACK_LOCATION IrpSp
;
483 UDFPrint(("UDFPerformVerify:\n"));
484 if(!IrpContext
) return STATUS_INVALID_PARAMETER
;
485 if(!Irp
) return STATUS_INVALID_PARAMETER
;
487 // Check if this Irp has a status of Verify required and if it does
488 // then call the I/O system to do a verify.
490 // Skip the IoVerifyVolume if this is a mount or verify request
491 // itself. Trying a recursive mount will cause a deadlock with
492 // the DeviceObject->DeviceLock.
493 if ((IrpContext
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
494 ((IrpContext
->MinorFunction
== IRP_MN_MOUNT_VOLUME
) ||
495 (IrpContext
->MinorFunction
== IRP_MN_VERIFY_VOLUME
))) {
497 return UDFPostRequest(IrpContext
, Irp
);
500 // Extract a pointer to the Vcb from the VolumeDeviceObject.
501 // Note that since we have specifically excluded mount,
502 // requests, we know that IrpSp->DeviceObject is indeed a
503 // volume device object.
505 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
507 Vcb
= (PVCB
)IrpSp
->DeviceObject
->DeviceExtension
;
509 UDFPrint(("UDFPerformVerify: check\n"));
510 // Check if the volume still thinks it needs to be verified,
511 // if it doesn't then we can skip doing a verify because someone
512 // else beat us to it.
515 if (DeviceToVerify
->Flags
& DO_VERIFY_VOLUME
) {
517 // If the IopMount in IoVerifyVolume did something, and
518 // this is an absolute open, force a reparse.
519 RC
= IoVerifyVolume( DeviceToVerify
, FALSE
);
522 /* if (UDFIsRawDevice(RC)) {
523 RC = STATUS_WRONG_VOLUME;
526 // If the verify operation completed it will return
527 // either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly.
528 if (RC
== STATUS_SUCCESS
) {
529 IrpContext
->IrpContextFlags
&= ~UDF_IRP_CONTEXT_EXCEPTION
;
531 // If UDFVerifyVolume encountered an error during
532 // processing, it will return that error. If we got
533 // STATUS_WRONG_VOLUME from the verify, and our volume
534 // is now mounted, commute the status to STATUS_SUCCESS.
535 if ((RC
== STATUS_WRONG_VOLUME
) &&
536 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) {
540 // Do a quick unprotected check here. The routine will do
541 // a safe check. After here we can release the resource.
542 // Note that if the volume really went away, we will be taking
545 // If the device might need to go away then call our dismount routine.
546 if ( (!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) ||
547 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_BEING_DISMOUNTED
)) &&
548 (Vcb
->VCBOpenCount
<= UDF_RESIDUAL_REFERENCE
) )
550 UDFPrint(("UDFPerformVerify: UDFCheckForDismount\n"));
551 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
552 UDFCheckForDismount( IrpContext
, Vcb
, FALSE
);
553 UDFReleaseResource(&(UDFGlobalData
.GlobalDataResource
));
556 // If this is a create and the verify succeeded then complete the
557 // request with a REPARSE status.
558 if ((IrpContext
->MajorFunction
== IRP_MJ_CREATE
) &&
559 (IrpSp
->FileObject
->RelatedFileObject
== NULL
) &&
560 ((RC
== STATUS_SUCCESS
) || (RC
== STATUS_WRONG_VOLUME
)) ) {
562 UDFPrint(("UDFPerformVerify: IO_REMOUNT\n"));
564 Irp
->IoStatus
.Information
= IO_REMOUNT
;
566 Irp
->IoStatus
.Status
= STATUS_REPARSE
;
567 IoCompleteRequest(Irp
,IO_DISK_INCREMENT
);
569 UDFReleaseIrpContext(IrpContext
);
575 // If there is still an error to process then call the Io system
577 } else if ((Irp
!= NULL
) && !NT_SUCCESS( RC
)) {
579 UDFPrint(("UDFPerformVerify: check IoIsErrorUserInduced\n"));
580 // Fill in the device object if required.
581 if (IoIsErrorUserInduced( RC
) ) {
582 IoSetHardErrorOrVerifyDevice( Irp
, DeviceToVerify
);
584 UDFPrint(("UDFPerformVerify: UDFNormalizeAndRaiseStatus\n"));
585 UDFNormalizeAndRaiseStatus( IrpContext
, RC
);
589 // If there is still an Irp, send it off to an Ex Worker thread.
590 if (IrpContext
!= NULL
) {
592 RC
= UDFPostRequest( IrpContext
, Irp
);
595 } _SEH2_EXCEPT(UDFExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation())) {
596 // We had some trouble trying to perform the verify or raised
597 // an error ourselves. So we'll abort the I/O request with
598 // the error status that we get back from the execption code.
599 RC
= UDFExceptionHandler( IrpContext
, Irp
);
602 UDFPrint(("UDFPerformVerify: RC = %x\n", RC
));
606 } // end UDFPerformVerify()
612 This routine is called to check if a volume is ready for dismount. This
613 occurs when only file system references are left on the volume.
615 If the dismount is not currently underway and the user reference count
616 has gone to zero then we can begin the dismount.
618 If the dismount is in progress and there are no references left on the
619 volume (we check the Vpb for outstanding references as well to catch
620 any create calls dispatched to the file system) then we can delete
625 Vcb - Vcb for the volume to try to dismount.
630 IN PtrUDFIrpContext IrpContext
,
632 IN BOOLEAN _VcbAcquired
635 BOOLEAN VcbPresent
= TRUE
;
638 ULONG ResidualReferenceCount
;
640 UDFPrint(("UDFCheckForDismount:\n"));
641 if(!Vcb
) return FALSE
;
643 // GlobalDataResource is already acquired
645 VcbAcquired
= UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
/*FALSE*/ );
652 if ((IrpContext
->MajorFunction
== IRP_MJ_CREATE
) &&
653 (IrpContext
->TargetDeviceObject
== Vcb
->TargetDeviceObject
)) {
655 ResidualReferenceCount
= 2;
659 ResidualReferenceCount
= 1;
662 // If the dismount is not already underway then check if the
663 // user reference count has gone to zero. If so start the teardown
665 if (!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_BEING_DISMOUNTED
)) {
666 if (Vcb
->VCBOpenCount
<= UDF_RESIDUAL_REFERENCE
) {
667 VcbPresent
= UDFDismountVcb(Vcb
, VcbAcquired
);
669 VcbAcquired
= VcbAcquired
&& VcbPresent
;
671 // If the teardown is underway and there are absolutely no references
672 // remaining then delete the Vcb. References here include the
673 // references in the Vcb and Vpb.
674 } else if (!(Vcb
->VCBOpenCount
)) {
676 IoAcquireVpbSpinLock( &SavedIrql
);
677 // If there are no file objects and no reference counts in the
678 // Vpb we can delete the Vcb. Don't forget that we have the
679 // last reference in the Vpb.
680 if (Vcb
->Vpb
->ReferenceCount
<= ResidualReferenceCount
) {
682 IoReleaseVpbSpinLock( SavedIrql
);
684 UDFReleaseResource(&(Vcb
->VCBResource
));
685 UDFStopEjectWaiter(Vcb
);
692 IoReleaseVpbSpinLock( SavedIrql
);
696 // Release any resources still acquired.
697 if (!_VcbAcquired
&& VcbAcquired
) {
698 UDFReleaseResource(&(Vcb
->VCBResource
));
702 } // end UDFCheckForDismount()
709 This routine is called when all of the user references to a volume are
710 gone. We will initiate all of the teardown any system resources.
712 If all of the references to this volume are gone at the end of this routine
713 then we will complete the teardown of this Vcb and mark the current Vpb
714 as not mounted. Otherwise we will allocated a new Vpb for this device
715 and keep the current Vpb attached to the Vcb.
719 Vcb - Vcb for the volume to dismount.
723 BOOLEAN - TRUE if we didn't delete the Vcb, FALSE otherwise.
729 IN BOOLEAN VcbAcquired
735 BOOLEAN VcbPresent
= TRUE
;
738 BOOLEAN FinalReference
;
740 UDFPrint(("UDFDismountVcb:\n"));
741 // We should only take this path once.
742 ASSERT( !(Vcb
->VCBFlags
& UDF_VCB_FLAGS_BEING_DISMOUNTED
) );
744 // Mark the Vcb as DismountInProgress.
745 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_BEING_DISMOUNTED
;
747 // Allocate a new Vpb in case we will need it.
748 NewVpb
= (PVPB
)DbgAllocatePoolWithTag( NonPagedPool
, sizeof( VPB
), 'bpvU' );
750 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_BEING_DISMOUNTED
;
754 RtlZeroMemory( NewVpb
, sizeof(VPB
) );
758 // Remove the mount volume reference.
759 UDFCloseResidual(Vcb
);
760 // the only residual reference is cleaned above
762 // Acquire the Vpb spinlock to check for Vpb references.
763 IoAcquireVpbSpinLock(&SavedIrql
);
765 // Remember if this is the last reference on this Vcb. We incremented
766 // the count on the Vpb earlier so we get one last crack it. If our
767 // reference has gone to zero but the vpb reference count is greater
768 // than zero then the Io system will be responsible for deleting the
770 FinalReference
= (BOOLEAN
)(OldVpb
->ReferenceCount
== 1);
772 // There is a reference count in the Vpb and in the Vcb. We have
773 // incremented the reference count in the Vpb to make sure that
774 // we have last crack at it. If this is a failed mount then we
775 // want to return the Vpb to the IO system to use for the next
777 if (OldVpb
->RealDevice
->Vpb
== OldVpb
) {
779 // If not the final reference then swap out the Vpb.
780 if (!FinalReference
) {
782 NewVpb
->Type
= IO_TYPE_VPB
;
783 NewVpb
->Size
= sizeof( VPB
);
784 NewVpb
->RealDevice
= OldVpb
->RealDevice
;
786 NewVpb
->RealDevice
->Vpb
= NewVpb
;
789 IoReleaseVpbSpinLock(SavedIrql
);
790 // We want to leave the Vpb for the IO system. Mark it
791 // as being not mounted. Go ahead and delete the Vcb as
795 // Make sure to remove the last reference on the Vpb.
797 OldVpb
->ReferenceCount
--;
799 OldVpb
->DeviceObject
= NULL
;
800 Vcb
->Vpb
->Flags
&= ~VPB_MOUNTED
;
802 // Clear the Vpb flag so we know not to delete it.
805 IoReleaseVpbSpinLock(SavedIrql
);
807 UDFReleaseResource(&(Vcb
->VCBResource
));
808 UDFStopEjectWaiter(Vcb
);
813 // Someone has already swapped in a new Vpb. If this is the final reference
814 // then the file system is responsible for deleting the Vpb.
815 } else if (FinalReference
) {
817 // Make sure to remove the last reference on the Vpb.
818 OldVpb
->ReferenceCount
--;
820 IoReleaseVpbSpinLock( SavedIrql
);
822 UDFReleaseResource(&(Vcb
->VCBResource
));
823 UDFStopEjectWaiter(Vcb
);
827 // The current Vpb is no longer the Vpb for the device (the IO system
828 // has already allocated a new one). We leave our reference in the
829 // Vpb and will be responsible for deleting it at a later time.
832 OldVpb
->DeviceObject
= NULL
;
833 Vcb
->Vpb
->Flags
&= ~VPB_MOUNTED
;
835 IoReleaseVpbSpinLock( SavedIrql
);
838 // Deallocate the new Vpb if we don't need it.
839 if (NewVpb
!= NULL
) {
840 DbgFreePool( NewVpb
);
843 // Let our caller know whether the Vcb is still present.
845 } // end UDFDismountVcb()
852 IN BOOLEAN PhysicalOnly
856 UDF_FILE_INFO RootFileInfo
;
857 BOOLEAN SimpleLogicalCheck
= FALSE
;
859 UDFPrint(("UDFCompareVcb:\n"));
860 if(UDFGlobalData
.UDFFlags
& UDF_DATA_FLAGS_BEING_UNLOADED
) {
861 UDFPrint((" WRONG_VOLUME\n"));
862 return STATUS_WRONG_VOLUME
;
865 #define VCB_NE(x) (OldVcb->x != NewVcb->x)
867 // compare physical parameters
869 UDFPrint((" PhysicalOnly\n"));
870 if(VCB_NE(FirstLBA
) ||
872 VCB_NE(FirstTrackNum
) ||
873 VCB_NE(LastTrackNum
) ||
875 VCB_NE(LastPossibleLBA
) ||
876 VCB_NE(PhSerialNumber
) ||
877 VCB_NE(PhErasable
) ||
878 VCB_NE(PhDiskType
) ||
879 VCB_NE(MediaClassEx
) ||
881 /* We cannot compare these flags, because NewVcb is in unconditional ReadOnly */
883 /*((OldVcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) != (NewVcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) ||
884 ((OldVcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) != (NewVcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) ||*/
886 VCB_NE(TargetDeviceObject
) ||
889 VCB_NE(LastSession
) ) {
891 UDFPrint((" WRONG_VOLUME (2)\n"));
892 return STATUS_WRONG_VOLUME
;
894 // Note, MRWStatus can change while media is mounted (stoppped/in-progress/complete)
895 // We can compare only (Vcb->MRWStatus == 0) values
896 if((OldVcb
->MRWStatus
== 0) != (NewVcb
->MRWStatus
== 0)) {
897 UDFPrint((" WRONG_VOLUME (4), missmatch MRW status\n"));
899 for(uint32 i
=OldVcb
->FirstTrackNum
; i
<=OldVcb
->LastTrackNum
; i
++) {
900 if(VCB_NE(TrackMap
[i
].FirstLba
) ||
901 VCB_NE(TrackMap
[i
].LastLba
) ||
902 VCB_NE(TrackMap
[i
].PacketSize
) ||
903 VCB_NE(TrackMap
[i
].TrackParam
) ||
904 VCB_NE(TrackMap
[i
].DataParam
) ||
905 VCB_NE(TrackMap
[i
].NWA_V
) ) {
906 UDFPrint((" WRONG_VOLUME (3), missmatch trk %d\n", i
));
907 return STATUS_WRONG_VOLUME
;
910 UDFPrint((" Vcb compare Ok\n"));
911 return STATUS_SUCCESS
;
914 // Something is nasty!!! We perform verify for not flushed volume
915 // This should never happen, but some devices/buses and their drivers
916 // can lead us to such condition. For example with help of RESET.
917 // Now, we hope, that nobody changed media.
918 // We shall make simplified logical structure check
919 if(OldVcb
->Modified
) {
920 UDFPrint((" Vcb SIMPLE compare on !!!MODIFIED!!! volume\n"));
922 SimpleLogicalCheck
= TRUE
;
925 // compare logical structure
926 if(!SimpleLogicalCheck
&& (OldVcb
->InitVatCount
!= NewVcb
->InitVatCount
)) {
927 UDFPrint((" InitVatCount %d != %d \n", OldVcb
->InitVatCount
, NewVcb
->InitVatCount
));
928 return STATUS_WRONG_VOLUME
;
931 // Compare volume creation time
932 if(OldVcb
->VolCreationTime
!= NewVcb
->VolCreationTime
) {
933 UDFPrint((" VolCreationTime %I64x != %I64x \n", OldVcb
->VolCreationTime
, NewVcb
->VolCreationTime
));
934 return STATUS_WRONG_VOLUME
;
936 // Compare serial numbers
937 if(OldVcb
->SerialNumber
!= NewVcb
->SerialNumber
) {
938 UDFPrint((" SerialNumber %x != %x \n", OldVcb
->SerialNumber
, NewVcb
->SerialNumber
));
939 return STATUS_WRONG_VOLUME
;
941 // Compare volume idents
942 if(!SimpleLogicalCheck
&&
943 RtlCompareUnicodeString(&(OldVcb
->VolIdent
),&(NewVcb
->VolIdent
),FALSE
)) {
944 UDFPrint((" VolIdent missmatch \n"));
945 return STATUS_WRONG_VOLUME
;
947 if(SimpleLogicalCheck
) {
948 // do not touch RootDir. It can be partially recorded
949 UDFPrint((" SimpleLogicalCheck Ok\n"));
950 return STATUS_SUCCESS
;
953 RC
= UDFOpenRootFile__(NewVcb
, &(NewVcb
->RootLbAddr
), &RootFileInfo
);
954 if(!NT_SUCCESS(RC
)) {
955 UDFPrint((" Can't open root file, status %x\n", RC
));
956 UDFCleanUpFile__(NewVcb
, &RootFileInfo
);
957 return STATUS_WRONG_VOLUME
;
959 // perform exhaustive check
960 if(!(OldVcb
->RootDirFCB
)) {
961 UDFPrint((" !(OldVcb->RootDirFCB)\n"));
963 UDFCloseFile__(NewVcb
, &RootFileInfo
);
964 UDFCleanUpFile__(NewVcb
, &RootFileInfo
);
965 return STATUS_WRONG_VOLUME
;
968 if(!UDFCompareFileInfo(&RootFileInfo
, OldVcb
->RootDirFCB
->FileInfo
)) {
969 UDFPrint((" !UDFCompareFileInfo\n"));
972 UDFCloseFile__(NewVcb
, &RootFileInfo
);
973 UDFCleanUpFile__(NewVcb
, &RootFileInfo
);
975 UDFPrint(("UDFCompareVcb: Ok\n"));
976 return STATUS_SUCCESS
;
980 } // end UDFCompareVcb()