📄 dirsup.c
字号:
((*Dirent)->Attributes == FAT_DIRENT_ATTR_LFN)) {
PLFN_DIRENT Lfn;
Lfn = (PLFN_DIRENT)*Dirent;
if (LfnInProgress) {
//
// Check for a proper continuation of the Lfn in progress.
//
if ((Lfn->Ordinal & FAT_LAST_LONG_ENTRY) ||
(Lfn->Ordinal == 0) ||
(Lfn->Ordinal != Ordinal - 1) ||
(Lfn->Checksum != LfnChecksum) ||
(Lfn->MustBeZero != 0)) {
//
// The Lfn is not proper, stop constructing it.
//
LfnInProgress = FALSE;
} else {
ASSERT( ((LfnIndex % 13) == 0) && LfnIndex );
LfnIndex -= 13;
RtlCopyMemory( &LongFileName->Buffer[LfnIndex+0],
&Lfn->Name1[0],
5*sizeof(WCHAR) );
RtlCopyMemory( &LongFileName->Buffer[LfnIndex+5],
&Lfn->Name2[0],
6 * sizeof(WCHAR) );
RtlCopyMemory( &LongFileName->Buffer[LfnIndex+11],
&Lfn->Name3[0],
2 * sizeof(WCHAR) );
Ordinal = Lfn->Ordinal;
LfnByteOffset = *ByteOffset;
}
}
//
// Now check (maybe again) if we should analyze this entry
// for a possible last entry.
//
if ((!LfnInProgress) &&
(Lfn->Ordinal & FAT_LAST_LONG_ENTRY) &&
((Lfn->Ordinal & ~FAT_LAST_LONG_ENTRY) <= MAX_LFN_DIRENTS) &&
(Lfn->MustBeZero == 0)) {
BOOLEAN CheckTail = FALSE;
Ordinal = Lfn->Ordinal & ~FAT_LAST_LONG_ENTRY;
//
// We're usually permissive (following the lead of Win9x) when we find
// malformation of the LFN dirent pile. I'm not sure this is a good idea,
// so I'm going to trigger corruption on this particularly ugly one. Perhaps
// we should come back and redo the original code here with this in mind in the
// future.
//
if (Ordinal == 0) {
//
// First LFN in the pile was zero marked as the last. This is never
// possible since oridinals are 1-based.
//
FatPopUpFileCorrupt( IrpContext, ParentDirectory );
FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
}
LfnIndex = (Ordinal - 1) * 13;
FatEnsureStringBufferEnough( LongFileName,
(USHORT)((LfnIndex + 13) << 1));
RtlCopyMemory( &LongFileName->Buffer[LfnIndex+0],
&Lfn->Name1[0],
5*sizeof(WCHAR));
RtlCopyMemory( &LongFileName->Buffer[LfnIndex+5],
&Lfn->Name2[0],
6 * sizeof(WCHAR) );
RtlCopyMemory( &LongFileName->Buffer[LfnIndex+11],
&Lfn->Name3[0],
2 * sizeof(WCHAR) );
//
// Now compute the Lfn size and make sure that the tail
// bytes are correct.
//
while (LfnIndex != (ULONG)Ordinal * 13) {
if (!CheckTail) {
if (LongFileName->Buffer[LfnIndex] == 0x0000) {
LfnSize = LfnIndex;
CheckTail = TRUE;
}
} else {
if (LongFileName->Buffer[LfnIndex] != 0xffff) {
break;
}
}
LfnIndex += 1;
}
//
// If we exited this loop prematurely, the LFN is not valid.
//
if (LfnIndex == (ULONG)Ordinal * 13) {
//
// If we didn't find the NULL terminator, then the size
// is LfnIndex.
//
if (!CheckTail) {
LfnSize = LfnIndex;
}
LfnIndex -= 13;
LfnInProgress = TRUE;
LfnChecksum = Lfn->Checksum;
LfnByteOffset = *ByteOffset;
}
}
//
// Move on to the next dirent.
//
goto GetNextDirent;
}
//
// If this is the volume label, skip. Note that we never arrive here
// while building the LFN. If we did, we weren't asked to find LFNs
// and that is another good reason to skip this LFN fragment.
//
if (FlagOn((*Dirent)->Attributes, FAT_DIRENT_ATTR_VOLUME_ID)) {
//
// If we actually were asked to hand back volume labels,
// do it.
//
if (FlagOn(Ccb->Flags, CCB_FLAG_MATCH_VOLUME_ID)) {
break;
}
goto GetNextDirent;
}
//
// We may have just stepped off a valid Lfn run. Check to see if
// it is indeed valid for the following dirent.
//
if (LfnInProgress &&
(*ByteOffset == LfnByteOffset + sizeof(DIRENT)) &&
(LfnIndex == 0) &&
(FatComputeLfnChecksum(*Dirent) == LfnChecksum)) {
ASSERT( Ordinal == 1);
FoundValidLfn = TRUE;
LongFileName->Length = (USHORT)(LfnSize * sizeof(WCHAR));
} else {
FoundValidLfn = FALSE;
}
//
// If we are supposed to match all entries, then match this entry.
//
if (FlagOn(Ccb->Flags, CCB_FLAG_MATCH_ALL)) {
break;
}
//
// Check against the short name given if one was.
//
if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE )) {
if (Ccb->ContainsWildCards) {
//
// If we get one, note that all out parameters are already set.
//
(VOID)Fat8dot3ToString( IrpContext, (*Dirent), FALSE, &Name );
//
// For fat we special case the ".." dirent because we want it to
// match ????????.??? and to do that we change ".." to "." before
// calling the Fsrtl routine. But only do this if the expression
// is greater than one character long.
//
if ((Name.Length == 2) &&
(Name.Buffer[0] == '.') &&
(Name.Buffer[1] == '.') &&
(Ccb->OemQueryTemplate.Wild.Length > 1)) {
Name.Length = 1;
}
if (FatIsNameInExpression( IrpContext,
Ccb->OemQueryTemplate.Wild,
Name)) {
DebugTrace( 0, Dbg, "Entry found: Name = \"%Z\"\n", &Name);
DebugTrace( 0, Dbg, " VBO = %08lx\n", *ByteOffset);
if (FileNameDos) {
*FileNameDos = TRUE;
}
break;
}
} else {
//
// Do the quickest 8.3 equivalency check possible
//
if (!FlagOn((*Dirent)->Attributes, FAT_DIRENT_ATTR_VOLUME_ID) &&
(*(PULONG)&(Ccb->OemQueryTemplate.Constant[0]) == *(PULONG)&((*Dirent)->FileName[0])) &&
(*(PULONG)&(Ccb->OemQueryTemplate.Constant[4]) == *(PULONG)&((*Dirent)->FileName[4])) &&
(*(PUSHORT)&(Ccb->OemQueryTemplate.Constant[8]) == *(PUSHORT)&((*Dirent)->FileName[8])) &&
(*(PUCHAR)&(Ccb->OemQueryTemplate.Constant[10]) == *(PUCHAR)&((*Dirent)->FileName[10]))) {
DebugTrace( 0, Dbg, "Entry found.\n", 0);
if (FileNameDos) {
*FileNameDos = TRUE;
}
break;
}
}
}
//
// No matches were found with the short name. If an LFN exists,
// use it for the search.
//
if (FoundValidLfn) {
//
// First do a quick check here for different sized constant
// name and expression before upcasing.
//
if (!Ccb->ContainsWildCards &&
Ccb->UnicodeQueryTemplate.Length != (USHORT)(LfnSize * sizeof(WCHAR))) {
//
// Move on to the next dirent.
//
FoundValidLfn = FALSE;
LongFileName->Length = 0;
goto GetNextDirent;
}
//
// We need to upcase the name we found.
// We need a buffer. Try to avoid doing an allocation.
//
FatEnsureStringBufferEnough( &UpcasedLfn,
LongFileName->Length);
Status = RtlUpcaseUnicodeString( &UpcasedLfn,
LongFileName,
FALSE );
if (!NT_SUCCESS(Status)) {
FatNormalizeAndRaiseStatus( IrpContext, Status );
}
//
// Do the compare
//
if (Ccb->ContainsWildCards) {
if (FsRtlIsNameInExpression( &Ccb->UnicodeQueryTemplate,
&UpcasedLfn,
TRUE,
NULL )) {
break;
}
} else {
if (FsRtlAreNamesEqual( &Ccb->UnicodeQueryTemplate,
&UpcasedLfn,
BooleanFlagOn( Ccb->Flags, CCB_FLAG_QUERY_TEMPLATE_MIXED ),
NULL )) {
break;
}
}
}
//
// This long name was not a match. Zero out the Length field.
//
if (FoundValidLfn) {
FoundValidLfn = FALSE;
LongFileName->Length = 0;
}
GetNextDirent:
//
// Move on to the next dirent.
//
*ByteOffset += sizeof(DIRENT);
*Dirent += 1;
}
} finally {
FatFreeStringBuffer( &UpcasedLfn);
}
DebugTrace(-1, Dbg, "FatLocateDirent -> (VOID)\n", 0);
TimerStop(Dbg,"FatLocateDirent");
return;
}
VOID
FatLocateSimpleOemDirent (
IN PIRP_CONTEXT IrpContext,
IN PDCB ParentDirectory,
IN POEM_STRING FileName,
OUT PDIRENT *Dirent,
OUT PBCB *Bcb,
OUT PVBO ByteOffset
)
/*++
Routine Description:
This routine locates on the disk an undelted simple Oem dirent. By simple
I mean that FileName cannot contain any extended characters, and we do
not search LFNs or return them.
Arguments:
ParentDirectory - Supplies the DCB for the directory in which
to search
FileName - Supplies the filename to search for. The name may contain
wild cards
OffsetToStartSearchFrom - Supplies the VBO within the parent directory
from which to start looking for another real dirent.
Dirent - Receives a pointer to the located dirent if one was found
or NULL otherwise.
Bcb - Receives the Bcb for the located dirent if one was found or
NULL otherwise.
ByteOffset - Receives the VBO within the Parent directory for
the located dirent if one was found, or 0 otherwise.
Return Value:
None.
--*/
{
CCB LocalCcb;
PAGED_CODE();
//
// Note, this routine is called rarely, so performance is not critical.
// Just fill in a Ccb structure on my stack with the values that are
// required.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -