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

Generated on Sat May 15 19:39:45 2004 for test by doxygen 1.3.7