📄 dirctrl.c
字号:
// strings.
//
if ((WildCardName.VersionString.Length == sizeof( WCHAR )) &&
(WildCardName.VersionString.Buffer[0] == L'*')) {
SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL );
}
}
//
// Now create the search expression to store in the Ccb.
//
SearchExpression.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
FileName->Length,
TAG_ENUM_EXPRESSION );
SearchExpression.FileName.MaximumLength = FileName->Length;
//
// Either copy the name directly or perform the upcase.
//
if (FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )) {
Status = RtlUpcaseUnicodeString( (PUNICODE_STRING) &SearchExpression.FileName,
FileName,
FALSE );
//
// This should never fail.
//
ASSERT( Status == STATUS_SUCCESS );
} else {
RtlCopyMemory( SearchExpression.FileName.Buffer,
FileName->Buffer,
FileName->Length );
}
//
// Now split into the separate name and version components.
//
SearchExpression.FileName.Length = WildCardName.FileName.Length;
SearchExpression.VersionString.Length = WildCardName.VersionString.Length;
SearchExpression.VersionString.MaximumLength = WildCardName.VersionString.MaximumLength;
SearchExpression.VersionString.Buffer = Add2Ptr( SearchExpression.FileName.Buffer,
SearchExpression.FileName.Length + sizeof( WCHAR ),
PWCHAR );
}
//
// But we do not want to return the constant "." and ".." entries for
// the root directory, for consistency with the rest of Microsoft's
// filesystems.
//
if (Fcb == Fcb->Vcb->RootIndexFcb) {
SetFlag( CcbFlags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY );
}
//
// Now lock the Fcb in order to update the Ccb with the inital
// enumeration values.
//
CdLockFcb( IrpContext, Fcb );
//
// Check again that this is the initial search.
//
if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) {
//
// Update the values in the Ccb.
//
Ccb->CurrentDirentOffset = Fcb->StreamOffset;
Ccb->SearchExpression = SearchExpression;
//
// Set the appropriate flags in the Ccb.
//
SetFlag( Ccb->Flags, CcbFlags | CCB_FLAG_ENUM_INITIALIZED );
//
// Otherwise cleanup any buffer allocated here.
//
} else {
if (!FlagOn( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL )) {
CdFreePool( &SearchExpression.FileName.Buffer );
}
}
//
// Otherwise lock the Fcb so we can read the current enumeration values.
//
} else {
CdLockFcb( IrpContext, Fcb );
}
//
// Capture the current state of the enumeration.
//
// If the user specified an index then use his offset. We always
// return the next entry in this case.
//
if (FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED )) {
KnownOffset = FALSE;
DirentOffset = IrpSp->Parameters.QueryDirectory.FileIndex;
*ReturnNextEntry = TRUE;
//
// If we are restarting the scan then go from the self entry.
//
} else if (FlagOn( IrpSp->Flags, SL_RESTART_SCAN )) {
KnownOffset = TRUE;
DirentOffset = Fcb->StreamOffset;
*ReturnNextEntry = FALSE;
//
// Otherwise use the values from the Ccb.
//
} else {
KnownOffset = TRUE;
DirentOffset = Ccb->CurrentDirentOffset;
*ReturnNextEntry = BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
}
//
// Unlock the Fcb.
//
CdUnlockFcb( IrpContext, Fcb );
//
// We have the starting offset in the directory and whether to return
// that entry or the next. If we are at the beginning of the directory
// and are returning that entry, then tell our caller this is the
// initial query.
//
*InitialQuery = FALSE;
if ((DirentOffset == Fcb->StreamOffset) &&
!(*ReturnNextEntry)) {
*InitialQuery = TRUE;
}
//
// If there is no file object then create it now.
//
CdVerifyOrCreateDirStreamFile( IrpContext, Fcb);
//
// Determine the offset in the stream to position the FileContext and
// whether this offset is known to be a file offset.
//
// If this offset is known to be safe then go ahead and position the
// file context. This handles the cases where the offset is the beginning
// of the stream, the offset is from a previous search or this is the
// initial query.
//
if (KnownOffset) {
CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, DirentOffset );
//
// Otherwise we walk through the directory from the beginning until
// we reach the entry which contains this offset.
//
} else {
LastDirentOffset = Fcb->StreamOffset;
Found = TRUE;
CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
//
// If the requested offset is prior to the beginning offset in the stream
// then don't return the next entry.
//
if (DirentOffset < LastDirentOffset) {
*ReturnNextEntry = FALSE;
//
// Else look for the last entry which ends past the desired index.
//
} else {
//
// Keep walking through the directory until we run out of
// entries or we find an entry which ends beyond the input
// index value.
//
do {
//
// If we have passed the index value then exit.
//
if (FileContext->InitialDirent->Dirent.DirentOffset > DirentOffset) {
Found = FALSE;
break;
}
//
// Remember the current position in case we need to go back.
//
LastDirentOffset = FileContext->InitialDirent->Dirent.DirentOffset;
//
// Exit if the next entry is beyond the desired index value.
//
if (LastDirentOffset + FileContext->InitialDirent->Dirent.DirentLength > DirentOffset) {
break;
}
Found = CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext );
} while (Found);
//
// If we didn't find the entry then go back to the last known entry.
// This can happen if the index lies in the unused range at the
// end of a sector.
//
if (!Found) {
CdCleanupFileContext( IrpContext, FileContext );
CdInitializeFileContext( IrpContext, FileContext );
CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
}
}
}
//
// Only update the dirent name if we will need it for some reason.
// Don't update this name if we are returning the next entry and
// the search string has a version component.
//
FileContext->ShortName.FileName.Length = 0;
if (!(*ReturnNextEntry) ||
(Ccb->SearchExpression.VersionString.Length == 0)) {
//
// Update the name in the dirent into filename and version components.
//
CdUpdateDirentName( IrpContext,
&FileContext->InitialDirent->Dirent,
FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
}
//
// Look at the flag in the IrpSp indicating whether to return just
// one entry.
//
*ReturnSingleEntry = FALSE;
if (FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )) {
*ReturnSingleEntry = TRUE;
}
return;
}
//
// Local support routine
//
BOOLEAN
CdEnumerateIndex (
IN PIRP_CONTEXT IrpContext,
IN PCCB Ccb,
IN OUT PFILE_ENUM_CONTEXT FileContext,
IN BOOLEAN ReturnNextEntry
)
/*++
Routine Description:
This routine is the worker routine for index enumeration. We are positioned
at some dirent in the directory and will either return the first match
at that point or look to the next entry. The Ccb contains details about
the type of matching to do. If the user didn't specify a version in
his search string then we only return the first version of a sequence
of files with versions. We also don't return any associated files.
Arguments:
Ccb - Ccb for this directory handle.
FileContext - File context already positioned at some entry in the directory.
ReturnNextEntry - Indicates if we are returning this entry or should start
with the next entry.
Return Value:
BOOLEAN - TRUE if next entry is found, FALSE otherwise.
--*/
{
PDIRENT PreviousDirent = NULL;
PDIRENT ThisDirent = &FileContext->InitialDirent->Dirent;
BOOLEAN Found = FALSE;
PAGED_CODE();
//
// Loop until we find a match or exaust the directory.
//
while (TRUE) {
//
// Move to the next entry unless we want to consider the current
// entry.
//
if (ReturnNextEntry) {
if (!CdLookupNextInitialFileDirent( IrpContext, Ccb->Fcb, FileContext )) {
break;
}
PreviousDirent = ThisDirent;
ThisDirent = &FileContext->InitialDirent->Dirent;
CdUpdateDirentName( IrpContext, ThisDirent, FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
} else {
ReturnNextEntry = TRUE;
}
//
// Don't bother if we have a constant entry and are ignoring them.
//
if (FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY ) &&
FlagOn( Ccb->Flags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY )) {
continue;
}
//
// Look at the current entry if it is not an associated file
// and the name doesn't match the previous file if the version
// name is not part of the search.
//
if (!FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_ASSOC )) {
//
// Check if this entry matches the previous entry except
// for version number and whether we should return the
// entry in that case. Go directly to the name comparison
// if:
//
// There is no previous entry.
// The search expression has a version component.
// The name length doesn't match the length of the previous entry.
// The base name strings don't match.
//
if ((PreviousDirent == NULL) ||
(Ccb->SearchExpression.VersionString.Length != 0) ||
(PreviousDirent->CdCaseFileName.FileName.Length != ThisDirent->CdCaseFileName.FileName.Length) ||
FlagOn( PreviousDirent->DirentFlags, CD_ATTRIBUTE_ASSOC ) ||
!RtlEqualMemory( PreviousDirent->CdCaseFileName.FileName.Buffer,
ThisDirent->CdCaseFileName.FileName.Buffer,
ThisDirent->CdCaseFileName.FileName.Length )) {
//
// If we match all names then return to our caller.
//
if (FlagOn( Ccb->Flags, CCB_FLAG_ENUM_MATCH_ALL )) {
FileContext->ShortName.FileName.Length = 0;
Found = TRUE;
break;
}
//
// Check if the long name matches the search expression.
//
if (CdIsNameInExpression( IrpContext,
&ThisDirent->CdCaseFileName,
&Ccb->SearchExpression,
Ccb->Flags,
TRUE )) {
//
// Let our caller know we found an entry.
//
Found = TRUE;
FileContext->ShortName.FileName.Length = 0;
break;
}
//
// The long name didn't match so we need to check for a
// possible short name match. There is no match if the
// long name is 8dot3 or the search expression has a
// version component. Special case the self and parent
// entries.
//
if ((Ccb->SearchExpression.VersionString.Length == 0) &&
!FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY ) &&
!CdIs8dot3Name( IrpContext,
ThisDirent->CdFileName.FileName )) {
CdGenerate8dot3Name( IrpContext,
&ThisDirent->CdCaseFileName.FileName,
ThisDirent->DirentOffset,
FileContext->ShortName.FileName.Buffer,
&FileContext->ShortName.FileName.Length );
//
// Check if this name matches.
//
if (CdIsNameInExpression( IrpContext,
&FileContext->ShortName,
&Ccb->SearchExpression,
Ccb->Flags,
FALSE )) {
//
// Let our caller know we found an entry.
//
Found = TRUE;
break;
}
}
}
}
}
//
// If we found the entry then make sure we walk through all of the
// file dirents.
//
if (Found) {
CdLookupLastFileDirent( IrpContext, Ccb->Fcb, FileContext );
}
return Found;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -