test: strucsup.c Source File

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