test: dirsup.c Source File

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

# dirsup.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1996  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     DirSup.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the support for walking across on-disk directory
    00012     structures.
    00013
    00014 Author:
    00015
    00016     Dan Lovinger    [DanLo]   11-Jun-1996
    00017
    00018 Revision History:
    00019
    00020 --*/
    00021
    00022 #include "UdfProcs.h"
    00023
    00024 //
    00025 //  The Bug check file id for this module
    00026 //
    00027
    00028 #define BugCheckFileId                   (UDFS_BUG_CHECK_DIRSUP)
    00029
    00030 //
    00031 //  The local debug trace level
    00032 //
    00033
    00034 #define Dbg                              (UDFS_DEBUG_LEVEL_DIRSUP)
    00035
    00036 //
    00037 //  Local support routines.
    00038 //
    00039
    00040 BOOLEAN
    00041 UdfLookupDirEntryPostProcessing (
    00042     IN PIRP_CONTEXT IrpContext,
    00043     IN PFCB Fcb,
    00044     IN PDIR_ENUM_CONTEXT DirContext,
    00045     IN BOOLEAN ReturnError
    00046     );
    00047
    00048 #ifdef ALLOC_PRAGMA
    00049 #pragma alloc_text(PAGE, UdfCleanupDirContext)
    00050 #pragma alloc_text(PAGE, UdfFindDirEntry)
    00051 #pragma alloc_text(PAGE, UdfInitializeDirContext)
    00052 #pragma alloc_text(PAGE, UdfLookupDirEntryPostProcessing)
    00053 #pragma alloc_text(PAGE, UdfLookupInitialDirEntry)
    00054 #pragma alloc_text(PAGE, UdfLookupNextDirEntry)
    00055 #pragma alloc_text(PAGE, UdfUpdateDirNames)
    00056 #endif
    00057
    00058
    00059 VOID
    00060 UdfInitializeDirContext (
    00061     IN PIRP_CONTEXT IrpContext,
    00062     IN PDIR_ENUM_CONTEXT DirContext
    00063     )
    00064
    00065 /*++
    00066
    00067 Routine Description:
    00068
    00069     This routine initializes a directory enumeartion context.
    00070
    00071     Call this exactly once in the lifetime of a context.
    00072
    00073 Arguments:
    00074
    00075     DirContext - a context to initialize
    00076
    00077 Return Value:
    00078
    00079     None.
    00080
    00081 --*/
    00082
    00083 {
    00084     //
    00085     //  Check inputs.
    00086     //
    00087
    00088     ASSERT_IRP_CONTEXT( IrpContext );
    00089
    00090     //
    00091     //  Provide defaults for fields, nothing too special.
    00092     //
    00093
    00094     RtlZeroMemory( DirContext, sizeof(DIR_ENUM_CONTEXT) );
    00095 }
    00096
    00097
    00098 VOID
    00099 UdfCleanupDirContext (
    00100     IN PIRP_CONTEXT IrpContext,
    00101     IN PDIR_ENUM_CONTEXT DirContext
    00102     )
    00103
    00104 /*++
    00105
    00106 Routine Description:
    00107
    00108     This routine cleans up a directory enumeration context for reuse.
    00109
    00110 Arguments:
    00111
    00112     DirContext - a context to clean.
    00113
    00114 Return Value:
    00115
    00116     None.
    00117
    00118 --*/
    00119
    00120 {
    00121     PAGED_CODE();
    00122
    00123     //
    00124     //  Check input.
    00125     //
    00126
    00127     ASSERT_IRP_CONTEXT( IrpContext );
    00128
    00129     //
    00130     //  Dump the allocation we store the triple of names in.
    00131     //
    00132
    00133     UdfFreePool( &DirContext->NameBuffer );
    00134
    00135     //
    00136     //  And the short name.
    00137     //
    00138
    00139     UdfFreePool( &DirContext->ShortObjectName.Buffer );
    00140
    00141     //
    00142     //  Unpin the view.
    00143     //
    00144
    00145     UdfUnpinData( IrpContext, &DirContext->Bcb );
    00146
    00147     //
    00148     //  Free a buffered Fid that may remain.
    00149     //
    00150
    00151     if (FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_FID_BUFFERED )) {
    00152
    00153         UdfFreePool( &DirContext->Fid );
    00154     }
    00155
    00156     //
    00157     //  Zero everything else out.
    00158     //
    00159
    00160     RtlZeroMemory( DirContext, sizeof( DIR_ENUM_CONTEXT ) );
    00161 }
    00162
    00163
    00164 BOOLEAN
    00165 UdfLookupInitialDirEntry (
    00166     IN PIRP_CONTEXT IrpContext,
    00167     IN PFCB Fcb,
    00168     IN PDIR_ENUM_CONTEXT DirContext,
    00169     IN PLONGLONG InitialOffset OPTIONAL
    00170     )
    00171
    00172 /*++
    00173
    00174 Routine Description:
    00175
    00176     This routine begins the enumeration of a directory by setting the context
    00177     at the first avaliable directory entry.
    00178
    00179 Arguments:
    00180
    00181     Fcb - the directory being enumerated.
    00182
    00183     DirContext - a corresponding context for the enumeration.
    00184
    00185     InitialOffset - an optional starting byte offset to base the enumeration.
    00186
    00187 Return Value:
    00188
    00189     If InitialOffset is unspecified, TRUE will always be returned.  Failure will result
    00190     in a raised status indicating corruption.
    00191
    00192     If InitialOffset is specified, TRUE will be returned if a valid entry is found at this
    00193     offset, FALSE otherwise.
    00194
    00195 --*/
    00196
    00197 {
    00198     BOOLEAN Result;
    00199
    00200     PAGED_CODE();
    00201
    00202     //
    00203     //  Check inputs.
    00204     //
    00205
    00206     ASSERT_IRP_CONTEXT( IrpContext );
    00207     ASSERT_FCB_INDEX( Fcb );
    00208
    00209     //
    00210     //  Create the internal stream if it isn't already in place.
    00211     //
    00212
    00213     if (Fcb->FileObject == NULL) {
    00214
    00215         UdfCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
    00216     }
    00217
    00218     //
    00219     //  Reset the flags.
    00220     //
    00221
    00222     DirContext->Flags = 0;
    00223
    00224     if (InitialOffset) {
    00225
    00226         //
    00227         //  If we are beginning in the middle of the stream, adjust the sanity check flags.
    00228         //
    00229
    00230         if (*InitialOffset != 0) {
    00231
    00232             DirContext->Flags = DIR_CONTEXT_FLAG_SEEN_NONCONSTANT | DIR_CONTEXT_FLAG_SEEN_PARENT;
    00233         }
    00234
    00235         //
    00236         //  Now set up the range we will map.  This is constrained by the size of a cache view.
    00237         //
    00238
    00239         DirContext->BaseOffset.QuadPart = GenericTruncate( *InitialOffset, VACB_MAPPING_GRANULARITY );
    00240         DirContext->ViewOffset = (ULONG) GenericOffset( *InitialOffset, VACB_MAPPING_GRANULARITY );
    00241
    00242     } else {
    00243
    00244         //
    00245         //  Map at the beginning.
    00246         //
    00247
    00248         DirContext->BaseOffset.QuadPart = 0;
    00249         DirContext->ViewOffset = 0;
    00250     }
    00251
    00252     //
    00253     //  Contain the view length by the size of the stream and map.
    00254     //
    00255
    00256     DirContext->ViewLength = VACB_MAPPING_GRANULARITY;
    00257
    00258     if (DirContext->BaseOffset.QuadPart + DirContext->ViewLength > Fcb->FileSize.QuadPart) {
    00259
    00260         DirContext->ViewLength = (ULONG) (Fcb->FileSize.QuadPart - DirContext->BaseOffset.QuadPart);
    00261     }
    00262
    00263     UdfUnpinData( IrpContext, &DirContext->Bcb );
    00264
    00265     CcMapData( Fcb->FileObject,
    00266                &DirContext->BaseOffset,
    00267                DirContext->ViewLength,
    00268                TRUE,
    00269                &DirContext->Bcb,
    00270                &DirContext->View );
    00271
    00272     DirContext->Fid = Add2Ptr( DirContext->View, DirContext->ViewOffset, PNSR_FID );
    00273
    00274     //
    00275     //  The state of the context is now valid.  Tail off into our common post-processor
    00276     //  to finish the work.
    00277     //
    00278
    00279     return UdfLookupDirEntryPostProcessing( IrpContext,
    00280                                             Fcb,
    00281                                             DirContext,
    00282                                             (BOOLEAN) (InitialOffset != NULL));
    00283 }
    00284
    00285
    00286 BOOLEAN
    00287 UdfLookupNextDirEntry (
    00288     IN PIRP_CONTEXT IrpContext,
    00289     IN PFCB Fcb,
    00290     IN PDIR_ENUM_CONTEXT DirContext
    00291     )
    00292
    00293 /*++
    00294
    00295 Routine Description:
    00296
    00297     This routine advances the enumeration of a directory by one entry.
    00298
    00299 Arguments:
    00300
    00301     Fcb - the directory being enumerated.
    00302
    00303     DirContext - a corresponding context for the enumeration.
    00304
    00305 Return Value:
    00306
    00307     BOOLEAN True if another Fid is avaliable, False if we are at the end.
    00308
    00309 --*/
    00310
    00311 {
    00312     PAGED_CODE();
    00313
    00314     //
    00315     //  Check inputs.
    00316     //
    00317
    00318     ASSERT_IRP_CONTEXT( IrpContext );
    00319     ASSERT_FCB_INDEX( Fcb );
    00320
    00321     //
    00322     //  If we have reached the end, stop.
    00323     //
    00324
    00325     if (DirContext->BaseOffset.QuadPart + DirContext->NextFidOffset == Fcb->FileSize.QuadPart) {
    00326
    00327         return FALSE;
    00328     }
    00329
    00330     //
    00331     //  If the previous Fid was buffered, dismantle it now.
    00332     //
    00333
    00334     if (FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_FID_BUFFERED )) {
    00335
    00336         ClearFlag( DirContext->Flags, DIR_CONTEXT_FLAG_FID_BUFFERED );
    00337         UdfFreePool( &DirContext->Fid );
    00338     }
    00339
    00340     //
    00341     //  Move the pointers based on the knowledge generated in the previous iteration.
    00342     //
    00343
    00344     DirContext->ViewOffset = DirContext->NextFidOffset;
    00345     DirContext->Fid = Add2Ptr( DirContext->View, DirContext->ViewOffset, PNSR_FID );
    00346
    00347     //
    00348     //  The state of the context is now valid.  Tail off into our common post-processor
    00349     //  to finish the work.
    00350     //
    00351
    00352     return UdfLookupDirEntryPostProcessing( IrpContext,
    00353                                             Fcb,
    00354                                             DirContext,
    00355                                             FALSE );
    00356 }
    00357
    00358
    00359 VOID
    00360 UdfUpdateDirNames (
    00361     IN PIRP_CONTEXT IrpContext,
    00362     IN PDIR_ENUM_CONTEXT DirContext,
    00363     IN BOOLEAN IgnoreCase
    00364     )
    00365
    00366 /*++
    00367
    00368 Routine Description:
    00369
    00370     This routine fills in the non-short names of a directory enumeration context
    00371     for the Fid currently referenced.
    00372
    00373 Arguments:
    00374
    00375     DirContext - a corresponding context to fill in.
    00376
    00377     IgnoreCase - whether the caller wants to be insensitive to case.
    00378
    00379 Return Value:
    00380
    00381     None.
    00382
    00383 --*/
    00384
    00385 {
    00386     PUCHAR NameDstring;
    00387     BOOLEAN ContainsIllegal;
    00388
    00389     USHORT NameLength;
    00390     USHORT BufferLength;
    00391     USHORT PresentLength;
    00392
    00393     PAGED_CODE();
    00394
    00395     //
    00396     //  Check input.
    00397     //
    00398
    00399     ASSERT_IRP_CONTEXT( IrpContext );
    00400
    00401     DebugTrace(( +1, Dbg, "UdfUpdateDirNames\n" ));
    00402
    00403     //
    00404     //  Handle the case of the self directory entry.
    00405     //
    00406
    00407     if (DirContext->Fid == NULL) {
    00408
    00409         //
    00410         //  Simply synthesize
    00411         //
    00412
    00413         //
    00414         //  It doesn't hurt to be pedantic about initialization, so do it all.
    00415         //
    00416
    00417         DirContext->PureObjectName.Length =
    00418         DirContext->CaseObjectName.Length =
    00419         DirContext->ObjectName.Length = UdfUnicodeDirectoryNames[SELF_ENTRY].Length;
    00420
    00421         DirContext->PureObjectName.MaximumLength =
    00422         DirContext->CaseObjectName.MaximumLength =
    00423         DirContext->ObjectName.MaximumLength = UdfUnicodeDirectoryNames[SELF_ENTRY].MaximumLength;
    00424
    00425         DirContext->PureObjectName.Buffer =
    00426         DirContext->CaseObjectName.Buffer =
    00427         DirContext->ObjectName.Buffer = UdfUnicodeDirectoryNames[SELF_ENTRY].Buffer;
    00428
    00429         //
    00430         //  All done.
    00431         //
    00432
    00433         DebugTrace((  0, Dbg, "Self Entry case\n" ));
    00434         DebugTrace(( -1, Dbg, "UdfUpdateDirNames -> VOID\n" ));
    00435
    00436         return;
    00437     }
    00438
    00439     //
    00440     //  Handle the case of the parent directory entry.
    00441     //
    00442
    00443     if (FlagOn( DirContext->Fid->Flags, NSR_FID_F_PARENT )) {
    00444
    00445         //
    00446         //  Parent entries must occur at the front of the directory and
    00447         //  have a fid length of zero (13346 4/14.4.4).
    00448         //
    00449
    00450         if (FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT ) ||
    00451             DirContext->Fid->FileIDLen != 0) {
    00452
    00453             UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
    00454         }
    00455
    00456         //
    00457         //  Note that we have seen the parent entry.
    00458         //
    00459
    00460         SetFlag( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_PARENT );
    00461
    00462         //
    00463         //  It doesn't hurt to be pedantic about initialization, so do it all.
    00464         //
    00465
    00466         DirContext->PureObjectName.Length =
    00467         DirContext->CaseObjectName.Length =
    00468         DirContext->ObjectName.Length = UdfUnicodeDirectoryNames[PARENT_ENTRY].Length;
    00469
    00470         DirContext->PureObjectName.MaximumLength =
    00471         DirContext->CaseObjectName.MaximumLength =
    00472         DirContext->ObjectName.MaximumLength = UdfUnicodeDirectoryNames[PARENT_ENTRY].MaximumLength;
    00473
    00474         DirContext->PureObjectName.Buffer =
    00475         DirContext->CaseObjectName.Buffer =
    00476         DirContext->ObjectName.Buffer = UdfUnicodeDirectoryNames[PARENT_ENTRY].Buffer;
    00477
    00478         //
    00479         //  All done.
    00480         //
    00481
    00482         DebugTrace((  0, Dbg, "Parent Entry case\n" ));
    00483         DebugTrace(( -1, Dbg, "UdfUpdateDirNames -> VOID\n" ));
    00484
    00485         return;
    00486     }
    00487
    00488     //
    00489     //  We now know that we will need to convert the name in a real FID, so figure out where
    00490     //  it sits in the descriptor.
    00491     //
    00492
    00493     NameDstring = Add2Ptr( DirContext->Fid, ISONsrFidConstantSize + DirContext->Fid->ImpUseLen, PUCHAR );
    00494
    00495     //
    00496     //  Every directory must record a parent entry.
    00497     //
    00498
    00499     if (!FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_PARENT)) {
    00500
    00501         UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
    00502     }
    00503
    00504     //
    00505     //  Note that we are proceeding into the non-constant portion of a directory.
    00506     //
    00507
    00508     SetFlag( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT );
    00509
    00510     //
    00511     //  Make sure the dstring is good CS0
    00512     //
    00513
    00514     UdfCheckLegalCS0Dstring( IrpContext,
    00515                              NameDstring,
    00516                              DirContext->Fid->FileIDLen,
    00517                              0,
    00518                              FALSE );
    00519
    00520     //
    00521     //  Don't bother allocating tiny buffers - always make sure we get enough for an 8.3 name.
    00522     //
    00523
    00524     BufferLength =
    00525     NameLength = Max( BYTE_COUNT_8_DOT_3, UdfCS0DstringUnicodeSize( IrpContext,
    00526                                                                     NameDstring,
    00527                                                                     DirContext->Fid->FileIDLen) );
    00528
    00529     //
    00530     //  Illegality is both actual illegal characters and too many characters.
    00531     //
    00532
    00533     ContainsIllegal = (!UdfCS0DstringContainsLegalCharacters( NameDstring, DirContext->Fid->FileIDLen ) ||
    00534                        (NameLength / sizeof( WCHAR )) > MAX_LEN);
    00535
    00536
    00537     //
    00538     //  If we're illegal, we will need more characters to hold the uniqifying stamp.
    00539     //
    00540
    00541     if (ContainsIllegal) {
    00542
    00543         BufferLength = (NameLength += (CRC_LEN * sizeof(WCHAR)));
    00544     }
    00545
    00546
    00547     //
    00548     //  If we need to build a case insensitive name, need more space.
    00549     //
    00550
    00551     if (IgnoreCase) {
    00552
    00553         BufferLength += NameLength;
    00554     }
    00555
    00556     //
    00557     //  If we need to render the names due to illegal characters, more space again.
    00558     //
    00559
    00560     if (ContainsIllegal) {
    00561
    00562         BufferLength += NameLength;
    00563
    00564     } else {
    00565
    00566         //
    00567         //  Make sure the names aren't seperated. If more illegal names are found we can
    00568         //  resplit the buffer but until then avoid the expense of having to copy bytes
    00569         //  ... odds are that illegal characters are going to be a rarish occurance.
    00570         //
    00571
    00572         DirContext->PureObjectName.Buffer = DirContext->ObjectName.Buffer;
    00573     }
    00574
    00575     DebugTrace(( 0, Dbg,
    00576                  "Ob %s%sneeds %d bytes (%d byte chunks), have %d\n",
    00577                  (IgnoreCase? "Ic " : ""),
    00578                  (ContainsIllegal? "Ci " : ""),
    00579                  BufferLength,
    00580                  NameLength,
    00581                  DirContext->AllocLength ));
    00582
    00583     //
    00584     //  Check if we need more space for the names.  We will need more if the name size is greater
    00585     //  than the maximum we can currently store, or if we have stumbled across illegal characters
    00586     //  and the current Pure name is not seperated from the exposed Object name.
    00587     //
    00588     //  Note that IgnoreCase remains constant across usage of a context so we don't have to wonder
    00589     //  if it has been seperated from the ObjectName - it'll always be correct.
    00590     //
    00591
    00592     if ((NameLength > DirContext->ObjectName.MaximumLength) ||
    00593         (ContainsIllegal && DirContext->ObjectName.Buffer == DirContext->PureObjectName.Buffer)) {
    00594
    00595         DebugTrace(( 0, Dbg, "Resizing buffers\n" ));
    00596
    00597         //
    00598         //  For some reason the sizing is not good for the current name we have to unroll.  Figure
    00599         //  out if we can break up the current allocation in a different way before falling back
    00600         //  to a new allocation.
    00601         //
    00602
    00603         if (DirContext->AllocLength >= BufferLength) {
    00604
    00605             //
    00606             //  So we can still use the current allocation.  Chop it up into the required number
    00607             //  of chunks.
    00608             //
    00609
    00610             DirContext->PureObjectName.MaximumLength =
    00611             DirContext->CaseObjectName.MaximumLength =
    00612             DirContext->ObjectName.MaximumLength = DirContext->AllocLength / (1 +
    00613                                                                               (IgnoreCase? 1 : 0) +
    00614                                                                               (ContainsIllegal? 1 : 0));
    00615
    00616             DebugTrace(( 0, Dbg,
    00617                          "... by resplit into %d byte chunks\n",
    00618                          DirContext->ObjectName.MaximumLength ));
    00619
    00620             //
    00621             //  Set the buffer pointers up.  Required adjustment will occur below.
    00622             //
    00623
    00624             DirContext->PureObjectName.Buffer =
    00625             DirContext->CaseObjectName.Buffer =
    00626             DirContext->ObjectName.Buffer = DirContext->NameBuffer;
    00627
    00628         } else {
    00629
    00630             DebugTrace(( 0, Dbg, "... by allocating new pool\n" ));
    00631
    00632             //
    00633             //  Oh well, no choice but to fall back into the pool.  Drop our previous hunk.
    00634             //
    00635
    00636             UdfFreePool( &DirContext->NameBuffer );
    00637             DirContext->AllocLength = 0;
    00638
    00639             //
    00640             //  The names share an allocation for efficiency.
    00641             //
    00642
    00643             DirContext->PureObjectName.MaximumLength =
    00644             DirContext->CaseObjectName.MaximumLength =
    00645             DirContext->ObjectName.MaximumLength = NameLength;
    00646
    00647             DirContext->NameBuffer =
    00648             DirContext->PureObjectName.Buffer =
    00649             DirContext->CaseObjectName.Buffer =
    00650             DirContext->ObjectName.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
    00651                                                                       BufferLength,
    00652                                                                       TAG_FILE_NAME );
    00653
    00654             DirContext->AllocLength = BufferLength;
    00655         }
    00656
    00657         //
    00658         //  In the presence of the "as appropriate" names, adjust the buffer locations.  Note
    00659         //  that ObjectName.Buffer is always the base of the allocated space.
    00660         //
    00661
    00662         if (IgnoreCase) {
    00663
    00664             DirContext->CaseObjectName.Buffer = Add2Ptr( DirContext->ObjectName.Buffer,
    00665                                                          DirContext->ObjectName.MaximumLength,
    00666                                                          PWCHAR );
    00667         }
    00668
    00669         if (ContainsIllegal) {
    00670
    00671             DirContext->PureObjectName.Buffer = Add2Ptr( DirContext->CaseObjectName.Buffer,
    00672                                                          DirContext->CaseObjectName.MaximumLength,
    00673                                                          PWCHAR );
    00674         }
    00675     }
    00676
    00677     ASSERT( BufferLength <= DirContext->AllocLength );
    00678
    00679     //
    00680     //  Convert the dstring.
    00681     //
    00682
    00683     UdfConvertCS0DstringToUnicode( IrpContext,
    00684                                    NameDstring,
    00685                                    DirContext->Fid->FileIDLen,
    00686                                    0,
    00687                                    &DirContext->PureObjectName );
    00688
    00689     //
    00690     //  If illegal characters were present, run the name through the UDF transmogrifier.
    00691     //
    00692
    00693     if (ContainsIllegal) {
    00694
    00695         UdfRenderNameToLegalUnicode( IrpContext,
    00696                                      &DirContext->PureObjectName,
    00697                                      &DirContext->ObjectName );
    00698
    00699     //
    00700     //  The ObjectName is the same as the PureObjectName.
    00701     //
    00702
    00703     } else {
    00704
    00705         DirContext->ObjectName.Length = DirContext->PureObjectName.Length;
    00706     }
    00707
    00708     //
    00709     //  Upcase the result if required.
    00710     //
    00711
    00712     if (IgnoreCase) {
    00713
    00714         UdfUpcaseName( IrpContext,
    00715                        &DirContext->ObjectName,
    00716                        &DirContext->CaseObjectName );
    00717     }
    00718
    00719     DebugTrace(( -1, Dbg, "UdfUpdateDirNames -> VOID\n" ));
    00720
    00721     return;
    00722 }
    00723
    00724
    00725 BOOLEAN
    00726 UdfFindDirEntry (
    00727     IN PIRP_CONTEXT IrpContext,
    00728     IN PFCB Fcb,
    00729     IN PUNICODE_STRING Name,
    00730     IN BOOLEAN IgnoreCase,
    00731     IN BOOLEAN ShortName,
    00732     IN PDIR_ENUM_CONTEXT DirContext
    00733     )
    00734
    00735 /*++
    00736
    00737 Routine Description:
    00738
    00739     This routine walks the directory specified for an entry which matches the input
    00740     criteria.
    00741
    00742 Arguments:
    00743
    00744     Fcb - the directory to search
    00745
    00746     Name - name to search for
    00747
    00748     IgnoreCase - whether this search should be case-insensitive (Name will already
    00749         be upcased)
    00750
    00751     ShortName - whether the name should be searched for according to short name rules
    00752
    00753     DirContext - context structure to use and return results in
    00754
    00755 Return Value:
    00756
    00757     BOOLEAN True if a matching directory entry is being returned, False otherwise.
    00758
    00759 --*/
    00760
    00761 {
    00762     PUNICODE_STRING MatchName;
    00763
    00764     PAGED_CODE();
    00765
    00766     //
    00767     //  Check inputs.
    00768     //
    00769
    00770     ASSERT_IRP_CONTEXT( IrpContext );
    00771     ASSERT_FCB_INDEX( Fcb );
    00772
    00773     DebugTrace(( +1, Dbg,
    00774                  "UdfFindDirEntry, Fcb=%08x Name=\"%wZ\" Ignore=%u Short=%u, DC=%08x\n",
    00775                  Fcb,
    00776                  Name,
    00777                  IgnoreCase,
    00778                  ShortName,
    00779                  DirContext ));
    00780
    00781     //
    00782     //  Depending on the kind of search we are performing a different flavor of the found name
    00783     //  wil be used in the comparison.
    00784     //
    00785
    00786     if (ShortName) {
    00787
    00788         MatchName = &DirContext->ShortObjectName;
    00789
    00790     } else {
    00791
    00792         MatchName = &DirContext->CaseObjectName;
    00793     }
    00794
    00795
    00796     //
    00797     //  Go get the first entry.
    00798     //
    00799
    00800     UdfLookupInitialDirEntry( IrpContext,
    00801                               Fcb,
    00802                               DirContext,
    00803                               NULL );
    00804
    00805     //
    00806     //  Now loop looking for a good match.
    00807     //
    00808
    00809     do {
    00810
    00811         //
    00812         //  If it is deleted, we obviously aren't interested in it.
    00813         //
    00814
    00815         if (FlagOn( DirContext->Fid->Flags, NSR_FID_F_DELETED )) {
    00816
    00817             continue;
    00818         }
    00819
    00820         UdfUpdateDirNames( IrpContext,
    00821                            DirContext,
    00822                            IgnoreCase );
    00823
    00824
    00825         //
    00826         //  If this is a constant entry, just keep going.
    00827         //
    00828
    00829         if (!FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT )) {
    00830
    00831             continue;
    00832         }
    00833
    00834         DebugTrace(( 0, Dbg,
    00835                      "\"%wZ\" (pure \"%wZ\") @ +%08x\n",
    00836                      &DirContext->ObjectName,
    00837                      &DirContext->PureObjectName,
    00838                      DirContext->ViewOffset ));
    00839
    00840         //
    00841         //  If we are searching for generated shortnames, a small subset of the names
    00842         //  in the directory are actually candidates for a match.  Go get the name.
    00843         //
    00844
    00845         if (ShortName) {
    00846
    00847             //
    00848             //  Now, only if this Fid's name is non 8.3 is it neccesary to work with it.
    00849             //
    00850
    00851             if (!UdfIs8dot3Name( IrpContext, DirContext->ObjectName )) {
    00852
    00853                 //
    00854                 //  Allocate the shortname if it isn't already done.
    00855                 //
    00856
    00857                 if (DirContext->ShortObjectName.Buffer == NULL) {
    00858
    00859                     DirContext->ShortObjectName.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
    00860                                                                                    BYTE_COUNT_8_DOT_3,
    00861                                                                                    TAG_SHORT_FILE_NAME );
    00862                     DirContext->ShortObjectName.MaximumLength = BYTE_COUNT_8_DOT_3;
    00863                 }
    00864
    00865                 UdfGenerate8dot3Name( IrpContext,
    00866                                       &DirContext->PureObjectName,
    00867                                       &DirContext->ShortObjectName );
    00868
    00869                 DebugTrace(( 0, Dbg,
    00870                              "built shortname \"%wZ\"\n", &DirContext->ShortObjectName ));
    00871
    00872             } else {
    00873
    00874                 //
    00875                 //  As an 8.3 name already, this name will not have caused us to have to generate
    00876                 //  a short name, so it can't be the case that the caller is looking for it.
    00877                 //
    00878
    00879                 continue;
    00880             }
    00881         }
    00882
    00883         if (UdfFullCompareNames( IrpContext,
    00884                                  MatchName,
    00885                                  Name ) == EqualTo) {
    00886
    00887             //
    00888             //  Got a match, so give it up.
    00889             //
    00890
    00891             DebugTrace((  0, Dbg, "HIT\n" ));
    00892             DebugTrace(( -1, Dbg, "UdfFindDirEntry -> TRUE\n" ));
    00893
    00894             return TRUE;
    00895         }
    00896
    00897     } while ( UdfLookupNextDirEntry( IrpContext,
    00898                                      Fcb,
    00899                                      DirContext ));
    00900
    00901     //
    00902     //  No match was found.
    00903     //
    00904
    00905     DebugTrace(( -1, Dbg, "UdfFindDirEntry -> FALSE\n" ));
    00906
    00907     return FALSE;
    00908 }
    00909
    00910
    00911 //
    00912 //  Local support routine
    00913 //
    00914
    00915 BOOLEAN
    00916 UdfLookupDirEntryPostProcessing (
    00917     IN PIRP_CONTEXT IrpContext,
    00918     IN PFCB Fcb,
    00919     IN PDIR_ENUM_CONTEXT DirContext,
    00920     IN BOOLEAN ReturnError
    00921     )
    00922
    00923 /*++
    00924
    00925 Routine Description:
    00926
    00927     This routine is the core engine of directory stream enumeration. It receives
    00928     a context which has been advanced and does the integrity checks and final
    00929     extraction of the Fid with respect to file cache granularity restrictions.
    00930
    00931     NOTE: we assume that a Fid cannot span a cache view.  The maximum size of a
    00932     Fid is just over 32k, so this is a good and likely permanent assumption.
    00933
    00934 Arguments:
    00935
    00936     Fcb - the directory being enumerated.
    00937
    00938     DirContext - a corresponding context for the enumeration.
    00939
    00940     ReturnError - whether errors should be returned (or raised)
    00941
    00942 Return Value:
    00943
    00944     BOOLEAN according to the successful extraction of the Fid.  If ReturnError is
    00945     FALSE, then failure will result in a raised status.
    00946
    00947 --*/
    00948
    00949 {
    00950     BOOLEAN Result = TRUE;
    00951
    00952     PNSR_FID FidBufferC = NULL;
    00953     PNSR_FID FidBuffer = NULL;
    00954
    00955     PNSR_FID FidC;
    00956     PNSR_FID Fid;
    00957
    00958     ULONG FidBytesInPreviousView = 0;
    00959
    00960     PAGED_CODE();
    00961
    00962     //
    00963     //  Check inputs.
    00964     //
    00965
    00966     ASSERT_IRP_CONTEXT( IrpContext );
    00967     ASSERT_FCB_INDEX( Fcb );
    00968
    00969     try {
    00970
    00971         //
    00972         //  First check that the stream can contain another FID.
    00973         //
    00974
    00975         if (DirContext->BaseOffset.QuadPart +
    00976             DirContext->ViewOffset +
    00977             ISONsrFidConstantSize > Fcb->FileSize.QuadPart) {
    00978
    00979             DebugTrace(( 0, Dbg,
    00980                          "UdfLookupDirEntryPostProcessing: DC %p, constant header overlaps end of dir\n",
    00981                          DirContext ));
    00982
    00983             try_leave( Result = FALSE );
    00984         }
    00985
    00986         //
    00987         //  We now build up the constant portion of the FID for use.  It may be the case that
    00988         //  this spans a view boundary and must be buffered, or is entirely in the next view
    00989         //  and we simply need to advance.
    00990         //
    00991
    00992         if (GenericTruncatePtr( Add2Ptr( DirContext->Fid, ISONsrFidConstantSize - 1, PUCHAR ), VACB_MAPPING_GRANULARITY ) !=
    00993             DirContext->View) {
    00994
    00995             FidBytesInPreviousView = GenericRemainderPtr( DirContext->Fid, VACB_MAPPING_GRANULARITY );
    00996
    00997             //
    00998             //  Only buffer if there are really bytes in the previous view.
    00999             //
    01000
    01001             if (FidBytesInPreviousView) {
    01002
    01003                 FidC =
    01004                 FidBufferC = FsRtlAllocatePoolWithTag( UdfPagedPool,
    01005                                                        ISONsrFidConstantSize,
    01006                                                        TAG_FID_BUFFER );
    01007
    01008                 RtlCopyMemory( FidBufferC,
    01009                                DirContext->Fid,
    01010                                FidBytesInPreviousView );
    01011             }
    01012
    01013             //
    01014             //  Now advance into the next view to pick up the rest.
    01015             //
    01016
    01017             DirContext->BaseOffset.QuadPart += VACB_MAPPING_GRANULARITY;
    01018             DirContext->ViewOffset = 0;
    01019
    01020             //
    01021             //  Contain the view length by the size of the stream and map.
    01022             //
    01023
    01024             DirContext->ViewLength = VACB_MAPPING_GRANULARITY;
    01025
    01026             if (DirContext->BaseOffset.QuadPart + DirContext->ViewLength > Fcb->FileSize.QuadPart) {
    01027
    01028                 DirContext->ViewLength = (ULONG) (Fcb->FileSize.QuadPart - DirContext->BaseOffset.QuadPart);
    01029             }
    01030
    01031             UdfUnpinData( IrpContext, &DirContext->Bcb );
    01032
    01033             CcMapData( Fcb->FileObject,
    01034                        &DirContext->BaseOffset,
    01035                        DirContext->ViewLength,
    01036                        TRUE,
    01037                        &DirContext->Bcb,
    01038                        &DirContext->View );
    01039
    01040             //
    01041             //  We are guaranteed that this much lies in the stream.  Build the rest of the
    01042             //  constant header.
    01043             //
    01044
    01045             if (FidBytesInPreviousView) {
    01046
    01047                 RtlCopyMemory( Add2Ptr( FidBufferC, FidBytesInPreviousView, PUCHAR ),
    01048                                DirContext->View,
    01049                                ISONsrFidConstantSize - FidBytesInPreviousView );
    01050
    01051             //
    01052             //  In fact, this FID is perfectly aligned to the front of this view.  No buffering
    01053             //  is required, and we just set the FID pointer.
    01054             //
    01055
    01056             } else {
    01057
    01058
    01059                 DirContext->Fid = DirContext->View;
    01060             }
    01061         }
    01062
    01063         //
    01064         //  If no buffering was required, we can use the cache directly.
    01065         //
    01066
    01067         if (!FidBytesInPreviousView) {
    01068
    01069             FidC = DirContext->Fid;
    01070         }
    01071
    01072         //
    01073         //  Now we can check that the Fid data lies within the stream bounds and is sized
    01074         //  within a logical block (per UDF).  This will complete the size-wise integrity
    01075         //  verification.
    01076         //
    01077
    01078         if (((DirContext->BaseOffset.QuadPart +
    01079               DirContext->ViewOffset -
    01080               FidBytesInPreviousView +
    01081               ISONsrFidSize( FidC ) > Fcb->FileSize.QuadPart) &&
    01082              DebugTrace(( 0, Dbg,
    01083                           "UdfLookupDirEntryPostProcessing: DC %p, FID (FidC %p, FBIPV %u) overlaps end of dir\n",
    01084                           DirContext,
    01085                           FidC,
    01086                           FidBytesInPreviousView )))
    01087               ||
    01088
    01089             (ISONsrFidSize( FidC ) > BlockSize( Fcb->Vcb ) &&
    01090              DebugTrace(( 0, Dbg,
    01091              "UdfLookupDirEntryPostProcessing: DC %p, FID (FidC %p) larger than a logical block\n",
    01092                           DirContext,
    01093                           FidC )))) {
    01094
    01095             try_leave( Result = FALSE );
    01096
    01097         }
    01098
    01099         //
    01100         //  Final Fid rollup.
    01101         //
    01102
    01103         //
    01104         //  The Fid may span a view boundary and should be buffered.  If we already buffered, we know
    01105         //  we have to do this.
    01106         //
    01107
    01108         if (FidBytesInPreviousView ||
    01109             GenericTruncatePtr( Add2Ptr( DirContext->Fid, ISONsrFidSize( FidC ) - 1, PUCHAR ), VACB_MAPPING_GRANULARITY ) !=
    01110             DirContext->View) {
    01111
    01112             Fid =
    01113             FidBuffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
    01114                                                   ISONsrFidSize( FidC ),
    01115                                                   TAG_FID_BUFFER );
    01116
    01117
    01118             //
    01119             //  If we already buffered and advanced for the header, just prefill
    01120             //  the final Fid buffer with the bytes that are now unavaliable.
    01121             //
    01122
    01123             if (FidBytesInPreviousView) {
    01124
    01125                 RtlCopyMemory( FidBuffer,
    01126                                FidBufferC,
    01127                                FidBytesInPreviousView );
    01128
    01129             } else {
    01130
    01131                 //
    01132                 //  Buffer and advance the view.
    01133                 //
    01134
    01135                 FidBytesInPreviousView = GenericRemainderPtr( DirContext->Fid, VACB_MAPPING_GRANULARITY );
    01136
    01137                 RtlCopyMemory( FidBuffer,
    01138                                DirContext->Fid,
    01139                                FidBytesInPreviousView );
    01140
    01141                 //
    01142                 //  Now advance into the next view to pick up the rest.
    01143                 //
    01144
    01145                 DirContext->BaseOffset.QuadPart += VACB_MAPPING_GRANULARITY;
    01146                 DirContext->ViewOffset = 0;
    01147
    01148                 //
    01149                 //  Contain the view length by the size of the stream and map.
    01150                 //
    01151
    01152                 DirContext->ViewLength = VACB_MAPPING_GRANULARITY;
    01153
    01154                 if (DirContext->BaseOffset.QuadPart + DirContext->ViewLength > Fcb->FileSize.QuadPart) {
    01155
    01156                     DirContext->ViewLength = (ULONG) (Fcb->FileSize.QuadPart - DirContext->BaseOffset.QuadPart);
    01157                 }
    01158
    01159                 UdfUnpinData( IrpContext, &DirContext->Bcb );
    01160
    01161                 CcMapData( Fcb->FileObject,
    01162                            &DirContext->BaseOffset,
    01163                            DirContext->ViewLength,
    01164                            TRUE,
    01165                            &DirContext->Bcb,
    01166                            &DirContext->View );
    01167             }
    01168
    01169             //
    01170             //  We are guaranteed that this much lies in the stream.
    01171             //
    01172
    01173             RtlCopyMemory( Add2Ptr( FidBuffer, FidBytesInPreviousView, PUCHAR ),
    01174                            DirContext->View,
    01175                            ISONsrFidSize( FidC ) - FidBytesInPreviousView );
    01176
    01177         } else {
    01178
    01179             Fid = DirContext->Fid;
    01180         }
    01181
    01182         //
    01183         //  We finally have the whole Fid safely extracted from the cache, so the
    01184         //  integrity check is now the last step before success.  For simplicity's
    01185         //  sake we trust the Lbn field.
    01186         //
    01187
    01188         Result = UdfVerifyDescriptor( IrpContext,
    01189                                       &Fid->Destag,
    01190                                       DESTAG_ID_NSR_FID,
    01191                                       ISONsrFidSize( Fid ),
    01192                                       Fid->Destag.Lbn,
    01193                                       ReturnError );
    01194
    01195         //
    01196         //  Prepare to return a buffered Fid.
    01197         //
    01198
    01199         if (FidBuffer && Result) {
    01200
    01201             SetFlag( DirContext->Flags, DIR_CONTEXT_FLAG_FID_BUFFERED );
    01202             DirContext->Fid = FidBuffer;
    01203             FidBuffer = NULL;
    01204         }
    01205
    01206     } finally {
    01207
    01208         UdfFreePool( &FidBuffer );
    01209         UdfFreePool( &FidBufferC );
    01210     }
    01211
    01212     if (!ReturnError && !Result) {
    01213
    01214         UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
    01215     }
    01216
    01217     //
    01218     //  On success update the next Fid information in the context.
    01219     //  Note that  we must drop in a hint as to where the next Fid
    01220     //  will be found so that the next advance will know how much
    01221     //  of a buffered Fid isn't in this view.
    01222     //
    01223
    01224     if (Result) {
    01225
    01226         DirContext->NextFidOffset = DirContext->ViewOffset +
    01227                                     ISONsrFidSize( Fid );
    01228
    01229         if (FidBytesInPreviousView) {
    01230
    01231             DirContext->NextFidOffset -= FidBytesInPreviousView;
    01232         }
    01233     }
    01234
    01235     return Result;
    01236 }
    01237
    01238