Reactos
1/*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Test for NtQueryObject
5 * COPYRIGHT: Copyright 2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
6 */
7
8#include "precomp.h"
9
10/* Flags combination allowing all the read, write and delete share modes.
11 * Currently similar to FILE_SHARE_VALID_FLAGS. */
12#define FILE_SHARE_ALL \
13 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
14
15/* Adapted from kmtests/ntos_ob/ObQuery.c!ObjectNameInformationTests().
16 * Please sync both tests in case you add or remove new features. */
17START_TEST(NtQueryObject)
18{
19 ULONG g_OsVersion =
20 SharedUserData->NtMajorVersion << 8 | SharedUserData->NtMinorVersion;
21
22 NTSTATUS Status;
23 HANDLE DeviceHandle;
24 UNICODE_STRING DeviceName;
25 OBJECT_ATTRIBUTES ObjectAttributes;
26 IO_STATUS_BLOCK IoStatusBlock;
27
28 ULONG BufferSize1, BufferSize2, BufferSize3;
29 struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ObjectNameBuffer;
30 PUNICODE_STRING ObjectName = &ObjectNameBuffer.Name;
31
32 /* Test the drive containing SystemRoot */
33 WCHAR NtDeviceName[] = L"\\DosDevices\\?:";
34 NtDeviceName[sizeof("\\DosDevices\\")-1] = SharedUserData->NtSystemRoot[0];
35
36 /* Open a handle to the device */
37 RtlInitUnicodeString(&DeviceName, NtDeviceName);
38 InitializeObjectAttributes(&ObjectAttributes,
39 &DeviceName,
40 OBJ_CASE_INSENSITIVE,
41 NULL,
42 NULL);
43 Status = NtOpenFile(&DeviceHandle,
44 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
45 &ObjectAttributes,
46 &IoStatusBlock,
47 FILE_SHARE_ALL,
48 FILE_SYNCHRONOUS_IO_NONALERT);
49 ok_ntstatus(Status, STATUS_SUCCESS);
50 if (!NT_SUCCESS(Status))
51 {
52 skip("Device '%S': Opening failed\n", NtDeviceName);
53 return;
54 }
55
56 /* Invoke ObjectNameInformation that retrieves the canonical device name */
57 Status = NtQueryObject(DeviceHandle,
58 ObjectNameInformation,
59 &ObjectNameBuffer,
60 0,
61 &BufferSize1);
62 ok_ntstatus(Status, STATUS_INFO_LENGTH_MISMATCH);
63
64 Status = NtQueryObject(DeviceHandle,
65 ObjectNameInformation,
66 &ObjectNameBuffer,
67 sizeof(OBJECT_NAME_INFORMATION),
68 &BufferSize2);
69 ok_ntstatus(Status, STATUS_BUFFER_OVERFLOW);
70
71 Status = NtQueryObject(DeviceHandle,
72 ObjectNameInformation,
73 &ObjectNameBuffer,
74 sizeof(ObjectNameBuffer),
75 &BufferSize3);
76 ok_ntstatus(Status, STATUS_SUCCESS);
77
78 NtClose(DeviceHandle);
79
80 /* Compare the returned buffer sizes */
81
82 /* The returned size behaviour changed (when NtQueryObject()'s
83 * input Length is zero) between Windows <= 2003 and Vista+ */
84 if (g_OsVersion < _WIN32_WINNT_VISTA)
85 ok_eq_ulong(BufferSize1, (ULONG)sizeof(OBJECT_NAME_INFORMATION));
86 else
87 ok_eq_ulong(BufferSize1, (ULONG)sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength);
88
89 ok_eq_ulong(BufferSize2, BufferSize3);
90 ok_eq_ulong(BufferSize3, (ULONG)sizeof(OBJECT_NAME_INFORMATION) + ObjectName->MaximumLength);
91
92 /* Test the name buffer */
93 ok(ObjectName->Length > 0, "ObjectName->Length == %hu, expected > 0\n", ObjectName->Length);
94 ok_eq_uint(ObjectName->MaximumLength, ObjectName->Length + sizeof(WCHAR));
95 ok(ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] == UNICODE_NULL,
96 "UNICODE_NULL not found at end of ObjectName->Buffer\n");
97 if (ObjectName->Buffer[ObjectName->Length / sizeof(WCHAR)] != UNICODE_NULL)
98 {
99 skip("ObjectName->Buffer string length check skipped\n");
100 return;
101 }
102
103 /* Verify that ObjectName->Length doesn't count extra NUL-terminators */
104 SIZE_T strLen = wcslen(ObjectName->Buffer) * sizeof(WCHAR);
105 ok_eq_size(strLen, (SIZE_T)ObjectName->Length);
106
107 /* Get the full path name of the current executable */
108 WCHAR ExecutablePath[MAX_PATH];
109 GetModuleFileNameW(NULL, ExecutablePath, MAX_PATH);
110
111 /* Open the executable file */
112 HANDLE FileHandle;
113 FileHandle = CreateFileW(ExecutablePath,
114 GENERIC_READ,
115 FILE_SHARE_READ | FILE_SHARE_WRITE,
116 NULL,
117 OPEN_EXISTING,
118 FILE_ATTRIBUTE_NORMAL,
119 NULL);
120 ok(FileHandle != INVALID_HANDLE_VALUE,
121 "File '%S': Opening failed\n", ExecutablePath);
122 if (FileHandle == INVALID_HANDLE_VALUE)
123 {
124 skip("File '%S': Opening failed\n", ExecutablePath);
125 return;
126 }
127
128 /* Query the name of the file */
129 Status = NtQueryObject(FileHandle,
130 ObjectNameInformation,
131 &ObjectNameBuffer,
132 sizeof(ObjectNameBuffer),
133 &BufferSize3);
134 ok_ntstatus(Status, STATUS_SUCCESS);
135
136 /* Validate that the name starts with "\\Device" */
137 ok(wcsncmp(ObjectName->Buffer, L"\\Device", 7) == 0,
138 "ObjectName->Buffer: '%S' does not start with '\\Device'\n",
139 ObjectName->Buffer);
140}