📄 namesup.c
字号:
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
NameSup.c
Abstract:
This module implements the Udfs Name support routines
Author:
Dan Lovinger [DanLo] 9-October-1996
Revision History:
--*/
#include "UdfProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (UDFS_BUG_CHECK_NAMESUP)
//
// The local debug trace level
//
#define Dbg (UDFS_DEBUG_LEVEL_NAMESUP)
//
// Local constants
//
static CONST CHAR UdfCrcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@";
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, UdfCandidateShortName)
#pragma alloc_text(PAGE, UdfCheckLegalCS0Dstring)
#pragma alloc_text(PAGE, UdfConvertCS0DstringToUnicode)
#pragma alloc_text(PAGE, UdfDissectName)
#pragma alloc_text(PAGE, UdfFullCompareNames)
#pragma alloc_text(PAGE, UdfGenerate8dot3Name)
#pragma alloc_text(PAGE, UdfIs8dot3Name)
#pragma alloc_text(PAGE, UdfIsNameInExpression)
#pragma alloc_text(PAGE, UdfRenderNameToLegalUnicode)
#endif
INLINE
ULONG
NativeDosCharLength (
IN WCHAR Wchar
)
/*++
Routine Description:
This routine is a translation layer for asking how big a given UNICODE
character will be when converted to OEM. Aside from adding more material
to the kernel export table, this is how ya do it.
Arguments:
Wchar - pointer to the character
Return Value:
Size in bytes.
--*/
{
NTSTATUS Status;
CHAR OemBuf[2];
ULONG Length;
Status = RtlUpcaseUnicodeToOemN( OemBuf,
sizeof(OemBuf),
&Length,
&Wchar,
sizeof(WCHAR));
ASSERT( NT_SUCCESS( Status ));
return Length;
}
VOID
UdfDissectName (
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();
//
// Check inputs.
//
ASSERT_IRP_CONTEXT( IrpContext );
//
// 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
UdfIs8dot3Name (
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();
//
// Check inputs.
//
ASSERT_IRP_CONTEXT( IrpContext );
//
// 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);
//
// We can't have a period at the end of the name.
//
if (LastCharDot) {
return FALSE;
}
//
// 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 );
}
BOOLEAN
UdfCandidateShortName (
IN PIRP_CONTEXT IrpContext,
IN PUNICODE_STRING Name
)
/*++
Routine Description:
This routine is called to determine if the input name could be a generated
short name.
Arguments:
Name - Pointer to the name to stare at.
Return Value:
BOOLEAN True if it is possible that this is a shortname, False otherwise.
--*/
{
ULONG Index, SubIndex;
BOOLEAN LooksShort = FALSE;
PAGED_CODE();
//
// Check inputs.
//
ASSERT_IRP_CONTEXT( IrpContext );
//
// The length can't be larger than an 8.3 name and must be
// at least as big as the uniqifier stamp.
//
ASSERT( Name->Length != 0 );
if (Name->Length > BYTE_COUNT_8_DOT_3 ||
Name->Length < DOS_CRC_LEN * sizeof(WCHAR)) {
return FALSE;
}
//
// Walk across the name looking for the uniquifier stamp. The stamp
// is of the form #<hex><hex><hex> so if we can stop before the end
// of the full name.
//
for ( Index = 0;
Index <= (Name->Length / sizeof(WCHAR)) - DOS_CRC_LEN;
Index++ ) {
//
// Is the current character the stamp UDF uses to offset the stamp?
//
if (Name->Buffer[Index] == CRC_MARK) {
//
// We may potentially have just a CRC at the end
// of the name OR have a period following. If we
// do, it is reasonable to think the name may be
// a generated shorty.
//
// #123 (a very special case - orignal name was ".")
// FOO#123
// FOO#123.TXT
//
if (Index == (Name->Length / sizeof(WCHAR)) - DOS_CRC_LEN ||
Name->Buffer[Index + DOS_CRC_LEN] == PERIOD) {
LooksShort = TRUE;
break;
}
}
}
return LooksShort;
}
VOID
UdfGenerate8dot3Name (
IN PIRP_CONTEXT IrpContext,
IN PUNICODE_STRING FileName,
OUT PUNICODE_STRING ShortFileName
)
/*++
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.
The short form is to convert all runs of illegal characters to "_" and tack
on a base41 representation of the CRC of the original name. The algorithm is
nearly directly lifted from the UDF (2.01 proposed!) standard, so apologies for the
style clash.
Arguments:
FileName - String of bytes containing the name.
ShortFileName - Pointer to the string to store the short name into.
Return Value:
None.
--*/
{
INT16 index;
INT16 targetIndex;
INT16 crcIndex;
INT16 extLen;
INT16 nameLen;
INT16 charLen;
INT16 overlayBytes;
INT16 bytesLeft;
UNICODE_CHAR current;
BOOLEAN needsCRC;
UNICODE_CHAR ext[DOS_EXT_LEN];
//
// So as to lift as directly as possible from the standard, chunk things around.
//
PWCHAR dosName = ShortFileName->Buffer;
PWCHAR udfName = FileName->Buffer;
LONG udfNameLen = FileName->Length / sizeof(WCHAR);
needsCRC = FALSE;
/* Start at the end of the UDF file name and scan for a period */
/* ('.'). This will be where the DOS extension starts (if */
/* any). */
index = udfNameLen;
while (index-- > 0) {
if (udfName[index] == PERIOD)
break;
}
if (index < 0) {
/* There name was scanned to the beginning of the buffer */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -