[RTL] Implement RtlGetLengthWithoutLastFullDorOrNtPathElement

CORE-17248
This commit is contained in:
Mark Jansen 2021-02-15 20:11:49 +01:00
parent 3e7e4ee360
commit 264aaa9e05
4 changed files with 195 additions and 3 deletions

View file

@ -494,11 +494,91 @@ RtlpApplyLengthFunction(IN ULONG Flags,
NTSTATUS
NTAPI
RtlGetLengthWithoutLastFullDosOrNtPathElement(IN ULONG Flags,
IN PWCHAR Path,
IN PCUNICODE_STRING Path,
OUT PULONG LengthOut)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
static const UNICODE_STRING PathDividers = RTL_CONSTANT_STRING(L"\\/");
USHORT Position;
RTL_PATH_TYPE PathType;
/* All failure paths have this in common, so simplify code */
if (LengthOut)
*LengthOut = 0;
if (Flags || !Path || !LengthOut)
{
return STATUS_INVALID_PARAMETER;
}
if ((Path->Length / sizeof(WCHAR)) == 0)
{
/* Nothing to do here */
return STATUS_SUCCESS;
}
PathType = RtlDetermineDosPathNameType_Ustr(Path);
switch (PathType)
{
case RtlPathTypeLocalDevice:
// Handle \\\\?\\C:\\ with the last ':' or '\\' missing:
if (Path->Length / sizeof(WCHAR) < 7 ||
Path->Buffer[5] != ':' ||
!IS_PATH_SEPARATOR(Path->Buffer[6]))
{
return STATUS_INVALID_PARAMETER;
}
break;
case RtlPathTypeRooted:
// "\\??\\"
break;
case RtlPathTypeUncAbsolute:
// "\\\\"
break;
case RtlPathTypeDriveAbsolute:
// "C:\\"
break;
default:
return STATUS_INVALID_PARAMETER;
}
/* Find the last path separator */
if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, Path, &PathDividers, &Position)))
Position = 0;
/* Is it the last char of the string? */
if (Position && Position + sizeof(WCHAR) == Path->Length)
{
UNICODE_STRING Tmp = *Path;
Tmp.Length = Position;
/* Keep walking path separators to eliminate multiple next to eachother */
while (Tmp.Length > sizeof(WCHAR) && IS_PATH_SEPARATOR(Tmp.Buffer[Tmp.Length / sizeof(WCHAR)]))
Tmp.Length -= sizeof(WCHAR);
/* Find the previous occurence */
if (!NT_SUCCESS(RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END, &Tmp, &PathDividers, &Position)))
Position = 0;
}
/* Simplify code by working in chars instead of bytes */
if (Position)
Position /= sizeof(WCHAR);
if (Position)
{
// Keep walking path separators to eliminate multiple next to eachother, but ensure we leave one in place!
while (Position > 1 && IS_PATH_SEPARATOR(Path->Buffer[Position - 1]))
Position--;
}
if (Position > 0)
{
/* Return a length, not an index */
*LengthOut = Position + 1;
}
return STATUS_SUCCESS;
}
NTSTATUS