mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[RTL] Implement RtlGetLengthWithoutLastFullDorOrNtPathElement
CORE-17248
This commit is contained in:
parent
3e7e4ee360
commit
264aaa9e05
4 changed files with 195 additions and 3 deletions
|
@ -62,6 +62,7 @@ list(APPEND SOURCE
|
|||
RtlGetFullPathName_U.c
|
||||
RtlGetFullPathName_Ustr.c
|
||||
RtlGetFullPathName_UstrEx.c
|
||||
RtlGetLengthWithoutLastFullDosOrNtPathElement.c
|
||||
RtlGetLengthWithoutTrailingPathSeperators.c
|
||||
RtlGetLongestNtPathLength.c
|
||||
RtlGetNtProductType.c
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* PROJECT: ReactOS API Tests
|
||||
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||
* PURPOSE: Test for RtlGetLengthWithoutLastFullDosOrNtPathElement
|
||||
* COPYRIGHT: Copyright 2021 Mark Jansen <mark.jansen@reactos.org>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlGetLengthWithoutLastFullDosOrNtPathElement(
|
||||
IN ULONG Flags,
|
||||
IN PCUNICODE_STRING Path,
|
||||
OUT PULONG LengthOut);
|
||||
|
||||
|
||||
typedef struct _rtl_test_data
|
||||
{
|
||||
LPCWSTR Path;
|
||||
ULONG Length;
|
||||
NTSTATUS Status;
|
||||
} rtl_test_data;
|
||||
|
||||
// Based on http://undoc.airesoft.co.uk/ntdll.dll/RtlGetLengthWithoutLastFullDosOrNtPathElement.php
|
||||
rtl_test_data tests[] = {
|
||||
{ L"", 0, STATUS_SUCCESS, },
|
||||
{ L"C", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"C:", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"C:\\", 0, STATUS_SUCCESS, },
|
||||
{ L"C:\\test", 3, STATUS_SUCCESS, },
|
||||
{ L"C:\\test\\", 3, STATUS_SUCCESS, },
|
||||
{ L"C:\\test\\a", 8, STATUS_SUCCESS, },
|
||||
{ L"C:\\test\\a\\", 8, STATUS_SUCCESS, },
|
||||
{ L"C://test", 3, STATUS_SUCCESS, },
|
||||
{ L"C://test\\", 3, STATUS_SUCCESS, },
|
||||
{ L"C://test\\\\", 3, STATUS_SUCCESS, },
|
||||
{ L"C://test/", 3, STATUS_SUCCESS, },
|
||||
{ L"C://test//", 3, STATUS_SUCCESS, },
|
||||
{ L"C://test\\a", 9, STATUS_SUCCESS, },
|
||||
{ L"C://test\\\\a", 9, STATUS_SUCCESS, },
|
||||
{ L"C://test/a", 9, STATUS_SUCCESS, },
|
||||
{ L"C://test//a", 9, STATUS_SUCCESS, },
|
||||
{ L"C://test\\a\\", 9, STATUS_SUCCESS, },
|
||||
{ L"C://test//a//", 9, STATUS_SUCCESS, },
|
||||
{ L"C://test//a/", 9, STATUS_SUCCESS, },
|
||||
{ L"X", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"X:", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"X:\\", 0, STATUS_SUCCESS, },
|
||||
{ L"D:\\Test\\hello.ext", 8, STATUS_SUCCESS, },
|
||||
{ L"\\\\?\\C", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"\\\\?\\C:", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"\\\\?\\CC", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"\\\\?\\C:\\", 4, STATUS_SUCCESS, },
|
||||
{ L"\\\\?\\::\\", 4, STATUS_SUCCESS, },
|
||||
{ L"\\\\?\\CCC", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"\\\\?\\CCC\\", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"\\??\\UNC\\Mytest", 8, STATUS_SUCCESS, },
|
||||
{ L"\\SystemRoot", 0, STATUS_SUCCESS, },
|
||||
{ L"\\SystemRoot\\", 0, STATUS_SUCCESS, },
|
||||
{ L"\\SystemRoot\\ntdll.dll", 12, STATUS_SUCCESS, },
|
||||
{ L"\\Device\\HarddiskVolume9000", 8, STATUS_SUCCESS, },
|
||||
{ L"\\Stuff\\doesnt\\really\\matter", 21, STATUS_SUCCESS, },
|
||||
{ L"this\\doesnt\\really\\work", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"multi(0)disk(0)rdisk(0)partition(1)", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"multi(0)disk(0)rdisk(0)partition(1)\\test", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"xyz", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"CON", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L":", 0, STATUS_INVALID_PARAMETER, },
|
||||
{ L"\\\\", 0, STATUS_SUCCESS, },
|
||||
};
|
||||
|
||||
|
||||
START_TEST(RtlGetLengthWithoutLastFullDosOrNtPathElement)
|
||||
{
|
||||
UNICODE_STRING Dum;
|
||||
NTSTATUS Status;
|
||||
ULONG Length;
|
||||
RtlInitUnicodeString(&Dum, L"c:\\test\\");
|
||||
|
||||
Length = 333;
|
||||
Status = RtlGetLengthWithoutLastFullDosOrNtPathElement(0, NULL, &Length);
|
||||
ok_int(Length, 0);
|
||||
ok_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
|
||||
Status = RtlGetLengthWithoutLastFullDosOrNtPathElement(0, &Dum, NULL);
|
||||
ok_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
|
||||
for (ULONG n = 0; n < 32; ++n)
|
||||
{
|
||||
Length = 333;
|
||||
Status = RtlGetLengthWithoutLastFullDosOrNtPathElement((1 << n), &Dum, &Length);
|
||||
ok_int(Length, 0);
|
||||
ok_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
for (ULONG n = 0; n < ARRAYSIZE(tests); ++n)
|
||||
{
|
||||
UNICODE_STRING Str;
|
||||
Length = 333;
|
||||
|
||||
RtlInitUnicodeString(&Str, tests[n].Path);
|
||||
|
||||
Status = RtlGetLengthWithoutLastFullDosOrNtPathElement(0, &Str, &Length);
|
||||
ok(Status == tests[n].Status, "Got Status=0x%lx, expected 0x%lx (%S)\n", Status, tests[n].Status, Str.Buffer);
|
||||
ok(Length == tests[n].Length, "Got Length=0x%lx, expected 0x%lx (%S)\n", Length, tests[n].Length, Str.Buffer);
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ extern void func_RtlGenerate8dot3Name(void);
|
|||
extern void func_RtlGetFullPathName_U(void);
|
||||
extern void func_RtlGetFullPathName_Ustr(void);
|
||||
extern void func_RtlGetFullPathName_UstrEx(void);
|
||||
extern void func_RtlGetLengthWithoutLastFullDosOrNtPathElement(void);
|
||||
extern void func_RtlGetLengthWithoutTrailingPathSeperators(void);
|
||||
extern void func_RtlGetLongestNtPathLength(void);
|
||||
extern void func_RtlGetNtProductType(void);
|
||||
|
@ -138,6 +139,7 @@ const struct test winetest_testlist[] =
|
|||
{ "RtlGetFullPathName_U", func_RtlGetFullPathName_U },
|
||||
{ "RtlGetFullPathName_Ustr", func_RtlGetFullPathName_Ustr },
|
||||
{ "RtlGetFullPathName_UstrEx", func_RtlGetFullPathName_UstrEx },
|
||||
{ "RtlGetLengthWithoutLastFullDosOrNtPathElement", func_RtlGetLengthWithoutLastFullDosOrNtPathElement },
|
||||
{ "RtlGetLengthWithoutTrailingPathSeperators", func_RtlGetLengthWithoutTrailingPathSeperators },
|
||||
{ "RtlGetLongestNtPathLength", func_RtlGetLongestNtPathLength },
|
||||
{ "RtlGetNtProductType", func_RtlGetNtProductType },
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue