https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3e7e4ee360a46cc48c818c...
commit 3e7e4ee360a46cc48c818c40f905d1b901e6d3c8 Author: Mark Jansen mark.jansen@reactos.org AuthorDate: Mon Feb 15 20:10:59 2021 +0100 Commit: Mark Jansen mark.jansen@reactos.org CommitDate: Sat May 8 19:24:23 2021 +0200
[RTL] Implement RtlpApplyLengthFunction
CORE-17248 --- modules/rostests/apitests/ntdll/CMakeLists.txt | 1 + .../apitests/ntdll/RtlpApplyLengthFunction.c | 143 +++++++++++++++++++++ modules/rostests/apitests/ntdll/testlist.c | 2 + sdk/lib/rtl/path.c | 45 ++++++- 4 files changed, 188 insertions(+), 3 deletions(-)
diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt b/modules/rostests/apitests/ntdll/CMakeLists.txt index ed0a199a903..545d935e144 100644 --- a/modules/rostests/apitests/ntdll/CMakeLists.txt +++ b/modules/rostests/apitests/ntdll/CMakeLists.txt @@ -73,6 +73,7 @@ list(APPEND SOURCE RtlMemoryStream.c RtlMultipleAllocateHeap.c RtlNtPathNameToDosPathName.c + RtlpApplyLengthFunction.c RtlpEnsureBufferSize.c RtlQueryTimeZoneInfo.c RtlReAllocateHeap.c diff --git a/modules/rostests/apitests/ntdll/RtlpApplyLengthFunction.c b/modules/rostests/apitests/ntdll/RtlpApplyLengthFunction.c new file mode 100644 index 00000000000..60b9ee6a53e --- /dev/null +++ b/modules/rostests/apitests/ntdll/RtlpApplyLengthFunction.c @@ -0,0 +1,143 @@ +/* + * PROJECT: ReactOS API Tests + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Test for RtlpApplyLengthFunction + * COPYRIGHT: Copyright 2021 Mark Jansen mark.jansen@reactos.org + */ + +#include "precomp.h" +#include <ntstrsafe.h> + + +NTSTATUS +NTAPI +RtlpApplyLengthFunction(IN ULONG Flags, + IN ULONG Type, + IN PVOID UnicodeStringOrUnicodeStringBuffer, + IN NTSTATUS(NTAPI*LengthFunction)(ULONG, PUNICODE_STRING, PULONG)); + + +NTSTATUS NTAPI LengthFunctionFail(ULONG Unknown, PUNICODE_STRING String, PULONG Length) +{ + ok_int(*Length, 0); + /* Show that this is ignored when an error is returned */ + *Length = 3; + return STATUS_INVALID_ACCOUNT_NAME; +} + +NTSTATUS NTAPI LengthFunctionOk(ULONG Unknown, PUNICODE_STRING String, PULONG Length) +{ + ok_int(*Length, 0); + *Length = 4; + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI LengthFunctionReturn1(ULONG Unknown, PUNICODE_STRING String, PULONG Length) +{ + ok_int(*Length, 0); + *Length = 4; + return (NTSTATUS)1; +} + +NTSTATUS NTAPI LengthFunctionCopyLen(ULONG Unknown, PUNICODE_STRING String, PULONG Length) +{ + /* Use Buffer as length, to show that the function does not interpret the contents at all */ + *Length = (ULONG)(ULONG_PTR)String->Buffer; + return STATUS_SUCCESS; +} + + +START_TEST(RtlpApplyLengthFunction) +{ + NTSTATUS Status; + /* Show that RtlpApplyLengthFunction does not interpret anything in the UNICODE_STRING */ + UNICODE_STRING String = { 1, 2, (PWSTR)3 }; + RTL_UNICODE_STRING_BUFFER Buffer; + WCHAR StaticBuffer[10] = { 0 }; + ULONG n; + + Status = RtlpApplyLengthFunction(0, 0, NULL, LengthFunctionFail); + ok_int(String.Length, 1); + ok_hex(Status, STATUS_INVALID_PARAMETER); + + Status = RtlpApplyLengthFunction(0, 0, &String, LengthFunctionFail); + ok_int(String.Length, 1); + ok_hex(Status, STATUS_INVALID_PARAMETER); + + /* Show that no flag is accepted */ + for (n = 0; n < 32; ++n) + { + Status = RtlpApplyLengthFunction((1 << n), sizeof(String), &String, LengthFunctionFail); + ok_int(String.Length, 1); + ok_hex(Status, STATUS_INVALID_PARAMETER); + } + + Status = RtlpApplyLengthFunction(0, sizeof(String), &String, NULL); + ok_int(String.Length, 1); + ok_hex(Status, STATUS_INVALID_PARAMETER); + + /* Still Length 1 when the function returns an error */ + Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionFail); + ok_int(String.Length, 1); + ok_hex(Status, STATUS_INVALID_ACCOUNT_NAME); + + Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionOk); + ok_int(String.Length, 8); /* Value returned from LengthFunction is multiplied by sizeof(WCHAR) */ + ok_hex(Status, STATUS_SUCCESS); + + String.Length = 1; + Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionReturn1); + ok_int(String.Length, 8); + ok_hex(Status, STATUS_SUCCESS); /* Returns STATUS_SUCCESS regardless of success code from the function */ + + /* Show max length */ + String.Buffer = (PWCHAR)UNICODE_STRING_MAX_CHARS; + String.Length = 2; + Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionCopyLen); + ok_int(String.Length, UNICODE_STRING_MAX_CHARS * sizeof(WCHAR)); + ok_hex(Status, STATUS_SUCCESS); + + String.Buffer = (PWCHAR)(UNICODE_STRING_MAX_CHARS + 1); + String.Length = 2; + Status = RtlpApplyLengthFunction(0, sizeof(String), &String, LengthFunctionCopyLen); + ok_int(String.Length, 2); /* Unchanged */ + ok_hex(Status, STATUS_NAME_TOO_LONG); + + /* Now try it with the RTL_UNICODE_STRING_BUFFER, this works fine on 2k3 but not on Win10!! */ + RtlInitBuffer(&Buffer.ByteBuffer, (PUCHAR)StaticBuffer, sizeof(StaticBuffer)); + /* In this case the Buffer is modified, so we should have a valid UNICODE_STRING! */ + Buffer.String.Length = 5; + Buffer.String.MaximumLength = Buffer.ByteBuffer.StaticSize; + Buffer.String.Buffer = (PWSTR)Buffer.ByteBuffer.Buffer; + wcscpy(StaticBuffer, L"123456789"); + + /* Show that no flag is accepted */ + for (n = 0; n < 32; ++n) + { + Status = RtlpApplyLengthFunction((1 << n), sizeof(Buffer), &Buffer, LengthFunctionFail); + ok_int(Buffer.String.Length, 5); + ok_hex(Status, STATUS_INVALID_PARAMETER); + ok_wstr(StaticBuffer, L"123456789"); + } + + /* Still Length 1 when the function returns an error */ + Status = RtlpApplyLengthFunction(0, sizeof(Buffer), &Buffer, LengthFunctionFail); + ok_int(Buffer.String.Length, 5); + ok_hex(Status, STATUS_INVALID_ACCOUNT_NAME); + ok_wstr(StaticBuffer, L"123456789"); + + Status = RtlpApplyLengthFunction(0, sizeof(Buffer), &Buffer, LengthFunctionOk); + ok_int(Buffer.String.Length, 8); /* Value returned from LengthFunction is multiplied by sizeof(WCHAR) */ + ok_hex(Status, STATUS_SUCCESS); + ok_wstr(StaticBuffer, L"1234"); /* Buffer is truncated */ + ok_wstr(StaticBuffer + 5, L"6789"); /* Rest is not overwritten*/ + + Buffer.String.Length = 1; + wcscpy(StaticBuffer, L"123456789"); + Status = RtlpApplyLengthFunction(0, sizeof(Buffer), &Buffer, LengthFunctionReturn1); + ok_int(Buffer.String.Length, 8); + ok_hex(Status, STATUS_SUCCESS); /* Returns STATUS_SUCCESS regardless of success code from the function */ + ok_wstr(StaticBuffer, L"1234"); /* Buffer is truncated */ + ok_wstr(StaticBuffer + 5, L"6789"); /* Rest is not overwritten*/ +} + diff --git a/modules/rostests/apitests/ntdll/testlist.c b/modules/rostests/apitests/ntdll/testlist.c index 8b7df571591..7c9cdb2f694 100644 --- a/modules/rostests/apitests/ntdll/testlist.c +++ b/modules/rostests/apitests/ntdll/testlist.c @@ -70,6 +70,7 @@ extern void func_RtlIsNameLegalDOS8Dot3(void); extern void func_RtlMemoryStream(void); extern void func_RtlMultipleAllocateHeap(void); extern void func_RtlNtPathNameToDosPathName(void); +extern void func_RtlpApplyLengthFunction(void); extern void func_RtlpEnsureBufferSize(void); extern void func_RtlQueryTimeZoneInformation(void); extern void func_RtlReAllocateHeap(void); @@ -148,6 +149,7 @@ const struct test winetest_testlist[] = { "RtlMemoryStream", func_RtlMemoryStream }, { "RtlMultipleAllocateHeap", func_RtlMultipleAllocateHeap }, { "RtlNtPathNameToDosPathName", func_RtlNtPathNameToDosPathName }, + { "RtlpApplyLengthFunction", func_RtlpApplyLengthFunction }, { "RtlpEnsureBufferSize", func_RtlpEnsureBufferSize }, { "RtlQueryTimeZoneInformation", func_RtlQueryTimeZoneInformation }, { "RtlReAllocateHeap", func_RtlReAllocateHeap }, diff --git a/sdk/lib/rtl/path.c b/sdk/lib/rtl/path.c index 6031ae32087..fb28160141b 100644 --- a/sdk/lib/rtl/path.c +++ b/sdk/lib/rtl/path.c @@ -446,10 +446,49 @@ NTAPI RtlpApplyLengthFunction(IN ULONG Flags, IN ULONG Type, IN PVOID UnicodeStringOrUnicodeStringBuffer, - IN PVOID LengthFunction) + IN NTSTATUS(NTAPI* LengthFunction)(ULONG, PUNICODE_STRING, PULONG)) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + NTSTATUS Status; + PUNICODE_STRING String; + ULONG Length; + + if (Flags || UnicodeStringOrUnicodeStringBuffer == NULL || LengthFunction == NULL) + { + DPRINT1("ERROR: Flags=0x%x, UnicodeStringOrUnicodeStringBuffer=%p, LengthFunction=%p\n", + Flags, UnicodeStringOrUnicodeStringBuffer, LengthFunction); + return STATUS_INVALID_PARAMETER; + } + + if (Type == sizeof(UNICODE_STRING)) + { + String = (PUNICODE_STRING)UnicodeStringOrUnicodeStringBuffer; + } + else if (Type == sizeof(RTL_UNICODE_STRING_BUFFER)) + { + String = &((PRTL_UNICODE_STRING_BUFFER)UnicodeStringOrUnicodeStringBuffer)->String; + } + else + { + DPRINT1("ERROR: Type = %u\n", Type); + return STATUS_INVALID_PARAMETER; + } + + Length = 0; + Status = LengthFunction(0, String, &Length); + if (!NT_SUCCESS(Status)) + return Status; + + if (Length > UNICODE_STRING_MAX_CHARS) + return STATUS_NAME_TOO_LONG; + + String->Length = (USHORT)(Length * sizeof(WCHAR)); + + if (Type == sizeof(RTL_UNICODE_STRING_BUFFER)) + { + String->Buffer[Length] = UNICODE_NULL; + } + + return STATUS_SUCCESS; }
NTSTATUS