📄 namesup.c
字号:
/*++
Copyright (c) 1991-2000 Microsoft Corporation
Module Name:
NameSup.c
Abstract:
This module implements the Cdfs Name support routines
--*/
#include "CdProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (CDFS_BUG_CHECK_NAMESUP)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CdConvertBigToLittleEndian)
#pragma alloc_text(PAGE, CdConvertNameToCdName)
#pragma alloc_text(PAGE, CdDissectName)
#pragma alloc_text(PAGE, CdGenerate8dot3Name)
#pragma alloc_text(PAGE, CdFullCompareNames)
#pragma alloc_text(PAGE, CdIs8dot3Name)
#pragma alloc_text(PAGE, CdIsNameInExpression)
#pragma alloc_text(PAGE, CdShortNameDirentOffset)
#pragma alloc_text(PAGE, CdUpcaseName)
#endif
VOID
CdConvertNameToCdName (
IN PIRP_CONTEXT IrpContext,
IN OUT PCD_NAME CdName
)
/*++
Routine Description:
This routine is called to convert a string of bytes into a CdName.
The full name is already in the CdName structure in the FileName field.
We split this into the filename and version strings.
Arguments:
CdName - Pointer to CdName structure to update.
Return Value:
None.
--*/
{
ULONG NameLength = 0;
PWCHAR CurrentCharacter = CdName->FileName.Buffer;
PAGED_CODE();
//
// Look for a separator character.
//
while ((NameLength < CdName->FileName.Length) &&
(*CurrentCharacter != L';')) {
CurrentCharacter += 1;
NameLength += 2;
}
//
// If there is at least one more character after a possible separator then it
// and all following characters are part of the version string.
//
CdName->VersionString.Length = 0;
if (NameLength + sizeof( WCHAR ) < CdName->FileName.Length) {
CdName->VersionString.MaximumLength =
CdName->VersionString.Length = (USHORT) (CdName->FileName.Length - NameLength - sizeof( WCHAR ));
CdName->VersionString.Buffer = Add2Ptr( CdName->FileName.Buffer,
NameLength + sizeof( WCHAR ),
PWCHAR );
}
//
// Now update the filename portion of the name.
//
CdName->FileName.Length = (USHORT) NameLength;
return;
}
VOID
CdConvertBigToLittleEndian (
IN PIRP_CONTEXT IrpContext,
IN PCHAR BigEndian,
IN ULONG ByteCount,
OUT PCHAR LittleEndian
)
/*++
Routine Description:
This routine is called to convert a unicode string in big endian to
little endian. We start by copying all of the source bytes except
the first. This will put the low order bytes in the correct position.
We then copy each high order byte in its correct position.
Arguments:
BigEndian - Pointer to the string of big endian characters.
ByteCount - Number of unicode characters in this string.
LittleEndian - Pointer to array to store the little endian characters.
Return Value:
None.
--*/
{
ULONG RemainingByteCount = ByteCount;
PCHAR Source = BigEndian;
PCHAR Destination = LittleEndian;
PAGED_CODE();
//
// If the byte count isn't an even number then the disk is corrupt.
//
if (FlagOn( ByteCount, 1 )) {
CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
}
//
// Start by copy the low-order bytes into the correct position. Do
// this by skipping the first byte in the BigEndian string.
//
RtlCopyMemory( Destination,
Source + 1,
RemainingByteCount - 1 );
//
// Now move the high-order bytes into position.
//
Destination += 1;
while (RemainingByteCount != 0) {
*Destination = *Source;
Source += 2;
Destination += 2;
RemainingByteCount -= 2;
}
return;
}
VOID
CdUpcaseName (
IN PIRP_CONTEXT IrpContext,
IN PCD_NAME Name,
IN OUT PCD_NAME UpcaseName
)
/*++
Routine Description:
This routine is called to upcase a CdName structure. We will do both
the filename and version strings.
Arguments:
Name - This is the mixed case version of the name.
UpcaseName - This is the destination for the upcase operation.
Return Value:
None. This routine will raise all errors.
--*/
{
NTSTATUS Status;
PVOID NewBuffer;
PAGED_CODE();
//
// If the name structures are different then initialize the different components.
//
if (Name != UpcaseName) {
//
// Initialize the version string portion of the name.
//
UpcaseName->VersionString.Length = 0;
if (Name->VersionString.Length != 0) {
UpcaseName->VersionString.MaximumLength =
UpcaseName->VersionString.Length = Name->VersionString.Length;
//
// Initially set the buffer to point to where we need to insert
// the separator.
//
UpcaseName->VersionString.Buffer = Add2Ptr( UpcaseName->FileName.Buffer,
Name->FileName.Length,
PWCHAR );
//
// We are currently pointing to the location to store the separator.
// Store the ';' and then move to the next character to
// copy the data.
//
*(UpcaseName->VersionString.Buffer) = L';';
UpcaseName->VersionString.Buffer += 1;
}
}
//
// Upcase the string using the correct upcase routine.
//
Status = RtlUpcaseUnicodeString( &UpcaseName->FileName,
&Name->FileName,
FALSE );
//
// This should never fail.
//
ASSERT( Status == STATUS_SUCCESS );
if (Name->VersionString.Length != 0) {
Status = RtlUpcaseUnicodeString( &UpcaseName->VersionString,
&Name->VersionString,
FALSE );
//
// This should never fail.
//
ASSERT( Status == STATUS_SUCCESS );
}
return;
}
VOID
CdDissectName (
IN PIRP_CONTEXT IrpContext,
IN OUT PUNICODE_STRING RemainingName,
OUT PUNICODE_STRING FinalName
)
/*++
Routine Description:
This routine is called to strip off leading components of the name strings. We search
for either the end of the string or separating characters. The input remaining
name strings should have neither a trailing or leading backslash.
Arguments:
RemainingName - Remaining name.
FinalName - Location to store next component of name.
Return Value:
None.
--*/
{
ULONG NameLength;
PWCHAR NextWchar;
PAGED_CODE();
//
// Find the offset of the next component separators.
//
for (NameLength = 0, NextWchar = RemainingName->Buffer;
(NameLength < RemainingName->Length) && (*NextWchar != L'\\');
NameLength += sizeof( WCHAR) , NextWchar += 1);
//
// Adjust all the strings by this amount.
//
FinalName->Buffer = RemainingName->Buffer;
FinalName->MaximumLength = FinalName->Length = (USHORT) NameLength;
//
// If this is the last component then set the RemainingName lengths to zero.
//
if (NameLength == RemainingName->Length) {
RemainingName->Length = 0;
//
// Otherwise we adjust the string by this amount plus the separating character.
//
} else {
RemainingName->MaximumLength -= (USHORT) (NameLength + sizeof( WCHAR ));
RemainingName->Length -= (USHORT) (NameLength + sizeof( WCHAR ));
RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
NameLength + sizeof( WCHAR ),
PWCHAR );
}
return;
}
BOOLEAN
CdIs8dot3Name (
IN PIRP_CONTEXT IrpContext,
IN UNICODE_STRING FileName
)
/*++
Routine Description:
This routine checks if the name follows the 8.3 name conventions. We check for
the name length and whether the characters are valid.
Arguments:
FileName - String of bytes containing the name.
Return Value:
BOOLEAN - TRUE if this name is a legal 8.3 name, FALSE otherwise.
--*/
{
CHAR DbcsNameBuffer[ BYTE_COUNT_8_DOT_3 ];
STRING DbcsName;
PWCHAR NextWchar;
ULONG Count;
ULONG DotCount = 0;
BOOLEAN LastCharDot = FALSE;
PAGED_CODE();
//
// The length must be less than 24 bytes.
//
ASSERT( FileName.Length != 0 );
if (FileName.Length > BYTE_COUNT_8_DOT_3) {
return FALSE;
}
//
// Walk though and check for a space character.
//
NextWchar = FileName.Buffer;
Count = 0;
do {
//
// No spaces allowed.
//
if (*NextWchar == L' ') { return FALSE; }
if (*NextWchar == L'.') {
//
// Not an 8.3 name if more than 1 dot or more than 8 characters
// remaining. (It is legal for the dot to be in the ninth
// position)
//
if ((DotCount > 0) ||
(Count > 8 * sizeof( WCHAR ))) {
return FALSE;
}
DotCount += 1;
LastCharDot = TRUE;
} else {
LastCharDot = FALSE;
}
Count += 2;
NextWchar += 1;
} while (Count < FileName.Length);
//
// Go ahead and truncate the dot if at the end.
//
if (LastCharDot) {
FileName.Length -= sizeof( WCHAR );
}
//
// Create an Oem name to use to check for a valid short name.
//
DbcsName.MaximumLength = BYTE_COUNT_8_DOT_3;
DbcsName.Buffer = DbcsNameBuffer;
if (!NT_SUCCESS( RtlUnicodeStringToCountedOemString( &DbcsName,
&FileName,
FALSE ))) {
return FALSE;
}
//
// We have now initialized the Oem string. Call the FsRtl package to check for a
// valid FAT name.
//
return FsRtlIsFatDbcsLegal( DbcsName, FALSE, FALSE, FALSE );
}
VOID
CdGenerate8dot3Name (
IN PIRP_CONTEXT IrpContext,
IN PUNICODE_STRING FileName,
IN ULONG DirentOffset,
OUT PWCHAR ShortFileName,
OUT PUSHORT ShortByteCount
)
/*++
Routine Description:
This routine is called to generate a short name from the given long name. We will
generate a short name from the given long name.
We go through the following steps to make this conversion.
1 - Generate the generic short name. This will also be in unicode format.
2 - Build the string representation of the dirent offset.
3 - Build the biased short name string by combining the generic short name with
the dirent offset string.
4 - Copy the final unicode string back to our caller's buffer.
Arguments:
FileName - String of bytes containing the name.
DirentOffset - Offset in the directory for this filename. We incorporate the offset into
the short name by dividing this by 32 and prepending a tilde character to the
digit character. We then append this to the base of the generated short name.
ShortFileName - Pointer to the buffer to store the short name into.
ShortByteCount - Address to store the number of bytes in the short name.
Return Value:
None.
--*/
{
NTSTATUS Status;
UNICODE_STRING ShortName;
UNICODE_STRING BiasedShortName;
WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -