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

dirctrl.c File Reference

#include "UdfProcs.h"

Go to the source code of this file.

Classes

struct  _COMPOUND_DIR_ENUM_CONTEXT

Defines

#define BugCheckFileId   (UDFS_BUG_CHECK_DIRCTRL)
#define Dbg   (UDFS_DEBUG_LEVEL_DIRCTRL)
#define UDF_FILE_INDEX_VIRTUAL_SELF   0
#define UDF_FILE_INDEX_PHYSICAL   1

Typedefs

typedef _COMPOUND_DIR_ENUM_CONTEXT COMPOUND_DIR_ENUM_CONTEXT
typedef _COMPOUND_DIR_ENUM_CONTEXTPCOMPOUND_DIR_ENUM_CONTEXT

Functions

INLINE VOID UdfInitializeCompoundDirContext (IN PIRP_CONTEXT IrpContext, IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext)
INLINE VOID UdfCleanupCompoundDirContext (IN PIRP_CONTEXT IrpContext, IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext)
INLINE LONGLONG UdfFileIndexToPhysicalOffset (LONGLONG FileIndex)
INLINE LONGLONG UdfPhysicalOffsetToFileIndex (LONGLONG PhysicalOffset)
INLINE BOOLEAN UdfIsFileIndexVirtual (LONGLONG FileIndex)
NTSTATUS UdfQueryDirectory (IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PFCB Fcb, IN PCCB Ccb)
NTSTATUS UdfNotifyChangeDirectory (IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, IN PCCB Ccb)
VOID UdfInitializeEnumeration (IN PIRP_CONTEXT IrpContext, IN PIO_STACK_LOCATION IrpSp, IN PFCB Fcb, IN OUT PCCB Ccb, IN OUT PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext, OUT PBOOLEAN ReturnNextEntry, OUT PBOOLEAN ReturnSingleEntry, OUT PBOOLEAN InitialQuery)
BOOLEAN UdfEnumerateIndex (IN PIRP_CONTEXT IrpContext, IN PCCB Ccb, IN OUT PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext, IN BOOLEAN ReturnNextEntry)
VOID UdfLookupFileEntryInEnumeration (IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext)
BOOLEAN UdfLookupInitialFileIndex (IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext, IN PLONGLONG InitialIndex)
BOOLEAN UdfLookupNextFileIndex (IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCOMPOUND_DIR_ENUM_CONTEXT CompoundDirContext)
NTSTATUS UdfCommonDirControl (IN PIRP_CONTEXT IrpContext, IN PIRP Irp)


Define Documentation

#define BugCheckFileId   (UDFS_BUG_CHECK_DIRCTRL)
 

Definition at line 28 of file dirctrl.c.

#define Dbg   (UDFS_DEBUG_LEVEL_DIRCTRL)
 

Definition at line 34 of file dirctrl.c.

#define UDF_FILE_INDEX_PHYSICAL   1
 

Definition at line 88 of file dirctrl.c.

Referenced by UdfFileIndexToPhysicalOffset(), UdfInitializeEnumeration(), UdfIsFileIndexVirtual(), UdfLookupNextFileIndex(), and UdfPhysicalOffsetToFileIndex().

#define UDF_FILE_INDEX_VIRTUAL_SELF   0
 

Definition at line 82 of file dirctrl.c.

Referenced by UdfInitializeEnumeration(), and UdfLookupInitialFileIndex().


Typedef Documentation

typedef struct _COMPOUND_DIR_ENUM_CONTEXT COMPOUND_DIR_ENUM_CONTEXT
 

typedef struct _COMPOUND_DIR_ENUM_CONTEXT * PCOMPOUND_DIR_ENUM_CONTEXT
 


Function Documentation

INLINE VOID UdfCleanupCompoundDirContext IN PIRP_CONTEXT  IrpContext,
IN PCOMPOUND_DIR_ENUM_CONTEXT  CompoundDirContext
 

Definition at line 112 of file dirctrl.c.

References UdfCleanupDirContext(), and UdfCleanupIcbContext().

Referenced by UdfQueryDirectory().

00116 { 00117 00118 UdfCleanupDirContext( IrpContext, &CompoundDirContext->DirContext ); 00119 UdfCleanupIcbContext( IrpContext, &CompoundDirContext->IcbContext ); 00120 }

NTSTATUS UdfCommonDirControl IN PIRP_CONTEXT  IrpContext,
IN PIRP  Irp
 

Definition at line 255 of file dirctrl.c.

References _IO_STACK_LOCATION::FileObject, IoGetCurrentIrpStackLocation, Irp, IRP_MN_NOTIFY_CHANGE_DIRECTORY, IRP_MN_QUERY_DIRECTORY, _IO_STACK_LOCATION::MinorFunction, NTSTATUS(), PAGED_CODE, Status, UdfCompleteRequest(), UdfDecodeFileObject(), UdfNotifyChangeDirectory(), UdfQueryDirectory(), and UserDirectoryOpen.

Referenced by UdfFsdDispatch(), and UdfFspDispatch().

00262 : 00263 00264 This routine is the entry point for the directory control operations. These 00265 are directory enumerations and directory notify calls. We verify the 00266 user's handle is for a directory and then call the appropriate routine. 00267 00268 Arguments: 00269 00270 Irp - Irp for this request. 00271 00272 Return Value: 00273 00274 NTSTATUS - Status returned from the lower level routines. 00275 00276 --*/ 00277 00278 { 00279 NTSTATUS Status; 00280 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00281 00282 PFCB Fcb; 00283 PCCB Ccb; 00284 00285 PAGED_CODE(); 00286 00287 // 00288 // Decode the user file object and fail this request if it is not 00289 // a user directory. 00290 // 00291 00292 if (UdfDecodeFileObject( IrpSp->FileObject, 00293 &Fcb, 00294 &Ccb ) != UserDirectoryOpen) { 00295 00296 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 00297 return STATUS_INVALID_PARAMETER; 00298 } 00299 00300 // 00301 // We know this is a directory control so we'll case on the 00302 // minor function, and call a internal worker routine to complete 00303 // the irp. 00304 // 00305 00306 switch (IrpSp->MinorFunction) { 00307 00308 case IRP_MN_QUERY_DIRECTORY: 00309 00310 Status = UdfQueryDirectory( IrpContext, Irp, IrpSp, Fcb, Ccb ); 00311 break; 00312 00313 case IRP_MN_NOTIFY_CHANGE_DIRECTORY: 00314 00315 Status = UdfNotifyChangeDirectory( IrpContext, Irp, IrpSp, Ccb ); 00316 break; 00317 00318 default: 00319 00320 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 00321 Status = STATUS_INVALID_DEVICE_REQUEST; 00322 break; 00323 } 00324 00325 return Status; 00326 }

BOOLEAN UdfEnumerateIndex IN PIRP_CONTEXT  IrpContext,
IN PCCB  Ccb,
IN OUT PCOMPOUND_DIR_ENUM_CONTEXT  CompoundDirContext,
IN BOOLEAN  ReturnNextEntry
 

Definition at line 1500 of file dirctrl.c.

References ASSERT_CCB, ASSERT_IRP_CONTEXT, BooleanFlagOn, BYTE_COUNT_8_DOT_3, _DIR_ENUM_CONTEXT::CaseObjectName, CCB_FLAG_ENUM_MATCH_ALL, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY, CCB_FLAG_IGNORE_CASE, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT, FALSE, _DIR_ENUM_CONTEXT::Fid, FlagOn, NSR_FID::Flags, _DIR_ENUM_CONTEXT::Flags, FsRtlAllocatePoolWithTag, NSR_FID_F_DELETED, NULL, PAGED_CODE, _DIR_ENUM_CONTEXT::PureObjectName, _DIR_ENUM_CONTEXT::ShortObjectName, TAG_SHORT_FILE_NAME, TRUE, UdfGenerate8dot3Name(), UdfIs8dot3Name(), UdfIsNameInExpression(), UdfLookupNextFileIndex(), UdfPagedPool, and UdfUpdateDirNames().

Referenced by UdfQueryDirectory().

01509 : 01510 01511 This routine is the worker routine for index enumeration. We are positioned 01512 at some dirent in the directory and will either return the first match 01513 at that point or look to the next entry. The Ccb contains details about 01514 the type of matching to do. 01515 01516 Arguments: 01517 01518 Ccb - Ccb for this directory handle. 01519 01520 CompoundDirContext - context already positioned at some entry in the directory. 01521 01522 ReturnNextEntry - Indicates if we are returning this entry or should start 01523 with the next entry. 01524 01525 Return Value: 01526 01527 BOOLEAN - TRUE if next entry is found, FALSE otherwise. 01528 01529 --*/ 01530 01531 { 01532 BOOLEAN Found = FALSE; 01533 PNSR_FID Fid; 01534 PDIR_ENUM_CONTEXT DirContext; 01535 01536 PAGED_CODE(); 01537 01538 // 01539 // Check inputs. 01540 // 01541 01542 ASSERT_IRP_CONTEXT( IrpContext ); 01543 ASSERT_CCB( Ccb ); 01544 01545 // 01546 // Directly reference the directory enumeration context for convenience. 01547 // 01548 01549 DirContext = &CompoundDirContext->DirContext; 01550 01551 // 01552 // Loop until we find a match or exaust the directory. 01553 // 01554 01555 while (TRUE) { 01556 01557 // 01558 // Move to the next entry unless we want to consider the current 01559 // entry. 01560 // 01561 01562 if (ReturnNextEntry) { 01563 01564 if (!UdfLookupNextFileIndex( IrpContext, Ccb->Fcb, CompoundDirContext )) { 01565 01566 break; 01567 } 01568 01569 UdfUpdateDirNames( IrpContext, 01570 DirContext, 01571 BooleanFlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )); 01572 } else { 01573 01574 ReturnNextEntry = TRUE; 01575 } 01576 01577 // 01578 // Don't bother if we have a constant entry and are ignoring them. 01579 // 01580 01581 if (!FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT ) && 01582 FlagOn( Ccb->Flags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY )) { 01583 01584 continue; 01585 } 01586 01587 // 01588 // Directly reference the Fid for convenience. 01589 // 01590 01591 Fid = DirContext->Fid; 01592 01593 // 01594 // Look at the current entry if it is pointing at real space on the disk. If the Fid is NULL, this 01595 // means it is to be synthesized (and thus interesting to look at). 01596 // 01597 01598 if (Fid == NULL || !FlagOn( Fid->Flags, NSR_FID_F_DELETED )) { 01599 01600 // 01601 // If we match all names then return to our caller. 01602 // 01603 01604 if (FlagOn( Ccb->Flags, CCB_FLAG_ENUM_MATCH_ALL )) { 01605 01606 DirContext->ShortObjectName.Length = 0; 01607 Found = TRUE; 01608 01609 break; 01610 } 01611 01612 // 01613 // Check if the long name matches the search expression. 01614 // 01615 01616 if (UdfIsNameInExpression( IrpContext, 01617 &DirContext->CaseObjectName, 01618 &Ccb->SearchExpression, 01619 BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD ))) { 01620 01621 // 01622 // Let our caller know we found an entry. 01623 // 01624 01625 DirContext->ShortObjectName.Length = 0; 01626 Found = TRUE; 01627 01628 break; 01629 } 01630 01631 // 01632 // The long name didn't match so we need to check for a 01633 // possible short name match. There is no match if the 01634 // long name is one of the constant entries or already 01635 // is 8dot3. 01636 // 01637 01638 if (!(!FlagOn( DirContext->Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT ) || 01639 UdfIs8dot3Name( IrpContext, 01640 DirContext->CaseObjectName ))) { 01641 01642 // 01643 // Allocate the shortname if it isn't already done. 01644 // 01645 01646 if (DirContext->ShortObjectName.Buffer == NULL) { 01647 01648 DirContext->ShortObjectName.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool, 01649 BYTE_COUNT_8_DOT_3, 01650 TAG_SHORT_FILE_NAME ); 01651 DirContext->ShortObjectName.MaximumLength = BYTE_COUNT_8_DOT_3; 01652 } 01653 01654 UdfGenerate8dot3Name( IrpContext, 01655 &DirContext->PureObjectName, 01656 &DirContext->ShortObjectName ); 01657 01658 // 01659 // Check if this name matches. 01660 // 01661 01662 if (UdfIsNameInExpression( IrpContext, 01663 &DirContext->ShortObjectName, 01664 &Ccb->SearchExpression, 01665 BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD ))) { 01666 01667 // 01668 // Let our caller know we found an entry. 01669 // 01670 01671 Found = TRUE; 01672 01673 break; 01674 } 01675 } 01676 } 01677 } 01678 01679 return Found; 01680 }

INLINE LONGLONG UdfFileIndexToPhysicalOffset LONGLONG  FileIndex  ) 
 

Definition at line 151 of file dirctrl.c.

References UDF_FILE_INDEX_PHYSICAL.

Referenced by UdfLookupInitialFileIndex().

00154 { 00155 00156 return FileIndex - UDF_FILE_INDEX_PHYSICAL; 00157 }

INLINE VOID UdfInitializeCompoundDirContext IN PIRP_CONTEXT  IrpContext,
IN PCOMPOUND_DIR_ENUM_CONTEXT  CompoundDirContext
 

Definition at line 96 of file dirctrl.c.

References TIMESTAMP_BUNDLE, UdfFastInitializeIcbContext(), and UdfInitializeDirContext().

Referenced by UdfQueryDirectory().

00100 { 00101 00102 UdfInitializeDirContext( IrpContext, &CompoundDirContext->DirContext ); 00103 UdfFastInitializeIcbContext( IrpContext, &CompoundDirContext->IcbContext ); 00104 00105 RtlZeroMemory( &CompoundDirContext->Timestamps, sizeof( TIMESTAMP_BUNDLE )); 00106 00107 CompoundDirContext->FileIndex.QuadPart = 0; 00108 }

VOID UdfInitializeEnumeration IN PIRP_CONTEXT  IrpContext,
IN PIO_STACK_LOCATION  IrpSp,
IN PFCB  Fcb,
IN OUT PCCB  Ccb,
IN OUT PCOMPOUND_DIR_ENUM_CONTEXT  CompoundDirContext,
OUT PBOOLEAN  ReturnNextEntry,
OUT PBOOLEAN  ReturnSingleEntry,
OUT PBOOLEAN  InitialQuery
 

Definition at line 1003 of file dirctrl.c.

References ASSERT, ASSERT_CCB, ASSERT_FCB_INDEX, ASSERT_IRP_CONTEXT, BooleanFlagOn, CCB_FLAG_ENUM_INITIALIZED, CCB_FLAG_ENUM_MATCH_ALL, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY, CCB_FLAG_ENUM_RETURN_NEXT, CCB_FLAG_IGNORE_CASE, EqualTo, FALSE, FileName, FlagOn, FsRtlAllocatePoolWithTag, FsRtlDoesNameContainWildCards(), ISONsrFidSize, L, Max, NTSTATUS(), NULL, PAGED_CODE, RtlUpcaseUnicodeString(), SELF_ENTRY, SetFlag, SL_INDEX_SPECIFIED, SL_RESTART_SCAN, SL_RETURN_SINGLE_ENTRY, Status, TAG_ENUM_EXPRESSION, TRUE, UDF_FILE_INDEX_PHYSICAL, UDF_FILE_INDEX_VIRTUAL_SELF, UdfCleanupDirContext(), UdfFreePool(), UdfFullCompareNames(), UdfInitializeDirContext(), UdfLockFcb, UdfLookupInitialFileIndex(), UdfLookupNextFileIndex(), UdfPagedPool, UdfRaiseStatus(), UdfUnicodeDirectoryNames, UdfUnlockFcb, and UdfUpdateDirNames().

Referenced by UdfQueryDirectory().

01016 : 01017 01018 This routine is called to initialize the enumeration variables and structures. 01019 We look at the state of a previous enumeration from the Ccb as well as any 01020 input values from the user. On exit we will position the DirContext at 01021 a file in the directory and let the caller know whether this entry or the 01022 next entry should be returned. 01023 01024 Arguments: 01025 01026 IrpSp - Irp stack location for this request. 01027 01028 Fcb - Fcb for this directory. 01029 01030 Ccb - Ccb for the directory handle. 01031 01032 CompoundDirContext - Context to use for this enumeration. 01033 01034 ReturnNextEntry - Address to store whether we should return the entry at 01035 the context position or the next entry. 01036 01037 ReturnSingleEntry - Address to store whether we should only return 01038 a single entry. 01039 01040 InitialQuery - Address to store whether this is the first enumeration 01041 query on this handle. 01042 01043 Return Value: 01044 01045 None. 01046 01047 --*/ 01048 01049 { 01050 NTSTATUS Status; 01051 01052 PUNICODE_STRING FileName; 01053 UNICODE_STRING SearchExpression; 01054 01055 PUNICODE_STRING RestartName = NULL; 01056 01057 ULONG CcbFlags; 01058 01059 LONGLONG FileIndex; 01060 ULONG HighFileIndex; 01061 BOOLEAN KnownIndex; 01062 01063 BOOLEAN Found; 01064 01065 PAGED_CODE(); 01066 01067 // 01068 // Check inputs. 01069 // 01070 01071 ASSERT_IRP_CONTEXT( IrpContext ); 01072 ASSERT_FCB_INDEX( Fcb ); 01073 ASSERT_CCB( Ccb ); 01074 01075 // 01076 // If this is the initial query then build a search expression from the input 01077 // file name. 01078 // 01079 01080 if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) { 01081 01082 FileName = (PUNICODE_STRING) IrpSp->Parameters.QueryDirectory.FileName; 01083 01084 CcbFlags = 0; 01085 01086 // 01087 // If the filename is not specified or is a single '*' then we will 01088 // match all names. 01089 // 01090 01091 if ((FileName == NULL) || 01092 (FileName->Buffer == NULL) || 01093 (FileName->Length == 0) || 01094 ((FileName->Length == sizeof( WCHAR )) && 01095 (FileName->Buffer[0] == L'*'))) { 01096 01097 SetFlag( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL ); 01098 01099 SearchExpression.Length = 01100 SearchExpression.MaximumLength = 0; 01101 SearchExpression.Buffer = NULL; 01102 01103 // 01104 // Otherwise build the name from the name in the stack location. 01105 // This involves checking for wild card characters and upcasing the 01106 // string if this is a case-insensitive search. 01107 // 01108 01109 } else { 01110 01111 // 01112 // The name better have at least one character. 01113 // 01114 01115 if (FileName->Length == 0) { 01116 01117 UdfRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER ); 01118 } 01119 01120 // 01121 // Check for wildcards in the separate components. 01122 // 01123 01124 if (FsRtlDoesNameContainWildCards( FileName)) { 01125 01126 SetFlag( CcbFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD ); 01127 } 01128 01129 // 01130 // Now create the search expression to store in the Ccb. 01131 // 01132 01133 SearchExpression.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool, 01134 FileName->Length, 01135 TAG_ENUM_EXPRESSION ); 01136 01137 SearchExpression.MaximumLength = FileName->Length; 01138 01139 // 01140 // Either copy the name directly or perform the upcase. 01141 // 01142 01143 if (FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )) { 01144 01145 Status = RtlUpcaseUnicodeString( &SearchExpression, 01146 FileName, 01147 FALSE ); 01148 01149 // 01150 // This should never fail. 01151 // 01152 01153 ASSERT( Status == STATUS_SUCCESS ); 01154 01155 } else { 01156 01157 RtlCopyMemory( SearchExpression.Buffer, 01158 FileName->Buffer, 01159 FileName->Length ); 01160 } 01161 01162 SearchExpression.Length = FileName->Length; 01163 } 01164 01165 // 01166 // But we do not want to return the constant "." and ".." entries for 01167 // the root directory, for consistency with the rest of Microsoft's 01168 // filesystems. 01169 // 01170 01171 if (Fcb == Fcb->Vcb->RootIndexFcb) { 01172 01173 SetFlag( CcbFlags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY ); 01174 } 01175 01176 // 01177 // Now lock the Fcb in order to update the Ccb with the inital 01178 // enumeration values. 01179 // 01180 01181 UdfLockFcb( IrpContext, Fcb ); 01182 01183 // 01184 // Check again that this is the initial search. 01185 // 01186 01187 if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) { 01188 01189 // 01190 // Update the values in the Ccb. 01191 // 01192 01193 Ccb->CurrentFileIndex = 0; 01194 Ccb->SearchExpression = SearchExpression; 01195 01196 // 01197 // Set the appropriate flags in the Ccb. 01198 // 01199 01200 SetFlag( Ccb->Flags, CcbFlags | CCB_FLAG_ENUM_INITIALIZED ); 01201 01202 // 01203 // Otherwise cleanup any buffer allocated here. 01204 // 01205 01206 } else { 01207 01208 if (!FlagOn( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL )) { 01209 01210 UdfFreePool( &SearchExpression.Buffer ); 01211 } 01212 } 01213 01214 // 01215 // Otherwise lock the Fcb so we can read the current enumeration values. 01216 // 01217 01218 } else { 01219 01220 UdfLockFcb( IrpContext, Fcb ); 01221 } 01222 01223 // 01224 // Capture the current state of the enumeration. 01225 // 01226 // If the user specified an index then use his offset. We always 01227 // return the next entry in this case. If no name is specified, 01228 // then we can't perform the restart. 01229 // 01230 01231 if (FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED ) && 01232 IrpSp->Parameters.QueryDirectory.FileName != NULL) { 01233 01234 KnownIndex = FALSE; 01235 FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; 01236 RestartName = (PUNICODE_STRING) IrpSp->Parameters.QueryDirectory.FileName; 01237 *ReturnNextEntry = TRUE; 01238 01239 // 01240 // We will use the highest file index reportable to the caller as a 01241 // starting point as required if we cannot directly land at the 01242 // specified location. 01243 // 01244 01245 HighFileIndex = Ccb->HighestReturnableFileIndex; 01246 01247 // 01248 // If we are restarting the scan then go from the self entry. 01249 // 01250 01251 } else if (FlagOn( IrpSp->Flags, SL_RESTART_SCAN )) { 01252 01253 KnownIndex = TRUE; 01254 FileIndex = 0; 01255 *ReturnNextEntry = FALSE; 01256 01257 // 01258 // Otherwise use the values from the Ccb. 01259 // 01260 01261 } else { 01262 01263 KnownIndex = TRUE; 01264 FileIndex = Ccb->CurrentFileIndex; 01265 *ReturnNextEntry = BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT ); 01266 } 01267 01268 // 01269 // Unlock the Fcb. 01270 // 01271 01272 UdfUnlockFcb( IrpContext, Fcb ); 01273 01274 // 01275 // We have the starting offset in the directory and whether to return 01276 // that entry or the next. If we are at the beginning of the directory 01277 // and are returning that entry, then tell our caller this is the 01278 // initial query. 01279 // 01280 01281 *InitialQuery = FALSE; 01282 01283 if ((FileIndex == 0) && 01284 !(*ReturnNextEntry)) { 01285 01286 *InitialQuery = TRUE; 01287 } 01288 01289 // 01290 // Determine the offset in the stream to position the context and 01291 // whether this offset is known to be a file offset. 01292 // 01293 // If this offset is known to be safe then go ahead and position the 01294 // context. This handles the cases where the offset is the beginning 01295 // of the stream, the offset is from a previous search or this is the 01296 // initial query. 01297 // 01298 01299 if (KnownIndex) { 01300 01301 Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &FileIndex ); 01302 01303 ASSERT( Found ); 01304 01305 // 01306 // Try to directly jump to the specified file index. Otherwise we walk through 01307 // the directory from the beginning (or the saved highest known offset if that is 01308 // useful) until we reach the entry which contains this offset. 01309 // 01310 01311 } else { 01312 01313 // 01314 // We need to handle the special case of a restart from a synthesized 01315 // entry - this is the one time where the restart index can be zero 01316 // without requiring us to search above the 2^32 byte mark. 01317 // 01318 01319 if (UdfFullCompareNames( IrpContext, 01320 RestartName, 01321 &UdfUnicodeDirectoryNames[SELF_ENTRY] ) == EqualTo) { 01322 01323 FileIndex = UDF_FILE_INDEX_VIRTUAL_SELF; 01324 01325 Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &FileIndex ); 01326 01327 ASSERT( Found ); 01328 01329 // 01330 // We are restarting from a physical entry. If the restart index is zero, we were 01331 // unable to inform the caller as to the "real" file index due to the dispartity 01332 // between the ULONG FileIndex in the return structures and the LONGLONG offsets 01333 // possible in directory streams. In this case, we will go as high as we were able 01334 // to inform the caller of and search linearly from that point forward. 01335 // 01336 // It is also possible (realistic? unknown) that the restart index is somewhere in the 01337 // middle of an entry and we won't find anything useable. In this case we try to find 01338 // the entry which contains this index, using it as the real restart point. 01339 // 01340 01341 } else { 01342 01343 // 01344 // See if we need the high water mark. 01345 // 01346 01347 if (FileIndex == 0) { 01348 01349 // 01350 // We know that this is good. 01351 // 01352 01353 FileIndex = Max( Ccb->HighestReturnableFileIndex, UDF_FILE_INDEX_PHYSICAL );; 01354 KnownIndex = TRUE; 01355 01356 } 01357 01358 // 01359 // The file index is now useful, falling into two cases 01360 // 01361 // 1) KnownIndex == FALSE - searching by index 01362 // 2) KnownIndex == TRUE - searching by name 01363 // 01364 // Go set up our inquiry. 01365 // 01366 01367 Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &FileIndex ); 01368 01369 if (KnownIndex) { 01370 01371 // 01372 // Walk forward to discover an entry named per the caller's expectation. 01373 // 01374 01375 do { 01376 01377 UdfUpdateDirNames( IrpContext, 01378 &CompoundDirContext->DirContext, 01379 BooleanFlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )); 01380 01381 if (UdfFullCompareNames( IrpContext, 01382 &CompoundDirContext->DirContext.CaseObjectName, 01383 RestartName ) == EqualTo) { 01384 01385 break; 01386 } 01387 01388 Found = UdfLookupNextFileIndex( IrpContext, Fcb, CompoundDirContext ); 01389 01390 } while (Found); 01391 01392 } else if (!Found) { 01393 01394 LONGLONG LastFileIndex; 01395 01396 // 01397 // Perform the search for the entry by index from the beginning of the physical directory. 01398 // 01399 01400 LastFileIndex = UDF_FILE_INDEX_PHYSICAL; 01401 01402 Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &LastFileIndex ); 01403 01404 ASSERT( Found ); 01405 01406 // 01407 // Keep walking through the directory until we run out of 01408 // entries or we find an entry which ends beyond the input 01409 // index value (index search case) or corresponds to the 01410 // name we are looking for (name search case). 01411 // 01412 01413 do { 01414 01415 // 01416 // If we have passed the index value then exit. 01417 // 01418 01419 if (CompoundDirContext->FileIndex.QuadPart > FileIndex) { 01420 01421 Found = FALSE; 01422 break; 01423 } 01424 01425 // 01426 // Remember the current position in case we need to go back. 01427 // 01428 01429 LastFileIndex = CompoundDirContext->FileIndex.QuadPart; 01430 01431 // 01432 // Exit if the next entry is beyond the desired index value. 01433 // 01434 01435 if (LastFileIndex + ISONsrFidSize( CompoundDirContext->DirContext.Fid ) > FileIndex) { 01436 01437 break; 01438 } 01439 01440 Found = UdfLookupNextFileIndex( IrpContext, Fcb, CompoundDirContext ); 01441 01442 } while (Found); 01443 01444 // 01445 // If we didn't find the entry then go back to the last known entry. 01446 // 01447 01448 if (!Found) { 01449 01450 UdfCleanupDirContext( IrpContext, &CompoundDirContext->DirContext ); 01451 UdfInitializeDirContext( IrpContext, &CompoundDirContext->DirContext ); 01452 01453 Found = UdfLookupInitialFileIndex( IrpContext, Fcb, CompoundDirContext, &LastFileIndex ); 01454 01455 ASSERT( Found ); 01456 } 01457 } 01458 } 01459 } 01460 01461 // 01462 // Only update the dirent name if we will need it for some reason. 01463 // Don't update this name if we are returning the next entry, and 01464 // don't update it if it was already done. 01465 // 01466 01467 if (!(*ReturnNextEntry) && 01468 CompoundDirContext->DirContext.PureObjectName.Buffer == NULL) { 01469 01470 // 01471 // Update the names in the dirent. 01472 // 01473 01474 UdfUpdateDirNames( IrpContext, 01475 &CompoundDirContext->DirContext, 01476 BooleanFlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )); 01477 } 01478 01479 // 01480 // Look at the flag in the IrpSp indicating whether to return just 01481 // one entry. 01482 // 01483 01484 *ReturnSingleEntry = FALSE; 01485 01486 if (FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )) { 01487 01488 *ReturnSingleEntry = TRUE; 01489 } 01490 01491 return; 01492 }

INLINE BOOLEAN UdfIsFileIndexVirtual LONGLONG  FileIndex  ) 
 

Definition at line 171 of file dirctrl.c.

References UDF_FILE_INDEX_PHYSICAL.

Referenced by UdfLookupFileEntryInEnumeration(), UdfLookupInitialFileIndex(), and UdfLookupNextFileIndex().

00174 { 00175 00176 return FileIndex < UDF_FILE_INDEX_PHYSICAL; 00177 }

VOID UdfLookupFileEntryInEnumeration IN PIRP_CONTEXT  IrpContext,
IN PFCB  Fcb,
IN PCOMPOUND_DIR_ENUM_CONTEXT  CompoundDirContext
 

Definition at line 1688 of file dirctrl.c.

References ASSERT, ICBFILE::Destag, DESTAG_ID_NSR_FILE, ICBTAG::FileType, FlagOn, NSR_FID::Flags, NSR_FID::Icb, ICBFILE::Icbtag, ICBTAG_FILE_T_BLOCK_DEV, ICBTAG_FILE_T_C_ISSOCK, ICBTAG_FILE_T_CHAR_DEV, ICBTAG_FILE_T_DIRECTORY, ICBTAG_FILE_T_FIFO, ICBTAG_FILE_T_FILE, ICBTAG_FILE_T_PATHLINK, DESTAG::Ident, NSRLBA::Lbn, NSRLENGTH::Length, LONGAD::Length, NSR_FID_F_DIRECTORY, NULL, NSRLBA::Partition, LONGAD::Start, UdfCleanupIcbContext(), UdfInitializeIcbContext(), UdfInitializeIcbContextFromFcb(), UdfIsFileIndexVirtual(), UdfLookupActiveIcb(), and UdfRaiseStatus().

