📄 namesup.c
字号:
WCHAR BiasedShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
GENERATE_NAME_CONTEXT NameContext;
ULONG BiasedDirentOffset;
ULONG MaximumBaseBytes;
ULONG BaseNameOffset;
PWCHAR NextWchar;
WCHAR ThisWchar;
USHORT Length;
BOOLEAN FoundTilde = FALSE;
OEM_STRING OemName;
USHORT OemNameOffset = 0;
BOOLEAN OverflowBuffer = FALSE;
PAGED_CODE();
//
// Initialize the short string to use the input buffer.
//
ShortName.Buffer = ShortNameBuffer;
ShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
//
// Initialize the name context.
//
RtlZeroMemory( &NameContext, sizeof( GENERATE_NAME_CONTEXT ));
//
// We now have the unicode name for the input string. Go ahead and generate
// the short name.
//
RtlGenerate8dot3Name( FileName, TRUE, &NameContext, &ShortName );
//
// We now have the generic short name. We want incorporate the dirent offset
// into the name in order to reduce the chance of name conflicts. We will use
// a tilde character followed by a character representation of the dirent offset.
// This will be the hexadecimal representation of the dirent offset in the directory.
// It is actuall this offset divided by 32 since we don't need the full
// granularity.
//
BiasedDirentOffset = DirentOffset >> SHORT_NAME_SHIFT;
//
// Point to a local buffer to store the offset string. We start
// at the end of the buffer and work backwards.
//
NextWchar = Add2Ptr( BiasedShortNameBuffer,
BYTE_COUNT_8_DOT_3,
PWCHAR );
BiasedShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
//
// Generate an OEM version of the string so that we can check for double
// byte characters.
//
Status = RtlUnicodeStringToOemString(&OemName, &ShortName, TRUE);
//
// If this failed, bail out. Don't expect any problems other than no mem.
//
if (!NT_SUCCESS( Status)) {
ASSERT( STATUS_INSUFFICIENT_RESOURCES == Status);
CdRaiseStatus( IrpContext, Status);
}
Length = 0;
//
// Now add the characters for the dirent offset. We need to start
// from the least significant digit and work backwards.
//
do {
NextWchar -= 1;
ThisWchar = (WCHAR) (BiasedDirentOffset & 0x0000000f);
//
// Store in the next character. Bias against either '0' or 'A'
//
if (ThisWchar <= 9) {
*NextWchar = ThisWchar + L'0';
} else {
*NextWchar = ThisWchar + L'A' - 0xA;
}
Length += sizeof( WCHAR );
//
// Shift out the low 4 bits of the offset.
//
BiasedDirentOffset >>= 4;
} while (BiasedDirentOffset != 0);
//
// Now store in the tilde character.
//
NextWchar -= 1;
*NextWchar = L'~';
Length += sizeof( WCHAR );
//
// Set the length of this string.
//
BiasedShortName.Length = Length;
BiasedShortName.Buffer = NextWchar;
//
// Figure out the maximum number of characters we can copy of the base
// name. We subract the number of characters in the dirent string from 8.
// We will copy this many characters or stop when we reach a '.' character
// or a '~' character in the name.
//
MaximumBaseBytes = 16 - Length;
BaseNameOffset = 0;
//
// Keep copying from the base name until we hit a '.', '~' or the end of
// the short name.
//
NextWchar = ShortFileName;
Length = 0;
while ((BaseNameOffset < ShortName.Length) &&
(ShortName.Buffer[BaseNameOffset / 2] != L'.')) {
//
// Remember if we found a tilde character in the short name,
// so we don't copy it or anything following it.
//
if (ShortName.Buffer[BaseNameOffset / 2] == L'~') {
FoundTilde = TRUE;
}
//
// We need to consider the DBCS code page, because Unicode characters
// may use 2 bytes as DBCS characters.
//
if (FsRtlIsLeadDbcsCharacter(OemName.Buffer[OemNameOffset])) {
OemNameOffset += 2;
if ((OemNameOffset + (BiasedShortName.Length / sizeof(WCHAR))) > 8) {
OverflowBuffer = TRUE;
}
}
else {
OemNameOffset++;
}
//
// Only copy the bytes if we still have space for the dirent string.
//
if (!FoundTilde && !OverflowBuffer && (BaseNameOffset < MaximumBaseBytes)) {
*NextWchar = ShortName.Buffer[BaseNameOffset / 2];
Length += sizeof( WCHAR );
NextWchar += 1;
}
BaseNameOffset += 2;
}
RtlFreeOemString(&OemName);
//
// Now copy the dirent string into the biased name buffer.
//
RtlCopyMemory( NextWchar,
BiasedShortName.Buffer,
BiasedShortName.Length );
Length += BiasedShortName.Length;
NextWchar += (BiasedShortName.Length / sizeof( WCHAR ));
//
// Now copy any remaining bytes over to the biased short name.
//
if (BaseNameOffset != ShortName.Length) {
RtlCopyMemory( NextWchar,
&ShortName.Buffer[BaseNameOffset / 2],
ShortName.Length - BaseNameOffset );
Length += (ShortName.Length - (USHORT) BaseNameOffset);
}
//
// The final short name is stored in the user's buffer.
//
*ShortByteCount = Length;
}
BOOLEAN
CdIsNameInExpression (
IN PIRP_CONTEXT IrpContext,
IN PCD_NAME CurrentName,
IN PCD_NAME SearchExpression,
IN ULONG WildcardFlags,
IN BOOLEAN CheckVersion
)
/*++
Routine Description:
This routine will compare two CdName strings. We assume that if this
is to be a case-insensitive search then they are already upcased.
We compare the filename portions of the name and if they match we
compare the version strings if requested.
Arguments:
CurrentName - Filename from the disk.
SearchExpression - Filename expression to use for match.
WildcardFlags - Flags field which indicates which parts of the
search expression might have wildcards. These flags are the
same as in the Ccb flags field.
CheckVersion - Indicates whether we should check both the name and the
version strings or just the name.
Return Value:
BOOLEAN - TRUE if the expressions match, FALSE otherwise.
--*/
{
BOOLEAN Match = TRUE;
PAGED_CODE();
//
// If there are wildcards in the expression then we call the
// appropriate FsRtlRoutine.
//
if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD )) {
Match = FsRtlIsNameInExpression( &SearchExpression->FileName,
&CurrentName->FileName,
FALSE,
NULL );
//
// Otherwise do a direct memory comparison for the name string.
//
} else {
if ((CurrentName->FileName.Length != SearchExpression->FileName.Length) ||
(!RtlEqualMemory( CurrentName->FileName.Buffer,
SearchExpression->FileName.Buffer,
CurrentName->FileName.Length ))) {
Match = FALSE;
}
}
//
// Check the version numbers if requested by the user and we have a
// match on the name and the version number is present.
//
if (Match && CheckVersion && SearchExpression->VersionString.Length &&
!FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL )) {
//
// If there are wildcards in the expression then call the
// appropriate search expression.
//
if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD )) {
Match = FsRtlIsNameInExpression( &SearchExpression->VersionString,
&CurrentName->VersionString,
FALSE,
NULL );
//
// Otherwise do a direct memory comparison for the name string.
//
} else {
if ((CurrentName->VersionString.Length != SearchExpression->VersionString.Length) ||
(!RtlEqualMemory( CurrentName->VersionString.Buffer,
SearchExpression->VersionString.Buffer,
CurrentName->VersionString.Length ))) {
Match = FALSE;
}
}
}
return Match;
}
ULONG
CdShortNameDirentOffset (
IN PIRP_CONTEXT IrpContext,
IN PUNICODE_STRING Name
)
/*++
Routine Description:
This routine is called to examine a name to see if the dirent offset string is contained.
This consists of a tilde character followed by the offset represented as a hexadecimal
characters. We don't do any other checks to see if this is a short name. We
catch that later outside this routine.
Arguments:
Name - This is the CdName to examine.
Return Value:
ULONG - MAXULONG if there is no valid dirent offset string embedded, otherwise the
convert the value to numeric form.
--*/
{
ULONG ResultOffset = MAXULONG;
ULONG RemainingByteCount = Name->Length;
BOOLEAN FoundTilde = FALSE;
PWCHAR NextWchar;
PAGED_CODE();
//
// Walk through the name until we either reach the end of the name
// or find a tilde character.
//
for (NextWchar = Name->Buffer;
RemainingByteCount != 0;
NextWchar += 1, RemainingByteCount -= sizeof( WCHAR )) {
//
// Check if this is a dot. Stop constructing any string if
// we found a dot.
//
if (*NextWchar == L'.') {
break;
}
//
// If we already found a tilde then check this character as a
// valid character. It must be a digit or A to F.
//
if (FoundTilde) {
if ((*NextWchar < L'0') ||
(*NextWchar > L'F') ||
((*NextWchar > L'9') && (*NextWchar < 'A'))) {
ResultOffset = MAXULONG;
break;
}
//
// Shift the result by 4 bits and add in this new character.
//
ResultOffset <<= 4;
if (*NextWchar < L'A') {
ResultOffset += *NextWchar - L'0';
} else {
ResultOffset += (*NextWchar - L'A') + 10;
}
continue;
}
//
// If this is a tilde then start building the dirent string.
//
if (*NextWchar == L'~') {
FoundTilde = TRUE;
ResultOffset = 0;
}
}
return ResultOffset;
}
//
// Local support routine
//
FSRTL_COMPARISON_RESULT
CdFullCompareNames (
IN PIRP_CONTEXT IrpContext,
IN PUNICODE_STRING NameA,
IN PUNICODE_STRING NameB
)
/*++
Routine Description:
This function compares two names as fast as possible. Note that since
this comparison is case sensitive we can do a direct memory comparison.
Arguments:
NameA & NameB - The names to compare.
Return Value:
COMPARISON - returns
LessThan if NameA < NameB lexicalgraphically,
GreaterThan if NameA > NameB lexicalgraphically,
EqualTo if NameA is equal to NameB
--*/
{
SIZE_T i;
ULONG MinLength = NameA->Length;
FSRTL_COMPARISON_RESULT Result = LessThan;
PAGED_CODE();
//
// Figure out the minimum of the two lengths
//
if (NameA->Length > NameB->Length) {
MinLength = NameB->Length;
Result = GreaterThan;
} else if (NameA->Length == NameB->Length) {
Result = EqualTo;
}
//
// Loop through looking at all of the characters in both strings
// testing for equalilty, less than, and greater than
//
i = RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinLength );
if (i < MinLength) {
//
// We know the offset of the first character which is different.
//
return ((NameA->Buffer[ i / 2 ] < NameB->Buffer[ i / 2 ]) ?
LessThan :
GreaterThan);
}
//
// The names match up to the length of the shorter string.
// The shorter string lexically appears first.
//
return Result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -