Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

fsctrl.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1996 Microsoft Corporation 00004 00005 Module Name: 00006 00007 FsCtrl.c 00008 00009 Abstract: 00010 00011 This module implements the File System Control routines for Udfs called 00012 by the Fsd/Fsp dispatch drivers. 00013 00014 Author: 00015 00016 Dan Lovinger [DanLo] 11-Jun-1996 00017 00018 Revision History: 00019 00020 --*/ 00021 00022 #include "UdfProcs.h" 00023 00024 // 00025 // The Bug check file id for this module 00026 // 00027 00028 #define BugCheckFileId (UDFS_BUG_CHECK_FSCTRL) 00029 00030 // 00031 // The local debug trace level 00032 // 00033 00034 #define Dbg (UDFS_DEBUG_LEVEL_FSCTRL) 00035 00036 // 00037 // Local constants 00038 // 00039 00040 BOOLEAN UdfDisable = FALSE; 00041 00042 // 00043 // Local macros 00044 // 00045 00046 INLINE 00047 VOID 00048 UdfStoreFileSetDescriptorIfPrevailing ( 00049 IN OUT PNSR_FSD *StoredFSD, 00050 IN OUT PNSR_FSD *NewFSD 00051 ) 00052 { 00053 PNSR_FSD TempFSD; 00054 00055 // 00056 // If we haven't stored a fileset descriptor or the fileset number 00057 // of the stored descriptor is less than the new descriptor, swap the 00058 // pointers around. 00059 // 00060 00061 if (*StoredFSD == NULL || (*StoredFSD)->FileSet < (*NewFSD)->FileSet) { 00062 00063 TempFSD = *StoredFSD; 00064 *StoredFSD = *NewFSD; 00065 *NewFSD = TempFSD; 00066 } 00067 } 00068 00069 // 00070 // Local support routines 00071 // 00072 00073 VOID 00074 UdfDetermineVolumeBounding ( 00075 IN PIRP_CONTEXT IrpContext, 00076 IN PVCB Vcb, 00077 IN PULONG S, 00078 IN PULONG N 00079 ); 00080 00081 NTSTATUS 00082 UdfDismountVolume ( 00083 IN PIRP_CONTEXT IrpContext, 00084 IN PIRP Irp 00085 ); 00086 00087 NTSTATUS 00088 UdfFindAnchorVolumeDescriptor ( 00089 IN PIRP_CONTEXT IrpContext, 00090 IN PVCB Vcb, 00091 IN OUT PNSR_ANCHOR *AnchorVolumeDescriptor 00092 ); 00093 00094 NTSTATUS 00095 UdfFindFileSetDescriptor ( 00096 IN PIRP_CONTEXT IrpContext, 00097 IN PVCB Vcb, 00098 IN PLONGAD LongAd, 00099 IN OUT PNSR_FSD *FileSetDescriptor 00100 ); 00101 00102 NTSTATUS 00103 UdfFindVolumeDescriptors ( 00104 IN PIRP_CONTEXT IrpContext, 00105 IN PVCB Vcb, 00106 IN PEXTENTAD Extent, 00107 IN OUT PPCB *Pcb, 00108 IN OUT PNSR_PVD *PrimaryVolumeDescriptor, 00109 IN OUT PNSR_LVOL *LogicalVolumeDescriptor 00110 ); 00111 00112 NTSTATUS 00113 UdfInvalidateVolumes ( 00114 IN PIRP_CONTEXT IrpContext, 00115 IN PIRP Irp 00116 ); 00117 00118 NTSTATUS 00119 UdfIsPathnameValid ( 00120 IN PIRP_CONTEXT IrpContext, 00121 IN PIRP Irp 00122 ); 00123 00124 BOOLEAN 00125 UdfIsRemount ( 00126 IN PIRP_CONTEXT IrpContext, 00127 IN PVCB Vcb, 00128 OUT PVCB *OldVcb 00129 ); 00130 00131 UdfIsVolumeDirty ( 00132 IN PIRP_CONTEXT IrpContext, 00133 IN PIRP Irp 00134 ); 00135 00136 NTSTATUS 00137 UdfIsVolumeMounted ( 00138 IN PIRP_CONTEXT IrpContext, 00139 IN PIRP Irp 00140 ); 00141 00142 NTSTATUS 00143 UdfLockVolume ( 00144 IN PIRP_CONTEXT IrpContext, 00145 IN PIRP Irp 00146 ); 00147 00148 NTSTATUS 00149 UdfMountVolume( 00150 IN PIRP_CONTEXT IrpContext, 00151 IN PIRP Irp 00152 ); 00153 00154 NTSTATUS 00155 UdfOplockRequest ( 00156 IN PIRP_CONTEXT IrpContext, 00157 IN PIRP Irp 00158 ); 00159 00160 BOOLEAN 00161 UdfRecognizeVolume ( 00162 IN PIRP_CONTEXT IrpContext, 00163 IN PDEVICE_OBJECT DeviceObject, 00164 IN ULONG SectorSize, 00165 IN OUT PBOOLEAN Bridge 00166 ); 00167 00168 VOID 00169 UdfScanForDismountedVcb ( 00170 IN PIRP_CONTEXT IrpContext 00171 ); 00172 00173 NTSTATUS 00174 UdfUnlockVolume ( 00175 IN PIRP_CONTEXT IrpContext, 00176 IN PIRP Irp 00177 ); 00178 00179 VOID 00180 UdfUpdateVolumeLabel ( 00181 IN PIRP_CONTEXT IrpContext, 00182 IN PWCHAR VolumeLabel, 00183 IN OUT PUSHORT VolumeLabelLength, 00184 IN PUCHAR Dstring, 00185 IN UCHAR FieldLength 00186 ); 00187 00188 VOID 00189 UdfUpdateVolumeSerialNumber ( 00190 IN PIRP_CONTEXT IrpContext, 00191 IN OUT PULONG VolumeSerialNumber, 00192 IN PNSR_FSD Fsd 00193 ); 00194 00195 NTSTATUS 00196 UdfUserFsctl ( 00197 IN PIRP_CONTEXT IrpContext, 00198 IN PIRP Irp 00199 ); 00200 00201 NTSTATUS 00202 UdfVerifyVolume ( 00203 IN PIRP_CONTEXT IrpContext, 00204 IN PIRP Irp 00205 ); 00206 00207 #ifdef ALLOC_PRAGMA 00208 #pragma alloc_text(PAGE, UdfCommonFsControl) 00209 #pragma alloc_text(PAGE, UdfDetermineVolumeBounding) 00210 #pragma alloc_text(PAGE, UdfDismountVolume) 00211 #pragma alloc_text(PAGE, UdfFindAnchorVolumeDescriptor) 00212 #pragma alloc_text(PAGE, UdfFindFileSetDescriptor) 00213 #pragma alloc_text(PAGE, UdfFindVolumeDescriptors) 00214 #pragma alloc_text(PAGE, UdfIsPathnameValid) 00215 #pragma alloc_text(PAGE, UdfIsRemount) 00216 #pragma alloc_text(PAGE, UdfIsVolumeDirty) 00217 #pragma alloc_text(PAGE, UdfIsVolumeMounted) 00218 #pragma alloc_text(PAGE, UdfLockVolume) 00219 #pragma alloc_text(PAGE, UdfLockVolumeInternal) 00220 #pragma alloc_text(PAGE, UdfMountVolume) 00221 #pragma alloc_text(PAGE, UdfOplockRequest) 00222 #pragma alloc_text(PAGE, UdfRecognizeVolume) 00223 #pragma alloc_text(PAGE, UdfScanForDismountedVcb) 00224 #pragma alloc_text(PAGE, UdfStoreVolumeDescriptorIfPrevailing) 00225 #pragma alloc_text(PAGE, UdfUnlockVolume) 00226 #pragma alloc_text(PAGE, UdfUnlockVolumeInternal) 00227 #pragma alloc_text(PAGE, UdfUpdateVolumeLabel) 00228 #pragma alloc_text(PAGE, UdfUpdateVolumeSerialNumber) 00229 #pragma alloc_text(PAGE, UdfUserFsctl) 00230 #pragma alloc_text(PAGE, UdfVerifyVolume) 00231 #endif 00232 00233 00234 VOID 00235 UdfStoreVolumeDescriptorIfPrevailing ( 00236 IN OUT PNSR_VD_GENERIC *StoredVD, 00237 IN OUT PNSR_VD_GENERIC NewVD 00238 ) 00239 00240 /*++ 00241 00242 Routine Description: 00243 00244 This routine updates Volume Descriptor if the new descriptor 00245 is more prevailing than the one currently stored. 00246 00247 Arguments: 00248 00249 StoredVD - pointer to a currently stored descriptor 00250 00251 NewVD - pointer to a candidate descriptor 00252 00253 Return Value: 00254 00255 None. 00256 00257 --*/ 00258 00259 { 00260 PNSR_VD_GENERIC TempVD; 00261 00262 // 00263 // If we haven't stored a volume descriptor or the sequence number 00264 // of the stored descriptor is less than the new descriptor, make a copy 00265 // of it and store it. 00266 // 00267 00268 if ((NULL == *StoredVD) || ((*StoredVD)->Sequence < NewVD->Sequence)) { 00269 00270 if ( NULL == *StoredVD) { 00271 00272 *StoredVD = (PNSR_VD_GENERIC) FsRtlAllocatePoolWithTag( UdfNonPagedPool, 00273 sizeof(NSR_VD_GENERIC), 00274 TAG_NSR_VDSD ); 00275 } 00276 00277 RtlCopyMemory( *StoredVD, NewVD, sizeof( NSR_VD_GENERIC)); 00278 } 00279 } 00280 00281 00282 NTSTATUS 00283 UdfCommonFsControl ( 00284 IN PIRP_CONTEXT IrpContext, 00285 IN PIRP Irp 00286 ) 00287 00288 /*++ 00289 00290 Routine Description: 00291 00292 This is the common routine for doing FileSystem control operations called 00293 by both the fsd and fsp threads 00294 00295 Arguments: 00296 00297 Irp - Supplies the Irp to process 00298 00299 Return Value: 00300 00301 NTSTATUS - The return status for the operation 00302 00303 --*/ 00304 00305 { 00306 NTSTATUS Status; 00307 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00308 00309 PAGED_CODE(); 00310 00311 // 00312 // Check the input parameters 00313 // 00314 00315 ASSERT_IRP_CONTEXT( IrpContext ); 00316 ASSERT_IRP( Irp ); 00317 00318 // 00319 // Get a pointer to the current Irp stack location 00320 // 00321 00322 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00323 00324 // 00325 // We know this is a file system control so we'll case on the 00326 // minor function, and call a internal worker routine to complete 00327 // the irp. 00328 // 00329 00330 switch (IrpSp->MinorFunction) { 00331 00332 case IRP_MN_MOUNT_VOLUME: 00333 00334 Status = UdfMountVolume( IrpContext, Irp ); 00335 break; 00336 00337 case IRP_MN_VERIFY_VOLUME: 00338 00339 Status = UdfVerifyVolume( IrpContext, Irp ); 00340 break; 00341 00342 case IRP_MN_USER_FS_REQUEST: 00343 00344 Status = UdfUserFsctl( IrpContext, Irp ); 00345 break; 00346 00347 default: 00348 00349 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 00350 Status = STATUS_INVALID_DEVICE_REQUEST; 00351 break; 00352 } 00353 00354 return Status; 00355 } 00356 00357 00358 // 00359 // Local support routine 00360 // 00361 00362 NTSTATUS 00363 UdfUserFsctl ( 00364 IN PIRP_CONTEXT IrpContext, 00365 IN PIRP Irp 00366 ) 00367 /*++ 00368 00369 Routine Description: 00370 00371 This is the common routine for implementing the user's requests made 00372 through NtFsControlFile. 00373 00374 Arguments: 00375 00376 Irp - Supplies the Irp being processed 00377 00378 Return Value: 00379 00380 NTSTATUS - The return status for the operation 00381 00382 --*/ 00383 00384 { 00385 NTSTATUS Status; 00386 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00387 00388 PAGED_CODE(); 00389 00390 // 00391 // Case on the control code. 00392 // 00393 00394 switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) { 00395 00396 case FSCTL_REQUEST_OPLOCK_LEVEL_1 : 00397 case FSCTL_REQUEST_OPLOCK_LEVEL_2 : 00398 case FSCTL_REQUEST_BATCH_OPLOCK : 00399 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE : 00400 case FSCTL_OPBATCH_ACK_CLOSE_PENDING : 00401 case FSCTL_OPLOCK_BREAK_NOTIFY : 00402 case FSCTL_OPLOCK_BREAK_ACK_NO_2 : 00403 case FSCTL_REQUEST_FILTER_OPLOCK : 00404 00405 Status = UdfOplockRequest( IrpContext, Irp ); 00406 break; 00407 00408 case FSCTL_LOCK_VOLUME : 00409 00410 Status = UdfLockVolume( IrpContext, Irp ); 00411 break; 00412 00413 case FSCTL_UNLOCK_VOLUME : 00414 00415 Status = UdfUnlockVolume( IrpContext, Irp ); 00416 break; 00417 00418 case FSCTL_DISMOUNT_VOLUME : 00419 00420 Status = UdfDismountVolume( IrpContext, Irp ); 00421 break; 00422 00423 case FSCTL_IS_VOLUME_DIRTY : 00424 00425 Status = UdfIsVolumeDirty( IrpContext, Irp ); 00426 break; 00427 00428 case FSCTL_IS_VOLUME_MOUNTED : 00429 00430 Status = UdfIsVolumeMounted( IrpContext, Irp ); 00431 break; 00432 00433 case FSCTL_IS_PATHNAME_VALID : 00434 00435 Status = UdfIsPathnameValid( IrpContext, Irp ); 00436 break; 00437 00438 case FSCTL_INVALIDATE_VOLUMES : 00439 00440 Status = UdfInvalidateVolumes( IrpContext, Irp ); 00441 break; 00442 00443 00444 // 00445 // We don't support any of the known or unknown requests. 00446 // 00447 00448 case FSCTL_MARK_VOLUME_DIRTY : 00449 case FSCTL_QUERY_RETRIEVAL_POINTERS : 00450 case FSCTL_GET_COMPRESSION : 00451 case FSCTL_SET_COMPRESSION : 00452 case FSCTL_MARK_AS_SYSTEM_HIVE : 00453 case FSCTL_QUERY_FAT_BPB : 00454 default: 00455 00456 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 00457 Status = STATUS_INVALID_DEVICE_REQUEST; 00458 break; 00459 } 00460 00461 return Status; 00462 } 00463 00464 00465 // 00466 // Local support routine 00467 // 00468 00469 NTSTATUS 00470 UdfOplockRequest ( 00471 IN PIRP_CONTEXT IrpContext, 00472 IN PIRP Irp 00473 ) 00474 00475 /*++ 00476 00477 Routine Description: 00478 00479 This is the common routine to handle oplock requests made via the 00480 NtFsControlFile call. 00481 00482 Arguments: 00483 00484 Irp - Supplies the Irp being processed 00485 00486 Return Value: 00487 00488 NTSTATUS - The return status for the operation 00489 00490 --*/ 00491 00492 { 00493 NTSTATUS Status; 00494 PFCB Fcb; 00495 PCCB Ccb; 00496 00497 ULONG OplockCount = 0; 00498 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00499 00500 PAGED_CODE(); 00501 00502 // 00503 // We only permit oplock requests on files. 00504 // 00505 00506 if (UdfDecodeFileObject( IrpSp->FileObject, 00507 &Fcb, 00508 &Ccb ) != UserFileOpen ) { 00509 00510 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 00511 return STATUS_INVALID_PARAMETER; 00512 } 00513 00514 // 00515 // Make this a waitable Irpcontext so we don't fail to acquire 00516 // the resources. 00517 // 00518 00519 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 00520 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); 00521 00522 // 00523 // Switch on the function control code. We grab the Fcb exclusively 00524 // for oplock requests, shared for oplock break acknowledgement. 00525 // 00526 00527 switch (IrpSp->Parameters.FileSystemControl.FsControlCode) { 00528 00529 case FSCTL_REQUEST_OPLOCK_LEVEL_1 : 00530 case FSCTL_REQUEST_OPLOCK_LEVEL_2 : 00531 case FSCTL_REQUEST_BATCH_OPLOCK : 00532 case FSCTL_REQUEST_FILTER_OPLOCK : 00533 00534 UdfAcquireFcbExclusive( IrpContext, Fcb, FALSE ); 00535 00536 if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) { 00537 00538 if (Fcb->FileLock != NULL) { 00539 00540 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Fcb->FileLock ); 00541 } 00542 00543 } else { 00544 00545 OplockCount = Fcb->FcbCleanup; 00546 } 00547 00548 break; 00549 00550 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: 00551 case FSCTL_OPBATCH_ACK_CLOSE_PENDING: 00552 case FSCTL_OPLOCK_BREAK_NOTIFY: 00553 case FSCTL_OPLOCK_BREAK_ACK_NO_2: 00554 00555 UdfAcquireFcbShared( IrpContext, Fcb, FALSE ); 00556 break; 00557 00558 default: 00559 00560 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 00561 return STATUS_INVALID_PARAMETER; 00562 } 00563 00564 // 00565 // Use a try finally to free the Fcb. 00566 // 00567 00568 try { 00569 00570 // 00571 // Verify the Fcb. 00572 // 00573 00574 UdfVerifyFcbOperation( IrpContext, Fcb ); 00575 00576 // 00577 // Call the FsRtl routine to grant/acknowledge oplock. 00578 // 00579 00580 Status = FsRtlOplockFsctrl( &Fcb->Oplock, 00581 Irp, 00582 OplockCount ); 00583 00584 // 00585 // Set the flag indicating if Fast I/O is possible 00586 // 00587 00588 UdfLockFcb( IrpContext, Fcb ); 00589 Fcb->IsFastIoPossible = UdfIsFastIoPossible( Fcb ); 00590 UdfUnlockFcb( IrpContext, Fcb ); 00591 00592 // 00593 // The oplock package will complete the Irp. 00594 // 00595 00596 Irp = NULL; 00597 00598 } finally { 00599 00600 // 00601 // Release all of our resources 00602 // 00603 00604 UdfReleaseFcb( IrpContext, Fcb ); 00605 } 00606 00607 // 00608 // Complete the request if there was no exception. 00609 // 00610 00611 UdfCompleteRequest( IrpContext, Irp, Status ); 00612 return Status; 00613 } 00614 00615 00616 // 00617 // Local support routine 00618 // 00619 00620 NTSTATUS 00621 UdfLockVolumeInternal ( 00622 IN PIRP_CONTEXT IrpContext, 00623 IN PVCB Vcb, 00624 IN PFILE_OBJECT FileObject OPTIONAL 00625 ) 00626 00627 /*++ 00628 00629 Routine Description: 00630 00631 This routine performs the actual lock volume operation. It will be called 00632 by anyone wishing to try to protect the volume for a long duration. PNP 00633 operations are such a user. 00634 00635 The volume must be held exclusive by the caller. 00636 00637 Arguments: 00638 00639 Vcb - The volume being locked. 00640 00641 FileObject - File corresponding to the handle locking the volume. If this 00642 is not specified, a system lock is assumed. 00643 00644 Return Value: 00645 00646 NTSTATUS - The return status for the operation 00647 00648 --*/ 00649 00650 { 00651 NTSTATUS Status; 00652 NTSTATUS FinalStatus = (FileObject? STATUS_ACCESS_DENIED: STATUS_DEVICE_BUSY); 00653 ULONG RemainingUserReferences = (FileObject? 1: 0); 00654 00655 PAGED_CODE(); 00656 00657 ASSERT_EXCLUSIVE_VCB( Vcb ); 00658 00659 // 00660 // If the volume is already locked then complete with success if this file 00661 // object has the volume locked, fail otherwise. 00662 // 00663 00664 if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) { 00665 00666 if (FileObject && Vcb->VolumeLockFileObject == FileObject) { 00667 00668 FinalStatus = STATUS_SUCCESS; 00669 } 00670 00671 } else if (Vcb->VcbCleanup == RemainingUserReferences) { 00672 00673 // 00674 // The cleanup count for the volume only reflects the fileobject that 00675 // will lock the volume. Otherwise, we must fail the request. 00676 // 00677 // Since the only cleanup is for the provided fileobject, we will try 00678 // to get rid of all of the other user references. If there is only one 00679 // remaining after the purge then we can allow the volume to be locked. 00680 // 00681 00682 UdfPurgeVolume( IrpContext, Vcb, FALSE ); 00683 00684 // 00685 // Now back out of our synchronization and wait for the lazy writer 00686 // to finish off any lazy closes that could have been outstanding. 00687 // 00688 // Since we purged, we know that the lazy writer will issue all 00689 // possible lazy closes in the next tick - if we hadn't, an otherwise 00690 // unopened file with a large amount of dirty data could have hung 00691 // around for a while as the data trickled out to the disk. 00692 // 00693 // This is even more important now since we send notification to 00694 // alert other folks that this style of check is about to happen so 00695 // that they can close their handles. We don't want to enter a fast 00696 // race with the lazy writer tearing down his references to the file. 00697 // 00698 00699 UdfReleaseVcb( IrpContext, Vcb ); 00700 00701 Status = CcWaitForCurrentLazyWriterActivity(); 00702 00703 // 00704 // This is intentional. If we were able to get the Vcb before, just 00705 // wait for it and take advantage of knowing that it is OK to leave 00706 // the flag up. 00707 // 00708 00709 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 00710 UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 00711 00712 if (!NT_SUCCESS( Status )) { 00713 00714 return Status; 00715 } 00716 00717 UdfFspClose( Vcb ); 00718 00719 if (Vcb->VcbUserReference == Vcb->VcbResidualUserReference + RemainingUserReferences) { 00720 00721 SetFlag( Vcb->VcbState, VCB_STATE_LOCKED ); 00722 Vcb->VolumeLockFileObject = FileObject; 00723 FinalStatus = STATUS_SUCCESS; 00724 } 00725 } 00726 00727 return FinalStatus; 00728 } 00729 00730 00731 NTSTATUS 00732 UdfUnlockVolumeInternal ( 00733 IN PIRP_CONTEXT IrpContext, 00734 IN PVCB Vcb, 00735 IN PFILE_OBJECT FileObject OPTIONAL 00736 ) 00737 00738 /*++ 00739 00740 Routine Description: 00741 00742 This routine performs the actual unlock volume operation. 00743 00744 The volume must be held exclusive by the caller. 00745 00746 Arguments: 00747 00748 Vcb - The volume being locked. 00749 00750 FileObject - File corresponding to the handle locking the volume. If this 00751 is not specified, a system lock is assumed. 00752 00753 Return Value: 00754 00755 NTSTATUS - The return status for the operation 00756 00757 Attempting to remove a system lock that did not exist is OK. 00758 00759 --*/ 00760 00761 { 00762 NTSTATUS Status = STATUS_INVALID_PARAMETER; 00763 00764 if (FlagOn(Vcb->VcbState, VCB_STATE_LOCKED) && FileObject == Vcb->VolumeLockFileObject) { 00765 00766 ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED ); 00767 Vcb->VolumeLockFileObject = NULL; 00768 Status = STATUS_SUCCESS; 00769 } 00770 00771 return Status; 00772 } 00773 00774 00775 // 00776 // Local support routine 00777 // 00778 00779 NTSTATUS 00780 UdfLockVolume ( 00781 IN PIRP_CONTEXT IrpContext, 00782 IN PIRP Irp 00783 ) 00784 00785 /*++ 00786 00787 Routine Description: 00788 00789 This routine performs the lock volume operation. It is responsible for 00790 either completing of enqueuing the input Irp. 00791 00792 Arguments: 00793 00794 Irp - Supplies the Irp to process 00795 00796 Return Value: 00797 00798 NTSTATUS - The return status for the operation 00799 00800 --*/ 00801 00802 { 00803 NTSTATUS Status; 00804 00805 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00806 00807 PVCB Vcb; 00808 PFCB Fcb; 00809 PCCB Ccb; 00810 00811 PAGED_CODE(); 00812 00813 // 00814 // Decode the file object, the only type of opens we accept are 00815 // user volume opens. 00816 // 00817 00818 if (UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen) { 00819 00820 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 00821 00822 return STATUS_INVALID_PARAMETER; 00823 } 00824 00825 // 00826 // Send our notification so that folks that like to hold handles on 00827 // volumes can get out of the way. 00828 // 00829 00830 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK ); 00831 00832 // 00833 // Acquire exclusive access to the Vcb. 00834 // 00835 00836 Vcb = Fcb->Vcb; 00837 UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 00838 00839 try { 00840 00841 // 00842 // Verify the Vcb. 00843 // 00844 00845 UdfVerifyVcb( IrpContext, Vcb ); 00846 00847 Status = UdfLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject ); 00848 00849 } finally { 00850 00851 // 00852 // Release the Vcb. 00853 // 00854 00855 UdfReleaseVcb( IrpContext, Vcb ); 00856 00857 if (AbnormalTermination() || !NT_SUCCESS( Status )) { 00858 00859 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED ); 00860 } 00861 } 00862 00863 // 00864 // Complete the request if there haven't been any exceptions. 00865 // 00866 00867 UdfCompleteRequest( IrpContext, Irp, Status ); 00868 return Status; 00869 } 00870 00871 00872 // 00873 // Local support routine 00874 // 00875 00876 NTSTATUS 00877 UdfUnlockVolume ( 00878 IN PIRP_CONTEXT IrpContext, 00879 IN PIRP Irp 00880 ) 00881 00882 /*++ 00883 00884 Routine Description: 00885 00886 This routine performs the unlock volume operation. It is responsible for 00887 either completing of enqueuing the input Irp. 00888 00889 Arguments: 00890 00891 Irp - Supplies the Irp to process 00892 00893 Return Value: 00894 00895 NTSTATUS - The return status for the operation 00896 00897 --*/ 00898 00899 { 00900 NTSTATUS Status; 00901 00902 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00903 00904 PVCB Vcb; 00905 PFCB Fcb; 00906 PCCB Ccb; 00907 00908 PAGED_CODE(); 00909 00910 // 00911 // Decode the file object, the only type of opens we accept are 00912 // user volume opens. 00913 // 00914 00915 if (UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) { 00916 00917 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 00918 return STATUS_INVALID_PARAMETER; 00919 } 00920 00921 // 00922 // Acquire exclusive access to the Vcb. 00923 // 00924 00925 Vcb = Fcb->Vcb; 00926 00927 UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 00928 00929 // 00930 // We won't check for a valid Vcb for this request. An unlock will always 00931 // succeed on a locked volume. 00932 // 00933 00934 Status = UdfUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject ); 00935 00936 // 00937 // Release all of our resources 00938 // 00939 00940 UdfReleaseVcb( IrpContext, Vcb ); 00941 00942 // 00943 // Send notification that the volume is avaliable. 00944 // 00945 00946 if (NT_SUCCESS( Status )) { 00947 00948 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK ); 00949 } 00950 00951 // 00952 // Complete the request if there haven't been any exceptions. 00953 // 00954 00955 UdfCompleteRequest( IrpContext, Irp, Status ); 00956 return Status; 00957 } 00958 00959 00960 00961 // 00962 // Local support routine 00963 // 00964 00965 NTSTATUS 00966 UdfDismountVolume ( 00967 IN PIRP_CONTEXT IrpContext, 00968 IN PIRP Irp 00969 ) 00970 00971 /*++ 00972 00973 Routine Description: 00974 00975 This routine performs the dismount volume operation. It is responsible for 00976 either completing of enqueuing the input Irp. We only dismount a volume which 00977 has been locked. The intent here is that someone has locked the volume (they are the 00978 only remaining handle). We set the volume state to invalid so that it will be torn 00979 down quickly. 00980 00981 Arguments: 00982 00983 Irp - Supplies the Irp to process 00984 00985 Return Value: 00986 00987 NTSTATUS - The return status for the operation 00988 00989 --*/ 00990 00991 { 00992 NTSTATUS Status; 00993 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00994 00995 PVCB Vcb; 00996 PFCB Fcb; 00997 PCCB Ccb; 00998 00999 PAGED_CODE(); 01000 01001 if (UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) { 01002 01003 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 01004 return STATUS_INVALID_PARAMETER; 01005 } 01006 01007 // 01008 // Send notification. 01009 // 01010 01011 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT ); 01012 01013 // 01014 // Acquire exclusive access to the Vcb. 01015 // 01016 01017 Vcb = Fcb->Vcb; 01018 01019 UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 01020 01021 // 01022 // Mark the volume as invalid, but only do it if the vcb is locked 01023 // by this handle and the volume is currently mounted. No more 01024 // operations will occur on this vcb except cleanup/close. 01025 // 01026 01027 if ((Vcb->VcbCondition != VcbMounted) && 01028 (Vcb->VolumeLockFileObject != IrpSp->FileObject)) { 01029 01030 Status = STATUS_NOT_IMPLEMENTED; 01031 01032 } else { 01033 01034 SetFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME ); 01035 SetFlag( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT ); 01036 01037 Status = STATUS_SUCCESS; 01038 } 01039 01040 // 01041 // Release all of our resources 01042 // 01043 01044 UdfReleaseVcb( IrpContext, Vcb ); 01045 01046 if (!NT_SUCCESS( Status )) { 01047 01048 FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT_FAILED ); 01049 } 01050 01051 // 01052 // Complete the request if there haven't been any exceptions. 01053 // 01054 01055 UdfCompleteRequest( IrpContext, Irp, Status ); 01056 return Status; 01057 } 01058 01059 01060 // 01061 // Local support routine 01062 // 01063 01064 UdfIsVolumeDirty ( 01065 IN PIRP_CONTEXT IrpContext, 01066 IN PIRP Irp 01067 ) 01068 01069 /*++ 01070 01071 Routine Description: 01072 01073 This routine determines if a volume is currently dirty. 01074 01075 Arguments: 01076 01077 Irp - Supplies the Irp to process 01078 01079 Return Value: 01080 01081 NTSTATUS - The return status for the operation 01082 01083 --*/ 01084 01085 { 01086 PIO_STACK_LOCATION IrpSp; 01087 01088 TYPE_OF_OPEN TypeOfOpen; 01089 PVCB Vcb; 01090 PFCB Fcb; 01091 PCCB Ccb; 01092 01093 PULONG VolumeState; 01094 01095 // 01096 // Get the current stack location and extract the output 01097 // buffer information. 01098 // 01099 01100 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01101 01102 // 01103 // Get a pointer to the output buffer. Look at the system buffer field in the 01104 // irp first. Then the Irp Mdl. 01105 // 01106 01107 if (Irp->AssociatedIrp.SystemBuffer != NULL) { 01108 01109 VolumeState = Irp->AssociatedIrp.SystemBuffer; 01110 01111 } else if (Irp->MdlAddress != NULL) { 01112 01113 VolumeState = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority ); 01114 01115 if (NULL == VolumeState) { 01116 01117 UdfCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES ); 01118 return STATUS_INSUFFICIENT_RESOURCES; 01119 } 01120 } else { 01121 01122 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_USER_BUFFER ); 01123 return STATUS_INVALID_USER_BUFFER; 01124 } 01125 01126 // 01127 // Make sure the output buffer is large enough and then initialize 01128 // the answer to be that the volume isn't dirty. 01129 // 01130 01131 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) { 01132 01133 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 01134 return STATUS_INVALID_PARAMETER; 01135 } 01136 01137 *VolumeState = 0; 01138 01139 // 01140 // Decode the file object 01141 // 01142 01143 TypeOfOpen = UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ); 01144 01145 if (TypeOfOpen != UserVolumeOpen) { 01146 01147 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 01148 return STATUS_INVALID_PARAMETER; 01149 } 01150 01151 if (Fcb->Vcb->VcbCondition != VcbMounted) { 01152 01153 UdfCompleteRequest( IrpContext, Irp, STATUS_VOLUME_DISMOUNTED ); 01154 return STATUS_VOLUME_DISMOUNTED; 01155 } 01156 01157 // 01158 // Now set up to return the clean state. If we paid attention to the dirty 01159 // state of the media we could be more accurate, but since this is a readonly 01160 // implementation at the moment we think it is clean all of the time. 01161 // 01162 01163 Irp->IoStatus.Information = sizeof( ULONG ); 01164 01165 UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 01166 return STATUS_SUCCESS; 01167 } 01168 01169 01170 // 01171 // Local support routine 01172 // 01173 01174 NTSTATUS 01175 UdfIsVolumeMounted ( 01176 IN PIRP_CONTEXT IrpContext, 01177 IN PIRP Irp 01178 ) 01179 01180 /*++ 01181 01182 Routine Description: 01183 01184 This routine determines if a volume is currently mounted. 01185 01186 Arguments: 01187 01188 Irp - Supplies the Irp to process 01189 01190 Return Value: 01191 01192 NTSTATUS - The return status for the operation 01193 01194 --*/ 01195 01196 { 01197 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01198 01199 PFCB Fcb; 01200 PCCB Ccb; 01201 01202 PAGED_CODE(); 01203 01204 // 01205 // Decode the file object. 01206 // 01207 01208 UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ); 01209 01210 if (Fcb != NULL) { 01211 01212 // 01213 // Disable PopUps, we want to return any error. 01214 // 01215 01216 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS ); 01217 01218 // 01219 // Verify the Vcb. This will raise in the error condition. 01220 // 01221 01222 UdfVerifyVcb( IrpContext, Fcb->Vcb ); 01223 } 01224 01225 UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 01226 01227 return STATUS_SUCCESS; 01228 } 01229 01230 01231 // 01232 // Local support routine 01233 // 01234 01235 NTSTATUS 01236 UdfIsPathnameValid ( 01237 IN PIRP_CONTEXT IrpContext, 01238 IN PIRP Irp 01239 ) 01240 01241 /*++ 01242 01243 Routine Description: 01244 01245 This routine determines if pathname is a valid UDFS pathname. 01246 We always succeed this request. 01247 01248 Arguments: 01249 01250 Irp - Supplies the Irp to process. 01251 01252 Return Value: 01253 01254 None 01255 01256 --*/ 01257 01258 { 01259 PAGED_CODE(); 01260 01261 UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 01262 return STATUS_SUCCESS; 01263 } 01264 01265 01266 // 01267 // Local support routine 01268 // 01269 01270 NTSTATUS 01271 UdfInvalidateVolumes ( 01272 IN PIRP_CONTEXT IrpContext, 01273 IN PIRP Irp 01274 ) 01275 01276 /*++ 01277 01278 Routine Description: 01279 01280 This routine searches for all the volumes mounted on the same real device 01281 of the current DASD handle, and marks them all bad. The only operation 01282 that can be done on such handles is cleanup and close. 01283 01284 Arguments: 01285 01286 Irp - Supplies the Irp to process 01287 01288 Return Value: 01289 01290 NTSTATUS - The return status for the operation 01291 01292 --*/ 01293 01294 { 01295 NTSTATUS Status; 01296 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01297 KIRQL SavedIrql; 01298 01299 LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0}; 01300 01301 HANDLE Handle; 01302 01303 PVPB NewVpb; 01304 PVCB Vcb; 01305 01306 PLIST_ENTRY Links; 01307 01308 PFILE_OBJECT FileToMarkBad; 01309 PDEVICE_OBJECT DeviceToMarkBad; 01310 01311 // 01312 // Check for the correct security access. 01313 // The caller must have the SeTcbPrivilege. 01314 // 01315 01316 if (!SeSinglePrivilegeCheck( TcbPrivilege, Irp->RequestorMode )) { 01317 01318 UdfCompleteRequest( IrpContext, Irp, STATUS_PRIVILEGE_NOT_HELD ); 01319 01320 return STATUS_PRIVILEGE_NOT_HELD; 01321 } 01322 01323 // 01324 // Try to get a pointer to the device object from the handle passed in. 01325 // 01326 01327 if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) { 01328 01329 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 01330 return STATUS_INVALID_PARAMETER; 01331 } 01332 01333 Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer); 01334 01335 Status = ObReferenceObjectByHandle( Handle, 01336 0, 01337 *IoFileObjectType, 01338 KernelMode, 01339 &FileToMarkBad, 01340 NULL ); 01341 01342 if (!NT_SUCCESS(Status)) { 01343 01344 UdfCompleteRequest( IrpContext, Irp, Status ); 01345 return Status; 01346 } 01347 01348 // 01349 // Grab the DeviceObject from the FileObject. 01350 // 01351 01352 DeviceToMarkBad = FileToMarkBad->DeviceObject; 01353 01354 // 01355 // We only needed the device object involved, not a reference to the file. 01356 // 01357 01358 ObDereferenceObject( FileToMarkBad ); 01359 01360 // 01361 // Create a new Vpb for this device so that any new opens will mount 01362 // a new volume. 01363 // 01364 01365 NewVpb = ExAllocatePoolWithTag( NonPagedPoolMustSucceed, sizeof( VPB ), TAG_VPB ); 01366 RtlZeroMemory( NewVpb, sizeof( VPB ) ); 01367 01368 NewVpb->Type = IO_TYPE_VPB; 01369 NewVpb->Size = sizeof( VPB ); 01370 NewVpb->RealDevice = DeviceToMarkBad; 01371 NewVpb->Flags = FlagOn( DeviceToMarkBad->Vpb->Flags, VPB_REMOVE_PENDING ); 01372 01373 // 01374 // Make sure this request can wait. 01375 // 01376 01377 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 01378 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); 01379 01380 UdfAcquireUdfData( IrpContext ); 01381 01382 // 01383 // Nothing can go wrong now. 01384 // 01385 01386 IoAcquireVpbSpinLock( &SavedIrql ); 01387 DeviceToMarkBad->Vpb = NewVpb; 01388 IoReleaseVpbSpinLock( SavedIrql ); 01389 01390 // 01391 // Now walk through all the mounted Vcb's looking for candidates to 01392 // mark invalid. 01393 // 01394 // On volumes we mark invalid, check for dismount possibility (which is 01395 // why we have to get the next link so early). 01396 // 01397 01398 Links = UdfData.VcbQueue.Flink; 01399 01400 while (Links != &UdfData.VcbQueue) { 01401 01402 Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks); 01403 01404 Links = Links->Flink; 01405 01406 // 01407 // If we get a match, mark the volume Bad, and also check to 01408 // see if the volume should go away. 01409 // 01410 01411 UdfLockVcb( IrpContext, Vcb ); 01412 01413 if (Vcb->Vpb->RealDevice == DeviceToMarkBad) { 01414 01415 if (Vcb->VcbCondition != VcbDismountInProgress) { 01416 01417 Vcb->VcbCondition = VcbInvalid; 01418 } 01419 01420 UdfUnlockVcb( IrpContext, Vcb ); 01421 01422 UdfPurgeVolume( IrpContext, Vcb, FALSE ); 01423 01424 UdfCheckForDismount( IrpContext, Vcb, FALSE ); 01425 01426 } else { 01427 01428 UdfUnlockVcb( IrpContext, Vcb ); 01429 } 01430 } 01431 01432 UdfReleaseUdfData( IrpContext ); 01433 01434 UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 01435 return STATUS_SUCCESS; 01436 } 01437 01438 01439 // 01440 // Local support routine 01441 // 01442 01443 NTSTATUS 01444 UdfMountVolume ( 01445 IN PIRP_CONTEXT IrpContext, 01446 IN PIRP Irp 01447 ) 01448 01449 /*++ 01450 01451 Routine Description: 01452 01453 This routine performs the mount volume operation. It is responsible for 01454 either completing of enqueuing the input Irp. 01455 01456 Its job is to verify that the volume denoted in the IRP is a UDF volume, 01457 and create the VCB and root directory FCB structures. The algorithm it 01458 uses is essentially as follows: 01459 01460 1. Create a new Vcb Structure, and initialize it enough to do I/O 01461 through the on-disk volume descriptors. 01462 01463 2. Read the disk and check if it is a UDF volume. 01464 01465 3. If it is not a UDF volume then delete the Vcb and 01466 complete the IRP with STATUS_UNRECOGNIZED_VOLUME 01467 01468 4. Check if the volume was previously mounted and if it was then do a 01469 remount operation. This involves deleting the VCB, hook in the 01470 old VCB, and complete the IRP. 01471 01472 5. Otherwise create a Vcb and root directory FCB 01473 01474 Arguments: 01475 01476 Irp - Supplies the Irp to process 01477 01478 Return Value: 01479 01480 NTSTATUS - The return status for the operation 01481 01482 --*/ 01483 01484 { 01485 NTSTATUS Status; 01486 01487 PVOLUME_DEVICE_OBJECT VolDo = NULL; 01488 PVCB Vcb = NULL; 01489 PVCB OldVcb = NULL; 01490 PPCB Pcb = NULL; 01491 01492 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01493 PDEVICE_OBJECT DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject; 01494 PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb; 01495 01496 PFILE_OBJECT FileObjectToNotify = NULL; 01497 01498 ULONG MediaChangeCount = 0; 01499 01500 DISK_GEOMETRY DiskGeometry; 01501 01502 PNSR_ANCHOR AnchorVolumeDescriptor = NULL; 01503 PNSR_PVD PrimaryVolumeDescriptor = NULL; 01504 PNSR_LVOL LogicalVolumeDescriptor = NULL; 01505 PNSR_FSD FileSetDescriptor = NULL; 01506 01507 BOOLEAN BridgeMedia; 01508 01509 PAGED_CODE(); 01510 01511 // 01512 // Check the input parameters 01513 // 01514 01515 ASSERT_IRP_CONTEXT( IrpContext ); 01516 ASSERT_IRP( Irp ); 01517 01518 // 01519 // Check that we are talking to a Cdrom or Disk device. This request should 01520 // always be waitable. 01521 // 01522 01523 ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM || 01524 Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK ); 01525 ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )); 01526 01527 DebugTrace(( +1, Dbg, "UdfMountVolume\n" )); 01528 01529 // 01530 // Update the real device in the IrpContext from the Vpb. There was no available 01531 // file object when the IrpContext was created. 01532 // 01533 01534 IrpContext->RealDevice = Vpb->RealDevice; 01535 01536 // 01537 // Check if we have disabled the mount process. 01538 // 01539 01540 if (UdfDisable) { 01541 01542 UdfCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME ); 01543 DebugTrace(( 0, Dbg, "UdfMountVolume, disabled\n" )); 01544 DebugTrace(( -1, Dbg, "UdfMountVolume -> STATUS_UNRECOGNIZED_VOLUME\n" )); 01545 01546 return STATUS_UNRECOGNIZED_VOLUME; 01547 } 01548 01549 // 01550 // Do a CheckVerify here to lift the MediaChange ticker from the driver 01551 // 01552 01553 Status = UdfPerformDevIoCtrl( IrpContext, 01554 ( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ? 01555 IOCTL_CDROM_CHECK_VERIFY : 01556 IOCTL_DISK_CHECK_VERIFY ), 01557 DeviceObjectWeTalkTo, 01558 &MediaChangeCount, 01559 sizeof(ULONG), 01560 FALSE, 01561 TRUE, 01562 NULL ); 01563 01564 if (!NT_SUCCESS( Status )) { 01565 01566 UdfCompleteRequest( IrpContext, Irp, Status ); 01567 DebugTrace(( 0, Dbg, 01568 "UdfMountVolume, CHECK_VERIFY handed back status %08x (so don't continue)\n", 01569 Status )); 01570 DebugTrace(( -1, Dbg, 01571 "UdfMountVolume -> %08x\n", 01572 Status )); 01573 01574 return Status; 01575 } 01576 01577 // 01578 // Now let's make Jeff delirious and call to get the disk geometry. This 01579 // will fix the case where the first change line is swallowed. 01580 // 01581 // This IOCTL does not have a generic STORAGE equivalent, so we must figure 01582 // our which variant to pass down from the real underlying device object (as 01583 // opposed to the top of the driver filter stack we will really be attaching 01584 // on top of). 01585 // 01586 01587 Status = UdfPerformDevIoCtrl( IrpContext, 01588 ( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ? 01589 IOCTL_CDROM_GET_DRIVE_GEOMETRY : 01590 IOCTL_DISK_GET_DRIVE_GEOMETRY ), 01591 DeviceObjectWeTalkTo, 01592 &DiskGeometry, 01593 sizeof( DISK_GEOMETRY ), 01594 FALSE, 01595 TRUE, 01596 NULL ); 01597 01598 // 01599 // If this call failed, we might be able to get away with a heuristic guess as to 01600 // what the sector size is (per CDFS), but that is playing with fire. Nearly every 01601 // failure here will be a permanent problem of some form. 01602 // 01603 01604 if (!NT_SUCCESS( Status )) { 01605 01606 UdfCompleteRequest( IrpContext, Irp, Status ); 01607 DebugTrace(( 0, Dbg, "UdfMountVolume, GET_DRIVE_GEOMETRY failed\n" )); 01608 DebugTrace(( -1, Dbg, 01609 "UdfMountVolume -> %08x\n", 01610 Status )); 01611 01612 return Status; 01613 } 01614 01615 // 01616 // Acquire the global resource to do mount operations. 01617 // 01618 01619 UdfAcquireUdfData( IrpContext ); 01620 01621 // 01622 // Use a try-finally to facilitate cleanup. 01623 // 01624 01625 try { 01626 01627 // 01628 // Do a quick check to see if there any Vcb's which can be removed. 01629 // 01630 01631 UdfScanForDismountedVcb( IrpContext ); 01632 01633 // 01634 // Make sure that the driver/drive is not screwing up underneath of us by 01635 // feeding us garbage for the sector size. 01636 // 01637 01638 if (DiskGeometry.BytesPerSector == 0 || 01639 (DiskGeometry.BytesPerSector & ~( 1 << UdfHighBit( DiskGeometry.BytesPerSector ))) != 0) { 01640 01641 DebugTrace(( 0, 0, 01642 "UdfMountVolume, bad DiskGeometry (%08x) .BytesPerSector == %08x\n", 01643 &DiskGeometry, 01644 DiskGeometry.BytesPerSector )); 01645 01646 ASSERT( FALSE ); 01647 01648 try_leave( Status = STATUS_DRIVER_INTERNAL_ERROR ); 01649 } 01650 01651 // 01652 // Now go confirm that this volume may be a UDF image by looking for a 01653 // valid ISO 13346 Volume Recognition Sequence. 01654 // 01655 01656 if (!UdfRecognizeVolume( IrpContext, 01657 DeviceObjectWeTalkTo, 01658 DiskGeometry.BytesPerSector, 01659 &BridgeMedia )) { 01660 01661 DebugTrace(( 0, Dbg, "UdfMountVolume, recognition failed so not mounting\n" )); 01662 01663 try_leave( Status = STATUS_UNRECOGNIZED_VOLUME ); 01664 } 01665 01666 // 01667 // Create the DeviceObject for this mount attempt 01668 // 01669 01670 Status = IoCreateDevice( UdfData.DriverObject, 01671 sizeof( VOLUME_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ), 01672 NULL, 01673 FILE_DEVICE_CD_ROM_FILE_SYSTEM, 01674 0, 01675 FALSE, 01676 (PDEVICE_OBJECT *) &VolDo ); 01677 01678 if (!NT_SUCCESS( Status )) { 01679 01680 DebugTrace(( 0, Dbg, "UdfMountVolume, couldn't get voldo! (%08x)\n", Status )); 01681 try_leave( Status ); 01682 } 01683 01684 // 01685 // Our alignment requirement is the larger of the processor alignment requirement 01686 // already in the volume device object and that in the DeviceObjectWeTalkTo 01687 // 01688 01689 if (DeviceObjectWeTalkTo->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) { 01690 01691 VolDo->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement; 01692 } 01693 01694 ClearFlag( VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING ); 01695 01696 // 01697 // Initialize the overflow queue for the volume 01698 // 01699 01700 VolDo->OverflowQueueCount = 0; 01701 InitializeListHead( &VolDo->OverflowQueue ); 01702 01703 VolDo->PostedRequestCount = 0; 01704 KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock ); 01705 01706 // 01707 // Now before we can initialize the Vcb we need to set up the 01708 // device object field in the VPB to point to our new volume device 01709 // object. 01710 // 01711 01712 Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo; 01713 01714 // 01715 // Initialize the Vcb. This routine will raise on an allocation 01716 // failure. 01717 // 01718 01719 UdfInitializeVcb( IrpContext, 01720 &VolDo->Vcb, 01721 DeviceObjectWeTalkTo, 01722 Vpb, 01723 &DiskGeometry, 01724 MediaChangeCount ); 01725 01726 // 01727 // We must initialize the stack size in our device object before 01728 // the following reads, because the I/O system has not done it yet. 01729 // 01730 01731 ((PDEVICE_OBJECT) VolDo)->StackSize = (CCHAR) (DeviceObjectWeTalkTo->StackSize + 1); 01732 01733 // 01734 // Pick up a local pointer to the new Vcb. Here is where we start 01735 // thinking about cleanup of structures if the mount is failed. 01736 // 01737 01738 Vcb = &VolDo->Vcb; 01739 Vpb = NULL; 01740 VolDo = NULL; 01741 01742 // 01743 // Store the Vcb in the IrpContext as we didn't have one before. 01744 // 01745 01746 IrpContext->Vcb = Vcb; 01747 01748 UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 01749 01750 // 01751 // Let's reference the Vpb to make sure we are the one to 01752 // have the last dereference. 01753 // 01754 01755 Vcb->Vpb->ReferenceCount += 1; 01756 01757 // 01758 // Clear the verify bit for the start of mount. 01759 // 01760 01761 ClearFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME ); 01762 01763 // 01764 // Now find the multi-session bounds on this media. 01765 // 01766 01767 UdfDetermineVolumeBounding( IrpContext, 01768 Vcb, 01769 &Vcb->BoundS, 01770 &Vcb->BoundN ); 01771 01772 // 01773 // Now find the Anchor Volume Descriptor so we can discover the Volume Set 01774 // Descriptor Sequence extent. 01775 // 01776 01777 Status = UdfFindAnchorVolumeDescriptor( IrpContext, 01778 Vcb, 01779 &AnchorVolumeDescriptor ); 01780 01781 if (!NT_SUCCESS(Status)) { 01782 01783 DebugTrace(( 0, Dbg, "UdfMountVolume, couldn't find anchor descriptors\n" )); 01784 try_leave( Status ); 01785 } 01786 01787 // 01788 // Now search for the prevailing copies of the PVD, LVD, and related PD in the 01789 // extents indicated by the AVD. 01790 // 01791 01792 Status = UdfFindVolumeDescriptors( IrpContext, 01793 Vcb, 01794 &AnchorVolumeDescriptor->Main, 01795 &Pcb, 01796 &PrimaryVolumeDescriptor, 01797 &LogicalVolumeDescriptor ); 01798 01799 // 01800 // If we discovered invalid structures on the main extent, we may still 01801 // be able to use the reserve extent. By definition the two extents 01802 // must be logically equal, so just plow into it on any error. 01803 // 01804 01805 if (!NT_SUCCESS( Status )) { 01806 01807 Status = UdfFindVolumeDescriptors( IrpContext, 01808 Vcb, 01809 &AnchorVolumeDescriptor->Reserve, 01810 &Pcb, 01811 &PrimaryVolumeDescriptor, 01812 &LogicalVolumeDescriptor ); 01813 } 01814 01815 if (!NT_SUCCESS(Status)) { 01816 01817 DebugTrace(( 0, Dbg, "UdfMountVolume, couldn't find good VSD descriptors (PVD/LVD/PD)\n" )); 01818 try_leave( Status ); 01819 } 01820 01821 // 01822 // Now go complete initialization of the Pcb. After this point, we can perform 01823 // physical partition mappings and know that the partition table is good. 01824 // 01825 01826 Status = UdfCompletePcb( IrpContext, 01827 Vcb, 01828 Pcb ); 01829 01830 if (!NT_SUCCESS(Status)) { 01831 01832 DebugTrace(( 0, Dbg, "UdfMountVolume, Pcb completion failed\n" )); 01833 try_leave( Status ); 01834 } 01835 01836 Vcb->Pcb = Pcb; 01837 Pcb = NULL; 01838 01839 // 01840 // Set up all the support we need to do reads into the volume. 01841 // 01842 01843 UdfUpdateVcbPhase0( IrpContext, Vcb ); 01844 01845 // 01846 // Now go get the fileset descriptor that will finally reveal the location 01847 // of the root directory on this volume. 01848 // 01849 01850 Status = UdfFindFileSetDescriptor( IrpContext, 01851 Vcb, 01852 &LogicalVolumeDescriptor->FSD, 01853 &FileSetDescriptor ); 01854 01855 if (!NT_SUCCESS(Status)) { 01856 01857 try_leave( NOTHING ); 01858 } 01859 01860 // 01861 // Now that we have everything together, update the Vpb with identification 01862 // of this volume. 01863 // 01864 01865 UdfUpdateVolumeLabel( IrpContext, 01866 Vcb->Vpb->VolumeLabel, 01867 &Vcb->Vpb->VolumeLabelLength, 01868 LogicalVolumeDescriptor->VolumeID, 01869 sizeof( LogicalVolumeDescriptor->VolumeID )); 01870 01871 UdfUpdateVolumeSerialNumber( IrpContext, 01872 &Vcb->Vpb->SerialNumber, 01873 FileSetDescriptor ); 01874 01875 // 01876 // Check if this is a remount operation. If so then clean up 01877 // the data structures passed in and created here. 01878 // 01879 01880 if (UdfIsRemount( IrpContext, Vcb, &OldVcb )) { 01881 01882 // 01883 // Link the old Vcb to point to the new device object that we 01884 // should be talking to, dereferencing the previous. 01885 // 01886 01887 ObDereferenceObject( OldVcb->TargetDeviceObject ); 01888 01889 Vcb->Vpb->RealDevice->Vpb = OldVcb->Vpb; 01890 01891 OldVcb->Vpb->RealDevice = Vcb->Vpb->RealDevice; 01892 01893 OldVcb->TargetDeviceObject = DeviceObjectWeTalkTo; 01894 OldVcb->VcbCondition = VcbMounted; 01895 01896 OldVcb->MediaChangeCount = Vcb->MediaChangeCount; 01897 01898 // 01899 // Push the state of the method 2 bit across. In changing the device, 01900 // we may now be on one with a different requirement. 01901 // 01902 01903 ClearFlag( OldVcb->VcbState, VCB_STATE_METHOD_2_FIXUP ); 01904 SetFlag( OldVcb->VcbState, FlagOn( Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP )); 01905 01906 // 01907 // See if we will need to provide notification of the remount. This is the readonly 01908 // filesystem's form of dismount/mount notification - we promise that whenever a 01909 // volume is "dismounted", that a mount notification will occur when it is revalidated. 01910 // Note that we do not send mount on normal remounts - that would duplicate the media 01911 // arrival notification of the device driver. 01912 // 01913 01914 if (FlagOn( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) { 01915 01916 ClearFlag( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT ); 01917 01918 FileObjectToNotify = OldVcb->RootIndexFcb->FileObject; 01919 ObReferenceObject( FileObjectToNotify ); 01920 } 01921 01922 DebugTrace(( 0, Dbg, "UdfMountVolume, remounted old Vcb %08x\n", OldVcb )); 01923 01924 try_leave( Status = STATUS_SUCCESS ); 01925 } 01926 01927 // 01928 // Initialize the Vcb and associated structures from our volume descriptors 01929 // 01930 01931 UdfUpdateVcbPhase1( IrpContext, 01932 Vcb, 01933 FileSetDescriptor ); 01934 01935 // 01936 // Drop an extra reference on the root dir file so we'll be able to send 01937 // notification. 01938 // 01939 01940 if (Vcb->RootIndexFcb) { 01941 01942 FileObjectToNotify = Vcb->RootIndexFcb->FileObject; 01943 ObReferenceObject( FileObjectToNotify ); 01944 } 01945 01946 // 01947 // The new mount is complete. Remove the additional references on this 01948 // Vcb since, at this point, we have added the real references this volume 01949 // will have during its lifetime. We also need to drop the additional 01950 // reference on the device we mounted. 01951 // 01952 01953 Vcb->VcbReference -= Vcb->VcbResidualReference; 01954 ASSERT( Vcb->VcbReference == Vcb->VcbResidualReference ); 01955 01956 ObDereferenceObject( Vcb->TargetDeviceObject ); 01957 01958 Vcb->VcbCondition = VcbMounted; 01959 01960 UdfReleaseVcb( IrpContext, Vcb ); 01961 Vcb = NULL; 01962 01963 Status = STATUS_SUCCESS; 01964 01965 } finally { 01966 01967 DebugUnwind( "UdfMountVolume" ); 01968 01969 // 01970 // If we didn't complete the mount then cleanup any remaining structures. 01971 // 01972 01973 if (Vpb != NULL) { Vpb->DeviceObject = NULL; } 01974 01975 if (Pcb != NULL) { 01976 01977 UdfDeletePcb( Pcb ); 01978 } 01979 01980 if (Vcb != NULL) { 01981 01982 // 01983 // Make sure there is no Vcb in the IrpContext since it could go away 01984 // 01985 01986 IrpContext->Vcb = NULL; 01987 01988 Vcb->VcbReference -= Vcb->VcbResidualReference; 01989 01990 if (UdfDismountVcb( IrpContext, Vcb )) { 01991 01992 UdfReleaseVcb( IrpContext, Vcb ); 01993 } 01994 01995 } else if (VolDo != NULL) { 01996 01997 IoDeleteDevice( (PDEVICE_OBJECT)VolDo ); 01998 Vpb->DeviceObject = NULL; 01999 } 02000 02001 // 02002 // Release the global resource. 02003 // 02004 02005 UdfReleaseUdfData( IrpContext ); 02006 02007 // 02008 // Free any structures we may have been allocated 02009 // 02010 02011 UdfFreePool( &AnchorVolumeDescriptor ); 02012 UdfFreePool( &PrimaryVolumeDescriptor ); 02013 UdfFreePool( &LogicalVolumeDescriptor ); 02014 UdfFreePool( &FileSetDescriptor ); 02015 } 02016 02017 // 02018 // Now send mount notification. 02019 // 02020 02021 if (FileObjectToNotify) { 02022 02023 FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT ); 02024 ObDereferenceObject( FileObjectToNotify ); 02025 } 02026 02027 // 02028 // Complete the request if no exception. 02029 // 02030 02031 UdfCompleteRequest( IrpContext, Irp, Status ); 02032 DebugTrace(( -1, Dbg, "UdfMountVolume -> %08x\n", Status )); 02033 02034 return Status; 02035 } 02036 02037 02038 // 02039 // Local support routine 02040 // 02041 02042 NTSTATUS 02043 UdfVerifyVolume ( 02044 IN PIRP_CONTEXT IrpContext, 02045 IN PIRP Irp 02046 ) 02047 02048 /*++ 02049 02050 Routine Description: 02051 02052 This routine performs the verify volume operation. It is responsible for 02053 either completing of enqueuing the input Irp. 02054 02055 Arguments: 02056 02057 Irp - Supplies the Irp to process 02058 02059 Return Value: 02060 02061 NTSTATUS - The return status for the operation 02062 02063 --*/ 02064 02065 { 02066 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 02067 PVPB Vpb = IrpSp->Parameters.VerifyVolume.Vpb; 02068 PVCB Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->Parameters.VerifyVolume.DeviceObject)->Vcb; 02069 02070 PPCB Pcb = NULL; 02071 02072 PNSR_ANCHOR AnchorVolumeDescriptor = NULL; 02073 PNSR_PVD PrimaryVolumeDescriptor = NULL; 02074 PNSR_LVOL LogicalVolumeDescriptor = NULL; 02075 PNSR_FSD FileSetDescriptor = NULL; 02076 02077 ULONG MediaChangeCount = 0; 02078 ULONG Index; 02079 02080 PFILE_OBJECT FileObjectToNotify = NULL; 02081 02082 BOOLEAN ReturnError; 02083 BOOLEAN ReleaseVcb; 02084 02085 IO_STATUS_BLOCK Iosb; 02086 02087 WCHAR VolumeLabel[ MAXIMUM_VOLUME_LABEL_LENGTH / sizeof( WCHAR )]; 02088 USHORT VolumeLabelLength; 02089 ULONG VolumeSerialNumber; 02090 02091 NTSTATUS Status; 02092 02093 PAGED_CODE(); 02094 02095 // 02096 // Check input. 02097 // 02098 02099 ASSERT_IRP_CONTEXT( IrpContext ); 02100 02101 // 02102 // Check that we are talking to a Cdrom or Disk device. This request should 02103 // always be waitable. 02104 // 02105 02106 ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM || 02107 Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK ); 02108 02109 ASSERT_VCB( Vcb ); 02110 02111 // 02112 // Update the real device in the IrpContext from the Vpb. There was no available 02113 // file object when the IrpContext was created. 02114 // 02115 02116 IrpContext->RealDevice = Vpb->RealDevice; 02117 02118 // 02119 // Acquire shared global access, the termination handler for the 02120 // following try statement will free the access. 02121 // 02122 02123 UdfAcquireUdfData( IrpContext ); 02124 UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 02125 ReleaseVcb = TRUE; 02126 02127 DebugTrace(( +1, Dbg, "UdfVerifyVolume, Vcb %08x\n", Vcb )); 02128 02129 try { 02130 02131 // 02132 // Check if the real device still needs to be verified. If it doesn't 02133 // then obviously someone beat us here and already did the work 02134 // so complete the verify irp with success. Otherwise reenable 02135 // the real device and get to work. 02136 // 02137 02138 if (!FlagOn( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME )) { 02139 02140 DebugTrace(( 0, Dbg, "UdfVerifyVolume, verify bit was cleared out ahead of us\n" )); 02141 02142 MediaChangeCount = Vcb->MediaChangeCount; 02143 try_leave( Status = STATUS_SUCCESS ); 02144 } 02145 02146 // 02147 // Verify that there is a disk here. 02148 // 02149 02150 Status = UdfPerformDevIoCtrl( IrpContext, 02151 ( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ? 02152 IOCTL_CDROM_CHECK_VERIFY : 02153 IOCTL_DISK_CHECK_VERIFY ), 02154 Vcb->TargetDeviceObject, 02155 &MediaChangeCount, 02156 sizeof(ULONG), 02157 FALSE, 02158 TRUE, 02159 &Iosb ); 02160 02161 if (!NT_SUCCESS( Status )) { 02162 02163 DebugTrace(( 0, Dbg, "UdfVerifyVolume, CHECK_VERIFY failed\n" )); 02164 02165 // 02166 // If we will allow a raw mount then return WRONG_VOLUME to 02167 // allow the volume to be mounted by raw. 02168 // 02169 02170 if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) { 02171 02172 DebugTrace(( 0, Dbg, "UdfVerifyVolume, ... allowing raw mount\n" )); 02173 02174 Status = STATUS_WRONG_VOLUME; 02175 } 02176 02177 try_leave( Status ); 02178 } 02179 02180 if (Iosb.Information != sizeof(ULONG)) { 02181 02182 // 02183 // Be safe about the count in case the driver didn't fill it in 02184 // 02185 02186 MediaChangeCount = 0; 02187 } 02188 02189 // 02190 // Verify that the device actually saw a change. If the driver does not 02191 // support the MCC, then we must verify the volume in any case. 02192 // 02193 02194 if (MediaChangeCount == 0 || Vcb->MediaChangeCount != MediaChangeCount) { 02195 02196 // 02197 // Now we need to navigate the disc to find the relavent decriptors. This is 02198 // much the same as the mount process. 02199 // 02200 02201 // 02202 // Find the AVD. 02203 // 02204 02205 Status = UdfFindAnchorVolumeDescriptor( IrpContext, 02206 Vcb, 02207 &AnchorVolumeDescriptor ); 02208 02209 if (!NT_SUCCESS(Status)) { 02210 02211 DebugTrace(( 0, Dbg, "UdfVerifyVolume, No AVD visible\n" )); 02212 try_leave( Status = STATUS_WRONG_VOLUME ); 02213 } 02214 02215 // 02216 // Get the prevailing descriptors out of the VDS, building a fresh Pcb. 02217 // 02218 02219 Status = UdfFindVolumeDescriptors( IrpContext, 02220 Vcb, 02221 &AnchorVolumeDescriptor->Main, 02222 &Pcb, 02223 &PrimaryVolumeDescriptor, 02224 &LogicalVolumeDescriptor ); 02225 02226 // 02227 // Try the reserve sequence in case of error. 02228 // 02229 02230 if (Status == STATUS_DISK_CORRUPT_ERROR) { 02231 02232 Status = UdfFindVolumeDescriptors( IrpContext, 02233 Vcb, 02234 &AnchorVolumeDescriptor->Reserve, 02235 &Pcb, 02236 &PrimaryVolumeDescriptor, 02237 &LogicalVolumeDescriptor ); 02238 } 02239 02240 // 02241 // If we're totally unable to find a VDS, give up. 02242 // 02243 02244 if (!NT_SUCCESS(Status)) { 02245 02246 DebugTrace(( 0, Dbg, "UdfVerifyVolume, PVD/LVD/PD pickup failed\n" )); 02247 02248 try_leave( Status = STATUS_WRONG_VOLUME ); 02249 } 02250 02251 // 02252 // Now go complete initialization of the Pcb so we can compare it. 02253 // 02254 02255 Status = UdfCompletePcb( IrpContext, 02256 Vcb, 02257 Pcb ); 02258 02259 if (!NT_SUCCESS(Status)) { 02260 02261 DebugTrace(( 0, Dbg, "UdfVerifyVolume, Pcb completion failed\n" )); 02262 02263 try_leave( Status = STATUS_WRONG_VOLUME ); 02264 } 02265 02266 // 02267 // Now let's compare this new Pcb to the previous Vcb's Pcb to see if they 02268 // appear to be equivalent. 02269 // 02270 02271 if (!UdfEquivalentPcb( IrpContext, 02272 Pcb, 02273 Vcb->Pcb)) { 02274 02275 DebugTrace(( 0, Dbg, "UdfVerifyVolume, Pcbs are not equivalent\n" )); 02276 02277 try_leave( Status = STATUS_WRONG_VOLUME ); 02278 } 02279 02280 // 02281 // At this point we know that the Vcb's Pcb is OK for mapping to find the fileset 02282 // descriptor, so we can drop the new one we built for comparison purposes. 02283 // 02284 02285 UdfDeletePcb( Pcb ); 02286 Pcb = NULL; 02287 02288 // 02289 // Go pick up the fileset descriptor. 02290 // 02291 02292 Status = UdfFindFileSetDescriptor( IrpContext, 02293 Vcb, 02294 &LogicalVolumeDescriptor->FSD, 02295 &FileSetDescriptor ); 02296 02297 if (!NT_SUCCESS(Status)) { 02298 02299 try_leave( Status = STATUS_WRONG_VOLUME ); 02300 } 02301 02302 // 02303 // Now that everything is in place, build a volume label and serial number from these 02304 // descriptors and perform the final check that this Vcb is (or is not) the right one 02305 // for the media now in the drive. 02306 // 02307 02308 UdfUpdateVolumeLabel( IrpContext, 02309 VolumeLabel, 02310 &VolumeLabelLength, 02311 LogicalVolumeDescriptor->VolumeID, 02312 sizeof( LogicalVolumeDescriptor->VolumeID )); 02313 02314 UdfUpdateVolumeSerialNumber( IrpContext, 02315 &VolumeSerialNumber, 02316 FileSetDescriptor ); 02317 02318 if (Vcb->Vpb->SerialNumber != VolumeSerialNumber || 02319 Vcb->Vpb->VolumeLabelLength != VolumeLabelLength || 02320 RtlCompareMemory( Vcb->Vpb->VolumeLabel, 02321 VolumeLabel, 02322 VolumeLabelLength )) { 02323 02324 DebugTrace(( 0, Dbg, "UdfVerifyVolume, volume label/sn mismatch\n" )); 02325 02326 try_leave( Status = STATUS_WRONG_VOLUME ); 02327 } 02328 } 02329 02330 // 02331 // The volume is OK, clear the verify bit. 02332 // 02333 02334 DebugTrace(( 0, Dbg, "UdfVerifyVolume, looks like the same volume\n" )); 02335 02336 Vcb->VcbCondition = VcbMounted; 02337 02338 ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME ); 02339 02340 // 02341 // See if we will need to provide notification of the remount. This is the readonly 02342 // filesystem's form of dismount/mount notification. 02343 // 02344 02345 if (FlagOn( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) { 02346 02347 ClearFlag( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT ); 02348 02349 FileObjectToNotify = Vcb->RootIndexFcb->FileObject; 02350 ObReferenceObject( FileObjectToNotify ); 02351 } 02352 02353 } finally { 02354 02355 // 02356 // If we did not raise an exception, update the current Vcb. 02357 // 02358 02359 if (!AbnormalTermination()) { 02360 02361 // 02362 // Update the media change count to note that we have verified the volume 02363 // at this value 02364 // 02365 02366 Vcb->MediaChangeCount = MediaChangeCount; 02367 02368 // 02369 // Mark the Vcb as not mounted. 02370 // 02371 02372 if (Status == STATUS_WRONG_VOLUME) { 02373 02374 Vcb->VcbCondition = VcbNotMounted; 02375 02376 // 02377 // Now, if there are no user handles to the volume, try to spark 02378 // teardown by purging the volume. 02379 // 02380 02381 if (Vcb->VcbCleanup == 0) { 02382 02383 if (NT_SUCCESS( UdfPurgeVolume( IrpContext, Vcb, FALSE ))) { 02384 02385 ReleaseVcb = UdfCheckForDismount( IrpContext, Vcb, FALSE ); 02386 } 02387 } 02388 } 02389 } 02390 02391 DebugTrace(( -1, Dbg, "UdfVerifyVolume -> %08x\n", Status )); 02392 02393 if (ReleaseVcb) { 02394 02395 UdfReleaseVcb( IrpContext, Vcb ); 02396 } 02397 02398 UdfReleaseUdfData( IrpContext ); 02399 02400 // 02401 // Delete the Pcb if built. 02402 // 02403 02404 if (Pcb != NULL) { 02405 02406 UdfDeletePcb( Pcb ); 02407 } 02408 02409 UdfFreePool( &AnchorVolumeDescriptor ); 02410 UdfFreePool( &PrimaryVolumeDescriptor ); 02411 UdfFreePool( &LogicalVolumeDescriptor ); 02412 UdfFreePool( &FileSetDescriptor ); 02413 } 02414 02415 // 02416 // Now send mount notification. 02417 // 02418 02419 if (FileObjectToNotify) { 02420 02421 FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT ); 02422 ObDereferenceObject( FileObjectToNotify ); 02423 } 02424 02425 // 02426 // Complete the request if no exception. 02427 // 02428 02429 UdfCompleteRequest( IrpContext, Irp, Status ); 02430 return Status; 02431 } 02432 02433 02434 // 02435 // Local support routine 02436 // 02437 02438 BOOLEAN 02439 UdfIsRemount ( 02440 IN PIRP_CONTEXT IrpContext, 02441 IN PVCB Vcb, 02442 OUT PVCB *OldVcb 02443 ) 02444 02445 /*++ 02446 02447 Routine Description: 02448 02449 This routine walks through the links of the Vcb chain in the global 02450 data structure. The remount condition is met when the following 02451 conditions are all met: 02452 02453 1 - The 32 serial for this VPB matches that in a previous 02454 VPB. 02455 02456 2 - The volume label for this VPB matches that in the previous 02457 VPB. 02458 02459 3 - The system pointer to the real device object in the current 02460 VPB matches that in the same previous VPB. 02461 02462 4 - Finally the previous Vcb cannot be invalid or have a dismount 02463 underway. 02464 02465 If a VPB is found which matches these conditions, then the address of 02466 the Vcb for that VPB is returned via the pointer OldVcb. 02467 02468 Skip over the current Vcb. 02469 02470 Arguments: 02471 02472 Vcb - This is the Vcb we are checking for a remount. 02473 02474 OldVcb - A pointer to the address to store the address for the Vcb 02475 for the volume if this is a remount. (This is a pointer to 02476 a pointer) 02477 02478 Return Value: 02479 02480 BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise. 02481 02482 --*/ 02483 02484 { 02485 PLIST_ENTRY Link; 02486 02487 PVPB Vpb = Vcb->Vpb; 02488 PVPB OldVpb; 02489 02490 BOOLEAN Remount = FALSE; 02491 02492 PAGED_CODE(); 02493 02494 // 02495 // Check input. 02496 // 02497 02498 ASSERT_IRP_CONTEXT( IrpContext ); 02499 ASSERT_VCB( Vcb ); 02500 02501 DebugTrace(( +1, Dbg, "UdfIsRemount, Vcb %08x\n", Vcb )); 02502 02503 for (Link = UdfData.VcbQueue.Flink; 02504 Link != &UdfData.VcbQueue; 02505 Link = Link->Flink) { 02506 02507 *OldVcb = CONTAINING_RECORD( Link, VCB, VcbLinks ); 02508 02509 // 02510 // Skip ourselves. 02511 // 02512 02513 if (Vcb == *OldVcb) { continue; } 02514 02515 // 02516 // Look at the Vpb and state of the previous Vcb. 02517 // 02518 02519 OldVpb = (*OldVcb)->Vpb; 02520 02521 if ((OldVpb != Vpb) && 02522 (OldVpb->RealDevice == Vpb->RealDevice) && 02523 ((*OldVcb)->VcbCondition == VcbNotMounted)) { 02524 02525 // 02526 // Go ahead and compare serial numbers and volume label. 02527 // 02528 02529 if ((OldVpb->SerialNumber == Vpb->SerialNumber) && 02530 (Vpb->VolumeLabelLength == OldVpb->VolumeLabelLength) && 02531 (RtlEqualMemory( OldVpb->VolumeLabel, 02532 Vpb->VolumeLabel, 02533 Vpb->VolumeLabelLength ))) { 02534 02535 // 02536 // Got it. 02537 // 02538 02539 DebugTrace(( 0, Dbg, "UdfIsRemount, matched OldVcb %08x\n", *OldVcb )); 02540 02541 Remount = TRUE; 02542 break; 02543 } 02544 } 02545 } 02546 02547 DebugTrace(( -1, Dbg, "UdfIsRemount -> %c\n", (Remount? 'T' : 'F' ))); 02548 02549 return Remount; 02550 } 02551 02552 02553 // 02554 // Local support routine 02555 // 02556 02557 NTSTATUS 02558 UdfFindFileSetDescriptor ( 02559 IN PIRP_CONTEXT IrpContext, 02560 IN PVCB Vcb, 02561 IN PLONGAD LongAd, 02562 IN OUT PNSR_FSD *FileSetDescriptor 02563 ) 02564 02565 /*++ 02566 02567 Routine Description: 02568 02569 This routine walks a Fileset Descriptor Sequence looking for the default 02570 descriptor. This will reveal the location of the root directory on the 02571 volume. 02572 02573 Arguments: 02574 02575 Vcb - Vcb of volume to search 02576 02577 LongAd - Long allocation descriptor describing the start of the sequence 02578 02579 FileSetDescriptor - Address of caller's pointer to an FSD 02580 02581 Return Value: 02582 02583 STATUS_SUCCESS if all descriptors are found, read, and are valid. 02584 02585 STATUS_DISK_CORRUPT_ERROR if corrupt/bad descriptors are found (may be raised) 02586 02587 --*/ 02588 02589 { 02590 PNSR_FSD FSD = NULL; 02591 ULONGLONG Offset; 02592 ULONG Lbn, Len; 02593 02594 NTSTATUS Status = STATUS_SUCCESS; 02595 02596 PAGED_CODE(); 02597 02598 // 02599 // Check inputs 02600 // 02601 02602 ASSERT_IRP_CONTEXT( IrpContext ); 02603 ASSERT( *FileSetDescriptor == NULL ); 02604 02605 DebugTrace(( +1, Dbg, 02606 "UdfFindFileSetDescriptor, Vcb %08x, LongAd %08x %x/%08x +%08x (type %x)\n", 02607 Vcb, 02608 LongAd, 02609 LongAd->Start.Partition, 02610 LongAd->Start.Lbn, 02611 LongAd->Length.Length, 02612 LongAd->Length.Type )); 02613 02614 // 02615 // If the extent we begin from is not a whole number of recorded logical blocks, 02616 // we can't continue. 02617 // 02618 02619 #ifndef UDF_SUPPORT_NONSTANDARD_ALLSTOR 02620 02621 // 02622 // Disable checking the sanity of the longad here. 02623 // 02624 // Reason: first drop of Allstor media recorded the type as unrecorded (!) 02625 // 02626 02627 if (LongAd->Length.Length == 0 || 02628 LongAd->Length.Type != NSRLENGTH_TYPE_RECORDED || 02629 BlockOffset( Vcb, LongAd->Length.Length )) { 02630 02631 DebugTrace(( +0, Dbg, 02632 "UdfFindFileSetDescriptor, bad longad length\n" )); 02633 DebugTrace(( -1, Dbg, 02634 "UdfFindFileSetDescriptor -> STATUS_DISK_CORRUPT_ERROR\n" )); 02635 02636 return STATUS_DISK_CORRUPT_ERROR; 02637 } 02638 02639 #endif 02640 02641 // 02642 // Use a try-finally for cleanup 02643 // 02644 02645 try { 02646 02647 try { 02648 02649 for ( // 02650 // Home ourselves in the search and make a pass through the sequence. 02651 // 02652 02653 Len = LongAd->Length.Length, 02654 Lbn = LongAd->Start.Lbn, 02655 Offset = LlBytesFromSectors( Vcb, UdfLookupPsnOfExtent( IrpContext, 02656 Vcb, 02657 LongAd->Start.Partition, 02658 Lbn, 02659 Len )); 02660 02661 Len; 02662 02663 // 02664 // Advance to the next descriptor offset in the sequence. 02665 // 02666 02667 Len -= BlockSize( Vcb ), 02668 Lbn++, 02669 Offset += BlockSize( Vcb )) { 02670 02671 // 02672 // Allocate a buffer to read fileset descriptors. 02673 // 02674 02675 if (FSD == NULL) { 02676 02677 FSD = FsRtlAllocatePoolWithTag( UdfNonPagedPool, 02678 UdfRawBufferSize( Vcb, sizeof(NSR_FSD) ), 02679 TAG_NSR_FSD ); 02680 } 02681 02682 Status = UdfReadSectors( IrpContext, 02683 Offset, 02684 UdfRawReadSize( Vcb, sizeof(NSR_FSD) ), 02685 TRUE, 02686 FSD, 02687 Vcb->TargetDeviceObject ); 02688 02689 if (!NT_SUCCESS( Status ) || 02690 FSD->Destag.Ident == DESTAG_ID_NOTSPEC) { 02691 02692 // 02693 // These are both an excellent sign that this is an unrecorded sector, which 02694 // is defined to terminate the sequence. (3/8.4.2) 02695 // 02696 02697 break; 02698 } 02699 02700 if ((FSD->Destag.Ident != DESTAG_ID_NSR_FSD && 02701 FSD->Destag.Ident != DESTAG_ID_NSR_TERM) || 02702 02703 !UdfVerifyDescriptor( IrpContext, 02704 &FSD->Destag, 02705 FSD->Destag.Ident, 02706 sizeof(NSR_FSD), 02707 Lbn, 02708 TRUE)) { 02709 02710 // 02711 // If we spot an illegal descriptor type in the stream, there is no reasonable 02712 // way to guess that we can continue (the disc may be trash beyond this point). 02713 // Clearly, we also cannot trust the next extent pointed to by a corrupt 02714 // descriptor. 02715 // 02716 02717 try_leave( Status = STATUS_DISK_CORRUPT_ERROR ); 02718 } 02719 02720 if (FSD->Destag.Ident == DESTAG_ID_NSR_TERM) { 02721 02722 // 02723 // This is a way to terminate the sequence. 02724 // 02725 02726 break; 02727 } 02728 02729 // 02730 // Reset the pointers to the possible next extent 02731 // 02732 02733 LongAd = &FSD->NextExtent; 02734 02735 if (LongAd->Length.Length) { 02736 02737 // 02738 // A fileset descriptor containing a nonzero next extent pointer also 02739 // terminates this extent of the FSD sequence. (4/8.3.1) 02740 // 02741 // If the extent referred to is not fully recorded, this will 02742 // terminate the sequence. 02743 // 02744 02745 if (LongAd->Length.Type != NSRLENGTH_TYPE_RECORDED) { 02746 02747 break; 02748 } 02749 02750 Len = LongAd->Length.Length; 02751 02752 // 02753 // The extent must be a multiple of a block size. 02754 // 02755 02756 if (BlockOffset( Vcb, Len )) { 02757 02758 DebugTrace(( +0, Dbg, 02759 "UdfFindFileSetDescriptor, interior extent not blocksize in length\n" )); 02760 try_leave ( Status = STATUS_DISK_CORRUPT_ERROR ); 02761 } 02762 02763 Lbn = LongAd->Start.Lbn; 02764 02765 Offset = LlBytesFromBlocks( Vcb, UdfLookupPsnOfExtent( IrpContext, 02766 Vcb, 02767 LongAd->Start.Partition, 02768 Lbn, 02769 Len )); 02770 02771 } 02772 02773 UdfStoreFileSetDescriptorIfPrevailing( FileSetDescriptor, &FSD ); 02774 } 02775 02776 } finally { 02777 02778 // 02779 // Free up the buffer space we may have allocated 02780 // 02781 02782 UdfFreePool( &FSD ); 02783 02784 } 02785 02786 } except( UdfExceptionFilter( IrpContext, GetExceptionInformation() )) { 02787 02788 // 02789 // Transmute raised apparent file corruption to disk corruption - we are not 02790 // yet touching the visible filesystem. 02791 // 02792 02793 Status = IrpContext->ExceptionStatus; 02794 02795 DebugTrace(( +0, Dbg, 02796 "UdfFindFileSetDescriptor, exception %08x thrown\n", Status )); 02797 02798 if (Status == STATUS_FILE_CORRUPT_ERROR) { 02799 02800 DebugTrace(( +0, Dbg, 02801 "UdfFindFileSetDescriptor, translating file corrupt to disk corrupt\n" )); 02802 Status = STATUS_DISK_CORRUPT_ERROR; 02803 } 02804 } 02805 02806 // 02807 // Success is when we've really found something. If we failed to find the 02808 // descriptor, commute whatever intermediate status was involved and clean up. 02809 // 02810 02811 if (*FileSetDescriptor == NULL) { 02812 02813 Status = STATUS_UNRECOGNIZED_VOLUME; 02814 } 02815 02816 if (!NT_SUCCESS( Status )) { 02817 02818 UdfFreePool( FileSetDescriptor ); 02819 } 02820 02821 DebugTrace(( -1, Dbg, 02822 "UdfFindFileSetDescriptor -> %08x\n", Status )); 02823 return Status; 02824 } 02825 02826 02827 // 02828 // Local support routine 02829 // 02830 02831 NTSTATUS 02832 UdfFindVolumeDescriptors ( 02833 IN PIRP_CONTEXT IrpContext, 02834 IN PVCB Vcb, 02835 IN PEXTENTAD Extent, 02836 IN OUT PPCB *Pcb, 02837 IN OUT PNSR_PVD *PrimaryVolumeDescriptor, 02838 IN OUT PNSR_LVOL *LogicalVolumeDescriptor 02839 ) 02840 02841 /*++ 02842 02843 Routine Description: 02844 02845 This routine walks the indicated Volume Descriptor Sequence searching for the 02846 active descriptors for this volume and generates an initializing Pcb from the 02847 referenced partitions. No updating of the Vcb occurs. 02848 02849 Arguments: 02850 02851 Vcb - Vcb of volume to search 02852 02853 Extent - Extent to search 02854 02855 Pcb - Address of a caller's pointer to a Pcb 02856 02857 PrimaryVolumeDescriptor - Address of caller's pointer to a PVD 02858 02859 LogicalVolumeDescriptor - Address of caller's pointer to an LVD 02860 02861 Return Value: 02862 02863 STATUS_SUCCESS if all descriptors are found, read, and are valid. 02864 02865 STATUS_DISK_CORRUPT_ERROR if corrupt descriptors are found. 02866 02867 STATUS_UNRECOGNIZED_VOLUME if noncompliant descriptors are found. 02868 02869 Descriptors are only returned on success. 02870 02871 --*/ 02872 02873 { 02874 PNSR_VD_GENERIC GenericVD = NULL; 02875 ULONGLONG Offset; 02876 ULONG Len; 02877 ULONG UnitSize = UdfRawReadSize( Vcb, sizeof(NSR_VD_GENERIC) ); 02878 02879 NTSTATUS Status = STATUS_SUCCESS; 02880 ULONG ThisPass = 1; 02881 02882 PAGED_CODE(); 02883 02884 // 02885 // Check the input parameters 02886 // 02887 02888 ASSERT_IRP_CONTEXT( IrpContext); 02889 ASSERT_VCB( Vcb ); 02890 ASSERT_OPTIONAL_PCB( *Pcb ); 02891 02892 DebugTrace(( +1, Dbg, 02893 "UdfFindVolumeDescriptors, Vcb %08x, Extent %08x +%08x\n", 02894 Vcb, 02895 Extent->Lsn, 02896 Extent->Len )); 02897 02898 // 02899 // If the extent we begin from is not at least the size of an aligned descriptor 02900 // or is sized in base units other than aligned descriptors, we can't continue. 02901 // 02902 02903 if (Extent->Len < UnitSize || 02904 Extent->Len % UnitSize) { 02905 02906 DebugTrace(( 0, Dbg, 02907 "UdfFindVolumeDescriptors, Base extent length %08x is mismatched with read size %08x\n", 02908 Extent->Len, 02909 UnitSize )); 02910 02911 DebugTrace(( -1, Dbg, 02912 "UdfFindVolumeDescriptors -> STATUS_DISK_CORRUPT_ERROR\n" )); 02913 02914 return STATUS_DISK_CORRUPT_ERROR; 02915 } 02916 02917 // 02918 // Use a try-finally to facilitate cleanup. 02919 // 02920 02921 try { 02922 02923 DebugTrace(( 0, Dbg, 02924 "UdfFindVolumeDescriptors, starting pass 1, find LVD/PVD\n" )); 02925 02926 // 02927 // We will make at least one pass through the Volume Descriptor Sequence to find 02928 // the prevailing versions of the two controlling descriptors - the PVD and LVD. 02929 // In order to avoid picking up partition descriptors that aren't actually going 02930 // to be referenced by the LVD, we will pick them up in a second pass if we find 02931 // a PVD and LVD that look reasonable and then stick them in a Pcb. 02932 // 02933 02934 for (ThisPass = 1; ThisPass <= 2; ThisPass++) { 02935 02936 for ( // 02937 // Home ourselves in the search and make a pass through the sequence. 02938 // 02939 02940 Offset = LlBytesFromSectors( Vcb, Extent->Lsn ), 02941 Len = Extent->Len; 02942 02943 // 02944 // If we have reached the end of the extent's indicated valid 02945 // length, we are done. This usually will not happen. 02946 // 02947 02948 Len; 02949 02950 // 02951 // Advance to the next descriptor offset in the sequence. 02952 // 02953 02954 Offset += UnitSize, 02955 Len -= UnitSize ) { 02956 02957 // 02958 // Allocate a buffer to read generic volume descriptors. 02959 // 02960 02961 if (GenericVD == NULL) { 02962 02963 GenericVD = (PNSR_VD_GENERIC) FsRtlAllocatePoolWithTag( UdfNonPagedPool, 02964 UdfRawBufferSize( Vcb, sizeof(NSR_VD_GENERIC) ), 02965 TAG_NSR_VDSD ); 02966 } 02967 02968 Status = UdfReadSectors( IrpContext, 02969 Offset, 02970 UnitSize, 02971 TRUE, 02972 GenericVD, 02973 Vcb->TargetDeviceObject ); 02974 02975 // 02976 // Thise is a decent sign that this is an unrecorded sector and is 02977 // defined to terminate the sequence. 02978 // 02979 02980 if (!NT_SUCCESS( Status )) { 02981 02982 break; 02983 } 02984 02985 if (GenericVD->Destag.Ident > DESTAG_ID_MAXIMUM_PART3 || 02986 02987 !UdfVerifyDescriptor( IrpContext, 02988 &GenericVD->Destag, 02989 GenericVD->Destag.Ident, 02990 sizeof(NSR_VD_GENERIC), 02991 (ULONG) SectorsFromBytes( Vcb, Offset ), 02992 TRUE)) { 02993 02994 // 02995 // If we spot an illegal descriptor type in the stream, there is no reasonable 02996 // way to guess that we can continue (the disc may be trash beyond this point). 02997 // Likewise, even if we have a single corrupt descriptor we cannot continue because 02998 // this may be corruption of a descriptor we may have otherwise required for operation 02999 // (i.e., one of the prevailing descriptors). 03000 // 03001 03002 DebugTrace(( 0, Dbg, 03003 "UdfFindVolumeDescriptors, descriptor didn't verify\n" )); 03004 03005 try_leave( Status = STATUS_DISK_CORRUPT_ERROR ); 03006 } 03007 03008 if (GenericVD->Destag.Ident == DESTAG_ID_NSR_TERM) { 03009 03010 // 03011 // The Terminating Descriptor (3/10.9) is the usual way to stop a search. 03012 // 03013 03014 break; 03015 } 03016 03017 if (GenericVD->Destag.Ident == DESTAG_ID_NSR_VDP) { 03018 03019 // 03020 // Follow a Volume Desciptor Pointer (3/10.3) to the next extent of the sequence. 03021 // 03022 03023 Offset = LlBytesFromSectors( Vcb, ((PNSR_VDP) GenericVD)->Next.Lsn ); 03024 Len = ((PNSR_VDP) GenericVD)->Next.Len; 03025 03026 // 03027 // We cannot do anything if the extent is invalid 03028 // 03029 03030 if (Len < UnitSize || 03031 Len % UnitSize) { 03032 03033 DebugTrace(( 0, Dbg, 03034 "UdfFindVolumeDescriptors, following extent length %08x is mismatched with read size %08x\n", 03035 Extent->Len, 03036 UnitSize )); 03037 03038 try_leave( Status = STATUS_DISK_CORRUPT_ERROR ); 03039 } 03040 } 03041 03042 DebugTrace(( 0, Dbg, 03043 "UdfFindVolumeDescriptors, descriptor tag %08x\n", 03044 GenericVD->Destag.Ident )); 03045 03046 if (ThisPass == 1) { 03047 03048 // 03049 // Our first pass is to find prevailing LVD and PVD. 03050 // 03051 03052 switch (GenericVD->Destag.Ident) { 03053 03054 case DESTAG_ID_NSR_PVD: 03055 03056 UdfStoreVolumeDescriptorIfPrevailing( (PNSR_VD_GENERIC *) PrimaryVolumeDescriptor, 03057 GenericVD ); 03058 break; 03059 03060 case DESTAG_ID_NSR_LVOL: 03061 03062 UdfStoreVolumeDescriptorIfPrevailing( (PNSR_VD_GENERIC *) LogicalVolumeDescriptor, 03063 GenericVD ); 03064 break; 03065 03066 default: 03067 03068 break; 03069 } 03070 03071 } else { 03072 03073 PNSR_PART PartitionDescriptor = (PNSR_PART) GenericVD; 03074 03075 // 03076 // Our second pass is to pick up all relavent NSR02 PD 03077 // 03078 03079 if (PartitionDescriptor->Destag.Ident != DESTAG_ID_NSR_PART || 03080 !UdfEqualEntityId( &PartitionDescriptor->ContentsID, &UdfNSR02Identifier, NULL )) { 03081 03082 continue; 03083 } 03084 03085 UdfAddToPcb( *Pcb, (PNSR_PART) GenericVD ); 03086 } 03087 } 03088 03089 // 03090 // Now that a pass through the VDS has been completed, analyze the results. 03091 // 03092 03093 if (ThisPass == 1) { 03094 03095 PNSR_PVD PVD; 03096 PNSR_LVOL LVD; 03097 03098 // 03099 // Reference the descriptors for ease of use 03100 // 03101 03102 PVD = *PrimaryVolumeDescriptor; 03103 LVD = *LogicalVolumeDescriptor; 03104 03105 // 03106 // Check that the descriptors indicate a logical volume which appears to 03107 // be a valid UDF volume. 03108 // 03109 03110 if ((PVD == NULL && 03111 DebugTrace(( 0, Dbg, 03112 "UdfFindVolumeDescriptors, don't have a PVD\n" ))) || 03113 (LVD == NULL && 03114 DebugTrace(( 0, Dbg, 03115 "UdfFindVolumeDescriptors, don't have an LVD\n" ))) || 03116 03117 // 03118 // Now check the PVD 03119 // 03120 03121 // 03122 // The Volume Set Sequence fields indicates how many volumes form 03123 // the volume set and what number this volume is in that sequence. 03124 // We are a level 2 implementation, meaning that the volumes we read 03125 // consist of a single volume. (3/11) 03126 // 03127 03128 (PVD->VolSetSeq > 1 && 03129 DebugTrace(( 0, Dbg, 03130 "UdfFindVolumeDescriptors, PVD VolSetSeq %08x - not volume 1 of a volume set\n", 03131 PVD->VolSetSeq ))) || 03132 (PVD->VolSetSeqMax > 1 && 03133 DebugTrace(( 0, Dbg, 03134 "UdfFindVolumeDescriptors, PVD VolSetSeqMax %08x - volume in a non-unit volume set\n", 03135 PVD->VolSetSeqMax ))) || 03136 03137 03138 #ifndef UDF_SUPPORT_NONSTANDARD_ALLSTOR 03139 03140 // 03141 // Disable checking of character set lists. 03142 // 03143 // Reason: first drop of Allstor media recorded these fields as 0x0. 03144 // 03145 03146 // 03147 // Insure that Character Set Lists conform to UDF 03148 // 03149 03150 (PVD->CharSetList != UDF_CHARSETLIST && 03151 DebugTrace(( 0, Dbg, 03152 "UdfFindVolumeDescriptors, PVD CharSetList %08x != CS0 only\n", 03153 PVD->CharSetList ))) || 03154 (PVD->CharSetListMax != UDF_CHARSETLIST && 03155 DebugTrace(( 0, Dbg, 03156 "UdfFindVolumeDescriptors, PVD CharSetListMax %08x != CS0 only\n", 03157 PVD->CharSetListMax ))) || 03158 03159 // 03160 // Disable checking of character set lists. 03161 // 03162 // Reason: first drop of Allstor media misspelled "Compressed" as "Copmressed" 03163 // 03164 03165 // 03166 // The two character sets must be UDF CS0. CS0 is a "by convention" 03167 // character set in ISO 13346, which UDF specifies for our domain. 03168 // 03169 03170 (!UdfEqualCharspec( &PVD->CharsetDesc, &UdfCS0Identifier, CHARSPEC_T_CS0 ) && 03171 DebugTrace(( 0, Dbg, 03172 "UdfFindVolumeDescriptors, PVD CharsetDesc != CS0 only\n" ))) || 03173 (!UdfEqualCharspec( &PVD->CharsetExplan, &UdfCS0Identifier, CHARSPEC_T_CS0 ) && 03174 DebugTrace(( 0, Dbg, 03175 "UdfFindVolumeDescriptors, PVD CharsetExplan != CS0 only\n" ))) || 03176 03177 #endif 03178 // 03179 // Now check the LVD 03180 // 03181 03182 // 03183 // The LVD is a variant sized structure. Check that the claimed size fits in a single 03184 // logical sector. Although an LVD may legally exceed a single sector, we will never 03185 // want to deal with such a volume. 03186 // 03187 03188 (ISONsrLvolSize( LVD ) > SectorSize( Vcb ) && 03189 DebugTrace(( 0, Dbg, 03190 "UdfFindVolumeDescriptors, LVD is bigger than a sector\n" ))) || 03191 03192 #ifndef UDF_SUPPORT_NONSTANDARD_ALLSTOR 03193 03194 // 03195 // Disable checking of character set lists. 03196 // 03197 // Reason: first drop of Allstor media recorded these fields as 0x0. 03198 // 03199 03200 // 03201 // The character set used in the LVD must be UDF CS0 as well. 03202 // 03203 03204 (!UdfEqualCharspec( &LVD->Charset, &UdfCS0Identifier, CHARSPEC_T_CS0 ) && 03205 DebugTrace(( 0, Dbg, 03206 "UdfFindVolumeDescriptors, LVD Charset != CS0 only\n" ))) || 03207 #endif 03208 03209 // 03210 // The specified block size must equal the physical sector size. 03211 // 03212 03213 (LVD->BlockSize != SectorSize( Vcb ) && 03214 DebugTrace(( 0, Dbg, 03215 "UdfFindVolumeDescriptors, LVD BlockSize %08x != SectorSize %08x\n" ))) || 03216 03217 // 03218 // The domain must be within the version we read 03219 // 03220 03221 (!UdfDomainIdentifierContained( &LVD->DomainID, 03222 &UdfDomainIdentifier, 03223 UDF_VERSION_MINIMUM, 03224 UDF_VERSION_RECOGNIZED ) && 03225 DebugTrace(( 0, Dbg, 03226 "UdfFindVolumeDescriptors, domain ID indicates unreadable volume\n" ))) || 03227 03228 // 03229 // Although we can handle any number of partitions, UDF only specifies 03230 // a single partition or special dual partition formats. 03231 // 03232 03233 (LVD->MapTableCount > 2 && 03234 DebugTrace(( 0, Dbg, 03235 "UdfFindVolumeDescriptors, LVD MapTableCount %08x greater than allowed (2)\n", 03236 LVD->MapTableCount ))) 03237 ) { 03238 03239 DebugTrace(( 0, Dbg, 03240 "UdfFindVolumeDescriptors, ... so returning STATUS_UNRECOGNIZED_VOLUME\n" )); 03241 03242 try_leave( Status = STATUS_UNRECOGNIZED_VOLUME ); 03243 } 03244 03245 // 03246 // Now that we have performed the simple field checks, build a Pcb. 03247 // 03248 03249 Status = UdfInitializePcb( IrpContext, Vcb, Pcb, LVD ); 03250 03251 if (!NT_SUCCESS(Status)) { 03252 03253 DebugTrace(( 0, Dbg, 03254 "UdfFindVolumeDescriptors, Pcb intialization failed (!)\n" )); 03255 03256 try_leave( Status ); 03257 } 03258 } 03259 03260 // 03261 // Go onto Pass 2 to find the Partition Descriptors 03262 // 03263 03264 DebugTrace(( 0, Dbg, 03265 "UdfFindVolumeDescriptors, starting pass 2, find associated PD\n" )); 03266 } 03267 03268 } finally { 03269 03270 DebugUnwind( "UdfFindVolumeDescriptors" ); 03271 03272 // 03273 // Free up the buffer space we may have allocated 03274 // 03275 03276 UdfFreePool( &GenericVD ); 03277 } 03278 03279 DebugTrace(( -1, Dbg, 03280 "UdfFindVolumeDescriptors -> %08x\n", Status )); 03281 03282 // 03283 // Success is when we've really found something. If we failed to find both 03284 // descriptors, commute whatever intermediate status was involved and clean up. 03285 // 03286 03287 if (*PrimaryVolumeDescriptor == NULL || *LogicalVolumeDescriptor == NULL) { 03288 03289 Status = STATUS_UNRECOGNIZED_VOLUME; 03290 } 03291 03292 if (!NT_SUCCESS( Status )) { 03293 03294 UdfFreePool(PrimaryVolumeDescriptor); 03295 UdfFreePool(LogicalVolumeDescriptor); 03296 } 03297 03298 return Status; 03299 } 03300 03301 03302 // 03303 // Local support routine 03304 // 03305 03306 NTSTATUS 03307 UdfFindAnchorVolumeDescriptor ( 03308 IN PIRP_CONTEXT IrpContext, 03309 IN PVCB Vcb, 03310 IN OUT PNSR_ANCHOR *AnchorVolumeDescriptor 03311 ) 03312 03313 /*++ 03314 03315 Routine Description: 03316 03317 This routine will find the Anchor Volume Descriptor for a piece of media 03318 03319 Arguments: 03320 03321 Vcb - Vcb of volume to search 03322 03323 AnchorVolumeDescriptor - Caller's pointer to an AVD 03324 03325 Return Value: 03326 03327 Boolean TRUE if AVD is discovered, FALSE otherwise. 03328 03329 --*/ 03330 03331 { 03332 ULONG ThisPass; 03333 ULONG ReadLsn; 03334 ULONG Lsn; 03335 BOOLEAN Found = FALSE; 03336 NTSTATUS Status; 03337 03338 PAGED_CODE(); 03339 03340 // 03341 // Check the input parameters 03342 // 03343 03344 ASSERT_IRP_CONTEXT( IrpContext); 03345 ASSERT_VCB( Vcb ); 03346 03347 ASSERT(*AnchorVolumeDescriptor == NULL); 03348 03349 // 03350 // Discover the Anchor Volume Descriptor, which will point towards the 03351 // Volume Set Descriptor Sequence. The AVD may exist at sector 256 or 03352 // in the last sector of the volume. 03353 // 03354 03355 *AnchorVolumeDescriptor = (PNSR_ANCHOR) FsRtlAllocatePoolWithTag( UdfNonPagedPool, 03356 UdfRawBufferSize( Vcb, sizeof(NSR_ANCHOR) ), 03357 TAG_NSR_VDSD ); 03358 03359 03360 // 03361 // Search the three possible locations for an AVD to exist on the volume, 03362 // plus check for the possibility of a method 2 fixup requirement. 03363 // 03364 03365 for ( ThisPass = 1; ThisPass <= 4; ThisPass++ ) { 03366 03367 if (ThisPass == 1) { 03368 03369 ReadLsn = Lsn = ANCHOR_SECTOR + Vcb->BoundS; 03370 03371 } else if (ThisPass == 2) { 03372 03373 // 03374 // It is so unlikely that we will get a disk that doesn't have 03375 // an anchor at 256 that this is a pretty good indication we 03376 // have a CD-RW here and the drive is method 2 goofy. Take 03377 // a shot. 03378 // 03379 03380 ReadLsn = UdfMethod2TransformSector( Vcb, ANCHOR_SECTOR ); 03381 Lsn = ANCHOR_SECTOR; 03382 03383 } else if (ThisPass == 3) { 03384 03385 // 03386 // Our remaining two chances depend on being able to determine 03387 // the last recorded sector for the volume. If we were unable 03388 // to do this, stop. 03389 // 03390 03391 if (!Vcb->BoundN) { 03392 03393 break; 03394 } 03395 03396 ReadLsn = Lsn = Vcb->BoundN; 03397 03398 } else if (ThisPass == 4) { 03399 03400 ReadLsn = Lsn = Vcb->BoundN - ANCHOR_SECTOR; 03401 } 03402 03403 // 03404 // We may have more chances to succeed if failure occurs. 03405 // 03406 03407 Status = UdfReadSectors( IrpContext, 03408 LlBytesFromSectors( Vcb, ReadLsn ), 03409 UdfRawReadSize( Vcb, sizeof(NSR_ANCHOR) ), 03410 TRUE, 03411 *AnchorVolumeDescriptor, 03412 Vcb->TargetDeviceObject ); 03413 03414 if (!NT_SUCCESS( Status )) { 03415 continue; 03416 } 03417 03418 if (!UdfVerifyDescriptor( IrpContext, 03419 &(*AnchorVolumeDescriptor)->Destag, 03420 DESTAG_ID_NSR_ANCHOR, 03421 sizeof(NSR_ANCHOR), 03422 Lsn, 03423 TRUE)) { 03424 03425 continue; 03426 } 03427 03428 // 03429 // Got one! Set the method 2 fixup appropriately. 03430 // 03431 03432 if (ThisPass == 2) { 03433 03434 DebugTrace(( 0, Dbg, "************************************************\n")); 03435 DebugTrace(( 0, Dbg, "METHOD 2 FIXUPS ACTIVATED FOR Vcb @ %08x\n", Vcb )); 03436 DebugTrace(( 0, Dbg, "************************************************\n")); 03437 03438 SetFlag( Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP ); 03439 03440 } else { 03441 03442 ClearFlag( Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP ); 03443 } 03444 03445 return STATUS_SUCCESS; 03446 } 03447 03448 return STATUS_UNRECOGNIZED_VOLUME; 03449 } 03450 03451 03452 // 03453 // Local support routine 03454 // 03455 03456 BOOLEAN 03457 UdfRecognizeVolume ( 03458 IN PIRP_CONTEXT IrpContext, 03459 IN PDEVICE_OBJECT DeviceObject, 03460 IN ULONG SectorSize, 03461 IN OUT PBOOLEAN Bridge 03462 ) 03463 03464 /*++ 03465 03466 Routine Description: 03467 03468 This routine walks the Volume Recognition Sequence to determine 03469 whether this volume contains an NSR02 (ISO 13346 Section 4) image. 03470 03471 Arguments: 03472 03473 DeviceObject - device we are checking 03474 03475 SectorSize - size of a physical sector on this device 03476 03477 Bridge - will return whether there appear to be ISO 9660 structures 03478 on the media 03479 03480 Return Value: 03481 03482 Boolean TRUE if we found NSR02, FALSE otherwise. 03483 03484 --*/ 03485 03486 { 03487 NTSTATUS Status; 03488 03489 BOOLEAN FoundBEA = FALSE; 03490 BOOLEAN FoundNSR = FALSE; 03491 BOOLEAN Resolved = FALSE; 03492 03493 PVSD_GENERIC VolumeStructureDescriptor; 03494 ULONGLONG Offset = SectorAlignN( SectorSize, VRA_BOUNDARY_LOCATION ); 03495 03496 PAGED_CODE(); 03497 03498 // 03499 // Check the input parameters 03500 // 03501 03502 ASSERT_IRP_CONTEXT( IrpContext); 03503 03504 VolumeStructureDescriptor = (PVSD_GENERIC) FsRtlAllocatePoolWithTag( UdfNonPagedPool, 03505 UdfRawBufferSizeN( SectorSize, 03506 sizeof(VSD_GENERIC) ), 03507 TAG_NSR_VSD ); 03508 03509 DebugTrace(( +1, Dbg, 03510 "UdfRecognizeVolume, DevObj %08x SectorSize %08x\n", 03511 DeviceObject, 03512 SectorSize )); 03513 03514 // 03515 // Use try-finally to facilitate cleanup 03516 // 03517 03518 try { 03519 03520 #ifdef UDF_SUPPORT_NONSTANDARD_ADAPTEC 03521 03522 // 03523 // Disable checking the recognition area. 03524 // 03525 // Reasons: 03526 // 03527 // ADAPTEC - early CDUDF did not bound NSR02 with BEA/TEA, instead 03528 // sticking it in the middle of the ISO 9660 sequence. 03529 // 03530 03531 Resolved = TRUE; 03532 #endif 03533 03534 while (!Resolved) { 03535 03536 Status = UdfReadSectors( IrpContext, 03537 Offset, 03538 UdfRawReadSizeN( SectorSize, 03539 sizeof(VSD_GENERIC) ), 03540 FALSE, 03541 VolumeStructureDescriptor, 03542 DeviceObject ); 03543 03544 if (!NT_SUCCESS( Status )) { 03545 break; 03546 } 03547 03548 // 03549 // Now check the type of the descriptor. All ISO 13346 VSDs are 03550 // of Type 0, 9660 PVDs are Type 1, 9660 SVDs are Type 2, and 9660 03551 // terminating descriptors are Type 255. 03552 // 03553 03554 if (VolumeStructureDescriptor->Type == 0) { 03555 03556 // 03557 // In order to properly recognize the volume, we must know all of the 03558 // Structure identifiers in ISO 13346 so that we can terminate if a 03559 // badly formatted (or, shockingly, non 13346) volume is presented to us. 03560 // 03561 03562 switch (UdfFindInParseTable( VsdIdentParseTable, 03563 VolumeStructureDescriptor->Ident, 03564 VSD_LENGTH_IDENT )) { 03565 case VsdIdentBEA01: 03566 03567 // 03568 // Only one BEA may exist and its version must be 1 (2/9.2.3) 03569 // 03570 03571 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, got a BEA01\n" )); 03572 03573 03574 if ((FoundBEA && 03575 DebugTrace(( 0, Dbg, 03576 "UdfRecognizeVolume, ... but it is a duplicate!\n" ))) || 03577 03578 (VolumeStructureDescriptor->Version != 1 && 03579 DebugTrace(( 0, Dbg, 03580 "UdfRecognizeVolume, ... but it has a wacky version number %02x != 1!\n", 03581 VolumeStructureDescriptor->Version )))) { 03582 03583 Resolved = TRUE; 03584 break; 03585 } 03586 03587 FoundBEA = TRUE; 03588 break; 03589 03590 case VsdIdentTEA01: 03591 03592 // 03593 // If we reach the TEA it must be the case that we don't recognize 03594 // 03595 03596 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, got a TEA01\n" )); 03597 Resolved = TRUE; 03598 break; 03599 03600 case VsdIdentNSR02: 03601 03602 // 03603 // We recognize NSR02 version 1 embedded after a BEA (3/9.1.3). For 03604 // simplicity we will not bother being a complete nitpick and check 03605 // for a bounding TEA, although we will be optimistic in the case where 03606 // we fail to match the version. 03607 // 03608 03609 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, got an NSR02\n" )); 03610 03611 if ((FoundBEA || 03612 !DebugTrace(( 0, Dbg, "UdfRecognizeVolume, ... but we haven't seen a BEA01 yet!\n" ))) && 03613 03614 (VolumeStructureDescriptor->Version == 1 || 03615 !DebugTrace(( 0, Dbg, "UdfRecognizeVolume, ... but it has a wacky version number %02x != 1\n", 03616 VolumeStructureDescriptor->Version )))) { 03617 03618 03619 FoundNSR = Resolved = TRUE; 03620 break; 03621 } 03622 03623 break; 03624 03625 case VsdIdentCD001: 03626 case VsdIdentCDW01: 03627 case VsdIdentNSR01: 03628 case VsdIdentCDW02: 03629 case VsdIdentBOOT2: 03630 03631 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, got a valid but uninteresting 13346 descriptor\n" )); 03632 03633 // 03634 // Valid but uninteresting (to us) descriptors 03635 // 03636 03637 break; 03638 03639 default: 03640 03641 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, got an invalid 13346 descriptor\n" )); 03642 03643 // 03644 // Stumbling across something we don't know, it must be that this 03645 // is not a valid 13346 image 03646 // 03647 03648 Resolved = TRUE; 03649 break; 03650 03651 } 03652 03653 } else if (!FoundBEA && (VolumeStructureDescriptor->Type < 3 || 03654 VolumeStructureDescriptor->Type == 255)) { 03655 03656 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, got a 9660 descriptor\n" )); 03657 03658 // 03659 // Only HSG (CDROM) and 9660 (CD001) are possible, and they are only legal 03660 // before the ISO 13346 BEA/TEA extent. By design, an ISO 13346 VSD precisely 03661 // overlaps a 9660 PVD/SVD in the appropriate fields. 03662 // 03663 // Note that we aren't being strict about the structure of the 9660 descriptors 03664 // since that really isn't very interesting. We care more about the 13346. 03665 // 03666 // 03667 03668 switch (UdfFindInParseTable( VsdIdentParseTable, 03669 VolumeStructureDescriptor->Ident, 03670 VSD_LENGTH_IDENT )) { 03671 case VsdIdentCDROM: 03672 case VsdIdentCD001: 03673 03674 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, ... seems we have 9660 here\n" )); 03675 03676 // 03677 // Note to our caller that we seem to have ISO 9660 here 03678 // 03679 03680 *Bridge = TRUE; 03681 03682 break; 03683 03684 default: 03685 03686 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, ... but it looks wacky\n" )); 03687 03688 // 03689 // This probably was a false alert, but in any case there is nothing 03690 // on this volume for us. 03691 // 03692 03693 Resolved = TRUE; 03694 break; 03695 } 03696 03697 } else { 03698 03699 // 03700 // Something else must be recorded on this volume. 03701 // 03702 03703 DebugTrace(( 0, Dbg, "UdfRecognizeVolume, got an unrecognizeable descriptor, probably not 13346/9660\n" )); 03704 break; 03705 } 03706 03707 // 03708 // Align our next read with the sector following the current descriptor 03709 // 03710 03711 Offset += SectorAlignN( SectorSize, sizeof(VSD_GENERIC) ); 03712 } 03713 03714 } finally { 03715 03716 DebugUnwind( "UdfRecognizeVolume" ); 03717 03718 // 03719 // Free up our temporary buffer 03720 // 03721 03722 UdfFreePool( &VolumeStructureDescriptor ); 03723 03724 if (AbnormalTermination()) { 03725 03726 // 03727 // Commute a status we raised for empty devices so that other filesystems 03728 // can have a crack at this. 03729 // 03730 03731 if (UdfIsRawDevice(IrpContext, IrpContext->ExceptionStatus)) { 03732 03733 IrpContext->ExceptionStatus = STATUS_UNRECOGNIZED_VOLUME; 03734 } 03735 } 03736 } 03737 03738 DebugTrace(( -1, Dbg, "UdfRecognizeVolume -> %u\n", FoundNSR )); 03739 03740 return FoundNSR; 03741 } 03742 03743 03744 // 03745 // Local support routine 03746 // 03747 03748 VOID 03749 UdfScanForDismountedVcb ( 03750 IN PIRP_CONTEXT IrpContext 03751 ) 03752 03753 /*++ 03754 03755 Routine Description: 03756 03757 This routine walks through the list of Vcb's looking for any which may 03758 now be deleted. They may have been left on the list because there were 03759 outstanding references. 03760 03761 Arguments: 03762 03763 Return Value: 03764 03765 None 03766 03767 --*/ 03768 03769 { 03770 PVCB Vcb; 03771 PLIST_ENTRY Links; 03772 03773 PAGED_CODE(); 03774 03775 // 03776 // Check input. 03777 // 03778 03779 ASSERT_IRP_CONTEXT( IrpContext ); 03780 03781 ASSERT_EXCLUSIVE_UDFDATA; 03782 03783 // 03784 // Walk through all of the Vcb's attached to the global data. 03785 // 03786 03787 Links = UdfData.VcbQueue.Flink; 03788 03789 while (Links != &UdfData.VcbQueue) { 03790 03791 Vcb = CONTAINING_RECORD( Links, VCB, VcbLinks ); 03792 03793 // 03794 // Move to the next link now since the current Vcb may be deleted. 03795 // 03796 03797 Links = Links->Flink; 03798 03799 // 03800 // If dismount is already underway then check if this Vcb can 03801 // go away. 03802 // 03803 03804 if ((Vcb->VcbCondition == VcbDismountInProgress) || 03805 (Vcb->VcbCondition == VcbInvalid) || 03806 ((Vcb->VcbCondition == VcbNotMounted) && (Vcb->VcbReference <= Vcb->VcbResidualReference))) { 03807 03808 UdfCheckForDismount( IrpContext, Vcb, FALSE ); 03809 } 03810 } 03811 03812 return; 03813 } 03814 03815 03816 VOID 03817 UdfDetermineVolumeBounding ( 03818 IN PIRP_CONTEXT IrpContext, 03819 IN PVCB Vcb, 03820 IN PULONG S, 03821 IN PULONG N 03822 ) 03823 03824 /*++ 03825 03826 Routine Description: 03827 03828 This routine will figure out where the base offset to discover volume descriptors 03829 lies and where the end of the disc is. In the case where this is a non-CD media, 03830 this will tend to not to set the end bound since there is no uniform way to figure 03831 that piece of information out. 03832 03833 The bounding information is used to start the hunt for CD-UDF (UDF 1.5) volumes. 03834 Anyone who puts CD-UDF on non-CD media deserves what they get. 03835 03836 Arguments: 03837 03838 Vcb - the volume we are operating on 03839 03840 S - an address to store the start of the volume for the purposes of finding descriptors 03841 03842 N - an address to store the end of the volume for the purposes of finding descriptors 03843 03844 Return Value: 03845 03846 None. 03847 03848 Benign inability find the S/N information will result in 0/0 being returned. 03849 03850 --*/ 03851 03852 { 03853 NTSTATUS Status; 03854 PCDROM_TOC CdromToc; 03855 PTRACK_DATA TrackData; 03856 03857 PAGED_CODE(); 03858 03859 // 03860 // Check input. 03861 // 03862 03863 ASSERT_IRP_CONTEXT( IrpContext ); 03864 ASSERT_VCB( Vcb ); 03865 03866 // 03867 // Allocate a buffer for the last session information. 03868 // 03869 03870 CdromToc = FsRtlAllocatePoolWithTag( UdfPagedPool, 03871 sizeof( CDROM_TOC ), 03872 TAG_CDROM_TOC ); 03873 03874 RtlZeroMemory( CdromToc, sizeof( CDROM_TOC )); 03875 03876 DebugTrace(( +1, Dbg, 03877 "UdfDetermineVolumeBounding, Vcb %08x S %08x N %08x\n", 03878 Vcb, 03879 S, 03880 N )); 03881 03882 // 03883 // Whack the inputs to the benign state. 03884 // 03885 03886 *S = *N = 0; 03887 03888 // 03889 // Try to retrieve the CDROM last session information. 03890 // 03891 03892 try { 03893 03894 // 03895 // Pull up the TOC. The information for track AA (start of leadout) 03896 // will get us the end of disc within some tolerance dependent on how 03897 // much the device manufacturer paid attention to specifications. 03898 // (-152, -150, -2, and 0 are possible offsets to the real end). 03899 // 03900 03901 Status = UdfPerformDevIoCtrl( IrpContext, 03902 IOCTL_CDROM_READ_TOC, 03903 Vcb->TargetDeviceObject, 03904 CdromToc, 03905 sizeof( CDROM_TOC ), 03906 FALSE, 03907 TRUE, 03908 NULL ); 03909 03910 // 03911 // Raise an exception if there was an allocation failure. 03912 // 03913 03914 if (Status == STATUS_INSUFFICIENT_RESOURCES) { 03915 03916 DebugTrace(( 0, Dbg, "UdfDetermineVolumeBounding, READ_TOC failed INSUFFICIENT_RESOURCES\n" )); 03917 UdfRaiseStatus( IrpContext, Status ); 03918 } 03919 03920 // 03921 // For other errors, just fail. Perhaps this will turn out to be benign, in any case 03922 // the mount will rapidly and correctly fail if it really was dependant on this work. 03923 // 03924 03925 if (!NT_SUCCESS( Status )) { 03926 03927 try_leave( NOTHING ); 03928 } 03929 03930 // 03931 // Sanity chck that the TOC is well-bounded. 03932 // 03933 03934 if (CdromToc->LastTrack - CdromToc->FirstTrack >= MAXIMUM_NUMBER_TRACKS) { 03935 03936 DebugTrace(( 0, Dbg, "UdfDetermineVolumeBounding, TOC malf (too many tracks)\n" )); 03937 try_leave( NOTHING ); 03938 } 03939 03940 TrackData = &CdromToc->TrackData[(CdromToc->LastTrack - CdromToc->FirstTrack + 1)]; 03941 03942 #if 0 03943 // 03944 // Better be AA ... 03945 // 03946 03947 if (TrackData->TrackNumber != 0xaa) { 03948 03949 DebugTrace(( 0, Dbg, "UdfDetermineVolumeBounding, TOC malf (aa not last)\n" )); 03950 try_leave( NOTHING ); 03951 } 03952 #endif 03953 03954 // 03955 // Now, find the AA info and convert MSF to a logical block address. 75 frames/sectors 03956 // per second, 60 seconds per minute. The MSF address is stored LSB (the F byte) high 03957 // in the word. 03958 // 03959 03960 // 03961 // NOTE: MSF is only capable of representing 256*(256+256*60)*75 = 0x11ce20 sectors. 03962 // This is 2.3gb, much less than the size of DVD media, which will respond to CDROM_TOC. 03963 // Caveat user. 03964 // 03965 03966 *N = (TrackData->Address[3] + (TrackData->Address[2] + TrackData->Address[1] * 60) * 75) - 1; 03967 03968 // 03969 // We must bias back by 0/2/0 MSF since that is the defined location of sector 0. This 03970 // works out to 150 sectors. 03971 // 03972 03973 if (*N <= 150) { 03974 03975 *N = 0; 03976 try_leave( NOTHING ); 03977 } 03978 03979 *N -= 150; 03980 03981 // 03982 // Query the last session information from the driver. 03983 // 03984 03985 Status = UdfPerformDevIoCtrl( IrpContext, 03986 IOCTL_CDROM_GET_LAST_SESSION, 03987 Vcb->TargetDeviceObject, 03988 CdromToc, 03989 sizeof( CDROM_TOC ), 03990 FALSE, 03991 TRUE, 03992 NULL ); 03993 03994 // 03995 // Raise an exception if there was an allocation failure. 03996 // 03997 03998 if (Status == STATUS_INSUFFICIENT_RESOURCES) { 03999 04000 DebugTrace(( 0, Dbg, "UdfDetermineVolumeBounding, GET_LAST_SESSION failed INSUFFICIENT_RESOURCES\n" )); 04001 UdfRaiseStatus( IrpContext, Status ); 04002 } 04003 04004 // 04005 // Now, if we got anything interesting out of this try, return it. If this 04006 // failed for any other reason, we don't really care - it just means that 04007 // if this was CDUDF media, we're gonna fail to figure it out pretty quickly. 04008 // 04009 // Life is tough. 04010 // 04011 04012 if (NT_SUCCESS( Status ) && 04013 CdromToc->FirstTrack != CdromToc->LastTrack) { 04014 04015 // 04016 // The 0 entry in TrackData tells us about the start of the session as a 04017 // logical block address. 04018 // 04019 04020 SwapCopyUchar4( S, &CdromToc->TrackData[0].Address ); 04021 04022 // 04023 // Save grief if the session info is screwed up. 04024 // 04025 04026 if (*N <= *S) { 04027 04028 DebugTrace(( 0, Dbg, "UdfDetermineVolumeBounding, N before S, whacking both back!\n" )); 04029 *S = *N = 0; 04030 } 04031 } 04032 04033 DebugTrace(( 0, Dbg, "UdfDetermineVolumeBounding, S %08x N %08x\n", *S, *N )); 04034 04035 } finally { 04036 04037 DebugUnwind( "UdfDetermineVolumeBounding" ); 04038 04039 if (CdromToc != NULL) { 04040 04041 UdfFreePool( &CdromToc ); 04042 } 04043 } 04044 04045 DebugTrace(( -1, Dbg, "UdfDetermineVolumeBounding -> VOID\n" )); 04046 04047 return; 04048 } 04049 04050 04051 // 04052 // Local support routine 04053 // 04054 04055 VOID 04056 UdfUpdateVolumeLabel ( 04057 IN PIRP_CONTEXT IrpContext, 04058 IN PWCHAR VolumeLabel, 04059 IN OUT PUSHORT VolumeLabelLength, 04060 IN PUCHAR Dstring, 04061 IN UCHAR FieldLength 04062 ) 04063 04064 /*++ 04065 04066 Routine Description: 04067 04068 This routine will retrieve an NT volume label from a logical volume descriptor. 04069 04070 Arguments: 04071 04072 VolumeLabel - a volume label to fill in. 04073 04074 VolumeLabelLength - returns the length of the returned volume label. 04075 04076 Dstring - the dstring field containing the volume id. 04077 04078 FieldLength - the length of the dstring field. 04079 04080 Return Value: 04081 04082 None. 04083 04084 --*/ 04085 04086 { 04087 BOOLEAN Result; 04088 04089 PAGED_CODE(); 04090 04091 // 04092 // Check inputs. 04093 // 04094 04095 ASSERT_IRP_CONTEXT( IrpContext ); 04096 04097 DebugTrace(( +1, Dbg, 04098 "UdfUpdateVolumeLabel, Label %08x, Dstring %08x FieldLength %02x\n", 04099 VolumeLabel, 04100 Dstring, 04101 FieldLength )); 04102 04103 // 04104 // Check that the dstring is usable as a volume identification. 04105 // 04106 04107 Result = UdfCheckLegalCS0Dstring( IrpContext, 04108 Dstring, 04109 0, 04110 FieldLength, 04111 TRUE ); 04112 04113 04114 // 04115 // Update the label directly if the dstring is good. 04116 // 04117 04118 if (Result) { 04119 04120 UNICODE_STRING TemporaryUnicodeString; 04121 04122 TemporaryUnicodeString.Buffer = VolumeLabel; 04123 TemporaryUnicodeString.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH; 04124 TemporaryUnicodeString.Length = 0; 04125 04126 UdfConvertCS0DstringToUnicode( IrpContext, 04127 Dstring, 04128 0, 04129 FieldLength, 04130 &TemporaryUnicodeString ); 04131 04132 // 04133 // Now retrieve the name for return to the caller. 04134 // 04135 04136 RtlCopyMemory( VolumeLabel, TemporaryUnicodeString.Buffer, TemporaryUnicodeString.Length ); 04137 *VolumeLabelLength = TemporaryUnicodeString.Length; 04138 04139 DebugTrace(( 0, Dbg, 04140 "UdfUpdateVolumeLabel, Labeled as \"%wZ\"\n", 04141 &TemporaryUnicodeString )); 04142 04143 // 04144 // Treat as label. 04145 // 04146 04147 } else { 04148 04149 *VolumeLabelLength = 0; 04150 04151 DebugTrace(( 0, Dbg, 04152 "UdfUpdateVolumeLabel, invalid label.\n" )); 04153 } 04154 04155 DebugTrace(( -1, Dbg, 04156 "UdfUpdateVolumeLabel -> VOID\n" )); 04157 } 04158 04159 04160 // 04161 // Local support routine 04162 // 04163 04164 VOID 04165 UdfUpdateVolumeSerialNumber ( 04166 IN PIRP_CONTEXT IrpContext, 04167 IN OUT PULONG VolumeSerialNumber, 04168 IN PNSR_FSD Fsd 04169 ) 04170 04171 /*++ 04172 04173 Routine Description: 04174 04175 This routine will compute the volume serial number for a set of descriptors. 04176 04177 Arguments: 04178 04179 VolumeSerialNumber - returns the volume serial number corresponding to these descriptors. 04180 04181 Fsd - the fileset descriptor to examine. 04182 04183 Return Value: 04184 04185 None. 04186 04187 --*/ 04188 04189 { 04190 ULONG VsnLe; 04191 PAGED_CODE(); 04192 04193 // 04194 // Check input. 04195 // 04196 04197 ASSERT_IRP_CONTEXT( IrpContext ); 04198 04199 // 04200 // The serial number is just off of the FSD. This matches Win9x. 04201 // 04202 04203 VsnLe = UdfSerial32( (PCHAR) Fsd, sizeof( NSR_FSD )); 04204 SwapCopyUchar4( VolumeSerialNumber, &VsnLe ); 04205 } 04206

Generated on Sat May 15 19:40:04 2004 for test by doxygen 1.3.7