Referenced by UdfQueryDirectory().

01696 : 01697 01698 This routine retrieves the file entry associated with the current location in 01699 the enumeration of a compound directory context. 01700 01701 Arguments: 01702 01703 Fcb - the directory being enumerated. 01704 01705 CompoundDirContext - a corresponding context for the enumeration. 01706 01707 Return Value: 01708 01709 None. Status may be raised on discovery of corruption. 01710 01711 --*/ 01712 01713 { 01714 PNSR_FID Fid; 01715 PICBFILE Fe; 01716 01717 Fid = CompoundDirContext->DirContext.Fid; 01718 01719 // 01720 // Figure out where the ICB we want is. 01721 // 01722 01723 if (UdfIsFileIndexVirtual( CompoundDirContext->FileIndex.QuadPart )) { 01724 01725 // 01726 // Synthesize! We only have to synthesize the self entry. The name is already done, 01727 // so the remaining work is trivial. 01728 // 01729 01730 ASSERT( Fid == NULL ); 01731 01732 // 01733 // Lift the FE corresponding to this directory 01734 // 01735 01736 UdfCleanupIcbContext( IrpContext, &CompoundDirContext->IcbContext ); 01737 01738 UdfInitializeIcbContextFromFcb( IrpContext, 01739 &CompoundDirContext->IcbContext, 01740 Fcb ); 01741 01742 } else { 01743 01744 // 01745 // Lift the FE corresponding to this FID. 01746 // 01747 01748 ASSERT( Fid != NULL ); 01749 01750 UdfCleanupIcbContext( IrpContext, &CompoundDirContext->IcbContext ); 01751 01752 UdfInitializeIcbContext( IrpContext, 01753 &CompoundDirContext->IcbContext, 01754 Fcb->Vcb, 01755 DESTAG_ID_NSR_FILE, 01756 Fid->Icb.Start.Partition, 01757 Fid->Icb.Start.Lbn, 01758 Fid->Icb.Length.Length ); 01759 } 01760 01761 // 01762 // Retrieve the ICB for inspection. 01763 // 01764 01765 UdfLookupActiveIcb( IrpContext, &CompoundDirContext->IcbContext ); 01766 01767 Fe = (PICBFILE) CompoundDirContext->IcbContext.Active.View; 01768 01769 // 01770 // Perform some basic verification that the FE is of the proper type and that 01771 // FID and FE agree as to the type of the object. We explicitly check that 01772 // a legal filesystem-level FE type is discovered, even though we don't support 01773 // them in other paths. 01774 // 01775 01776 if (Fe->Destag.Ident != DESTAG_ID_NSR_FILE || 01777 01778 (((Fid && FlagOn( Fid->Flags, NSR_FID_F_DIRECTORY )) || 01779 Fid == NULL) && 01780 Fe->Icbtag.FileType != ICBTAG_FILE_T_DIRECTORY) || 01781 01782 (Fe->Icbtag.FileType != ICBTAG_FILE_T_FILE && 01783 Fe->Icbtag.FileType != ICBTAG_FILE_T_DIRECTORY && 01784 Fe->Icbtag.FileType != ICBTAG_FILE_T_BLOCK_DEV && 01785 Fe->Icbtag.FileType != ICBTAG_FILE_T_CHAR_DEV && 01786 Fe->Icbtag.FileType != ICBTAG_FILE_T_FIFO && 01787 Fe->Icbtag.FileType != ICBTAG_FILE_T_C_ISSOCK && 01788 Fe->Icbtag.FileType != ICBTAG_FILE_T_PATHLINK)) { 01789 01790 UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR ); 01791 } 01792 }

BOOLEAN UdfLookupInitialFileIndex IN PIRP_CONTEXT  IrpContext,
IN PFCB  Fcb,
IN PCOMPOUND_DIR_ENUM_CONTEXT  CompoundDirContext,
IN PLONGLONG  InitialIndex
 

Definition at line 1800 of file dirctrl.c.

References TRUE, UDF_FILE_INDEX_VIRTUAL_SELF, UdfFileIndexToPhysicalOffset(), UdfIsFileIndexVirtual(), and UdfLookupInitialDirEntry().

Referenced by UdfInitializeEnumeration().

01809 : 01810 01811 This routine begins the enumeration of a directory by setting the context 01812 at the first avaliable virtual directory entry. 01813 01814 Arguments: 01815 01816 Fcb - the directory being enumerated. 01817 01818 CompoundDirContext - a corresponding context for the enumeration. 01819 01820 InitialIndex - an optional starting file index to base the enumeration. 01821 01822 Return Value: 01823 01824 TRUE will be returned if a valid entry is found at this offset, FALSE otherwise. 01825 01826 --*/ 01827 01828 { 01829 LONGLONG DirOffset; 01830 01831 if (UdfIsFileIndexVirtual( *InitialIndex )) { 01832 01833 // 01834 // We only synthesize a single virtual directory entry. Position the context 01835 // at the virtual self entry. 01836 // 01837 01838 CompoundDirContext->FileIndex.QuadPart = UDF_FILE_INDEX_VIRTUAL_SELF; 01839 01840 return TRUE; 01841 } 01842 01843 CompoundDirContext->FileIndex.QuadPart = *InitialIndex; 01844 01845 // 01846 // Find the base offset in the directory and look it up. 01847 // 01848 01849 DirOffset = UdfFileIndexToPhysicalOffset( *InitialIndex ); 01850 01851 return UdfLookupInitialDirEntry( IrpContext, 01852 Fcb, 01853 &CompoundDirContext->DirContext, 01854 &DirOffset ); 01855 }

BOOLEAN UdfLookupNextFileIndex IN PIRP_CONTEXT  IrpContext,
IN PFCB  Fcb,
IN PCOMPOUND_DIR_ENUM_CONTEXT  CompoundDirContext
 

Definition at line 1863 of file dirctrl.c.

References ISONsrFidSize, NULL, UDF_FILE_INDEX_PHYSICAL, UdfIsFileIndexVirtual(), UdfLookupInitialDirEntry(), and UdfLookupNextDirEntry().

Referenced by UdfEnumerateIndex(), and UdfInitializeEnumeration().

01871 : 01872 01873 This routine advances the enumeration of a virtual directory by one entry. 01874 01875 Arguments: 01876 01877 Fcb - the directory being enumerated. 01878 01879 CompoundDirContext - a corresponding context for the enumeration. 01880 01881 Return Value: 01882 01883 BOOLEAN True if another Fid is avaliable, False if we are at the end. 01884 01885 --*/ 01886 01887 { 01888 ULONG Advance; 01889 BOOLEAN Result; 01890 01891 // 01892 // Advance from the synthesized to the physical directory. 01893 // 01894 01895 if (UdfIsFileIndexVirtual( CompoundDirContext->FileIndex.QuadPart )) { 01896 01897 Result = UdfLookupInitialDirEntry( IrpContext, 01898 Fcb, 01899 &CompoundDirContext->DirContext, 01900 NULL ); 01901 01902 if (Result) { 01903 01904 CompoundDirContext->FileIndex.QuadPart = UDF_FILE_INDEX_PHYSICAL; 01905 } 01906 01907 return Result; 01908 } 01909 01910 Advance = ISONsrFidSize( CompoundDirContext->DirContext.Fid ); 01911 01912 // 01913 // Advance to the next entry in this directory. 01914 // 01915 01916 Result = UdfLookupNextDirEntry( IrpContext, Fcb, &CompoundDirContext->DirContext ); 01917 01918 if (Result) { 01919 01920 CompoundDirContext->FileIndex.QuadPart += Advance; 01921 } 01922 01923 return Result; 01924 }

NTSTATUS UdfNotifyChangeDirectory IN PIRP_CONTEXT  IrpContext,
IN PIRP  Irp,
IN PIO_STACK_LOCATION  IrpSp,
IN PCCB  Ccb
 

Definition at line 904 of file dirctrl.c.

References BooleanFlagOn, FALSE, FsRtlNotifyFullChangeDirectory(), Irp, IRP_CONTEXT_FLAG_WAIT, NULL, PAGED_CODE, SetFlag, SL_WATCH_TREE, UdfAcquireVcbShared, UdfCompleteRequest(), UdfReleaseVcb, and UdfVerifyVcb().

Referenced by UdfCommonDirControl().

00913 : 00914 00915 This routine performs the notify change directory operation. It is 00916 responsible for either completing of enqueuing the input Irp. Although there 00917 will never be a notify signalled on a readonly disk we still support this call. 00918 00919 We have already checked that this is not an OpenById handle. 00920 00921 Arguments: 00922 00923 Irp - Supplies the Irp to process 00924 00925 IrpSp - Io stack location for this request. 00926 00927 Ccb - Handle to the directory being watched. 00928 00929 Return Value: 00930 00931 NTSTATUS - STATUS_PENDING, any other error will raise. 00932 00933 --*/ 00934 00935 { 00936 PAGED_CODE(); 00937 00938 // 00939 // Always set the wait bit in the IrpContext so the initial wait can't fail. 00940 // 00941 00942 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 00943 00944 // 00945 // Acquire the Vcb shared. 00946 // 00947 00948 UdfAcquireVcbShared( IrpContext, IrpContext->Vcb, FALSE ); 00949 00950 // 00951 // Use a try-finally to facilitate cleanup. 00952 // 00953 00954 try { 00955 00956 // 00957 // Verify the Vcb. 00958 // 00959 00960 UdfVerifyVcb( IrpContext, IrpContext->Vcb ); 00961 00962 // 00963 // Call the Fsrtl package to process the request. We cast the 00964 // unicode strings to ansi strings as the dir notify package 00965 // only deals with memory matching. 00966 // 00967 00968 FsRtlNotifyFullChangeDirectory( IrpContext->Vcb->NotifySync, 00969 &IrpContext->Vcb->DirNotifyList, 00970 Ccb, 00971 (PSTRING) &IrpSp->FileObject->FileName, 00972 BooleanFlagOn( IrpSp->Flags, SL_WATCH_TREE ), 00973 FALSE, 00974 IrpSp->Parameters.NotifyDirectory.CompletionFilter, 00975 Irp, 00976 NULL, 00977 NULL ); 00978 00979 } finally { 00980 00981 // 00982 // Release the Vcb. 00983 // 00984 00985 UdfReleaseVcb( IrpContext, IrpContext->Vcb ); 00986 } 00987 00988 // 00989 // Cleanup the IrpContext. 00990 // 00991 00992 UdfCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); 00993 00994 return STATUS_PENDING; 00995 }

INLINE LONGLONG UdfPhysicalOffsetToFileIndex LONGLONG  PhysicalOffset  ) 
 

Definition at line 161 of file dirctrl.c.

References UDF_FILE_INDEX_PHYSICAL.

00164 { 00165 00166 return PhysicalOffset + UDF_FILE_INDEX_PHYSICAL; 00167 }

NTSTATUS UdfQueryDirectory IN PIRP_CONTEXT  IrpContext,
IN PIRP  Irp,
IN PIO_STACK_LOCATION  IrpSp,
IN PFCB  Fcb,
IN PCCB  Ccb
 

Definition at line 334 of file dirctrl.c.

References _TIMESTAMP_BUNDLE::AccessTime, _ICB_SEARCH_CONTEXT::Active, Add2Ptr, BYTE_COUNT_8_DOT_3, _DIR_ENUM_CONTEXT::CaseObjectName, CCB_FLAG_ENUM_RETURN_NEXT, ClearFlag, _TIMESTAMP_BUNDLE::CreationTime, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT, _COMPOUND_DIR_ENUM_CONTEXT::DirContext, EXCEPTION_CONTINUE_SEARCH, EXCEPTION_EXECUTE_HANDLER, FALSE, _DIR_ENUM_CONTEXT::Fid, _COMPOUND_DIR_ENUM_CONTEXT::FileIndex, FileName, ICBTAG::FileType, FlagOn, _DIR_ENUM_CONTEXT::Flags, NSR_FID::Flags, FsRtlIsNtstatusExpected(), _COMPOUND_DIR_ENUM_CONTEXT::IcbContext, ICBFILE::Icbtag, ICBTAG_FILE_T_DIRECTORY, ICBFILE::InfoLength, _IRP::IoStatus, Irp, LlBlockAlign, _TIMESTAMP_BUNDLE::ModificationTime, NSR_FID_F_HIDDEN, NT_ERROR, NTSTATUS(), _DIR_ENUM_CONTEXT::ObjectName, PAGED_CODE, PICBFILE, _DIR_ENUM_CONTEXT::PureObjectName, QuadAlign, SetFlag, _DIR_ENUM_CONTEXT::ShortObjectName, Status, _COMPOUND_DIR_ENUM_CONTEXT::Timestamps, TRUE, try_leave, UdfAcquireFileShared, UdfCleanupCompoundDirContext(), UdfCompleteRequest(), UdfEnumerateIndex(), UdfGenerate8dot3Name(), UdfInitializeCompoundDirContext(), UdfInitializeEnumeration(), UdfIs8dot3Name(), UdfLockFcb, UdfLookupFileEntryInEnumeration(), UdfMapUserBuffer, UdfReleaseFile, UdfUnlockFcb, UdfUpdateTimestampsFromIcbContext(), UdfVerifyFcbOperation(), and _MAPPED_PVIEW::View.

Referenced by UdfCommonDirControl().

00344 : 00345 00346 This routine performs the query directory operation. It is responsible 00347 for either completing of enqueuing the input Irp. We store the state of the 00348 search in the Ccb. 00349 00350 Arguments: 00351 00352 Irp - Supplies the Irp to process 00353 00354 IrpSp - Stack location for this Irp. 00355 00356 Fcb - Fcb for this directory. 00357 00358 Ccb - Ccb for this directory open. 00359 00360 Return Value: 00361 00362 NTSTATUS - The return status for the operation 00363 00364 --*/ 00365 00366 { 00367 NTSTATUS Status = STATUS_SUCCESS; 00368 ULONG Information = 0; 00369 00370 ULONG LastEntry = 0; 00371 ULONG NextEntry = 0; 00372 00373 ULONG FileNameBytes; 00374 ULONG BytesConverted; 00375 00376 COMPOUND_DIR_ENUM_CONTEXT CompoundDirContext; 00377 00378 PNSR_FID ThisFid; 00379 PICBFILE ThisFe; 00380 00381 BOOLEAN InitialQuery; 00382 BOOLEAN ReturnNextEntry; 00383 BOOLEAN ReturnSingleEntry; 00384 BOOLEAN Found; 00385 00386 PCHAR UserBuffer; 00387 ULONG BytesRemainingInBuffer; 00388 00389 ULONG BaseLength; 00390 00391 PFILE_BOTH_DIR_INFORMATION DirInfo; 00392 PFILE_NAMES_INFORMATION NamesInfo; 00393 00394 PAGED_CODE(); 00395 00396 // 00397 // Check if we support this search mode. Also remember the size of the base part of 00398 // each of these structures. 00399 // 00400 00401 switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) { 00402 00403 case FileDirectoryInformation: 00404 00405 BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, 00406 FileName[0] ); 00407 break; 00408 00409 case FileFullDirectoryInformation: 00410 00411 BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, 00412 FileName[0] ); 00413 break; 00414 00415 case FileNamesInformation: 00416 00417 BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, 00418 FileName[0] ); 00419 break; 00420 00421 case FileBothDirectoryInformation: 00422 00423 BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, 00424 FileName[0] ); 00425 break; 00426 00427 default: 00428 00429 UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_INFO_CLASS ); 00430 return STATUS_INVALID_INFO_CLASS; 00431 } 00432 00433 // 00434 // Get the user buffer. 00435 // 00436 00437 UdfMapUserBuffer( IrpContext, &UserBuffer); 00438 00439 // 00440 // Initialize our search context. 00441 // 00442 00443 UdfInitializeCompoundDirContext( IrpContext, &CompoundDirContext ); 00444 00445 // 00446 // Acquire the directory. 00447 // 00448 00449 UdfAcquireFileShared( IrpContext, Fcb ); 00450 00451 // 00452 // Use a try-finally to facilitate cleanup. 00453 // 00454 00455 try { 00456 00457 // 00458 // Verify the Fcb is still good. 00459 // 00460 00461 UdfVerifyFcbOperation( IrpContext, Fcb ); 00462 00463 // 00464 // Start by getting the initial state for the enumeration. This will set up the Ccb with 00465 // the initial search parameters and let us know the starting offset in the directory 00466 // to search. 00467 // 00468 00469 UdfInitializeEnumeration( IrpContext, 00470 IrpSp, 00471 Fcb, 00472 Ccb, 00473 &CompoundDirContext, 00474 &ReturnNextEntry, 00475 &ReturnSingleEntry, 00476 &InitialQuery ); 00477 00478 // 00479 // At this point we are about to enter our query loop. We have 00480 // determined the index into the directory file to begin the 00481 // search. LastEntry and NextEntry are used to index into the user 00482 // buffer. LastEntry is the last entry we've added, NextEntry is 00483 // current one we're working on. If NextEntry is non-zero, then 00484 // at least one entry was added. 00485 // 00486 00487 while (TRUE) { 00488 00489 // 00490 // If the user had requested only a single match and we have 00491 // returned that, then we stop at this point. We update the Ccb with 00492 // the status based on the last entry returned. 00493 // 00494 00495 if ((NextEntry != 0) && ReturnSingleEntry) { 00496 00497 try_leave( Status ); 00498 } 00499 00500 // 00501 // We try to locate the next matching dirent. Our search if based on a starting 00502 // dirent offset, whether we should return the current or next entry, whether 00503 // we should be doing a short name search and finally whether we should be 00504 // checking for a version match. 00505 // 00506 00507 Found = UdfEnumerateIndex( IrpContext, Ccb, &CompoundDirContext, ReturnNextEntry ); 00508 00509 // 00510 // Initialize the value for the next search. 00511 // 00512 00513 ReturnNextEntry = TRUE; 00514 00515 // 00516 // If we didn't receive a dirent, then we are at the end of the 00517 // directory. If we have returned any files, we exit with 00518 // success, otherwise we return STATUS_NO_MORE_FILES. 00519 // 00520 00521 if (!Found) { 00522 00523 if (NextEntry == 0) { 00524 00525 Status = STATUS_NO_MORE_FILES; 00526 00527 if (InitialQuery) { 00528 00529 Status = STATUS_NO_SUCH_FILE; 00530 } 00531 } 00532 00533 try_leave( Status ); 00534 } 00535 00536 // 00537 // Remember the dirent/file entry for the file we just found. 00538 // 00539 00540 ThisFid = CompoundDirContext.DirContext.Fid; 00541 00542 // 00543 // Here are the rules concerning filling up the buffer: 00544 // 00545 // 1. The Io system garentees that there will always be 00546 // enough room for at least one base record. 00547 // 00548 // 2. If the full first record (including file name) cannot 00549 // fit, as much of the name as possible is copied and 00550 // STATUS_BUFFER_OVERFLOW is returned. 00551 // 00552 // 3. If a subsequent record cannot completely fit into the 00553 // buffer, none of it (as in 0 bytes) is copied, and 00554 // STATUS_SUCCESS is returned. A subsequent query will 00555 // pick up with this record. 00556 // 00557 00558 // 00559 // We can look directly at the dirent that we found. 00560 // 00561 00562 FileNameBytes = CompoundDirContext.DirContext.CaseObjectName.Length; 00563 00564 // 00565 // If the slot for the next entry would be beyond the length of the 00566 // user's buffer just exit (we know we've returned at least one entry 00567 // already). This will happen when we align the pointer past the end. 00568 // 00569 00570 if (NextEntry > IrpSp->Parameters.QueryDirectory.Length) { 00571 00572 ReturnNextEntry = FALSE; 00573 try_leave( Status = STATUS_SUCCESS ); 00574 } 00575 00576 // 00577 // Compute the number of bytes remaining in the buffer. Round this 00578 // down to a WCHAR boundary so we can copy full characters. 00579 // 00580 00581 BytesRemainingInBuffer = IrpSp->Parameters.QueryDirectory.Length - NextEntry; 00582 ClearFlag( BytesRemainingInBuffer, 1 ); 00583 00584 // 00585 // If this won't fit and we have returned a previous entry then just 00586 // return STATUS_SUCCESS. 00587 // 00588 00589 if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) { 00590 00591 // 00592 // If we already found an entry then just exit. 00593 // 00594 00595 if (NextEntry != 0) { 00596 00597 ReturnNextEntry = FALSE; 00598 try_leave( Status = STATUS_SUCCESS ); 00599 } 00600 00601 // 00602 // Reduce the FileNameBytes to just fit in the buffer. 00603 // 00604 00605 FileNameBytes = BytesRemainingInBuffer - BaseLength; 00606 00607 // 00608 // Use a status code of STATUS_BUFFER_OVERFLOW. Also set 00609 // ReturnSingleEntry so that we will exit the loop at the top. 00610 // 00611 00612 Status = STATUS_BUFFER_OVERFLOW; 00613 ReturnSingleEntry = TRUE; 00614 } 00615 00616 // 00617 // Protect access to the user buffer with an exception handler. 00618 // Since (at our request) IO doesn't buffer these requests, we have 00619 // to guard against a user messing with the page protection and other 00620 // such trickery. 00621 // 00622 00623 try { 00624 00625 // 00626 // Zero and initialize the base part of the current entry. 00627 // 00628 00629 RtlZeroMemory( Add2Ptr( UserBuffer, NextEntry, PVOID ), 00630 BaseLength ); 00631 00632 // 00633 // Now we have an entry to return to our caller. 00634 // We'll case on the type of information requested and fill up 00635 // the user buffer if everything fits. 00636 // 00637 00638 switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) { 00639 00640 case FileBothDirectoryInformation: 00641 case FileFullDirectoryInformation: 00642 case FileDirectoryInformation: 00643 00644 DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION ); 00645 00646 // 00647 // These information types require we look up the file entry. 00648 // 00649 00650 UdfLookupFileEntryInEnumeration( IrpContext, 00651 Fcb, 00652 &CompoundDirContext ); 00653 // 00654 // Directly reference the file entry we just looked up. 00655 // 00656 00657 ThisFe = (PICBFILE) CompoundDirContext.IcbContext.Active.View; 00658 00659 // 00660 // Now go gather all of the timestamps for this guy. 00661 // 00662 00663 UdfUpdateTimestampsFromIcbContext ( IrpContext, 00664 &CompoundDirContext.IcbContext, 00665 &CompoundDirContext.Timestamps ); 00666 00667 DirInfo->CreationTime = CompoundDirContext.Timestamps.CreationTime; 00668 00669 DirInfo->LastWriteTime = 00670 DirInfo->ChangeTime = CompoundDirContext.Timestamps.ModificationTime; 00671 00672 DirInfo->LastAccessTime = CompoundDirContext.Timestamps.AccessTime; 00673 00674 // 00675 // Set the attributes and sizes separately for directories and 00676 // files. 00677 // 00678 00679 if (ThisFe->Icbtag.FileType == ICBTAG_FILE_T_DIRECTORY) { 00680 00681 DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0; 00682 00683 SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY ); 00684 00685 } else { 00686 00687 DirInfo->EndOfFile.QuadPart = ThisFe->InfoLength; 00688 DirInfo->AllocationSize.QuadPart = LlBlockAlign( Fcb->Vcb, ThisFe->InfoLength ); 00689 } 00690 00691 // 00692 // All Cdrom files are readonly. We also copy the existence 00693 // bit to the hidden attribute, assuming that synthesized FIDs 00694 // are never hidden. 00695 // 00696 00697 SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY ); 00698 00699 if (ThisFid && FlagOn( ThisFid->Flags, NSR_FID_F_HIDDEN )) { 00700 00701 SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN ); 00702 } 00703 00704 // 00705 // The file index for real file indices > 2^32 is zero. When asked to 00706 // restart at an index of zero, we will know to use a stashed starting 00707 // point to beging to search, by name, for the correct restart point. 00708 // 00709 00710 if (CompoundDirContext.FileIndex.HighPart == 0) { 00711 00712 DirInfo->FileIndex = CompoundDirContext.FileIndex.LowPart; 00713 00714 } else { 00715 00716 DirInfo->FileIndex = 0; 00717 } 00718 00719 DirInfo->FileNameLength = FileNameBytes; 00720 00721 break; 00722 00723 case FileNamesInformation: 00724 00725 NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION ); 00726 00727 if (CompoundDirContext.FileIndex.HighPart == 0) { 00728 00729 NamesInfo->FileIndex = CompoundDirContext.FileIndex.LowPart; 00730 00731 } else { 00732 00733 NamesInfo->FileIndex = 0; 00734 } 00735 00736 NamesInfo->FileNameLength = FileNameBytes; 00737 00738 break; 00739 } 00740 00741 // 00742 // Now copy as much of the name as possible. 00743 // 00744 00745 if (FileNameBytes != 0) { 00746 00747 // 00748 // This is a Unicode name, we can copy the bytes directly. 00749 // 00750 00751 RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ), 00752 CompoundDirContext.DirContext.ObjectName.Buffer, 00753 FileNameBytes ); 00754 } 00755 00756 // 00757 // Fill in the short name if we got STATUS_SUCCESS. The short name 00758 // may already be in the file context, otherwise we will check 00759 // whether the long name is 8.3. Special case the self and parent 00760 // directory names. 00761 // 00762 00763 if ((Status == STATUS_SUCCESS) && 00764 (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation) && 00765 FlagOn( CompoundDirContext.DirContext.Flags, DIR_CONTEXT_FLAG_SEEN_NONCONSTANT )) { 00766 00767 // 00768 // If we already have the short name then copy into the user's buffer. 00769 // 00770 00771 if (CompoundDirContext.DirContext.ShortObjectName.Length != 0) { 00772 00773 RtlCopyMemory( DirInfo->ShortName, 00774 CompoundDirContext.DirContext.ShortObjectName.Buffer, 00775 CompoundDirContext.DirContext.ShortObjectName.Length ); 00776 00777 DirInfo->ShortNameLength = (CCHAR) CompoundDirContext.DirContext.ShortObjectName.Length; 00778 00779 // 00780 // If the short name length is currently zero then check if 00781 // the long name is not 8.3. We can copy the short name in 00782 // unicode form directly into the caller's buffer. 00783 // 00784 00785 } else { 00786 00787 if (!UdfIs8dot3Name( IrpContext, 00788 CompoundDirContext.DirContext.ObjectName )) { 00789 00790 UNICODE_STRING ShortName; 00791 00792 ShortName.Buffer = DirInfo->ShortName; 00793 ShortName.MaximumLength = BYTE_COUNT_8_DOT_3; 00794 00795 UdfGenerate8dot3Name( IrpContext, 00796 &CompoundDirContext.DirContext.PureObjectName, 00797 &ShortName ); 00798 00799 DirInfo->ShortNameLength = (CCHAR) ShortName.Length; 00800 } 00801 } 00802 } 00803 00804 // 00805 // Update the information with the number of bytes stored in the 00806 // buffer. We quad-align the existing buffer to add any necessary 00807 // pad bytes. 00808 // 00809 00810 Information = NextEntry + BaseLength + FileNameBytes; 00811 00812 // 00813 // Go back to the previous entry and fill in the update to this entry. 00814 // 00815 00816 *(Add2Ptr( UserBuffer, LastEntry, PULONG )) = NextEntry - LastEntry; 00817 00818 // 00819 // Set up our variables for the next dirent. 00820 // 00821 00822 InitialQuery = FALSE; 00823 00824 LastEntry = NextEntry; 00825 NextEntry = QuadAlign( Information ); 00826 00827 } except (!FsRtlIsNtstatusExpected(GetExceptionCode()) ? 00828 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 00829 00830 // 00831 // We must have had a problem filling in the user's buffer, so stop 00832 // and fail this request. 00833 // 00834 00835 Information = 0; 00836 try_leave( Status = GetExceptionCode()); 00837 } 00838 } 00839 00840 } finally { 00841 00842 if (!AbnormalTermination() && !NT_ERROR( Status )) { 00843 00844 // 00845 // Update the Ccb to show the current state of the enumeration. 00846 // 00847 00848 UdfLockFcb( IrpContext, Fcb ); 00849 00850 Ccb->CurrentFileIndex = CompoundDirContext.FileIndex.QuadPart; 00851 00852 // 00853 // Update our notion of a high 32bit file index. We only do this once to avoid the hit 00854 // of thrashing the Fcb mutex to do this for every entry. If it is ever neccesary to use 00855 // this information, the difference of a few dozen entries from the optimal pick-up point 00856 // will be trivial. 00857 // 00858 00859 if (CompoundDirContext.FileIndex.HighPart == 0 && 00860 CompoundDirContext.FileIndex.LowPart > Ccb->HighestReturnableFileIndex) { 00861 00862 Ccb->HighestReturnableFileIndex = CompoundDirContext.FileIndex.LowPart; 00863 } 00864 00865 ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT ); 00866 00867 if (ReturnNextEntry) { 00868 00869 SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT ); 00870 } 00871 00872 UdfUnlockFcb( IrpContext, Fcb ); 00873 } 00874 00875 // 00876 // Cleanup our search context. 00877 // 00878 00879 UdfCleanupCompoundDirContext( IrpContext, &CompoundDirContext ); 00880 00881 // 00882 // Release the Fcb. 00883 // 00884 00885 UdfReleaseFile( IrpContext, Fcb ); 00886 } 00887 00888 // 00889 // Complete the request here. 00890 // 00891 00892 Irp->IoStatus.Information = Information; 00893 00894 UdfCompleteRequest( IrpContext, Irp, Status ); 00895 return Status; 00896 }


Generated on Sat May 15 19:43:27 2004 for test by doxygen 1.3.7