📄 namesup.c
字号:
DebugTrace(( 0, Dbg,
"UdfCheckLegalCS0Dstring, NameLength not odd, encoding 0x10!\n" )))) {
if (ReturnOnError) {
DebugTrace(( -1, Dbg, "UdfCheckLegalCS0Dstring -> FALSE\n" ));
return FALSE;
}
DebugTrace(( -1, Dbg, "UdfCheckLegalCS0Dstring -> raised status\n" ));
UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
}
DebugTrace(( -1, Dbg, "UdfCheckLegalCS0Dstring -> TRUE\n" ));
return TRUE;
}
VOID
UdfRenderNameToLegalUnicode (
IN PIRP_CONTEXT IrpContext,
IN PUNICODE_STRING Name,
IN PUNICODE_STRING RenderedName
)
/*++
Routine Description:
This routine will take a Unicode string containing illegal characters and
run it through the UDF standard algorithim to render it into a "legal"
name.
The short form is to convert all runs of illegal characters to "_" and tack
on a hex 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:
Name - the actual name
RenderedName - the name rendered into legal characters
Return Value:
BOOLEAN - TRUE if the expressions match, FALSE otherwise.
--*/
{
INT16 index;
INT16 targetIndex;
INT16 crcIndex;
INT16 extLen;
INT16 nameLen;
INT16 charLen;
INT16 overlayBytes;
INT16 bytesLeft;
UNICODE_CHAR current;
BOOLEAN needsCRC;
BOOLEAN foundDot;
UNICODE_CHAR ext[EXT_LEN];
//
// So as to lift as directly as possible from the standard, chunk things around.
//
PWCHAR newName = RenderedName->Buffer;
PWCHAR udfName = Name->Buffer;
LONG udfNameLen = Name->Length / sizeof(WCHAR);
/* Remove trailing periods ('.') and spaces (' '), Windows */
/* does not like them. */
foundDot = FALSE;
index = udfNameLen;
while (index-- > 0) {
if (udfName[index] == PERIOD)
foundDot = TRUE;
else if (udfName[index] != SPACE)
break;
}
/* If any trailing periods or spaces were found, a CRC code */
/* needs to be added to the resulting file name. */
nameLen = index + 1;
if (nameLen < udfNameLen)
needsCRC = TRUE;
needsCRC = FALSE;
bytesLeft = MAX_LEN;
extLen = 0;
if (needsCRC == FALSE || foundDot == FALSE) {
/* Look for an extension in the file name. We do not */
/* need to look for one if there were any trailing periods */
/* removed. */
INT16 endIndex;
INT16 prevCharLen = 1;
INT16 extBytes = 0;
targetIndex = 0;
index = nameLen;
/* Determine how many bytes we need to scan to find the */
/* extension delimiter. The extension has a maximum of */
/* five characters, but we do not want to scan past the */
/* beginning of the buffer. */
endIndex = (udfNameLen > EXT_LEN + 1) ?
udfNameLen - EXT_LEN - 1 : 1;
/* Start at the end of the name and scan backward, looking */
/* for the extension delimiter ("."). */
while (index-- > endIndex) {
/* Get the character to test. */
current = udfName[index];
if (current == '.') {
/* The extension delimiter was found, figure out */
/* how many characters the extension contains and */
/* the length of the resulting file name without */
/* the extension. */
extLen = nameLen - index - 1;
nameLen = index;
break;
}
/* Determine the byte length of the current character */
/* when converted to native format. */
charLen = (IsFileNameCharLegal(current)) ?
NativeCharLength(current) : 0;
if (charLen == 0) {
/* If the character byte length is zero, it is */
/* illegal or unprintable, place an underscore */
/* ("_") in the extension buffer if the previous */
/* character tested was legal. Not that the */
/* characters placed in the extension buffer are */
/* in reverse order. */
if (prevCharLen != 0) {
ext[targetIndex++] = ILLEGAL_CHAR_MARK;
extBytes++;
}
}
else {
/* The current character is legal and printable, */
/* put it in the extension buffer. Note that the */
/* characters placed in the extension buffer are */
/* in reverse order. */
ext[targetIndex++] = current;
extBytes += charLen;
}
/* Save the byte length of the current character, so */
/* we can determine if it was a legal character during */
/* the next test. */
prevCharLen = charLen;
}
/* If an extension was found, determine how many bytes */
/* remain in the file name buffer once we account for it. */
if (extLen > 0)
bytesLeft -= extBytes + 1;
}
index = 0;
targetIndex = 0;
crcIndex = 0;
overlayBytes = -1;
while (index < nameLen && bytesLeft > 0) {
/* Get the current character and convert it to upper case. */
current = udfName[index];
/* Determine if this is a valid file name char and */
/* calculate its corresponding native character byte */
/* length (zero if the char is not legal or undiplayable */
/* on this system). */
charLen = (IsFileNameCharLegal(current)) ?
NativeCharLength(current) : 0;
/* If the char is larger than the available space in the */
/* buffer, pretend it is undisplayable. */
if (charLen > bytesLeft)
charLen = 0;
if (charLen == 0) {
/* Undisplayable or illegal characters are substituted */
/* with an underscore ("_"), and requires a CRC code */
/* appended to the mangled file name. */
needsCRC = TRUE;
charLen = 1;
current = '_';
/* Skip over any following undiplayable or illegal */
/* chars. */
while (index + 1 < udfNameLen &&
(!IsFileNameCharLegal(udfName[index + 1]) ||
NativeCharLength(udfName[index + 1]) == 0))
index++;
/* Terminate loop if at the end of the file name. */
if (index >= udfNameLen)
break;
}
/* Assign the resulting char to the next index in the file */
/* name buffer and determine how many native bytes are */
/* left. */
newName[targetIndex++] = current;
bytesLeft -= charLen;
/* This figures out where the CRC code needs to start in */
/* the file name buffer. */
if (bytesLeft >= CRC_LEN) {
/* If there is enough space left, just tack it onto */
/* the end. */
crcIndex = targetIndex;
}
else {
/* If there is not enough space left, the CRC must */
/* overlay a character already in the file name */
/* buffer. Once this condition has been met, the */
/* value will not change. */
if (overlayBytes < 0) {
/* Determine the index and save the length of the */
/* native character that is overlayed. It is */
/* possible that the CRC might overlay half of a */
/* two-byte native character depending upon how */
/* the character boundaries line up. */
overlayBytes = (bytesLeft + charLen > CRC_LEN)
? 1 : 0;
crcIndex = targetIndex - 1;
}
}
/* Advance to the next character. */
index++;
}
/* If the scan did not reach the end of the file name, or the */
/* length of the file name is zero, a CRC code is needed. */
if (index < nameLen || index == 0)
needsCRC = TRUE;
/* If the name has illegal characters or and extension, it */
/* is not a DOS device name. */
if (needsCRC == FALSE && extLen == 0) {
/* If this is the name of a DOS device, a CRC code should */
/* be appended to the file name. */
if (IsDeviceName(udfName, udfNameLen))
needsCRC = TRUE;
}
/* Append the CRC code to the file name, if needed. */
if (needsCRC) {
/* Get the CRC value for the original Unicode string */
UINT16 udfCRCValue = UdfComputeCrc16Uni(udfName, udfNameLen);
/* Determine the character index where the CRC should */
/* begin. */
targetIndex = crcIndex;
/* If the character being overlayed is a two-byte native */
/* character, replace the first byte with an underscore. */
if (overlayBytes > 0)
newName[targetIndex++] = ILLEGAL_CHAR_MARK;
/* Append the encoded CRC value with delimiter. */
newName[targetIndex++] = CRC_MARK;
newName[targetIndex++] = UdfCrcChar[(udfCRCValue & 0xf000) >> 12];
newName[targetIndex++] = UdfCrcChar[(udfCRCValue & 0x0f00) >> 8];
newName[targetIndex++] = UdfCrcChar[(udfCRCValue & 0x00f0) >> 4];
newName[targetIndex++] = UdfCrcChar[(udfCRCValue & 0x000f)];
}
/* If an extension was found, append it here. */
if (extLen > 0) {
/* Add the period ('.') for the extension delimiter. */
newName[targetIndex++] = PERIOD;
/* Append the characters in the extension buffer. They */
/* were stored in reverse order, so we need to begin with */
/* the last character and work forward. */
while (extLen-- > 0)
newName[targetIndex++] = ext[extLen];
}
ASSERT( (targetIndex * sizeof(WCHAR)) <= RenderedName->MaximumLength );
RenderedName->Length = (USHORT) (targetIndex * sizeof(WCHAR));
}
BOOLEAN
UdfIsNameInExpression (
IN PIRP_CONTEXT IrpContext,
IN PUNICODE_STRING CurrentName,
IN PUNICODE_STRING SearchExpression,
IN BOOLEAN Wild
)
/*++
Routine Description:
This routine will compare two Unicode strings. We assume that if this
is to be a case-insensitive search then they are already upcased.
Arguments:
CurrentName - Filename from the disk.
SearchExpression - Filename expression to use for match.
Wild - True if wildcards are present in SearchExpression.
Return Value:
BOOLEAN - TRUE if the expressions match, FALSE otherwise.
--*/
{
BOOLEAN Match = TRUE;
PAGED_CODE();
//
// Check inputs.
//
ASSERT_IRP_CONTEXT( IrpContext );
//
// If there are wildcards in the expression then we call the
// appropriate FsRtlRoutine.
//
if (Wild) {
Match = FsRtlIsNameInExpression( SearchExpression,
CurrentName,
FALSE,
NULL );
//
// Otherwise do a direct memory comparison for the name string.
//
} else {
if ((CurrentName->Length != SearchExpression->Length) ||
(!RtlEqualMemory( CurrentName->Buffer,
SearchExpression->Buffer,
CurrentName->Length ))) {
Match = FALSE;
}
}
return Match;
}
FSRTL_COMPARISON_RESULT
UdfFullCompareNames (
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
--*/
{
ULONG i;
ULONG MinLength = NameA->Length;
FSRTL_COMPARISON_RESULT Result = LessThan;
PAGED_CODE();
//
// Check inputs.
//
ASSERT_IRP_CONTEXT( IrpContext );
//
// 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 = (ULONG) 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 + -