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

strucsup.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 StrucSup.c 00008 00009 Abstract: 00010 00011 This module implements the Udfs in-memory data structure manipulation 00012 routines 00013 00014 Author: 00015 00016 Dan Lovinger [DanLo] 19-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_STRUCSUP) 00029 00030 // 00031 // The local debug trace level 00032 // 00033 00034 #define Dbg (UDFS_DEBUG_LEVEL_STRUCSUP) 00035 00036 // 00037 // Local structures 00038 // 00039 00040 typedef struct _FCB_TABLE_ELEMENT { 00041 00042 FILE_ID FileId; 00043 PFCB Fcb; 00044 00045 } FCB_TABLE_ELEMENT, *PFCB_TABLE_ELEMENT; 00046 00047 // 00048 // Local macros 00049 // 00050 00051 // 00052 // PFCB 00053 // UdfAllocateFcbData ( 00054 // IN PIRP_CONTEXT IrpContext 00055 // ); 00056 // 00057 // VOID 00058 // UdfDeallocateFcbData ( 00059 // IN PIRP_CONTEXT IrpContext, 00060 // IN PFCB Fcb 00061 // ); 00062 // 00063 // PFCB 00064 // UdfAllocateFcbIndex ( 00065 // IN PIRP_CONTEXT IrpContext 00066 // ); 00067 // 00068 // VOID 00069 // UdfDeallocateFcbIndex ( 00070 // IN PIRP_CONTEXT IrpContext, 00071 // IN PFCB Fcb 00072 // ); 00073 // 00074 // PFCB_NONPAGED 00075 // UdfAllocateFcbNonpaged ( 00076 // IN PIRP_CONTEXT IrpContext 00077 // ); 00078 // 00079 // VOID 00080 // UdfDeallocateFcbNonpaged ( 00081 // IN PIRP_CONTEXT IrpContext, 00082 // IN PFCB_NONPAGED FcbNonpaged 00083 // ); 00084 // 00085 // PCCB 00086 // UdfAllocateCcb ( 00087 // IN PIRP_CONTEXT IrpContext 00088 // ); 00089 // 00090 // VOID 00091 // UdfDeallocateCcb ( 00092 // IN PIRP_CONTEXT IrpContext, 00093 // IN PCCB Ccb 00094 // ); 00095 // 00096 00097 #define UdfAllocateFcbData(IC) \ 00098 ExAllocateFromPagedLookasideList( &UdfFcbDataLookasideList ); 00099 00100 #define UdfDeallocateFcbData(IC,F) \ 00101 ExFreeToPagedLookasideList( &UdfFcbDataLookasideList, F ); 00102 00103 #define UdfAllocateFcbIndex(IC) \ 00104 ExAllocateFromPagedLookasideList( &UdfFcbIndexLookasideList ); 00105 00106 #define UdfDeallocateFcbIndex(IC,F) \ 00107 ExFreeToPagedLookasideList( &UdfFcbIndexLookasideList, F ); 00108 00109 #define UdfAllocateFcbNonpaged(IC) \ 00110 ExAllocateFromNPagedLookasideList( &UdfFcbNonPagedLookasideList ); 00111 00112 #define UdfDeallocateFcbNonpaged(IC,FNP) \ 00113 ExFreeToNPagedLookasideList( &UdfFcbNonPagedLookasideList, FNP ); 00114 00115 #define UdfAllocateCcb(IC) \ 00116 ExAllocateFromPagedLookasideList( &UdfCcbLookasideList ); 00117 00118 #define UdfDeallocateCcb(IC,C) \ 00119 ExFreeToPagedLookasideList( &UdfCcbLookasideList, C ); 00120 00121 // 00122 // VOID 00123 // UdfInsertFcbTable ( 00124 // IN PIRP_CONTEXT IrpContext, 00125 // IN PFCB Fcb 00126 // ); 00127 // 00128 // VOID 00129 // UdfDeleteFcbTable ( 00130 // IN PIRP_CONTEXT IrpContext, 00131 // IN PFCB Fcb 00132 // ); 00133 // 00134 00135 00136 #define UdfInsertFcbTable(IC,F) { \ 00137 FCB_TABLE_ELEMENT _Key; \ 00138 _Key.Fcb = (F); \ 00139 _Key.FileId = (F)->FileId; \ 00140 RtlInsertElementGenericTable( &(F)->Vcb->FcbTable, \ 00141 &_Key, \ 00142 sizeof( FCB_TABLE_ELEMENT ), \ 00143 NULL ); \ 00144 } 00145 00146 #define UdfDeleteFcbTable(IC,F) { \ 00147 FCB_TABLE_ELEMENT _Key; \ 00148 _Key.FileId = (F)->FileId; \ 00149 RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key ); \ 00150 } 00151 00152 // 00153 // Discovers the partition the current allocation descriptor's referred extent 00154 // is on, either explicitly throuigh the descriptor or implicitly through the 00155 // mapped view. 00156 // 00157 00158 INLINE 00159 USHORT 00160 UdfGetPartitionOfCurrentAllocation ( 00161 IN PALLOC_ENUM_CONTEXT AllocContext 00162 ) 00163 { 00164 if (AllocContext->AllocType == ICBTAG_F_ALLOC_LONG) { 00165 00166 return ((PLONGAD) AllocContext->Alloc)->Start.Partition; 00167 00168 } else { 00169 00170 return AllocContext->IcbContext->Active.Partition; 00171 } 00172 } 00173 00174 // 00175 // Builds the Mcb in an Fcb. Use this after knowing that an Mcb is required 00176 // for mapping information. 00177 // 00178 00179 INLINE 00180 VOID 00181 UdfInitializeFcbMcb ( 00182 IN PFCB Fcb 00183 ) 00184 { 00185 // 00186 // In certain rare situations, we may get called more than once. 00187 // Just reset the allocations. 00188 // 00189 00190 if (FlagOn( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED )) { 00191 00192 FsRtlResetLargeMcb( &Fcb->Mcb, TRUE ); 00193 00194 } else { 00195 00196 FsRtlInitializeLargeMcb( &Fcb->Mcb, UdfPagedPool ); 00197 SetFlag( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED ); 00198 } 00199 } 00200 00201 // 00202 // Teardown an Fcb's Mcb as required. 00203 // 00204 00205 INLINE 00206 VOID 00207 UdfUninitializeFcbMcb ( 00208 IN PFCB Fcb 00209 ) 00210 { 00211 if (FlagOn( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED )) { 00212 00213 FsRtlUninitializeLargeMcb( &Fcb->Mcb ); 00214 ClearFlag( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED ); 00215 } 00216 } 00217 00218 // 00219 // Local support routines 00220 // 00221 00222 PVOID 00223 UdfAllocateTable ( 00224 IN PRTL_GENERIC_TABLE Table, 00225 IN CLONG ByteSize 00226 ); 00227 00228 PFCB_NONPAGED 00229 UdfCreateFcbNonPaged ( 00230 IN PIRP_CONTEXT IrpContext 00231 ); 00232 00233 VOID 00234 UdfDeleteFcbNonpaged ( 00235 IN PIRP_CONTEXT IrpContext, 00236 IN PFCB_NONPAGED FcbNonpaged 00237 ); 00238 00239 VOID 00240 UdfDeallocateTable ( 00241 IN PRTL_GENERIC_TABLE Table, 00242 IN PVOID Buffer 00243 ); 00244 00245 RTL_GENERIC_COMPARE_RESULTS 00246 UdfFcbTableCompare ( 00247 IN PRTL_GENERIC_TABLE Table, 00248 IN PVOID id1, 00249 IN PVOID id2 00250 ); 00251 00252 VOID 00253 UdfInitializeAllocationContext ( 00254 IN PIRP_CONTEXT IrpContext, 00255 IN PALLOC_ENUM_CONTEXT AllocContext, 00256 IN PICB_SEARCH_CONTEXT IcbContext 00257 ); 00258 00259 BOOLEAN 00260 UdfGetNextAllocation ( 00261 IN PIRP_CONTEXT IrpContext, 00262 IN PALLOC_ENUM_CONTEXT AllocContext 00263 ); 00264 00265 BOOLEAN 00266 UdfGetNextAllocationPostProcessing ( 00267 IN PIRP_CONTEXT IrpContext, 00268 IN PALLOC_ENUM_CONTEXT AllocContext 00269 ); 00270 00271 VOID 00272 UdfLookupActiveIcbInExtent ( 00273 IN PIRP_CONTEXT IrpContext, 00274 IN PICB_SEARCH_CONTEXT IcbContext, 00275 IN ULONG Recurse 00276 ); 00277 00278 VOID 00279 UdfInitializeEaContext ( 00280 IN PIRP_CONTEXT IrpContext, 00281 IN PEA_SEARCH_CONTEXT EaContext, 00282 IN PICB_SEARCH_CONTEXT IcbContext, 00283 IN ULONG EAType, 00284 IN UCHAR EASubType 00285 ); 00286 00287 BOOLEAN 00288 UdfLookupEa ( 00289 IN PIRP_CONTEXT IrpContext, 00290 IN PEA_SEARCH_CONTEXT EaContext 00291 ); 00292 00293 #ifdef ALLOC_PRAGMA 00294 #pragma alloc_text(PAGE, UdfAllocateTable) 00295 #pragma alloc_text(PAGE, UdfCleanupIcbContext) 00296 #pragma alloc_text(PAGE, UdfCleanupIrpContext) 00297 #pragma alloc_text(PAGE, UdfCreateCcb) 00298 #pragma alloc_text(PAGE, UdfCreateFcb) 00299 #pragma alloc_text(PAGE, UdfCreateFcbNonPaged) 00300 #pragma alloc_text(PAGE, UdfCreateIrpContext) 00301 #pragma alloc_text(PAGE, UdfDeallocateTable) 00302 #pragma alloc_text(PAGE, UdfDeleteCcb) 00303 #pragma alloc_text(PAGE, UdfDeleteFcb) 00304 #pragma alloc_text(PAGE, UdfDeleteFcbNonpaged) 00305 #pragma alloc_text(PAGE, UdfDeleteVcb) 00306 #pragma alloc_text(PAGE, UdfFcbTableCompare) 00307 #pragma alloc_text(PAGE, UdfFindInParseTable) 00308 #pragma alloc_text(PAGE, UdfGetNextAllocation) 00309 #pragma alloc_text(PAGE, UdfGetNextAllocationPostProcessing) 00310 #pragma alloc_text(PAGE, UdfGetNextFcb) 00311 #pragma alloc_text(PAGE, UdfInitializeAllocationContext) 00312 #pragma alloc_text(PAGE, UdfInitializeAllocations) 00313 #pragma alloc_text(PAGE, UdfInitializeEaContext) 00314 #pragma alloc_text(PAGE, UdfInitializeFcbFromIcbContext) 00315 #pragma alloc_text(PAGE, UdfInitializeIcbContext) 00316 #pragma alloc_text(PAGE, UdfInitializeStackIrpContext) 00317 #pragma alloc_text(PAGE, UdfInitializeVcb) 00318 #pragma alloc_text(PAGE, UdfLookupActiveIcb) 00319 #pragma alloc_text(PAGE, UdfLookupActiveIcbInExtent) 00320 #pragma alloc_text(PAGE, UdfLookupEa) 00321 #pragma alloc_text(PAGE, UdfLookupFcbTable) 00322 #pragma alloc_text(PAGE, UdfTeardownStructures) 00323 #pragma alloc_text(PAGE, UdfUpdateTimestampsFromIcbContext) 00324 #pragma alloc_text(PAGE, UdfUpdateVcbPhase0) 00325 #pragma alloc_text(PAGE, UdfUpdateVcbPhase1) 00326 #pragma alloc_text(PAGE, UdfVerifyDescriptor) 00327 #endif ALLOC_PRAGMA 00328 00329 00330 BOOLEAN 00331 UdfInitializeVcb ( 00332 IN PIRP_CONTEXT IrpContext, 00333 IN OUT PVCB Vcb, 00334 IN PDEVICE_OBJECT TargetDeviceObject, 00335 IN PVPB Vpb, 00336 IN PDISK_GEOMETRY DiskGeometry, 00337 IN ULONG MediaChangeCount 00338 ) 00339 00340 /*++ 00341 00342 Routine Description: 00343 00344 This routine initializes and inserts a new Vcb record into the in-memory 00345 data structure. The Vcb record "hangs" off the end of the Volume device 00346 object and must be allocated by our caller. 00347 00348 Arguments: 00349 00350 Vcb - Supplies the address of the Vcb record being initialized. 00351 00352 TargetDeviceObject - Supplies the address of the target device object to 00353 associate with the Vcb record. 00354 00355 Vpb - Supplies the address of the Vpb to associate with the Vcb record. 00356 00357 MediaChangeCount - Initial media change count of the target device 00358 00359 Return Value: 00360 00361 Boolean TRUE if the volume looks reasonable to continue mounting, FALSE 00362 otherwise. This routine can raise on allocation failure. 00363 00364 --*/ 00365 00366 { 00367 PAGED_CODE(); 00368 00369 // 00370 // We start by first zeroing out all of the VCB, this will guarantee 00371 // that any stale data is wiped clean. 00372 // 00373 00374 RtlZeroMemory( Vcb, sizeof( VCB )); 00375 00376 // 00377 // Set the proper node type code and node byte size. 00378 // 00379 00380 Vcb->NodeTypeCode = UDFS_NTC_VCB; 00381 Vcb->NodeByteSize = sizeof( VCB ); 00382 00383 // 00384 // Initialize the DirNotify structures. Do this first so there is 00385 // no cleanup if it raises. Nothing else below will fail with 00386 // a raise. 00387 // 00388 00389 InitializeListHead( &Vcb->DirNotifyList ); 00390 FsRtlNotifyInitializeSync( &Vcb->NotifySync ); 00391 00392 // 00393 // Initialize the resource variable for the Vcb and files. 00394 // 00395 00396 ExInitializeResource( &Vcb->VcbResource ); 00397 ExInitializeResource( &Vcb->FileResource ); 00398 ExInitializeFastMutex( &Vcb->VcbMutex ); 00399 00400 // 00401 // Insert this Vcb record on the UdfData.VcbQueue. 00402 // 00403 00404 InsertHeadList( &UdfData.VcbQueue, &Vcb->VcbLinks ); 00405 00406 // 00407 // Set the Target Device Object and Vpb fields, referencing the 00408 // target device. 00409 // 00410 00411 ObReferenceObject( TargetDeviceObject ); 00412 Vcb->TargetDeviceObject = TargetDeviceObject; 00413 Vcb->Vpb = Vpb; 00414 00415 // 00416 // Set the removable media flag based on the real device's 00417 // characteristics 00418 // 00419 00420 if (FlagOn( Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA )) { 00421 00422 SetFlag( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA ); 00423 } 00424 00425 // 00426 // Initialize the generic Fcb Table. 00427 // 00428 00429 RtlInitializeGenericTable( &Vcb->FcbTable, 00430 (PRTL_GENERIC_COMPARE_ROUTINE) UdfFcbTableCompare, 00431 (PRTL_GENERIC_ALLOCATE_ROUTINE) UdfAllocateTable, 00432 (PRTL_GENERIC_FREE_ROUTINE) UdfDeallocateTable, 00433 NULL ); 00434 00435 // 00436 // Show that we have a mount in progress. 00437 // 00438 00439 Vcb->VcbCondition = VcbMountInProgress; 00440 00441 // 00442 // Refererence the Vcb for two reasons. The first is a reference 00443 // that prevents the Vcb from going away on the last close unless 00444 // dismount has already occurred. The second is to make sure 00445 // we don't go into the dismount path on any error during mount 00446 // until we get to the Mount cleanup. 00447 // 00448 00449 Vcb->VcbResidualReference = UDFS_BASE_RESIDUAL_REFERENCE; 00450 Vcb->VcbResidualUserReference = UDFS_BASE_RESIDUAL_USER_REFERENCE; 00451 00452 Vcb->VcbReference = 1 + Vcb->VcbResidualReference; 00453 00454 // 00455 // Set the sector size. 00456 // 00457 00458 Vcb->SectorSize = DiskGeometry->BytesPerSector; 00459 00460 // 00461 // Set the sector shift amount. 00462 // 00463 00464 Vcb->SectorShift = UdfHighBit( DiskGeometry->BytesPerSector ); 00465 00466 // 00467 // Set the media change count on the device 00468 // 00469 00470 Vcb->MediaChangeCount = MediaChangeCount; 00471 00472 return TRUE; 00473 } 00474 00475 00476 VOID 00477 UdfUpdateVcbPhase0 ( 00478 IN PIRP_CONTEXT IrpContext, 00479 IN OUT PVCB Vcb 00480 ) 00481 00482 /*++ 00483 00484 Routine Description: 00485 00486 This routine is called to perform the initial spinup of the volume so that 00487 we can do reads into it. Primarily, this is required since virtual partitions 00488 make us lift the remapping table, and the final sets of descriptors from the volume 00489 can be off in these virtual partitions. 00490 00491 So, we need to get everything set up to read. 00492 00493 Arguments: 00494 00495 Vcb - Vcb for the volume being mounted. We have already set up and completed 00496 the Pcb. 00497 00498 Return Value: 00499 00500 None 00501 00502 --*/ 00503 00504 { 00505 ICB_SEARCH_CONTEXT IcbContext; 00506 00507 LONGLONG FileId = 0; 00508 00509 PICBFILE VatIcb = NULL; 00510 PREGID RegId; 00511 ULONG ThisPass; 00512 ULONG Psn; 00513 ULONG Vsn; 00514 ULONG Lbn; 00515 ULONG SectorCount; 00516 USHORT Reference; 00517 00518 BOOLEAN UnlockVcb = FALSE; 00519 BOOLEAN CleanupIcbContext = FALSE; 00520 00521 PBCB Bcb = NULL; 00522 LARGE_INTEGER Offset; 00523 00524 PAGED_CODE(); 00525 00526 // 00527 // Check input. 00528 // 00529 00530 ASSERT_IRP_CONTEXT( IrpContext ); 00531 ASSERT_VCB( Vcb ); 00532 00533 DebugTrace(( +1, Dbg, "UdfUpdateVcbPhase0, Vcb %08x\n", Vcb )); 00534 00535 try { 00536 00538 // 00539 // Create the Metadata Fcb and refererence it and the Vcb. 00540 // 00542 00543 UdfLockVcb( IrpContext, Vcb ); 00544 UnlockVcb = TRUE; 00545 00546 Vcb->MetadataFcb = UdfCreateFcb( IrpContext, 00547 *((PFILE_ID) &FileId), 00548 UDFS_NTC_FCB_INDEX, 00549 NULL ); 00550 00551 UdfIncrementReferenceCounts( IrpContext, Vcb->MetadataFcb, 1, 1 ); 00552 UdfUnlockVcb( IrpContext, Vcb ); 00553 UnlockVcb = FALSE; 00554 00555 // 00556 // The metadata stream is grown lazily as we reference disk structures. 00557 // 00558 00559 Vcb->MetadataFcb->FileSize.QuadPart = 00560 Vcb->MetadataFcb->ValidDataLength.QuadPart = 00561 Vcb->MetadataFcb->AllocationSize.QuadPart = 0; 00562 00563 // 00564 // Initialize the volume Vmcb 00565 // 00566 00567 UdfLockFcb( IrpContext, Vcb->MetadataFcb ); 00568 00569 UdfInitializeVmcb( &Vcb->Vmcb, 00570 UdfPagedPool, 00571 MAXULONG, 00572 SectorSize(Vcb) ); 00573 00574 UdfUnlockFcb( IrpContext, Vcb->MetadataFcb ); 00575 00576 // 00577 // Point to the file resource and set the flag that will cause mappings 00578 // to go through the Vmcb 00579 // 00580 00581 Vcb->MetadataFcb->Resource = &Vcb->FileResource; 00582 00583 SetFlag( Vcb->MetadataFcb->FcbState, FCB_STATE_VMCB_MAPPING | FCB_STATE_INITIALIZED ); 00584 00585 // 00586 // Create the stream file for this. 00587 // 00588 00589 UdfCreateInternalStream( IrpContext, Vcb, Vcb->MetadataFcb ); 00590 00592 // 00593 // If this is a volume containing a virtual partition, set up the 00594 // Virtual Allocation Table Fcb and adjust the residual reference 00595 // counts comensurately. 00596 // 00598 00599 if (FlagOn( Vcb->Pcb->Flags, PCB_FLAG_VIRTUAL_PARTITION )) { 00600 00601 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, handling VAT setup\n" )); 00602 00603 // 00604 // Now if some dummy has stuck us in the situation of not giving us 00605 // the tools to figure out where the end of the media is, tough luck. 00606 // 00607 00608 if (!Vcb->BoundN || Vcb->BoundN < ANCHOR_SECTOR) { 00609 00610 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, no end bound was discoverable!\n" )); 00611 00612 UdfRaiseStatus( IrpContext, STATUS_UNRECOGNIZED_VOLUME ); 00613 } 00614 00615 // 00616 // We take care of this first since the residuals must be in place 00617 // if we raise while finding the VAT, else we will get horribly 00618 // confused when the in-progress references are seen. We will think 00619 // that the extra real referenes are indications that the volume can't 00620 // be dismounted. 00621 // 00622 00623 Vcb->VcbResidualReference += UDFS_CDUDF_RESIDUAL_REFERENCE; 00624 Vcb->VcbResidualUserReference += UDFS_CDUDF_RESIDUAL_USER_REFERENCE; 00625 00626 Vcb->VcbReference += UDFS_CDUDF_RESIDUAL_REFERENCE; 00627 00628 // 00629 // Now, we need to hunt about for the VAT ICB. This is defined, on 00630 // closed media (meaning that the sessions have been finalized for use 00631 // in CDROM drives), to be in the very last information sector on the 00632 // media. Complicating this simple picture is that CDROMs tell us the 00633 // "last sector" by telling us where the start of the leadout area is, 00634 // not where the end of the informational sectors are. This is an 00635 // important distinction because any combination of the following can 00636 // be used in closing a CDROM session: 2 runout sectors, and/or 150 00637 // sectors (2 seconds) of postgap, or nothing. Immediately after these 00638 // "closing" writes is where the leadout begins. 00639 // 00640 // Runout is usually found on CD-E media and corresponds to the time it 00641 // will take to turn the writing laser off. Postgap is what is used to 00642 // generate audio pauses. It is easy to see that the kind of media and 00643 // kind of mastering tool/system used will affect us here. There is no 00644 // way to know either ahead of time. 00645 // 00646 // So, finally, these are the offsets from our previously discovered 00647 // bounding information where we might find the last information sector: 00648 // 00649 // -152 runout + postgap 00650 // -150 postgap 00651 // -2 runout 00652 // 0 nothing 00653 // 00654 // We must search these from low to high since it is extrememly expensive 00655 // to guess wrong - CDROMs will sit there for tens of seconds trying to 00656 // read unwritten/unreadable sectors. Hopefully we will find the VAT 00657 // ICB beforehand. 00658 // 00659 // This should all be highly disturbing. 00660 // 00661 00662 VatIcb = FsRtlAllocatePoolWithTag( UdfPagedPool, 00663 UdfRawBufferSize( Vcb, BlockSize( Vcb )), 00664 TAG_NSR_VDSD); 00665 00666 for (ThisPass = 0; ThisPass < 4; ThisPass++) { 00667 00668 // 00669 // Lift the appropriate sector. The discerning reader will be confused that 00670 // this is done in sector terms, not block. So is the implementor. 00671 // 00672 00673 Psn = Vcb->BoundN - ( ThisPass == 0? 152 : 00674 ( ThisPass == 1? 150 : 00675 ( ThisPass == 2? 2 : 0 ))); 00676 00677 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, looking at Psn 0x%08x\n", Psn )); 00678 00679 // 00680 // Now, try to figure out what physical partition this sector lives in so 00681 // that we can eventually establish workable metadata mappings to it and 00682 // dereference short allocation descriptors it may use. 00683 // 00684 00685 for (Reference = 0; 00686 Reference < Vcb->Pcb->Partitions; 00687 Reference++) { 00688 00689 if (Vcb->Pcb->Partition[Reference].Type == Physical && 00690 Vcb->Pcb->Partition[Reference].Physical.Start <= Psn && 00691 Vcb->Pcb->Partition[Reference].Physical.Start + 00692 Vcb->Pcb->Partition[Reference].Physical.Length > Psn) { 00693 00694 break; 00695 } 00696 } 00697 00698 // 00699 // If this sector is not contained in a partition, we do not 00700 // need to look at it. 00701 // 00702 00703 if (Reference == Vcb->Pcb->Partitions) { 00704 00705 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but it isn't in a partition.\n" )); 00706 00707 continue; 00708 } 00709 00710 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... in partition Ref %u.\n", Reference )); 00711 00712 // 00713 // We must locate the Lbn of this Psn by figuring out the offset of it 00714 // in the partition we already know that it is recorded in. 00715 // 00716 00717 Lbn = BlocksFromSectors( Vcb, Psn - Vcb->Pcb->Partition[Reference].Physical.Start ); 00718 00719 if (!NT_SUCCESS( UdfReadSectors( IrpContext, 00720 LlBytesFromSectors( Vcb, Psn ), 00721 UdfRawReadSize( Vcb, BlockSize( Vcb )), 00722 TRUE, 00723 VatIcb, 00724 Vcb->TargetDeviceObject ))) { 00725 00726 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but couldn't read it.\n" )); 00727 00728 continue; 00729 } 00730 00731 // 00732 // First make sure this looks vageuly like a file entry. 00733 // 00734 00735 if (!UdfVerifyDescriptor( IrpContext, 00736 (PDESTAG) VatIcb, 00737 DESTAG_ID_NSR_FILE, 00738 BlockSize( Vcb ), 00739 Lbn, 00740 TRUE )) { 00741 00742 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but it didn't verify.\n" )); 00743 00744 continue; 00745 } 00746 00747 // 00748 // Make sure this is a NOTSPEC object. We can also presume that a VAT isn't 00749 // linked into any directory, so it would be surprising if the link count was 00750 // nonzero. 00751 // 00752 00753 if (VatIcb->Icbtag.FileType != ICBTAG_FILE_T_NOTSPEC || 00754 VatIcb->LinkCount) { 00755 00756 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but the type/linkcount is wrong.\n" )); 00757 00758 continue; 00759 } 00760 00761 // 00762 // The VAT must be at least large enough to contain the required information and 00763 // be a multiple of 4byte elements in length. We also have defined a sanity upper 00764 // bound beyond which we never expect to see a VAT go. 00765 // 00766 00767 ASSERT( !LongOffset( UDF_CDUDF_MINIMUM_VAT_SIZE )); 00768 00769 if (VatIcb->InfoLength < UDF_CDUDF_MINIMUM_VAT_SIZE || 00770 VatIcb->InfoLength > UDF_CDUDF_MAXIMUM_VAT_SIZE || 00771 LongOffset( VatIcb->InfoLength )) { 00772 00773 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but the size looks pretty bogus.\n" )); 00774 00775 continue; 00776 } 00777 00778 // 00779 // At this point we have to take a wild guess that this will be the guy. Since the only 00780 // way to be sure is to look at the very end of the file an look for the regid, we've got 00781 // to go map this thing. 00782 // 00783 00784 // 00785 // This is pretty ugly, but we have to cobble this maybe-Icb into the metadata stream 00786 // so that initialization/use is possible (embedded data!). Normally regular Icb searches 00787 // would have done this for us, but since we have to go through such an amusing search 00788 // procedure that isn't possible. So, add it as a single sector mapping. 00789 // 00790 // Since this lives in a partition, we can just do the "lookup" in the metadata stream. 00791 // If we did not have this guarantee, we'd need to do a bit more of this by hand. 00792 // 00793 // As this is at mount time, we are very sure we are the only person messing with the 00794 // metadata stream. 00795 // 00796 00797 // 00798 // Zap the previous mapping and invalidate the metadata and VAT stream content. 00799 // 00800 00801 if (Vcb->VatFcb) { 00802 00803 UdfResetVmcb( &Vcb->Vmcb ); 00804 00805 UdfUnpinData( IrpContext, &Bcb ); 00806 00807 CcPurgeCacheSection( Vcb->MetadataFcb->FileObject->SectionObjectPointer, 00808 NULL, 00809 0, 00810 FALSE ); 00811 00812 CcPurgeCacheSection( Vcb->VatFcb->FileObject->SectionObjectPointer, 00813 NULL, 00814 0, 00815 FALSE ); 00816 } 00817 00818 Vsn = UdfLookupMetaVsnOfExtent( IrpContext, 00819 Vcb, 00820 Reference, 00821 Lbn, 00822 BlockSize( Vcb ), 00823 TRUE ); 00824 00825 if (Vcb->VatFcb == NULL) { 00826 00827 // 00828 // Now stamp out the Fcb. 00829 // 00830 00831 UdfLockVcb( IrpContext, Vcb ); 00832 UnlockVcb = TRUE; 00833 00834 Vcb->VatFcb = UdfCreateFcb( IrpContext, 00835 *((PFILE_ID) &FileId), 00836 UDFS_NTC_FCB_INDEX, 00837 NULL ); 00838 00839 UdfIncrementReferenceCounts( IrpContext, Vcb->VatFcb, 1, 1 ); 00840 UdfUnlockVcb( IrpContext, Vcb ); 00841 UnlockVcb = FALSE; 00842 00843 // 00844 // Point to the file resource and set the flag that will cause mappings 00845 // to go through the Vmcb 00846 // 00847 00848 Vcb->VatFcb->Resource = &Vcb->FileResource; 00849 } 00850 00851 // 00852 // Now size and try to pick up all of the allocation descriptors for this guy. 00853 // We're going to need to conjure an IcbContext for this. 00854 // 00855 00856 Vcb->VatFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb, VatIcb->InfoLength ); 00857 00858 Vcb->VatFcb->FileSize.QuadPart = 00859 Vcb->VatFcb->ValidDataLength.QuadPart = VatIcb->InfoLength; 00860 00861 // 00862 // Clean out any previous failed attempts. 00863 // 00864 00865 if (CleanupIcbContext) { 00866 00867 UdfCleanupIcbContext( IrpContext, &IcbContext ); 00868 00869 } else { 00870 00871 RtlZeroMemory( &IcbContext, sizeof( ICB_SEARCH_CONTEXT )); 00872 } 00873 00874 // 00875 // Now construct the ICB search context we would have had 00876 // made in the process of normal ICB discovery. Since we 00877 // were unable to do that, gotta do it by hand. 00878 // 00879 00880 IcbContext.Active.View = (PVOID) VatIcb; 00881 IcbContext.Active.Partition = Reference; 00882 IcbContext.Active.Lbn = Lbn; 00883 CleanupIcbContext = TRUE; 00884 00885 UdfInitializeAllocations( IrpContext, 00886 Vcb->VatFcb, 00887 &IcbContext ); 00888 00889 // 00890 // Create or resize the stream file for the VAT as appropriate. 00891 // 00892 00893 if (!FlagOn( Vcb->VatFcb->FcbState, FCB_STATE_INITIALIZED )) { 00894 00895 UdfCreateInternalStream( IrpContext, Vcb, Vcb->VatFcb ); 00896 SetFlag( Vcb->VatFcb->FcbState, FCB_STATE_INITIALIZED ); 00897 00898 } else { 00899 00900 CcSetFileSizes( Vcb->VatFcb->FileObject, (PCC_FILE_SIZES) &Vcb->VatFcb->AllocationSize ); 00901 } 00902 00903 // 00904 // To complete VAT discovery, we now look for the regid at the end of the stream 00905 // that will definitively tell us that this is really a VAT. Bias from the back 00906 // by the previous VAT pointer and the regid itself. We already know the stream 00907 // is big enough by virtue of our preliminary sanity checks. 00908 // 00909 00910 Offset.QuadPart = Vcb->VatFcb->FileSize.QuadPart - UDF_CDUDF_TRAILING_DATA_SIZE; 00911 00912 CcMapData( Vcb->VatFcb->FileObject, 00913 &Offset, 00914 sizeof(REGID), 00915 TRUE, 00916 &Bcb, 00917 &RegId ); 00918 00919 if (!UdfUdfIdentifierContained( RegId, 00920 &UdfVatTableIdentifier, 00921 UDF_VERSION_150, 00922 UDF_VERSION_RECOGNIZED, 00923 OSCLASS_INVALID, 00924 OSIDENTIFIER_INVALID )) { 00925 00926 // 00927 // Oh well, no go here. 00928 // 00929 00930 continue; 00931 } 00932 00933 // 00934 // Got it! 00935 // 00936 00937 break; 00938 } 00939 00940 // 00941 // If we didn't find anything ... 00942 // 00943 00944 if (ThisPass == 4) { 00945 00946 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... and so we didn't find a VAT!\n" )); 00947 00948 UdfRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR ); 00949 } 00950 00951 // 00952 // Go find the virtual reference so we can further update the Pcb 00953 // with information from the VAT. 00954 // 00955 00956 for (Reference = 0; 00957 Reference < Vcb->Pcb->Partitions; 00958 Reference++) { 00959 00960 if (Vcb->Pcb->Partition[Reference].Type == Virtual) { 00961 00962 break; 00963 } 00964 } 00965 00966 ASSERT( Reference < Vcb->Pcb->Partitions ); 00967 00968 // 00969 // We note the length so we can easily do bounds checking for 00970 // virtual mappings. 00971 // 00972 00973 Offset.QuadPart = (Vcb->VatFcb->FileSize.QuadPart - 00974 UDF_CDUDF_TRAILING_DATA_SIZE) / sizeof(ULONG); 00975 00976 ASSERT( Offset.HighPart == 0 ); 00977 Vcb->Pcb->Partition[Reference].Virtual.Length = Offset.LowPart; 00978 00979 DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... got it!\n" )); 00980 } 00981 00982 } finally { 00983 00984 DebugUnwind( "UdfUpdateVcbPhase0" ); 00985 00986 UdfUnpinData( IrpContext, &Bcb ); 00987 if (CleanupIcbContext) { UdfCleanupIcbContext( IrpContext, &IcbContext ); } 00988 if (UnlockVcb) { UdfUnlockVcb( IrpContext, Vcb ); } 00989 if (VatIcb) { ExFreePool( VatIcb ); } 00990 } 00991 00992 DebugTrace(( -1, Dbg, "UdfUpdateVcbPhase0 -> VOID\n" )); 00993 } 00994 00995 00996 VOID 00997 UdfUpdateVcbPhase1 ( 00998 IN PIRP_CONTEXT IrpContext, 00999 IN OUT PVCB Vcb, 01000 IN PNSR_FSD Fsd 01001 ) 01002 01003 /*++ 01004 01005 Routine Description: 01006 01007 This routine is called to perform the final initialization of a Vcb and Vpb 01008 from the volume descriptors on the disk. 01009 01010 Arguments: 01011 01012 Vcb - Vcb for the volume being mounted. We have already done phase 0. 01013 01014 Fsd - The fileset descriptor for this volume. 01015 01016 Return Value: 01017 01018 None 01019 01020 --*/ 01021 01022 { 01023 ICB_SEARCH_CONTEXT IcbContext; 01024 01025 LONGLONG FileId = 0; 01026 01027 PFCB Fcb; 01028 01029 BOOLEAN UnlockVcb = FALSE; 01030 BOOLEAN UnlockFcb = FALSE; 01031 BOOLEAN CleanupIcbContext = FALSE; 01032 01033 ULONG Reference; 01034 01035 ULONG BoundSector = 0; 01036 01037 PAGED_CODE(); 01038 01039 // 01040 // Check input. 01041 // 01042 01043 ASSERT_IRP_CONTEXT( IrpContext ); 01044 ASSERT_VCB( Vcb ); 01045 01046 DebugTrace(( +1, Dbg, "UdfUpdateVcbPhase1, Vcb %08x Fsd %08x\n", Vcb, Fsd )); 01047 01048 // 01049 // Use a try-finally to facilitate cleanup. 01050 // 01051 01052 try { 01053 01054 // 01055 // Do the final internal Fcb's and other Vcb fields. 01056 // 01057 01059 // 01060 // Create the root index and reference it in the Vcb. 01061 // 01063 01064 UdfLockVcb( IrpContext, Vcb ); 01065 UnlockVcb = TRUE; 01066 01067 Vcb->RootIndexFcb = UdfCreateFcb( IrpContext, 01068 *((PFILE_ID) &FileId), 01069 UDFS_NTC_FCB_INDEX, 01070 NULL ); 01071 01072 UdfIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 ); 01073 UdfUnlockVcb( IrpContext, Vcb ); 01074 UnlockVcb = FALSE; 01075 01076 // 01077 // Create the File id by hand for this Fcb. 01078 // 01079 01080 UdfSetFidFromLbAddr( Vcb->RootIndexFcb->FileId, Fsd->IcbRoot.Start ); 01081 UdfSetFidDirectory( Vcb->RootIndexFcb->FileId ); 01082 Vcb->RootIndexFcb->RootExtentLength = Fsd->IcbRoot.Length.Length; 01083 01084 // 01085 // Get the direct entry for the root directory and initialize 01086 // the Fcb from it. 01087 // 01088 01089 UdfInitializeIcbContextFromFcb( IrpContext, 01090 &IcbContext, 01091 Vcb->RootIndexFcb ); 01092 CleanupIcbContext = TRUE; 01093 01094 UdfLookupActiveIcb( IrpContext, &IcbContext ); 01095 01096 UdfInitializeFcbFromIcbContext( IrpContext, 01097 Vcb->RootIndexFcb, 01098 &IcbContext ); 01099 01100 UdfCleanupIcbContext( IrpContext, &IcbContext ); 01101 CleanupIcbContext = FALSE; 01102 01103 // 01104 // Create the stream file for the root directory. 01105 // 01106 01107 UdfCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb ); 01108 01110 // 01111 // Now do the volume dasd Fcb. Create this and reference it in the 01112 // Vcb. 01113 // 01115 01116 UdfLockVcb( IrpContext, Vcb ); 01117 UnlockVcb = TRUE; 01118 01119 Vcb->VolumeDasdFcb = UdfCreateFcb( IrpContext, 01120 *((PFILE_ID) &FileId), 01121 UDFS_NTC_FCB_DATA, 01122 NULL ); 01123 01124 UdfIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 ); 01125 UdfUnlockVcb( IrpContext, Vcb ); 01126 UnlockVcb = FALSE; 01127 01128 Fcb = Vcb->VolumeDasdFcb; 01129 UdfLockFcb( IrpContext, Fcb ); 01130 UnlockFcb = TRUE; 01131 01132 // 01133 // If we were unable to determine a last sector on the media, walk the Pcb and guess 01134 // that it is probably OK to think of the last sector of the last partition as The 01135 // Last Sector. Note that we couldn't do this before since the notion of a last 01136 // sector has significance at mount time, if it had been possible to find one. 01137 // 01138 01139 for ( Reference = 0; 01140 Reference < Vcb->Pcb->Partitions; 01141 Reference++ ) { 01142 01143 if (Vcb->Pcb->Partition[Reference].Type == Physical && 01144 Vcb->Pcb->Partition[Reference].Physical.Start + 01145 Vcb->Pcb->Partition[Reference].Physical.Length > BoundSector) { 01146 01147 BoundSector = Vcb->Pcb->Partition[Reference].Physical.Start + 01148 Vcb->Pcb->Partition[Reference].Physical.Length; 01149 } 01150 } 01151 01152 // 01153 // Note that we cannot restrict the bound by the "physical" bound discovered 01154 // eariler. This is because the MSF format of the TOC request we send is only 01155 // capable of representing about 2.3gb, and a lot of media we will be on that 01156 // responds to TOCs will be quite a bit larger - ex: DVD. 01157 // 01158 // This, of course, barring proper means of discovering media bounding, prohibits 01159 // the possibility of having UDF virtual partitions on DVD-R. 01160 // 01161 01162 // 01163 // Build the mapping from [0, Bound). We have to initialize the Mcb by hand since 01164 // this is usually left to when we lift retrieval information from an Icb in 01165 // UdfInitializeAllocations. 01166 // 01167 01168 UdfInitializeFcbMcb( Fcb ); 01169 01170 FsRtlAddLargeMcbEntry( &Fcb->Mcb, 01171 (LONGLONG) 0, 01172 (LONGLONG) 0, 01173 (LONGLONG) BoundSector ); 01174 01175 Fcb->FileSize.QuadPart += LlBytesFromSectors( Vcb, BoundSector ); 01176 01177 Fcb->AllocationSize.QuadPart = 01178 Fcb->ValidDataLength.QuadPart = Fcb->FileSize.QuadPart; 01179 01180 UdfUnlockFcb( IrpContext, Fcb ); 01181 UnlockFcb = FALSE; 01182 01183 SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED ); 01184 01185 // 01186 // Point to the file resource. 01187 // 01188 01189 Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource; 01190 01191 Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY; 01192 01193 } finally { 01194 01195 DebugUnwind( "UdfUpdateVcbPhase1" ); 01196 01197 if (CleanupIcbContext) { UdfCleanupIcbContext( IrpContext, &IcbContext ); } 01198 01199 if (UnlockFcb) { UdfUnlockFcb( IrpContext, Fcb ); } 01200 if (UnlockVcb) { UdfUnlockVcb( IrpContext, Vcb ); } 01201 } 01202 01203 DebugTrace(( -1, Dbg, "UdfUpdateVcbPhase1 -> VOID\n" )); 01204 01205 return; 01206 } 01207 01208 01209 VOID 01210 UdfDeleteVcb ( 01211 IN PIRP_CONTEXT IrpContext, 01212 IN OUT PVCB Vcb 01213 ) 01214 01215 /*++ 01216 01217 Routine Description: 01218 01219 This routine is called to delete a Vcb which failed mount or has been 01220 dismounted. The dismount code should have already removed all of the 01221 open Fcb's. We do nothing here but clean up other auxilary structures. 01222 01223 Arguments: 01224 01225 Vcb - Vcb to delete. 01226 01227 Return Value: 01228 01229 None 01230 01231 --*/ 01232 01233 { 01234 PAGED_CODE(); 01235 01236 ASSERT_EXCLUSIVE_UDFDATA; 01237 ASSERT_EXCLUSIVE_VCB( Vcb ); 01238 01239 // 01240 // If there is a Vpb then we must delete it ourselves. 01241 // 01242 01243 if (Vcb->Vpb != NULL) { 01244 01245 UdfFreePool( &Vcb->Vpb ); 01246 } 01247 01248 // 01249 // Drop the Pcb. 01250 // 01251 01252 if (Vcb->Pcb != NULL) { 01253 01254 UdfDeletePcb( Vcb->Pcb ); 01255 } 01256 01257 // 01258 // Dereference our target if we haven't already done so. 01259 // 01260 01261 if (Vcb->TargetDeviceObject != NULL) { 01262 01263 ObDereferenceObject( Vcb->TargetDeviceObject ); 01264 } 01265 01266 // 01267 // Remove this entry from the global queue. 01268 // 01269 01270 RemoveEntryList( &Vcb->VcbLinks ); 01271 01272 // 01273 // Delete the Vcb and File resources. 01274 // 01275 01276 ExDeleteResource( &Vcb->VcbResource ); 01277 ExDeleteResource( &Vcb->FileResource ); 01278 01279 // 01280 // Uninitialize the notify structures. 01281 // 01282 01283 if (Vcb->NotifySync != NULL) { 01284 01285 FsRtlNotifyUninitializeSync( &Vcb->NotifySync ); 01286 } 01287 01288 // 01289 // Now delete the volume device object. 01290 // 01291 01292 IoDeleteDevice( (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb, 01293 VOLUME_DEVICE_OBJECT, 01294 Vcb )); 01295 01296 return; 01297 } 01298 01299 01300 PIRP_CONTEXT 01301 UdfCreateIrpContext ( 01302 IN PIRP Irp, 01303 IN BOOLEAN Wait 01304 ) 01305 01306 /*++ 01307 01308 Routine Description: 01309 01310 This routine is called to initialize an IrpContext for the current 01311 UDFS request. We allocate the structure and then initialize it from 01312 the given Irp. 01313 01314 Arguments: 01315 01316 Irp - Irp for this request. 01317 01318 Wait - TRUE if this request is synchronous, FALSE otherwise. 01319 01320 Return Value: 01321 01322 PIRP_CONTEXT - Allocated IrpContext. 01323 01324 --*/ 01325 01326 { 01327 PIRP_CONTEXT NewIrpContext = NULL; 01328 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01329 BOOLEAN IsFsDo = FALSE; 01330 ULONG Count; 01331 01332 PAGED_CODE(); 01333 01334 for (Count = 0; Count < NUMBER_OF_FS_OBJECTS; Count++) { 01335 01336 if (IrpSp->DeviceObject == UdfData.FileSystemDeviceObjects[Count]) { 01337 01338 IsFsDo = TRUE; 01339 break; 01340 } 01341 } 01342 01343 // 01344 // The only operations a filesystem device object should ever receive 01345 // are create/teardown of fsdo handles and operations which do not 01346 // occur in the context of fileobjects (i.e., mount). 01347 // 01348 01349 if (IsFsDo) { 01350 01351 if (IrpSp->FileObject != NULL && 01352 IrpSp->MajorFunction != IRP_MJ_CREATE && 01353 IrpSp->MajorFunction != IRP_MJ_CLEANUP && 01354 IrpSp->MajorFunction != IRP_MJ_CLOSE) { 01355 01356 ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST ); 01357 } 01358 01359 ASSERT( IrpSp->FileObject != NULL || 01360 01361 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && 01362 IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST && 01363 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) || 01364 01365 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && 01366 IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) || 01367 01368 IrpSp->MajorFunction == IRP_MJ_SHUTDOWN ); 01369 } 01370 01371 NewIrpContext = ExAllocateFromNPagedLookasideList( &UdfIrpContextLookasideList ); 01372 01373 RtlZeroMemory( NewIrpContext, sizeof( IRP_CONTEXT )); 01374 01375 // 01376 // Set the proper node type code and node byte size 01377 // 01378 01379 NewIrpContext->NodeTypeCode = UDFS_NTC_IRP_CONTEXT; 01380 NewIrpContext->NodeByteSize = sizeof( IRP_CONTEXT ); 01381 01382 // 01383 // Set the originating Irp field 01384 // 01385 01386 NewIrpContext->Irp = Irp; 01387 01388 // 01389 // Copy RealDevice for workque algorithms. We will update this in the Mount or 01390 // Verify since they have no file objects to use here. 01391 // 01392 01393 if (IrpSp->FileObject != NULL) { 01394 01395 NewIrpContext->RealDevice = IrpSp->FileObject->DeviceObject; 01396 } 01397 01398 // 01399 // This may be one of our filesystem device objects. In that case don't 01400 // initialize the Vcb field. 01401 // 01402 01403 if (!IsFsDo) { 01404 01405 NewIrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb; 01406 } 01407 01408 // 01409 // Major/Minor Function codes 01410 // 01411 01412 NewIrpContext->MajorFunction = IrpSp->MajorFunction; 01413 NewIrpContext->MinorFunction = IrpSp->MinorFunction; 01414 01415 // 01416 // Set the wait parameter 01417 // 01418 01419 if (Wait) { 01420 01421 SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 01422 01423 } else { 01424 01425 SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); 01426 } 01427 01428 // 01429 // return and tell the caller 01430 // 01431 01432 return NewIrpContext; 01433 } 01434 01435 01436 VOID 01437 UdfCleanupIrpContext ( 01438 IN PIRP_CONTEXT IrpContext, 01439 IN BOOLEAN Post 01440 ) 01441 01442 /*++ 01443 01444 Routine Description: 01445 01446 This routine is called to cleanup and possibly deallocate the Irp Context. 01447 If the request is being posted or this Irp Context is possibly on the 01448 stack then we only cleanup any auxilary structures. 01449 01450 Arguments: 01451 01452 Post - TRUE if we are posting this request, FALSE if we are deleting 01453 or retrying this in the current thread. 01454 01455 Return Value: 01456 01457 None. 01458 01459 --*/ 01460 01461 { 01462 PAGED_CODE(); 01463 01464 ASSERT_IRP_CONTEXT( IrpContext ); 01465 01466 // 01467 // If we aren't doing more processing then deallocate this as appropriate. 01468 // 01469 01470 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING)) { 01471 01472 // 01473 // If this context is the top level UDFS context then we need to 01474 // restore the top level thread context. 01475 // 01476 01477 if (IrpContext->ThreadContext != NULL) { 01478 01479 UdfRestoreThreadContext( IrpContext ); 01480 } 01481 01482 // 01483 // Deallocate the Io context if allocated. 01484 // 01485 01486 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) { 01487 01488 UdfFreeIoContext( IrpContext->IoContext ); 01489 } 01490 01491 // 01492 // Deallocate the IrpContext if not from the stack. 01493 // 01494 01495 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK )) { 01496 01497 ExFreeToNPagedLookasideList( &UdfIrpContextLookasideList, IrpContext ); 01498 } 01499 01500 // 01501 // Clear the appropriate flags. 01502 // 01503 01504 } else if (Post) { 01505 01506 // 01507 // If this context is the top level UDFS context then we need to 01508 // restore the top level thread context. 01509 // 01510 01511 if (IrpContext->ThreadContext != NULL) { 01512 01513 UdfRestoreThreadContext( IrpContext ); 01514 } 01515 01516 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST ); 01517 01518 } else { 01519 01520 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY ); 01521 } 01522 01523 return; 01524 } 01525 01526 01527 VOID 01528 UdfInitializeStackIrpContext ( 01529 OUT PIRP_CONTEXT IrpContext, 01530 IN PIRP_CONTEXT_LITE IrpContextLite 01531 ) 01532 01533 /*++ 01534 01535 Routine Description: 01536 01537 This routine is called to initialize an IrpContext for the current 01538 UDFS request. The IrpContext is on the stack and we need to initialize 01539 it for the current request. The request is a close operation. 01540 01541 Arguments: 01542 01543 IrpContext - IrpContext to initialize. 01544 01545 IrpContextLite - Structure containing the details of this request. 01546 01547 Return Value: 01548 01549 None 01550 01551 --*/ 01552 01553 { 01554 PAGED_CODE(); 01555 01556 ASSERT_IRP_CONTEXT_LITE( IrpContextLite ); 01557 01558 // 01559 // Zero and then initialize the structure. 01560 // 01561 01562 RtlZeroMemory( IrpContext, sizeof( IRP_CONTEXT )); 01563 01564 // 01565 // Set the proper node type code and node byte size 01566 // 01567 01568 IrpContext->NodeTypeCode = UDFS_NTC_IRP_CONTEXT; 01569 IrpContext->NodeByteSize = sizeof( IRP_CONTEXT ); 01570 01571 // 01572 // Note that this is from the stack. 01573 // 01574 01575 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK ); 01576 01577 // 01578 // Copy RealDevice for workque algorithms. 01579 // 01580 01581 IrpContext->RealDevice = IrpContextLite->RealDevice; 01582 01583 // 01584 // The Vcb is found in the Fcb. 01585 // 01586 01587 IrpContext->Vcb = IrpContextLite->Fcb->Vcb; 01588 01589 // 01590 // Major/Minor Function codes 01591 // 01592 01593 IrpContext->MajorFunction = IRP_MJ_CLOSE; 01594 01595 // 01596 // Set the wait parameter 01597 // 01598 01599 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 01600 01601 return; 01602 } 01603 01604 01605 VOID 01606 UdfTeardownStructures ( 01607 IN PIRP_CONTEXT IrpContext, 01608 IN PFCB StartingFcb, 01609 IN BOOLEAN Recursive, 01610 OUT PBOOLEAN RemovedStartingFcb 01611 ) 01612 01613 /*++ 01614 01615 Routine Description: 01616 01617 This routine is used to walk from some starting point in the Fcb tree towards 01618 the root. It will remove the Fcb and continue walking up the tree until 01619 it finds a point where we can't remove an Fcb. 01620 01621 We look at the following fields in the Fcb to determine whether we can 01622 remove this. 01623 01624 1 - Handle count must be zero. 01625 2 - If directory then only the only reference can be for a stream file. 01626 3 - Reference count must either be zero or go to zero here. 01627 01628 We return immediately if we are recursively entering this routine. 01629 01630 Arguments: 01631 01632 StartingFcb - This is the Fcb node in the tree to begin with. This Fcb 01633 must currently be acquired exclusively. 01634 01635 Recursive - Indicates if this call is an intentional recursion. 01636 01637 RemovedStartingFcb - Address to store whether we removed the starting Fcb. 01638 01639 Return Value: 01640 01641 None 01642 01643 --*/ 01644 01645 { 01646 PVCB Vcb = StartingFcb->Vcb; 01647 PFCB CurrentFcb = StartingFcb; 01648 BOOLEAN AcquiredCurrentFcb = FALSE; 01649 PFCB ParentFcb = NULL; 01650 PLCB Lcb; 01651 01652 PLIST_ENTRY ListLinks; 01653 BOOLEAN Abort = FALSE; 01654 BOOLEAN Removed; 01655 01656 PAGED_CODE(); 01657 01658 // 01659 // Check input. 01660 // 01661 01662 ASSERT_IRP_CONTEXT( IrpContext ); 01663 ASSERT_FCB( StartingFcb ); 01664 01665 *RemovedStartingFcb = FALSE; 01666 01667 // 01668 // If this is not an intentionally recursive call we need to check if this 01669 // is a layered close and we're already in another instance of teardown. 01670 // 01671 01672 DebugTrace(( +1, Dbg, 01673 "UdfTeardownStructures, StartingFcb %08x %s\n", 01674 StartingFcb, 01675 ( Recursive? "Recursive" : "Flat" ))); 01676 01677 if (!Recursive) { 01678 01679 // 01680 // If this is a recursive call to TearDownStructures we return immediately 01681 // doing no operation. 01682 // 01683 01684 if (FlagOn( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN )) { 01685 01686 return; 01687 } 01688 01689 SetFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN ); 01690 } 01691 01692 // 01693 // Use a try-finally to safely clear the top-level field. 01694 // 01695 01696 try { 01697 01698 // 01699 // Loop until we find an Fcb we can't remove. 01700 // 01701 01702 do { 01703 01704 // 01705 // See if there is an internal stream we should delete. 01706 // Only do this if it is the last reference on the Fcb. 01707 // 01708 01709 if ((SafeNodeType( CurrentFcb ) != UDFS_NTC_FCB_DATA) && 01710 (CurrentFcb->FcbUserReference == 0) && 01711 (CurrentFcb->FileObject != NULL)) { 01712 01713 // 01714 // Go ahead and delete the stream file object. 01715 // 01716 01717 UdfDeleteInternalStream( IrpContext, CurrentFcb ); 01718 } 01719 01720 // 01721 // If the reference count is non-zero then break. 01722 // 01723 01724 if (CurrentFcb->FcbReference != 0) { 01725 01726 break; 01727 } 01728 01729 // 01730 // It looks like we have a candidate for removal here. We 01731 // will need to walk the list of prefixes and delete them 01732 // from their parents. If it turns out that we have multiple 01733 // parents of this Fcb, we are going to recursively teardown 01734 // on each of these. 01735 // 01736 01737 for ( ListLinks = CurrentFcb->ParentLcbQueue.Flink; 01738 ListLinks != &CurrentFcb->ParentLcbQueue; ) { 01739 01740 Lcb = CONTAINING_RECORD( ListLinks, LCB, ChildFcbLinks ); 01741 01742 ASSERT_LCB( Lcb ); 01743 01744 // 01745 // We advance the pointer now because we will be toasting this guy, 01746 // invalidating whatever is here. 01747 // 01748 01749 ListLinks = ListLinks->Flink; 01750 01751 // 01752 // We may have multiple parents through hard links. If the previous parent we 01753 // dealt with is not the parent of this new Lcb, lets do some work. 01754 // 01755 01756 if (ParentFcb != Lcb->ParentFcb) { 01757 01758 // 01759 // We need to deal with the previous parent. It may now be the case that 01760 // we deleted the last child reference and it wants to go away at this point. 01761 // 01762 01763 if (ParentFcb) { 01764 01765 // 01766 // It should never be the case that we have to recurse more than one level on 01767 // any teardown since no cross-linkage of directories is possible. 01768 // 01769 01770 ASSERT( !Recursive ); 01771 01772 UdfTeardownStructures( IrpContext, ParentFcb, TRUE, &Removed ); 01773 01774 if (!Removed) { 01775 01776 UdfReleaseFcb( IrpContext, ParentFcb ); 01777 } 01778 } 01779 01780 // 01781 // Get this new parent Fcb to work on. 01782 // 01783 01784 ParentFcb = Lcb->ParentFcb; 01785 UdfAcquireFcbExclusive( IrpContext, ParentFcb, FALSE ); 01786 } 01787 01788 // 01789 // Lock the Vcb so we can look at references. 01790 // 01791 01792 UdfLockVcb( IrpContext, Vcb ); 01793 01794 // 01795 // Now check that the reference counts on the Lcb are zero. 01796 // 01797 01798 if ( Lcb->Reference != 0 ) { 01799 01800 // 01801 // A create is interested in getting in here, so we should 01802 // stop right now. 01803 // 01804 01805 UdfUnlockVcb( IrpContext, Vcb ); 01806 UdfReleaseFcb( IrpContext, ParentFcb ); 01807 Abort = TRUE; 01808 01809 break; 01810 } 01811 01812 // 01813 // Now remove this prefix and drop the references to the parent. 01814 // 01815 01816 ASSERT( Lcb->ChildFcb == CurrentFcb ); 01817 ASSERT( Lcb->ParentFcb == ParentFcb ); 01818 01819 DebugTrace(( +0, Dbg, 01820 "UdfTeardownStructures, Lcb %08x P %08x <-> C %08x Vcb %d/%d PFcb %d/%d CFcb %d/%d\n", 01821 Lcb, 01822 ParentFcb, 01823 CurrentFcb, 01824 Vcb->VcbReference, 01825 Vcb->VcbUserReference, 01826 ParentFcb->FcbReference, 01827 ParentFcb->FcbUserReference, 01828 CurrentFcb->FcbReference, 01829 CurrentFcb->FcbUserReference )); 01830 01831 UdfRemovePrefix( IrpContext, Lcb ); 01832 UdfDecrementReferenceCounts( IrpContext, ParentFcb, 1, 1 ); 01833 01834 DebugTrace(( +0, Dbg, 01835 "UdfTeardownStructures, Vcb %d/%d PFcb %d/%d\n", 01836 Vcb->VcbReference, 01837 Vcb->VcbUserReference, 01838 ParentFcb->FcbReference, 01839 ParentFcb->FcbUserReference )); 01840 01841 UdfUnlockVcb( IrpContext, Vcb ); 01842 } 01843 01844 // 01845 // Now really leave if we have to. 01846 // 01847 01848 if (Abort) { 01849 01850 break; 01851 } 01852 01853 // 01854 // Now that we have removed all of the prefixes of this Fcb we can make the final check. 01855 // Lock the Vcb again so we can inspect the child's references. 01856 // 01857 01858 UdfLockVcb( IrpContext, Vcb ); 01859 01860 if (CurrentFcb->FcbReference != 0) { 01861 01862 DebugTrace(( +0, Dbg, 01863 "UdfTeardownStructures, saving Fcb %08x %d/%d\n", 01864 CurrentFcb, 01865 CurrentFcb->FcbReference, 01866 CurrentFcb->FcbUserReference )); 01867 01868 // 01869 // Nope, nothing more to do. Stop right now. 01870 // 01871 01872 UdfUnlockVcb( IrpContext, Vcb ); 01873 01874 if (ParentFcb != NULL) { 01875 01876 UdfReleaseFcb( IrpContext, ParentFcb ); 01877 } 01878 01879 break; 01880 } 01881 01882 // 01883 // This Fcb is toast. Remove it from the Fcb Table as appropriate and delete. 01884 // 01885 01886 if (FlagOn( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE )) { 01887 01888 UdfDeleteFcbTable( IrpContext, CurrentFcb ); 01889 ClearFlag( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE ); 01890 01891 } 01892 01893 // 01894 // Unlock the Vcb but hold the parent in order to walk up 01895 // the tree. 01896 // 01897 01898 DebugTrace(( +0, Dbg, 01899 "UdfTeardownStructures, toasting Fcb %08x %d/%d\n", 01900 CurrentFcb, 01901 CurrentFcb->FcbReference, 01902 CurrentFcb->FcbUserReference )); 01903 01904 UdfUnlockVcb( IrpContext, Vcb ); 01905 UdfDeleteFcb( IrpContext, CurrentFcb ); 01906 01907 // 01908 // Move to the parent Fcb. 01909 // 01910 01911 CurrentFcb = ParentFcb; 01912 ParentFcb = NULL; 01913 AcquiredCurrentFcb = TRUE; 01914 01915 } while (CurrentFcb != NULL); 01916 01917 } finally { 01918 01919 // 01920 // Release the current Fcb if we have acquired it. 01921 // 01922 01923 if (AcquiredCurrentFcb && (CurrentFcb != NULL)) { 01924 01925 UdfReleaseFcb( IrpContext, CurrentFcb ); 01926 } 01927 01928 // 01929 // Clear the teardown flag. 01930 // 01931 01932 if (!Recursive) { 01933 01934 ClearFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN ); 01935 } 01936 } 01937 01938 *RemovedStartingFcb = (CurrentFcb != StartingFcb); 01939 01940 DebugTrace(( -1, Dbg, 01941 "UdfTeardownStructures, RemovedStartingFcb -> %c\n", 01942 ( *RemovedStartingFcb? 'T' : 'F' ))); 01943 01944 return; 01945 } 01946 01947 01948 PFCB 01949 UdfLookupFcbTable ( 01950 IN PIRP_CONTEXT IrpContext, 01951 IN PVCB Vcb, 01952 IN FILE_ID FileId 01953 ) 01954 01955 /*++ 01956 01957 Routine Description: 01958 01959 This routine will look through the Fcb table looking for a matching 01960 entry. 01961 01962 Arguments: 01963 01964 Vcb - Vcb for this volume. 01965 01966 FileId - This is the key value to use for the search. 01967 01968 Return Value: 01969 01970 PFCB - A pointer to the matching entry or NULL otherwise. 01971 01972 --*/ 01973 01974 { 01975 FCB_TABLE_ELEMENT Key; 01976 PFCB_TABLE_ELEMENT Hit; 01977 PFCB ReturnFcb = NULL; 01978 01979 PAGED_CODE(); 01980 01981 Key.FileId = FileId; 01982 01983 Hit = (PFCB_TABLE_ELEMENT) RtlLookupElementGenericTable( &Vcb->FcbTable, &Key ); 01984 01985 if (Hit != NULL) { 01986 01987 ReturnFcb = Hit->Fcb; 01988 } 01989 01990 return ReturnFcb; 01991 01992 UNREFERENCED_PARAMETER( IrpContext ); 01993 } 01994 01995 01996 PFCB 01997 UdfGetNextFcb ( 01998 IN PIRP_CONTEXT IrpContext, 01999 IN PVCB Vcb, 02000 IN PVOID *RestartKey 02001 ) 02002 02003 /*++ 02004 02005 Routine Description: 02006 02007 This routine will enumerate through all of the Fcb's in the Fcb table. 02008 02009 Arguments: 02010 02011 Vcb - Vcb for this volume. 02012 02013 RestartKey - This value is used by the table package to maintain 02014 its position in the enumeration. It is initialized to NULL 02015 for the first search. 02016 02017 Return Value: 02018 02019 PFCB - A pointer to the next fcb or NULL if the enumeration is 02020 completed 02021 02022 --*/ 02023 02024 { 02025 PFCB Fcb; 02026 02027 PAGED_CODE(); 02028 02029 Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey ); 02030 02031 if (Fcb != NULL) { 02032 02033 Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb; 02034 } 02035 02036 return Fcb; 02037 } 02038 02039 02040 PFCB 02041 UdfCreateFcb ( 02042 IN PIRP_CONTEXT IrpContext, 02043 IN FILE_ID FileId, 02044 IN NODE_TYPE_CODE NodeTypeCode, 02045 OUT PBOOLEAN FcbExisted OPTIONAL 02046 ) 02047 02048 /*++ 02049 02050 Routine Description: 02051 02052 This routine is called to find the Fcb for the given FileId. We will 02053 look this up first in the Fcb table and if not found we will create 02054 an Fcb. We don't initialize it or insert it into the FcbTable in this 02055 routine. 02056 02057 This routine is called while the Vcb is locked. 02058 02059 Arguments: 02060 02061 FileId - This is the Id for the target Fcb. 02062 02063 NodeTypeCode - Node type for this Fcb if we need to create. 02064 02065 FcbExisted - If specified, we store whether the Fcb existed. 02066 02067 Return Value: 02068 02069 PFCB - The Fcb found in the table or created if needed. 02070 02071 --*/ 02072 02073 { 02074 PFCB NewFcb; 02075 BOOLEAN LocalFcbExisted; 02076 02077 PAGED_CODE(); 02078 02079 // 02080 // Use the local boolean if one was not passed in. 02081 // 02082 02083 if (!ARGUMENT_PRESENT( FcbExisted )) { 02084 02085 FcbExisted = &LocalFcbExisted; 02086 } 02087 02088 // 02089 // Maybe this is already in the table. 02090 // 02091 02092 NewFcb = UdfLookupFcbTable( IrpContext, IrpContext->Vcb, FileId ); 02093 02094 // 02095 // If not then create the Fcb is requested by our caller. 02096 // 02097 02098 if (NewFcb == NULL) { 02099 02100 // 02101 // Use a try-finally for cleanup 02102 // 02103 02104 try { 02105 02106 // 02107 // Allocate and initialize the structure depending on the 02108 // type code. 02109 // 02110 02111 switch (NodeTypeCode) { 02112 02113 case UDFS_NTC_FCB_INDEX: 02114 02115 NewFcb = UdfAllocateFcbIndex( IrpContext ); 02116 02117 RtlZeroMemory( NewFcb, SIZEOF_FCB_INDEX ); 02118 02119 NewFcb->NodeByteSize = SIZEOF_FCB_INDEX; 02120 02121 break; 02122 02123 case UDFS_NTC_FCB_DATA : 02124 02125 NewFcb = UdfAllocateFcbData( IrpContext ); 02126 02127 RtlZeroMemory( NewFcb, SIZEOF_FCB_DATA ); 02128 02129 NewFcb->NodeByteSize = SIZEOF_FCB_DATA; 02130 02131 break; 02132 02133 default: 02134 02135 UdfBugCheck( 0, 0, 0 ); 02136 } 02137 02138 // 02139 // Now do the common initialization. 02140 // 02141 02142 NewFcb->NodeTypeCode = NodeTypeCode; 02143 02144 NewFcb->Vcb = IrpContext->Vcb; 02145 NewFcb->FileId = FileId; 02146 02147 InitializeListHead( &NewFcb->ParentLcbQueue ); 02148 InitializeListHead( &NewFcb->ChildLcbQueue ); 02149 02150 // 02151 // Now create the non-paged section object. 02152 // 02153 02154 NewFcb->FcbNonpaged = UdfCreateFcbNonPaged( IrpContext ); 02155 02156 *FcbExisted = FALSE; 02157 02158 } finally { 02159 02160 DebugUnwind( "UdfCreateFcb" ); 02161 02162 if (AbnormalTermination()) { 02163 02164 UdfFreePool( &NewFcb ); 02165 } 02166 } 02167 02168 } else { 02169 02170 *FcbExisted = TRUE; 02171 } 02172 02173 return NewFcb; 02174 } 02175 02176 02177 VOID 02178 UdfDeleteFcb ( 02179 IN PIRP_CONTEXT IrpContext, 02180 IN PFCB Fcb 02181 ) 02182 02183 /*++ 02184 02185 Routine Description: 02186 02187 This routine is called to cleanup and deallocate an Fcb. We know there 02188 are no references remaining. We cleanup any auxilary structures and 02189 deallocate this Fcb. 02190 02191 Arguments: 02192 02193 Fcb - This is the Fcb to deallcoate. 02194 02195 Return Value: 02196 02197 None 02198 02199 --*/ 02200 02201 { 02202 PVCB Vcb = NULL; 02203 02204 PAGED_CODE(); 02205 02206 // 02207 // Check inputs. 02208 // 02209 02210 ASSERT_IRP_CONTEXT( IrpContext ); 02211 ASSERT_FCB( Fcb ); 02212 02213 // 02214 // Sanity check the counts and Lcb lists. 02215 // 02216 02217 ASSERT( Fcb->FcbCleanup == 0 ); 02218 ASSERT( Fcb->FcbReference == 0 ); 02219 02220 ASSERT( IsListEmpty( &Fcb->ChildLcbQueue )); 02221 ASSERT( IsListEmpty( &Fcb->ParentLcbQueue )); 02222 02223 // 02224 // Start with the common structures. 02225 // 02226 02227 UdfUninitializeFcbMcb( Fcb ); 02228 02229 UdfDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged ); 02230 02231 // 02232 // Now do the type specific structures. 02233 // 02234 02235 switch (Fcb->NodeTypeCode) { 02236 02237 case UDFS_NTC_FCB_INDEX: 02238 02239 ASSERT( Fcb->FileObject == NULL ); 02240 02241 if (Fcb == Fcb->Vcb->RootIndexFcb) { 02242 02243 Vcb = Fcb->Vcb; 02244 Vcb->RootIndexFcb = NULL; 02245 02246 } else if (Fcb == Fcb->Vcb->MetadataFcb) { 02247 02248 Vcb = Fcb->Vcb; 02249 Vcb->MetadataFcb = NULL; 02250 02251 UdfUninitializeVmcb( &Vcb->Vmcb ); 02252 02253 } else if (Fcb == Fcb->Vcb->VatFcb) { 02254 02255 Vcb = Fcb->Vcb; 02256 Vcb->VatFcb = NULL; 02257 } 02258 02259 UdfDeallocateFcbIndex( IrpContext, Fcb ); 02260 break; 02261 02262 case UDFS_NTC_FCB_DATA : 02263 02264 if (Fcb->FileLock != NULL) { 02265 02266 FsRtlFreeFileLock( Fcb->FileLock ); 02267 } 02268 02269 FsRtlUninitializeOplock( &Fcb->Oplock ); 02270 02271 if (Fcb == Fcb->Vcb->VolumeDasdFcb) { 02272 02273 Vcb = Fcb->Vcb; 02274 Vcb->VolumeDasdFcb = NULL; 02275 } 02276 02277 UdfDeallocateFcbData( IrpContext, Fcb ); 02278 break; 02279 } 02280 02281 // 02282 // Decrement the Vcb reference count if this is a system 02283 // Fcb. 02284 // 02285 02286 if (Vcb != NULL) { 02287 02288 InterlockedDecrement( &Vcb->VcbReference ); 02289 InterlockedDecrement( &Vcb->VcbUserReference ); 02290 } 02291 02292 return; 02293 } 02294 02295 02296 VOID 02297 UdfInitializeFcbFromIcbContext ( 02298 IN PIRP_CONTEXT IrpContext, 02299 IN PFCB Fcb, 02300 IN PICB_SEARCH_CONTEXT IcbContext 02301 ) 02302 02303 /*++ 02304 02305 Routine Description: 02306 02307 This routine is called to initialize an Fcb from a direct ICB. It should 02308 only be called once in the lifetime of an Fcb and will fill in the Mcb 02309 from the chained allocation descriptors of the ICB. 02310 02311 Arguments: 02312 02313 Fcb - The Fcb being initialized 02314 02315 IcbOontext - An search context containing the active direct ICB for the object 02316 02317 Return Value: 02318 02319 None. 02320 02321 --*/ 02322 02323 { 02324 EA_SEARCH_CONTEXT EaContext; 02325 PICBFILE Icb; 02326 02327 PVCB Vcb; 02328 02329 PAGED_CODE(); 02330 02331 // 02332 // Check inputs 02333 // 02334 02335 ASSERT_IRP_CONTEXT( IrpContext ); 02336 ASSERT_FCB( Fcb ); 02337 02338 // 02339 // Directly reference for convenience 02340 // 02341 02342 Icb = IcbContext->Active.View; 02343 Vcb = Fcb->Vcb; 02344 02345 ASSERT( IcbContext->IcbType == DESTAG_ID_NSR_FILE && Icb->Destag.Ident == DESTAG_ID_NSR_FILE ); 02346 02347 // 02348 // Check that the full indicated size of the direct entry is sane and 02349 // that the length of the EA segment is correctly aligned. A direct 02350 // entry is less than a single logical block in size. 02351 // 02352 02353 if (LongOffset( Icb->EALength ) || 02354 FIELD_OFFSET( ICBFILE, EAs ) + Icb->EALength + Icb->AllocLength > BlockSize( IcbContext->Vcb )) { 02355 02356 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 02357 } 02358 02359 UdfLockFcb( IrpContext, Fcb ); 02360 02361 // 02362 // Try-finally for cleanup. 02363 // 02364 02365 try { 02366 02367 // 02368 // Verify that the types mesh and set state flags. 02369 // 02370 02371 if (Fcb->NodeTypeCode == UDFS_NTC_FCB_INDEX && Icb->Icbtag.FileType == ICBTAG_FILE_T_DIRECTORY) { 02372 02373 SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY ); 02374 02375 } else if (!(Fcb->NodeTypeCode == UDFS_NTC_FCB_DATA && Icb->Icbtag.FileType == ICBTAG_FILE_T_FILE)) { 02376 02377 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 02378 } 02379 02380 SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_READONLY ); 02381 02382 // 02383 // Initialize the common header in the Fcb. 02384 // 02385 02386 Fcb->Resource = &Fcb->Vcb->FileResource; 02387 02388 // 02389 // Size and lookup all allocations for this object. 02390 // 02391 02392 Fcb->AllocationSize.QuadPart = LlBlockAlign( Vcb, Icb->InfoLength ); 02393 02394 Fcb->FileSize.QuadPart = 02395 Fcb->ValidDataLength.QuadPart = Icb->InfoLength; 02396 02397 UdfInitializeAllocations( IrpContext, 02398 Fcb, 02399 IcbContext ); 02400 02401 // 02402 // Lift all of the timestamps for this guy. 02403 // 02404 02405 UdfUpdateTimestampsFromIcbContext( IrpContext, 02406 IcbContext, 02407 &Fcb->Timestamps ); 02408 02409 // 02410 // Pick up the link count. 02411 // 02412 02413 Fcb->LinkCount = Icb->LinkCount; 02414 02415 // 02416 // Link into the Fcb table. Someone else is responsible for the name linkage, which is 02417 // all that remains. We also note that the Fcb is fully initialized at this point. 02418 // 02419 02420 UdfInsertFcbTable( IrpContext, Fcb ); 02421 SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE | FCB_STATE_INITIALIZED ); 02422 02423 } finally { 02424 02425 UdfUnlockFcb( IrpContext, Fcb ); 02426 } 02427 02428 return; 02429 } 02430 02431 02432 PCCB 02433 UdfCreateCcb ( 02434 IN PIRP_CONTEXT IrpContext, 02435 IN PFCB Fcb, 02436 IN PLCB Lcb OPTIONAL, 02437 IN ULONG Flags 02438 ) 02439 02440 /*++ 02441 02442 Routine Description: 02443 02444 This routine is called to allocate and initialize the Ccb structure. 02445 02446 Arguments: 02447 02448 Fcb - This is the Fcb for the file being opened. 02449 02450 Lcb - This is the Lcb the Fcb is opened by. 02451 02452 Flags - User flags to set in this Ccb. 02453 02454 Return Value: 02455 02456 PCCB - Pointer to the created Ccb. 02457 02458 --*/ 02459 02460 { 02461 PCCB NewCcb; 02462 02463 PAGED_CODE(); 02464 02465 // 02466 // Check inputs. 02467 // 02468 02469 ASSERT_IRP_CONTEXT( IrpContext ); 02470 ASSERT_FCB( Fcb ); 02471 ASSERT_OPTIONAL_LCB( Lcb ); 02472 02473 // 02474 // Allocate and initialize the structure. 02475 // 02476 02477 NewCcb = UdfAllocateCcb( IrpContext ); 02478 02479 // 02480 // Set the proper node type code and node byte size 02481 // 02482 02483 NewCcb->NodeTypeCode = UDFS_NTC_CCB; 02484 NewCcb->NodeByteSize = sizeof( CCB ); 02485 02486 // 02487 // Set the initial value for the flags and Fcb/Lcb 02488 // 02489 02490 NewCcb->Flags = Flags; 02491 NewCcb->Fcb = Fcb; 02492 NewCcb->Lcb = Lcb; 02493 02494 // 02495 // Initialize the directory enumeration context 02496 // 02497 02498 NewCcb->CurrentFileIndex = 0; 02499 NewCcb->HighestReturnableFileIndex = 0; 02500 02501 NewCcb->SearchExpression.Length = 02502 NewCcb->SearchExpression.MaximumLength = 0; 02503 NewCcb->SearchExpression.Buffer = NULL; 02504 02505 return NewCcb; 02506 } 02507 02508 02509 VOID 02510 UdfDeleteCcb ( 02511 IN PIRP_CONTEXT IrpContext, 02512 IN PCCB Ccb 02513 ) 02514 02515 /*++ 02516 02517 Routine Description: 02518 02519 This routine is called to cleanup and deallocate a Ccb structure. 02520 02521 Arguments: 02522 02523 Ccb - This is the Ccb to delete. 02524 02525 Return Value: 02526 02527 None 02528 02529 --*/ 02530 02531 { 02532 PAGED_CODE(); 02533 02534 // 02535 // Check inputs. 02536 // 02537 02538 ASSERT_IRP_CONTEXT( IrpContext ); 02539 ASSERT_CCB( Ccb ); 02540 02541 if (Ccb->SearchExpression.Buffer != NULL) { 02542 02543 UdfFreePool( &Ccb->SearchExpression.Buffer ); 02544 } 02545 02546 UdfDeallocateCcb( IrpContext, Ccb ); 02547 return; 02548 } 02549 02550 02551 ULONG 02552 UdfFindInParseTable ( 02553 IN PPARSE_KEYVALUE ParseTable, 02554 IN PCHAR Id, 02555 IN ULONG MaxIdLen 02556 ) 02557 02558 /*++ 02559 02560 Routine Description: 02561 02562 This routine walks a table of string key/value information for a match of the 02563 input Id. MaxIdLen can be set to get a prefix match. 02564 02565 Arguments: 02566 02567 Table - This is the table being searched. 02568 02569 Id - Key value. 02570 02571 MaxIdLen - Maximum possible length of Id. 02572 02573 Return Value: 02574 02575 Value of matching entry, or the terminating (NULL) entry's value. 02576 02577 --*/ 02578 02579 { 02580 PAGED_CODE(); 02581 02582 while (ParseTable->Key != NULL) { 02583 02584 if (RtlEqualMemory(ParseTable->Key, Id, MaxIdLen)) { 02585 02586 break; 02587 } 02588 02589 ParseTable++; 02590 } 02591 02592 return ParseTable->Value; 02593 } 02594 02595 02596 #ifdef UDF_SANITY 02597 02598 // 02599 // Enumerate the reasons why a descriptor might be bad. 02600 // 02601 02602 typedef enum _VERIFY_FAILURE { 02603 02604 Nothing, 02605 BadLbn, 02606 BadTag, 02607 BadChecksum, 02608 BadCrcLength, 02609 BadCrc, 02610 BadDestagVersion 02611 02612 } VERIFY_FAILURE; 02613 02614 #endif 02615 02616 BOOLEAN 02617 UdfVerifyDescriptor ( 02618 IN PIRP_CONTEXT IrpContext, 02619 IN PDESTAG Descriptor, 02620 IN USHORT Tag, 02621 IN ULONG Size, 02622 IN ULONG Lbn, 02623 IN BOOLEAN ReturnError 02624 ) 02625 02626 /*++ 02627 02628 Routine Description: 02629 02630 This routine verifies that a descriptor using a Descriptor tag (3/7.2) is 02631 consistent with itself and the descriptor data. 02632 02633 Arguments: 02634 02635 Descriptor - This is the pointer to the descriptor tag, which is always 02636 at the front of a descriptor 02637 02638 Tag - The Tag Identifier this descriptor should have 02639 02640 Size - Size of this descriptor 02641 02642 Lbn - The logical block number this descriptor should claim it is recorded at 02643 02644 ReturnError - Whether this routine should return an error or raise 02645 02646 Return Value: 02647 02648 Boolean TRUE if the descriptor is consistent, FALSE or a raised status of 02649 STATUS_DISK_CORRUPT_ERROR otherwise. 02650 02651 --*/ 02652 02653 { 02654 UCHAR Checksum = 0; 02655 PCHAR CheckPtr; 02656 USHORT Crc; 02657 02658 #ifdef UDF_SANITY 02659 02660 VERIFY_FAILURE FailReason = Nothing; 02661 02662 #endif 02663 02664 // 02665 // Check our inputs 02666 // 02667 02668 ASSERT_IRP_CONTEXT( IrpContext ); 02669 02670 PAGED_CODE(); 02671 02672 #ifdef UDF_SANITY 02673 02674 if (UdfNoisyVerifyDescriptor) { 02675 02676 goto BeNoisy; 02677 } 02678 02679 RegularEntry: 02680 02681 #endif 02682 02683 // 02684 // The version of the Descriptor Tag specified in ISO 13346 and used in 02685 // UDF is a particular value; presumeably, previous versions were used 02686 // in some older revision of the standard. 02687 // 02688 02689 #ifdef UDF_SUPPORT_NONSTANDARD_ADAPTEC 02690 02691 // 02692 // Let bad descriptor version numbers through. 02693 // 02694 // Reasons: 02695 // 02696 // ADAPTEC - early CDUDF wrote version 1 as opposed to version 2. 02697 // 02698 02699 if (TRUE) 02700 02701 #else 02702 02703 if (Descriptor->Version == DESTAG_VER_CURRENT) 02704 02705 #endif 02706 02707 { 02708 02709 // 02710 // A descriptor is stamped in four ways. First, the Lbn of the sector 02711 // containing the descriptor is written here. (3/7.2.8) 02712 // 02713 02714 02715 #ifdef UDF_SUPPORT_NONSTANDARD_HP 02716 02717 // 02718 // Let bad lbn through. 02719 // 02720 // Reasons: 02721 // 02722 // HP - Rob Sim;s CD-RW model disc doesn't record this reliably. 02723 // 02724 02725 if (TRUE) 02726 02727 #else 02728 02729 if (Descriptor->Lbn == Lbn) 02730 02731 #endif 02732 { 02733 // 02734 // Next, the descriptor tag itself has an identifier which should match 02735 // the type we expect to find here (3/7.2.1) 02736 // 02737 02738 if (Descriptor->Ident == Tag) { 02739 02740 // 02741 // Next, the descriptor tag itself is checksumed, minus the byte 02742 // used to store the checksum. (3/7.2.3) 02743 // 02744 02745 for (CheckPtr = (PCHAR) Descriptor; 02746 CheckPtr < (PCHAR) Descriptor + FIELD_OFFSET( DESTAG, Checksum ); 02747 CheckPtr++) { 02748 02749 Checksum += *CheckPtr; 02750 } 02751 02752 for (CheckPtr = (PCHAR) Descriptor + FIELD_OFFSET( DESTAG, Checksum ) + sizeof(UCHAR); 02753 CheckPtr < (PCHAR) Descriptor + sizeof(DESTAG); 02754 CheckPtr++) { 02755 02756 Checksum += *CheckPtr; 02757 } 02758 02759 if (Descriptor->Checksum == Checksum) { 02760 02761 // 02762 // Now we check that the CRC in the Descriptor tag is sized sanely 02763 // and matches the Descriptor data. (3/7.2.6) 02764 // 02765 02766 #ifdef UDF_SUPPORT_NONSTANDARD_HP 02767 02768 // 02769 // Let zero-length CRCs through. 02770 // 02771 // Reasons: 02772 // 02773 // HP - early CDUDF didn't CRC the terminationg descriptors (tag 8). 02774 // 02775 02776 if (!Descriptor->CRCLen || 02777 Descriptor->CRCLen <= Size - sizeof(DESTAG)) 02778 #else 02779 02780 if (Descriptor->CRCLen && 02781 Descriptor->CRCLen <= Size - sizeof(DESTAG)) 02782 02783 #endif 02784 { 02785 02786 Crc = UdfComputeCrc16( (PCHAR) Descriptor + sizeof(DESTAG), 02787 Descriptor->CRCLen ); 02788 02789 #ifdef UDF_SUPPORT_NONSTANDARD_HP 02790 02791 // 02792 // Let zero-length CRCs through. 02793 // 02794 // Reasons: as above. 02795 // 02796 02797 if (!Descriptor->CRCLen || 02798 Descriptor->CRC == Crc) 02799 02800 #else 02801 02802 if (Descriptor->CRC == Crc) 02803 02804 #endif 02805 { 02806 02807 // 02808 // This descriptor checks out. 02809 // 02810 02811 #ifdef UDF_SANITY 02812 if (UdfNoisyVerifyDescriptor) { 02813 02814 DebugTrace(( -1, Dbg, "UdfVerifyDescriptor -> TRUE\n" )); 02815 } 02816 #endif 02817 return TRUE; 02818 02819 } else { 02820 #ifdef UDF_SANITY 02821 FailReason = BadCrc; 02822 goto ReportFailure; 02823 #endif 02824 } 02825 02826 } else { 02827 #ifdef UDF_SANITY 02828 FailReason = BadCrcLength; 02829 goto ReportFailure; 02830 #endif 02831 } 02832 02833 } else { 02834 #ifdef UDF_SANITY 02835 FailReason = BadChecksum; 02836 goto ReportFailure; 02837 #endif 02838 } 02839 02840 } else { 02841 #ifdef UDF_SANITY 02842 FailReason = BadTag; 02843 goto ReportFailure; 02844 #endif 02845 } 02846 02847 } else { 02848 #ifdef UDF_SANITY 02849 FailReason = BadLbn; 02850 goto ReportFailure; 02851 #endif 02852 } 02853 02854 } else { 02855 #ifdef UDF_SANITY 02856 FailReason = BadDestagVersion; 02857 goto ReportFailure; 02858 #endif 02859 } 02860 02861 #ifdef UDF_SANITY 02862 02863 BeNoisy: 02864 02865 DebugTrace(( +1, Dbg, 02866 "UdfVerifyDescriptor, Destag %08x, Tag %x, Size %x, Lbn %x\n", 02867 Descriptor, 02868 Tag, 02869 Size, 02870 Lbn )); 02871 02872 if (FailReason == Nothing) { 02873 02874 goto RegularEntry; 02875 02876 } else if (!UdfNoisyVerifyDescriptor) { 02877 02878 goto ReallyReportFailure; 02879 } 02880 02881 ReportFailure: 02882 02883 if (!UdfNoisyVerifyDescriptor) { 02884 02885 goto BeNoisy; 02886 } 02887 02888 ReallyReportFailure: 02889 02890 switch (FailReason) { 02891 case BadLbn: 02892 DebugTrace(( 0, Dbg, 02893 "Lbn mismatch - Lbn %x != expected %x\n", 02894 Descriptor->Lbn, 02895 Lbn )); 02896 break; 02897 02898 case BadTag: 02899 DebugTrace(( 0, Dbg, 02900 "Tag mismatch - Ident %x != expected %x\n", 02901 Descriptor->Ident, 02902 Tag )); 02903 break; 02904 02905 case BadChecksum: 02906 DebugTrace(( 0, Dbg, 02907 "Checksum mismatch - Checksum %x != descriptor's %x\n", 02908 Checksum, 02909 Descriptor->Checksum )); 02910 break; 02911 02912 case BadCrcLength: 02913 DebugTrace(( 0, Dbg, 02914 "CRC'd size bad - CrcLen %x is 0 or > max %x\n", 02915 Descriptor->CRCLen, 02916 Size - sizeof(DESTAG) )); 02917 break; 02918 02919 case BadCrc: 02920 DebugTrace(( 0, Dbg, 02921 "CRC mismatch - Crc %x != descriptor's %x\n", 02922 Crc, 02923 Descriptor->CRC )); 02924 break; 02925 02926 case BadDestagVersion: 02927 DebugTrace(( 0, Dbg, 02928 "Bad Destag Verion - %x != descriptor's %x\n", 02929 DESTAG_VER_CURRENT, 02930 Descriptor->Version )); 02931 break; 02932 02933 default: 02934 ASSERT( FALSE ); 02935 } 02936 02937 DebugTrace(( -1, Dbg, "UdfVerifyDescriptor -> FALSE\n" )); 02938 02939 #endif 02940 02941 if (!ReturnError) { 02942 02943 UdfRaiseStatus( IrpContext, STATUS_CRC_ERROR ); 02944 } 02945 02946 return FALSE; 02947 } 02948 02949 02950 VOID 02951 UdfInitializeIcbContextFromFcb ( 02952 IN PIRP_CONTEXT IrpContext, 02953 IN PICB_SEARCH_CONTEXT IcbContext, 02954 IN PFCB Fcb 02955 ) 02956 02957 /*++ 02958 02959 Routine Description: 02960 02961 This routine is called to initialize a context to search the Icb hierarchy 02962 associated with an Fcb. 02963 02964 Arguments: 02965 02966 Fcb - Fcb associated with the hierarchy to search. 02967 02968 Return Value: 02969 02970 None. 02971 02972 --*/ 02973 02974 { 02975 PAGED_CODE(); 02976 02977 // 02978 // Check input parameters. 02979 // 02980 02981 ASSERT_IRP_CONTEXT( IrpContext ); 02982 ASSERT_FCB( Fcb ); 02983 02984 RtlZeroMemory( IcbContext, sizeof( ICB_SEARCH_CONTEXT )); 02985 02986 IcbContext->Vcb = Fcb->Vcb; 02987 IcbContext->IcbType = DESTAG_ID_NSR_FILE; 02988 02989 // 02990 // It is possible that we don't have an idea what the length of the root extent is. 02991 // This will commonly happen in the OpenById case. 02992 // 02993 02994 if (Fcb->RootExtentLength == 0) { 02995 02996 PICBFILE Icb; 02997 02998 // 02999 // We have to lift the first entry from this (possibly bogus!) extent 03000 // and find out how many entries can be recorded, then unmap/remap the view 03001 // to try to get the extent. 03002 // 03003 03004 UdfMapMetadataView( IrpContext, 03005 &IcbContext->Current, 03006 IcbContext->Vcb, 03007 UdfGetFidPartition( Fcb->FileId ), 03008 UdfGetFidLbn( Fcb->FileId ), 03009 BlockSize( IcbContext->Vcb )); 03010 03011 Icb = IcbContext->Current.View; 03012 03013 // 03014 // We can only accomplish the guess if we have a descriptor which contains an ICB 03015 // Tag, which contains a field that can tell us what we need to know. 03016 // 03017 03018 if (Icb->Destag.Ident == DESTAG_ID_NSR_ICBIND || 03019 Icb->Destag.Ident == DESTAG_ID_NSR_ICBTRM || 03020 Icb->Destag.Ident == DESTAG_ID_NSR_FILE || 03021 Icb->Destag.Ident == DESTAG_ID_NSR_UASE || 03022 Icb->Destag.Ident == DESTAG_ID_NSR_PINTEG) { 03023 03024 UdfVerifyDescriptor( IrpContext, 03025 &Icb->Destag, 03026 Icb->Destag.Ident, 03027 BlockSize( IcbContext->Vcb ), 03028 UdfGetFidLbn( Fcb->FileId ), 03029 FALSE ); 03030 } else { 03031 03032 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03033 } 03034 03035 // 03036 // Now the MaxEntries (4/14.6.4) field of the Icb Tag should tell us how big the extent 03037 // should be. The tail of this could be unrecorded. We could even have landed in the middle 03038 // of an extent. This is only a guess. For whatever reason we are having to guess this 03039 // information, any results are expected to be coming with few guarantees. 03040 // 03041 03042 Fcb->RootExtentLength = Icb->Icbtag.MaxEntries * BlockSize( IcbContext->Vcb ); 03043 } 03044 03045 // 03046 // Map the first extent into the current slot. 03047 // 03048 03049 UdfMapMetadataView( IrpContext, 03050 &IcbContext->Current, 03051 IcbContext->Vcb, 03052 UdfGetFidPartition( Fcb->FileId ), 03053 UdfGetFidLbn( Fcb->FileId ), 03054 Fcb->RootExtentLength ); 03055 return; 03056 } 03057 03058 03059 VOID 03060 UdfInitializeIcbContext ( 03061 IN PIRP_CONTEXT IrpContext, 03062 IN PICB_SEARCH_CONTEXT IcbContext, 03063 IN PVCB Vcb, 03064 IN USHORT IcbType, 03065 IN USHORT Partition, 03066 IN ULONG Lbn, 03067 IN ULONG Length 03068 ) 03069 03070 /*++ 03071 03072 Routine Description: 03073 03074 This routine is called to initialize a context to search an Icb hierarchy. 03075 03076 Arguments: 03077 03078 Vcb - Vcb for the volume. 03079 03080 IcbType - Type of direct entry we expect to find (DESTAG_ID...) 03081 03082 Partition - partition of the hierarchy. 03083 03084 Lbn - lbn of the hierarchy. 03085 03086 Length - length of the root extent of the hierarchy. 03087 03088 Return Value: 03089 03090 None. 03091 03092 --*/ 03093 03094 { 03095 PAGED_CODE(); 03096 03097 // 03098 // Check input parameters. 03099 // 03100 03101 ASSERT_IRP_CONTEXT( IrpContext ); 03102 03103 RtlZeroMemory( IcbContext, sizeof( ICB_SEARCH_CONTEXT )); 03104 03105 IcbContext->Vcb = Vcb; 03106 IcbContext->IcbType = IcbType; 03107 03108 // 03109 // Map the first extent into the current slot. 03110 // 03111 03112 UdfMapMetadataView( IrpContext, 03113 &IcbContext->Current, 03114 Vcb, 03115 Partition, 03116 Lbn, 03117 Length ); 03118 return; 03119 03120 } 03121 03122 03123 VOID 03124 UdfLookupActiveIcb ( 03125 IN PIRP_CONTEXT IrpContext, 03126 IN PICB_SEARCH_CONTEXT IcbContext 03127 ) 03128 03129 /*++ 03130 03131 Routine Description: 03132 03133 This routine is called to cause the active Icb for an Icb hierarchy to be mapped. 03134 A context initialized by UdfInitializeIcbContext() is required. 03135 03136 Arguments: 03137 03138 IcbContext - Context which has been initialized to point into an Icb hierarchy. 03139 03140 Return Value: 03141 03142 None. 03143 03144 Raised status if the Icb hierarchy is invalid. 03145 03146 --*/ 03147 03148 { 03149 PAGED_CODE(); 03150 03151 // 03152 // Check input parameters. 03153 // 03154 03155 ASSERT_IRP_CONTEXT( IrpContext ); 03156 03157 // 03158 // Travel the Icb hierarchy. Due to the design of ISO 13346, it is convenient to 03159 // recursively descend the hierarchy. Place a limit on this recursion which will 03160 // allow traversal of most reasonable hierarchies (this will tail recurse off of 03161 // the end of extents). 03162 // 03163 03164 UdfLookupActiveIcbInExtent( IrpContext, 03165 IcbContext, 03166 UDF_ICB_RECURSION_LIMIT ); 03167 03168 // 03169 // We must have found an active ICB. Drop the last mapped part of the enumeration 03170 // at this point. 03171 // 03172 03173 UdfUnpinView( IrpContext, &IcbContext->Current ); 03174 03175 if (IcbContext->Active.View == NULL) { 03176 03177 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03178 } 03179 } 03180 03181 03182 VOID 03183 UdfCleanupIcbContext ( 03184 IN PIRP_CONTEXT IrpContext, 03185 IN PICB_SEARCH_CONTEXT IcbContext 03186 ) 03187 03188 /*++ 03189 03190 Routine Description: 03191 03192 This routine cleans an Icb search context for reuse/deletion. 03193 03194 Arguments: 03195 03196 IcbContext - context to clean 03197 03198 Return Value: 03199 03200 None. 03201 03202 --*/ 03203 03204 { 03205 PAGED_CODE(); 03206 03207 // 03208 // Check inputs 03209 // 03210 03211 ASSERT_IRP_CONTEXT( IrpContext ); 03212 03213 UdfUnpinView( IrpContext, &IcbContext->Active ); 03214 UdfUnpinView( IrpContext, &IcbContext->Current ); 03215 03216 RtlZeroMemory( IcbContext, sizeof( ICB_SEARCH_CONTEXT )); 03217 } 03218 03219 03220 VOID 03221 UdfInitializeEaContext ( 03222 IN PIRP_CONTEXT IrpContext, 03223 IN PEA_SEARCH_CONTEXT EaContext, 03224 IN PICB_SEARCH_CONTEXT IcbContext, 03225 IN ULONG EAType, 03226 IN UCHAR EASubType 03227 ) 03228 03229 /*++ 03230 03231 Routine Description: 03232 03233 This routine initializes a walk through the EA space of an Icb which has been 03234 previously discovered. 03235 03236 Note: only the embedded EA space is supported now. 03237 03238 Arguments: 03239 03240 EaContext - EA context to fill in 03241 03242 IcbContext - Elaborated ICB search structure 03243 03244 Return Value: 03245 03246 --*/ 03247 03248 { 03249 PICBFILE Icb; 03250 03251 PAGED_CODE(); 03252 03253 // 03254 // Check inputs 03255 // 03256 03257 ASSERT_IRP_CONTEXT( IrpContext ); 03258 03259 ASSERT( IcbContext->Active.Bcb && IcbContext->Active.View ); 03260 03261 Icb = IcbContext->Active.View; 03262 03263 EaContext->IcbContext = IcbContext; 03264 03265 // 03266 // Initialize to point at the first EA to return. 03267 // 03268 03269 EaContext->Ea = Icb->EAs; 03270 EaContext->Remaining = Icb->EALength; 03271 03272 EaContext->EAType = EAType; 03273 EaContext->EASubType = EASubType; 03274 } 03275 03276 03277 BOOLEAN 03278 UdfLookupEa ( 03279 IN PIRP_CONTEXT IrpContext, 03280 IN PEA_SEARCH_CONTEXT EaContext 03281 ) 03282 03283 /*++ 03284 03285 Routine Description: 03286 03287 This routine finds an EA in the EA space of an ICB. 03288 03289 Arguments: 03290 03291 EaContext - an initialized EA search context containing an elaborated 03292 ICB search context and a description of the EA to find. 03293 03294 Return Value: 03295 03296 BOOLEAN True if such an EA was found and returned, False otherwise. 03297 03298 --*/ 03299 { 03300 PICBFILE Icb; 03301 PNSR_EA_GENERIC GenericEa; 03302 03303 PAGED_CODE(); 03304 03305 // 03306 // Check inputs 03307 // 03308 03309 ASSERT_IRP_CONTEXT( IrpContext ); 03310 03311 // 03312 // Quickly terminate if the EA space is empty or not capable of containing 03313 // the header descriptor. A null EA space is perfectly legal. 03314 // 03315 03316 if (EaContext->Remaining == 0) { 03317 03318 return FALSE; 03319 03320 } else if (EaContext->Remaining < sizeof( NSR_EAH )) { 03321 03322 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03323 } 03324 03325 // 03326 // Verify the integrity of the EA header. This has a side effect of making 03327 // very sure that we really have an EA sequence underneath us. 03328 // 03329 03330 Icb = EaContext->IcbContext->Active.View; 03331 03332 UdfVerifyDescriptor( IrpContext, 03333 &((PNSR_EAH) EaContext->Ea)->Destag, 03334 DESTAG_ID_NSR_EA, 03335 sizeof( NSR_EAH ), 03336 Icb->Destag.Lbn, 03337 FALSE ); 03338 03339 // 03340 // Push forward the start of the EA space and loop while we have more EAs to inspect. 03341 // Since we only scan for ISO EA's right now, we don't need to open the EA header to 03342 // jump forward to the Implementation Use or Application Use segments. 03343 // 03344 03345 EaContext->Ea = Add2Ptr( EaContext->Ea, sizeof( NSR_EAH ), PVOID ); 03346 EaContext->Remaining -= sizeof( NSR_EAH ); 03347 03348 while (EaContext->Remaining) { 03349 03350 GenericEa = EaContext->Ea; 03351 03352 // 03353 // The EAs must appear on 4byte aligned boundaries, there must be room to find 03354 // the generic EA preamble and the claimed length of the EA must fit in the 03355 // remaining space. 03356 // 03357 03358 if (LongOffsetPtr( EaContext->Ea ) || 03359 EaContext->Remaining < FIELD_OFFSET( NSR_EA_GENERIC, EAData ) || 03360 EaContext->Remaining < GenericEa->EALength ) { 03361 03362 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03363 } 03364 03365 if (GenericEa->EAType == EaContext->EAType && GenericEa->EASubType == EaContext->EASubType) { 03366 03367 return TRUE; 03368 } 03369 03370 EaContext->Ea = Add2Ptr( EaContext->Ea, GenericEa->EALength, PVOID ); 03371 EaContext->Remaining -= GenericEa->EALength; 03372 } 03373 03374 // 03375 // If we failed to find the EA, we should have stopped at the precise end of the EA space. 03376 // 03377 03378 if (EaContext->Remaining) { 03379 03380 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03381 } 03382 03383 return FALSE; 03384 } 03385 03386 03387 VOID 03388 UdfInitializeAllocations ( 03389 IN PIRP_CONTEXT IrpContext, 03390 IN PFCB Fcb, 03391 IN PICB_SEARCH_CONTEXT IcbContext 03392 ) 03393 03394 /*++ 03395 03396 Routine Description: 03397 03398 This routine fills in the data retrieval information for an Fcb. 03399 03400 Arguments: 03401 03402 Fcb - Fcb to add retrieval information to. 03403 03404 IcbContext - Elaborated ICB search context corresponding to this Fcb. 03405 03406 Return Value: 03407 03408 None. 03409 03410 --*/ 03411 03412 { 03413 PICBFILE Icb = IcbContext->Active.View; 03414 PAD_GENERIC GenericAd; 03415 03416 ALLOC_ENUM_CONTEXT AllocContext; 03417 03418 LONGLONG RunningOffset; 03419 ULONG Psn; 03420 USHORT Partition; 03421 03422 PVCB Vcb = Fcb->Vcb; 03423 03424 BOOLEAN Result; 03425 BOOLEAN InFileTail = FALSE; 03426 03427 PAGED_CODE(); 03428 03429 // 03430 // Check inputs 03431 // 03432 03433 ASSERT_IRP_CONTEXT( IrpContext ); 03434 ASSERT_FCB( Fcb ); 03435 03436 // 03437 // Immediately return for objects with zero information space. Note that 03438 // passing this test does not indicate that the file has any recorded space. 03439 // 03440 03441 if (Fcb->FileSize.QuadPart == 0) { 03442 03443 return; 03444 } 03445 03446 UdfInitializeAllocationContext( IrpContext, 03447 &AllocContext, 03448 IcbContext ); 03449 03450 // 03451 // Handle the case of embedded data. 03452 // 03453 03454 if (AllocContext.AllocType == ICBTAG_F_ALLOC_IMMEDIATE) { 03455 03456 // 03457 // Teardown any existing mcb. 03458 // 03459 03460 UdfUninitializeFcbMcb( Fcb ); 03461 03462 // 03463 // Establish a single block mapping to the Icb itself and mark the Fcb as 03464 // having embedded data. Mapping will occur through the Metadata stream. 03465 // Note that by virtue of having an Icb here we know it has already had 03466 // a mapping established in the Metadata stream, so just retrieve that. 03467 // 03468 03469 SetFlag( Fcb->FcbState, FCB_STATE_EMBEDDED_DATA ); 03470 03471 Fcb->EmbeddedVsn = UdfLookupMetaVsnOfExtent( IrpContext, 03472 Vcb, 03473 IcbContext->Active.Partition, 03474 Icb->Destag.Lbn, 03475 BlockSize( Vcb ), 03476 FALSE ); 03477 03478 // 03479 // Note the offset of the data in the Icb. 03480 // 03481 03482 Fcb->EmbeddedOffset = FIELD_OFFSET( ICBFILE, EAs ) + Icb->EALength; 03483 03484 // 03485 // Check that the information length agrees. 03486 // 03487 03488 if (Icb->AllocLength != Fcb->FileSize.LowPart) { 03489 03490 DebugTrace(( 0, Dbg, "UdfInitializeAllocations, embedded alloc %08x != filesize %08x\n", 03491 Icb->AllocLength, 03492 Fcb->FileSize.LowPart )); 03493 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03494 } 03495 03496 return; 03497 } 03498 03499 // 03500 // Now initialize the mapping structure for this Fcb. 03501 // 03502 03503 UdfInitializeFcbMcb( Fcb ); 03504 03505 // 03506 // Now walk the chain of allocation descriptors for the object, adding them into the 03507 // mapping. 03508 // 03509 03510 RunningOffset = 0; 03511 03512 do { 03513 03514 // 03515 // Do file tail consistency checking (4/12.1). We will have a file body 03516 // which is exactly the size of the information length, and a run of allocated 03517 // but unrecorded space following. 03518 // 03519 03520 if (Fcb->FileSize.QuadPart == RunningOffset) { 03521 03522 InFileTail = TRUE; 03523 } 03524 03525 // 03526 // It is impermissible for an interior body extent of an object to not be 03527 // an integral multiple of a logical block in size (note that the last 03528 // will tend to be). Also check that the body didn't overshoot the information 03529 // length and that the tail descriptor type is correct. 03530 // 03531 03532 GenericAd = AllocContext.Alloc; 03533 03534 if ((!InFileTail && (BlockOffset( Vcb, RunningOffset ) || 03535 Fcb->FileSize.QuadPart < RunningOffset)) || 03536 (InFileTail && GenericAd->Length.Type != NSRLENGTH_TYPE_UNRECORDED)) { 03537 03538 DebugTrace(( 0, Dbg, "UdfInitializeAllocations, InFileTail == %u, bad alloc\n", 03539 InFileTail )); 03540 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03541 } 03542 03543 // 03544 // In the file tail we'll just slum along an be a nitpick. Technically, as a 03545 // readonly implementation I don't have to care at all about what is here. 03546 // 03547 03548 if (InFileTail) { 03549 03550 continue; 03551 } 03552 03553 // 03554 // Based on the descriptor type, pull it apart and add the mapping. 03555 // 03556 03557 if (GenericAd->Length.Type == NSRLENGTH_TYPE_RECORDED) { 03558 03559 // 03560 // Grab the Psn this extent starts at and add the allocation. 03561 // 03562 03563 Psn = UdfLookupPsnOfExtent( IrpContext, 03564 Vcb, 03565 UdfGetPartitionOfCurrentAllocation( &AllocContext ), 03566 GenericAd->Start, 03567 GenericAd->Length.Length ); 03568 03569 Result = FsRtlAddLargeMcbEntry( &Fcb->Mcb, 03570 LlSectorsFromBytes( Vcb, RunningOffset ), 03571 Psn, 03572 SectorsFromBytes( Vcb, SectorAlign( Vcb, GenericAd->Length.Length ) )); 03573 03574 ASSERT( Result ); 03575 } 03576 03577 RunningOffset += GenericAd->Length.Length; 03578 03579 } while ( UdfGetNextAllocation( IrpContext, &AllocContext )); 03580 03581 // 03582 // We must have had body allocation descriptors for the entire file 03583 // information length. 03584 // 03585 03586 if (Fcb->FileSize.QuadPart != RunningOffset) { 03587 03588 DebugTrace(( 0, Dbg, "UdfInitializeAllocations, total descriptors != filesize\n" )); 03589 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03590 } 03591 } 03592 03593 03594 VOID 03595 UdfUpdateTimestampsFromIcbContext ( 03596 IN PIRP_CONTEXT IrpContext, 03597 IN PICB_SEARCH_CONTEXT IcbContext, 03598 IN PTIMESTAMP_BUNDLE Timestamps 03599 ) 03600 03601 /*++ 03602 03603 Routine Description: 03604 03605 This routine converts the set of timestamps associated with a given ICB into 03606 an NT native form. 03607 03608 Arguments: 03609 03610 IcbOontext - An search context containing the active direct ICB for the object 03611 03612 Timestamps - the bundle of timestamps to receive the converted times. 03613 03614 Return Value: 03615 03616 None. 03617 03618 --*/ 03619 03620 { 03621 EA_SEARCH_CONTEXT EaContext; 03622 PICBFILE Icb; 03623 03624 PAGED_CODE(); 03625 03626 // 03627 // Check inputs 03628 // 03629 03630 ASSERT_IRP_CONTEXT( IrpContext ); 03631 03632 // 03633 // Directly reference for convenience. 03634 // 03635 03636 Icb = IcbContext->Active.View; 03637 03638 ASSERT( Icb->Destag.Ident == DESTAG_ID_NSR_FILE ); 03639 03640 // 03641 // Initialize the timestamps for this object. Due to basic idiocy in ISO 13346, 03642 // we must gather EAs and figure out which of several timestamps is most valid. 03643 // 03644 03645 // 03646 // Begin by using the fields in the ICB itself. 03647 // 03648 03649 UdfConvertUdfTimeToNtTime( IrpContext, 03650 &Icb->ModifyTime, 03651 (PLARGE_INTEGER) &Timestamps->ModificationTime ); 03652 03653 Timestamps->CreationTime = Timestamps->ModificationTime; 03654 03655 UdfConvertUdfTimeToNtTime( IrpContext, 03656 &Icb->AccessTime, 03657 (PLARGE_INTEGER) &Timestamps->AccessTime ); 03658 03659 // 03660 // Gather the File Times and Information Times EAs for this object, if they exist, 03661 // and set the timestamps. Just override timestamps if they exist. 03662 // 03663 03664 UdfInitializeEaContext( IrpContext, 03665 &EaContext, 03666 IcbContext, 03667 EA_TYPE_FILETIMES, 03668 EA_SUBTYPE_BASE ); 03669 03670 if (UdfLookupEa( IrpContext, &EaContext )) { 03671 03672 PNSR_EA_FILETIMES FileTimes = EaContext.Ea; 03673 03674 if (FlagOn(FileTimes->Existence, EA_FILETIMES_E_CREATION)) { 03675 03676 UdfConvertUdfTimeToNtTime( IrpContext, 03677 &FileTimes->Stamps[0], 03678 (PLARGE_INTEGER) &Timestamps->CreationTime ); 03679 } 03680 } 03681 03682 UdfInitializeEaContext( IrpContext, 03683 &EaContext, 03684 IcbContext, 03685 EA_TYPE_INFOTIMES, 03686 EA_SUBTYPE_BASE ); 03687 03688 if (UdfLookupEa( IrpContext, &EaContext )) { 03689 03690 PNSR_EA_FILETIMES InfoTimes = EaContext.Ea; 03691 BOOLEAN CreationPresent = FALSE; 03692 03693 if (FlagOn(InfoTimes->Existence, EA_INFOTIMES_E_CREATION)) { 03694 03695 UdfConvertUdfTimeToNtTime( IrpContext, 03696 &InfoTimes->Stamps[0], 03697 (PLARGE_INTEGER) &Timestamps->CreationTime ); 03698 03699 CreationPresent = TRUE; 03700 } 03701 03702 if (FlagOn(InfoTimes->Existence, EA_INFOTIMES_E_MODIFICATION)) { 03703 03704 UdfConvertUdfTimeToNtTime( IrpContext, 03705 &InfoTimes->Stamps[CreationPresent? 1: 0], 03706 (PLARGE_INTEGER) &Timestamps->CreationTime ); 03707 } 03708 } 03709 } 03710 03711 03712 BOOLEAN 03713 UdfCreateFileLock ( 03714 IN PIRP_CONTEXT IrpContext OPTIONAL, 03715 IN PFCB Fcb, 03716 IN BOOLEAN RaiseOnError 03717 ) 03718 03719 /*++ 03720 03721 Routine Description: 03722 03723 This routine is called when we want to attach a file lock structure to the 03724 given Fcb. It is possible the file lock is already attached. 03725 03726 This routine is sometimes called from the fast path and sometimes in the 03727 Irp-based path. We don't want to raise in the fast path, just return FALSE. 03728 03729 Arguments: 03730 03731 Fcb - This is the Fcb to create the file lock for. 03732 03733 RaiseOnError - If TRUE, we will raise on an allocation failure. Otherwise we 03734 return FALSE on an allocation failure. 03735 03736 Return Value: 03737 03738 BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise. 03739 03740 --*/ 03741 03742 { 03743 BOOLEAN Result = TRUE; 03744 PFILE_LOCK FileLock; 03745 03746 PAGED_CODE(); 03747 03748 // 03749 // Lock the Fcb and check if there is really any work to do. 03750 // 03751 03752 UdfLockFcb( IrpContext, Fcb ); 03753 03754 if (Fcb->FileLock != NULL) { 03755 03756 UdfUnlockFcb( IrpContext, Fcb ); 03757 return TRUE; 03758 } 03759 03760 Fcb->FileLock = FileLock = 03761 FsRtlAllocateFileLock( NULL, NULL ); 03762 03763 UdfUnlockFcb( IrpContext, Fcb ); 03764 03765 // 03766 // Return or raise as appropriate. 03767 // 03768 03769 if (FileLock == NULL) { 03770 03771 if (RaiseOnError) { 03772 03773 ASSERT( ARGUMENT_PRESENT( IrpContext )); 03774 03775 UdfRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); 03776 } 03777 03778 Result = FALSE; 03779 } 03780 03781 return Result; 03782 } 03783 03784 03785 // 03786 // Local support routine 03787 // 03788 03789 VOID 03790 UdfLookupActiveIcbInExtent ( 03791 IN PIRP_CONTEXT IrpContext, 03792 IN PICB_SEARCH_CONTEXT IcbContext, 03793 IN ULONG Recurse 03794 ) 03795 03796 /*++ 03797 03798 Routine Description: 03799 03800 This routine is called to traverse a single Icb hierarchy extent to discover 03801 an active Icb. This is a recursive operation on indirect Icbs that may be 03802 found in the sequence. 03803 03804 Arguments: 03805 03806 IcbContext - Context which has been initialized to point into an Icb hierarchy. 03807 03808 Recurse - Recursion limit. 03809 03810 Return Value: 03811 03812 None. 03813 03814 Raised status if the Icb hierarchy is invalid. 03815 03816 --*/ 03817 03818 { 03819 PVCB Vcb = IcbContext->Vcb; 03820 PFCB Fcb = Vcb->MetadataFcb; 03821 03822 ULONG Length; 03823 ULONG Lbn; 03824 USHORT Partition; 03825 03826 ULONG Vsn; 03827 03828 PICBIND Icb; 03829 03830 PAGED_CODE(); 03831 03832 // 03833 // Decrement our recursion allowance. 03834 // 03835 03836 Recurse--; 03837 03838 // 03839 // Grab our starting point 03840 // 03841 03842 Partition = IcbContext->Current.Partition; 03843 Lbn = IcbContext->Current.Lbn; 03844 Length = IcbContext->Current.Length; 03845 03846 Icb = IcbContext->Current.View; 03847 03848 // 03849 // Walk across the extent 03850 // 03851 03852 do { 03853 03854 switch (Icb->Destag.Ident) { 03855 03856 case DESTAG_ID_NSR_ICBIND: 03857 03858 UdfVerifyDescriptor( IrpContext, 03859 &Icb->Destag, 03860 DESTAG_ID_NSR_ICBIND, 03861 sizeof( ICBIND ), 03862 Lbn, 03863 FALSE ); 03864 03865 // 03866 // Go to the next extent if this indirect Icb actually points to something. 03867 // 03868 03869 if (Icb->Icb.Length.Type == NSRLENGTH_TYPE_RECORDED) { 03870 03871 // 03872 // If we are in the last entry of the Icb extent, we may tail recurse. This 03873 // is very important for strategy 4096, which is a linked list of extents 03874 // of depth equal to the number of times the direct Icb had to be re-recorded. 03875 // 03876 03877 UdfMapMetadataView( IrpContext, 03878 &IcbContext->Current, 03879 Vcb, 03880 Icb->Icb.Start.Partition, 03881 Icb->Icb.Start.Lbn, 03882 Icb->Icb.Length.Length ); 03883 03884 if (Length != BlockSize( Vcb )) { 03885 03886 // 03887 // We have to give up on this if we're going too deep. 03888 // 03889 03890 if (Recurse == 0) { 03891 03892 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03893 } 03894 03895 UdfLookupActiveIcbInExtent( IrpContext, 03896 IcbContext, 03897 Recurse ); 03898 03899 // 03900 // Need to remap the extent we were working on. 03901 // 03902 03903 UdfMapMetadataView( IrpContext, 03904 &IcbContext->Current, 03905 Vcb, 03906 Partition, 03907 Lbn, 03908 Length ); 03909 } else { 03910 03911 // 03912 // Tail recursion was possible so adjust our pointers and restart the scan. 03913 // 03914 03915 Partition = IcbContext->Current.Partition; 03916 Lbn = IcbContext->Current.Lbn; 03917 Length = IcbContext->Current.Length; 03918 03919 Icb = IcbContext->Current.View; 03920 03921 continue; 03922 } 03923 03924 } 03925 03926 break; 03927 03928 case DESTAG_ID_NSR_ICBTRM: 03929 03930 UdfVerifyDescriptor( IrpContext, 03931 &Icb->Destag, 03932 DESTAG_ID_NSR_ICBTRM, 03933 sizeof( ICBTRM ), 03934 Lbn, 03935 FALSE ); 03936 03937 // 03938 // Terminate the current extent. 03939 // 03940 03941 return; 03942 break; 03943 03944 case DESTAG_ID_NOTSPEC: 03945 03946 // 03947 // Perhaps this is an unrecorded sector. Treat this as terminating 03948 // the current extent. 03949 // 03950 03951 return; 03952 break; 03953 03954 default: 03955 03956 // 03957 // This is a data-full Icb. It must be of the expected type. 03958 // 03959 03960 if (Icb->Destag.Ident != IcbContext->IcbType) { 03961 03962 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 03963 } 03964 03965 // 03966 // Since direct entries are of variable size, we must allow up to 03967 // a block's worth of data. 03968 // 03969 03970 UdfVerifyDescriptor( IrpContext, 03971 &Icb->Destag, 03972 Icb->Destag.Ident, 03973 BlockSize( Vcb ), 03974 Lbn, 03975 FALSE ); 03976 // 03977 // We perform an in-order traversal of the hierarchy. This is important since 03978 // it means no tricks are neccesary to figure out the rightmost direct Icb - 03979 // always stash the last one we see. 03980 // 03981 // Map this logical block into the active slot. We know that a direct entry 03982 // must fit in a single logical block. 03983 // 03984 03985 UdfMapMetadataView( IrpContext, 03986 &IcbContext->Active, 03987 Vcb, 03988 Partition, 03989 Lbn, 03990 BlockSize( Vcb ) ); 03991 03992 break; 03993 } 03994 03995 // 03996 // Advance our pointer set. 03997 // 03998 03999 Lbn++; 04000 Length -= BlockSize( Vcb ); 04001 04002 Icb = Add2Ptr( Icb, BlockSize( Vcb ), PVOID ); 04003 04004 } while (Length); 04005 } 04006 04007 04008 // 04009 // Local support routine 04010 // 04011 04012 VOID 04013 UdfInitializeAllocationContext ( 04014 IN PIRP_CONTEXT IrpContext, 04015 IN PALLOC_ENUM_CONTEXT AllocContext, 04016 IN PICB_SEARCH_CONTEXT IcbContext 04017 ) 04018 04019 /*++ 04020 04021 Routine Description: 04022 04023 Initializes a walk of the allocation descriptors for an ICB which has already 04024 been found. The first allocation descriptor will be avaliable after the call. 04025 04026 Arguments: 04027 04028 AllocContext - Allocation enumeration context to use 04029 04030 IcbContext - Elaborated ICB search context for the ICB to enumerate 04031 04032 Return Value: 04033 04034 None. 04035 04036 --*/ 04037 04038 { 04039 PICBFILE Icb; 04040 04041 PAGED_CODE(); 04042 04043 // 04044 // Check inputs 04045 // 04046 04047 ASSERT_IRP_CONTEXT( IrpContext ); 04048 04049 ASSERT( IcbContext->Active.View ); 04050 04051 AllocContext->IcbContext = IcbContext; 04052 04053 // 04054 // Figure out what kind of descriptors will be here. 04055 // 04056 04057 Icb = IcbContext->Active.View; 04058 AllocContext->AllocType = FlagOn( Icb->Icbtag.Flags, ICBTAG_F_ALLOC_MASK ); 04059 04060 // 04061 // We are done if this is actually immediate data. 04062 // 04063 04064 if (AllocContext->AllocType == ICBTAG_F_ALLOC_IMMEDIATE) { 04065 04066 return; 04067 } 04068 04069 // 04070 // The initial chunk of allocation descriptors is inline with the ICB and 04071 // does not contain an Allocation Extent Descriptor. 04072 // 04073 04074 AllocContext->Alloc = Add2Ptr( Icb->EAs, Icb->EALength, PVOID ); 04075 AllocContext->Remaining = Icb->AllocLength; 04076 04077 ASSERT( LongOffsetPtr( AllocContext->Alloc ) == 0 ); 04078 04079 // 04080 // Check that an integral number of the appropriate allocation descriptors fit in 04081 // this extent and that the extent is not composed of extended allocation 04082 // descriptors, which are illegal on UDF. 04083 // 04084 // If the common post-processing fails, we probably did not find any allocation 04085 // descriptors (case of nothing but continuation). This is likewise bad. 04086 // 04087 04088 if (AllocContext->Remaining == 0 || 04089 AllocContext->Remaining % ISOAllocationDescriptorSize( AllocContext->AllocType ) || 04090 AllocContext->AllocType == ICBTAG_F_ALLOC_EXTENDED || 04091 !UdfGetNextAllocationPostProcessing( IrpContext, AllocContext )) { 04092 04093 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 04094 } 04095 } 04096 04097 04098 // 04099 // Local support routine 04100 // 04101 04102 BOOLEAN 04103 UdfGetNextAllocation ( 04104 IN PIRP_CONTEXT IrpContext, 04105 IN PALLOC_ENUM_CONTEXT AllocContext 04106 ) 04107 04108 /*++ 04109 04110 Routine Description: 04111 04112 This routine retrieves the next logical allocation descriptor given an enumeration 04113 context. 04114 04115 Arguments: 04116 04117 AllocContext - Context to advance to the next descriptor 04118 04119 Return Value: 04120 04121 BOOLEAN - TRUE if one is found, FALSE if the enumeration is complete. 04122 04123 This routine will raise if malformation is discovered. 04124 04125 --*/ 04126 04127 { 04128 PAGED_CODE(); 04129 04130 // 04131 // Check inputs 04132 // 04133 04134 ASSERT_IRP_CONTEXT( IrpContext ); 04135 04136 AllocContext->Remaining -= ISOAllocationDescriptorSize( AllocContext->AllocType ); 04137 AllocContext->Alloc = Add2Ptr( AllocContext->Alloc, ISOAllocationDescriptorSize( AllocContext->AllocType ), PVOID ); 04138 04139 return UdfGetNextAllocationPostProcessing( IrpContext, AllocContext ); 04140 } 04141 04142 04143 BOOLEAN 04144 UdfGetNextAllocationPostProcessing ( 04145 IN PIRP_CONTEXT IrpContext, 04146 IN PALLOC_ENUM_CONTEXT AllocContext 04147 ) 04148 04149 /*++ 04150 04151 Routine Description: 04152 04153 This routine retrieves the next logical allocation descriptor given an enumeration 04154 context. 04155 04156 Arguments: 04157 04158 AllocContext - Context to advance to the next descriptor 04159 04160 Return Value: 04161 04162 BOOLEAN - TRUE if one is found, FALSE if the enumeration is complete. 04163 04164 This routine will raise if malformation is discovered. 04165 04166 --*/ 04167 04168 { 04169 PAD_GENERIC GenericAd; 04170 PNSR_ALLOC AllocDesc; 04171 04172 PVCB Vcb = AllocContext->IcbContext->Vcb; 04173 04174 // 04175 // There are three ways to reach the end of the current block of allocation 04176 // descriptors, per ISO 13346 4/12: 04177 // 04178 // reach the end of the field (kept track of in the Remaining bytes) 04179 // reach an allocation descriptor with an extent length of zero 04180 // reach a continuation extent descriptor 04181 // 04182 04183 // 04184 // We are done in the first two cases. 04185 // 04186 04187 if (AllocContext->Remaining == 0) { 04188 04189 return FALSE; 04190 } 04191 04192 while (TRUE) { 04193 04194 GenericAd = AllocContext->Alloc; 04195 04196 if (GenericAd->Length.Length == 0) { 04197 04198 return FALSE; 04199 } 04200 04201 // 04202 // Check if this descriptor is a pointer to another extent of descriptors. 04203 // 04204 04205 if (GenericAd->Length.Type != NSRLENGTH_TYPE_CONTINUATION) { 04206 04207 break; 04208 } 04209 04210 // 04211 // UDF allocation extents are restricted to a single logical block. 04212 // 04213 04214 if (GenericAd->Length.Length > BlockSize( Vcb )) { 04215 04216 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 04217 } 04218 04219 UdfMapMetadataView( IrpContext, 04220 &AllocContext->IcbContext->Current, 04221 Vcb, 04222 UdfGetPartitionOfCurrentAllocation( AllocContext ), 04223 GenericAd->Start, 04224 BlockSize( Vcb ) ); 04225 04226 // 04227 // Now check that the allocation descriptor is valid. 04228 // 04229 04230 AllocDesc = (PNSR_ALLOC) AllocContext->IcbContext->Current.View; 04231 04232 UdfVerifyDescriptor( IrpContext, 04233 &AllocDesc->Destag, 04234 DESTAG_ID_NSR_ALLOC, 04235 BlockSize( Vcb ), 04236 AllocContext->IcbContext->Current.Lbn, 04237 FALSE ); 04238 04239 // 04240 // Note that a full logical block is mapped, but only the claimed number of 04241 // bytes are valid. 04242 // 04243 04244 AllocContext->Remaining = AllocDesc->AllocLen; 04245 AllocContext->Alloc = Add2Ptr( AllocContext->IcbContext->Current.View, sizeof( NSR_ALLOC ), PVOID ); 04246 04247 // 04248 // Check that the size is sane and that an integral number of the appropriate 04249 // allocation descriptors fit in this extent. 04250 // 04251 04252 if (AllocContext->Remaining == 0 || 04253 AllocContext->Remaining > BlockSize( Vcb ) - sizeof( NSR_ALLOC ) || 04254 AllocContext->Remaining % ISOAllocationDescriptorSize( AllocContext->AllocType )) { 04255 04256 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 04257 } 04258 } 04259 04260 return TRUE; 04261 } 04262 04263 04264 // 04265 // Local support routine 04266 // 04267 04268 PFCB_NONPAGED 04269 UdfCreateFcbNonPaged ( 04270 IN PIRP_CONTEXT IrpContext 04271 ) 04272 04273 /*++ 04274 04275 Routine Description: 04276 04277 This routine is called to create and initialize the non-paged portion 04278 of an Fcb. 04279 04280 Arguments: 04281 04282 Return Value: 04283 04284 PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created. 04285 04286 --*/ 04287 04288 { 04289 PFCB_NONPAGED FcbNonpaged; 04290 04291 PAGED_CODE(); 04292 04293 // 04294 // Allocate the non-paged pool and initialize the various 04295 // synchronization objects. 04296 // 04297 04298 FcbNonpaged = UdfAllocateFcbNonpaged( IrpContext ); 04299 04300 RtlZeroMemory( FcbNonpaged, sizeof( FCB_NONPAGED )); 04301 04302 FcbNonpaged->NodeTypeCode = UDFS_NTC_FCB_NONPAGED; 04303 FcbNonpaged->NodeByteSize = sizeof( FCB_NONPAGED ); 04304 04305 ExInitializeResource( &FcbNonpaged->FcbResource ); 04306 ExInitializeFastMutex( &FcbNonpaged->FcbMutex ); 04307 04308 return FcbNonpaged; 04309 } 04310 04311 04312 // 04313 // Local support routine 04314 // 04315 04316 VOID 04317 UdfDeleteFcbNonpaged ( 04318 IN PIRP_CONTEXT IrpContext, 04319 IN PFCB_NONPAGED FcbNonpaged 04320 ) 04321 04322 /*++ 04323 04324 Routine Description: 04325 04326 This routine is called to cleanup the non-paged portion of an Fcb. 04327 04328 Arguments: 04329 04330 FcbNonpaged - Structure to clean up. 04331 04332 Return Value: 04333 04334 None 04335 04336 --*/ 04337 04338 { 04339 PAGED_CODE(); 04340 04341 ExDeleteResource( &FcbNonpaged->FcbResource ); 04342 04343 UdfDeallocateFcbNonpaged( IrpContext, FcbNonpaged ); 04344 04345 return; 04346 } 04347 04348 04349 // 04350 // Local support routine 04351 // 04352 04353 RTL_GENERIC_COMPARE_RESULTS 04354 UdfFcbTableCompare ( 04355 IN PRTL_GENERIC_TABLE Table, 04356 IN PVOID id1, 04357 IN PVOID id2 04358 ) 04359 04360 /*++ 04361 04362 Routine Description: 04363 04364 This routine is the Udfs compare routine called by the generic table package. 04365 If will compare the two File Id values and return a comparison result. 04366 04367 Arguments: 04368 04369 Table - This is the table being searched. 04370 04371 id1 - First key value. 04372 04373 id2 - Second key value. 04374 04375 Return Value: 04376 04377 RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two 04378 input structures 04379 04380 --*/ 04381 04382 { 04383 FILE_ID Id1, Id2; 04384 PAGED_CODE(); 04385 04386 Id1 = *((FILE_ID UNALIGNED *) id1); 04387 Id2 = *((FILE_ID UNALIGNED *) id2); 04388 04389 if (Id1.QuadPart < Id2.QuadPart) { 04390 04391 return GenericLessThan; 04392 04393 } else if (Id1.QuadPart > Id2.QuadPart) { 04394 04395 return GenericGreaterThan; 04396 04397 } else { 04398 04399 return GenericEqual; 04400 } 04401 04402 UNREFERENCED_PARAMETER( Table ); 04403 } 04404 04405 04406 // 04407 // Local support routine 04408 // 04409 04410 PVOID 04411 UdfAllocateTable ( 04412 IN PRTL_GENERIC_TABLE Table, 04413 IN CLONG ByteSize 04414 ) 04415 04416 /*++ 04417 04418 Routine Description: 04419 04420 This is a generic table support routine to allocate memory 04421 04422 Arguments: 04423 04424 Table - Supplies the generic table being used 04425 04426 ByteSize - Supplies the number of bytes to allocate 04427 04428 Return Value: 04429 04430 PVOID - Returns a pointer to the allocated data 04431 04432 --*/ 04433 04434 { 04435 PAGED_CODE(); 04436 04437 return( FsRtlAllocatePoolWithTag( UdfPagedPool, ByteSize, TAG_GENERIC_TABLE )); 04438 } 04439 04440 04441 // 04442 // Local support routine 04443 // 04444 04445 VOID 04446 UdfDeallocateTable ( 04447 IN PRTL_GENERIC_TABLE Table, 04448 IN PVOID Buffer 04449 ) 04450 04451 /*++ 04452 04453 Routine Description: 04454 04455 This is a generic table support routine that deallocates memory 04456 04457 Arguments: 04458 04459 Table - Supplies the generic table being used 04460 04461 Buffer - Supplies the buffer being deallocated 04462 04463 Return Value: 04464 04465 None. 04466 04467 --*/ 04468 04469 { 04470 PAGED_CODE(); 04471 04472 ExFreePool( Buffer ); 04473 04474 return; 04475 UNREFERENCED_PARAMETER( Table ); 04476 } 04477

Generated on Sat May 15 19:41:54 2004 for test by doxygen 1.3.7