[NTDLL_APITEST]
[reactos.git] / rostests / apitests / ntdll / RtlGetFullPathName_UstrEx.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for RtlGetFullPathName_UstrEx
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
6 */
7
8 #define WIN32_NO_STATUS
9 #include <wine/test.h>
10 #include <pseh/pseh2.h>
11 #include <ndk/rtlfuncs.h>
12
13 /*
14 NTSTATUS
15 NTAPI
16 RtlGetFullPathName_UstrEx(
17 IN PUNICODE_STRING FileName,
18 IN PUNICODE_STRING StaticString,
19 IN PUNICODE_STRING DynamicString,
20 IN PUNICODE_STRING *StringUsed,
21 IN PSIZE_T FilePartSize OPTIONAL,
22 OUT PBOOLEAN NameInvalid,
23 OUT RTL_PATH_TYPE* PathType,
24 OUT PSIZE_T LengthNeeded OPTIONAL
25 );
26 */
27
28 #define StartSeh() ExceptionStatus = STATUS_SUCCESS; _SEH2_TRY {
29 #define EndSeh(ExpectedStatus) } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { ExceptionStatus = _SEH2_GetExceptionCode(); } _SEH2_END; ok(ExceptionStatus == ExpectedStatus, "Exception %lx, expected %lx\n", ExceptionStatus, ExpectedStatus)
30
31 #define ok_eq_ustr(str1, str2) do { \
32 ok((str1)->Buffer == (str2)->Buffer, "Buffer modified\n"); \
33 ok((str1)->Length == (str2)->Length, "Length modified\n"); \
34 ok((str1)->MaximumLength == (str2)->MaximumLength, "MaximumLength modified\n"); \
35 } while (0)
36
37 static
38 BOOLEAN
39 CheckStringBuffer(
40 PCUNICODE_STRING String,
41 PCWSTR Expected)
42 {
43 USHORT Length = wcslen(Expected) * sizeof(WCHAR);
44 SIZE_T EqualLength;
45 BOOLEAN Result = TRUE;
46 SIZE_T i;
47
48 if (String->Length != Length)
49 {
50 ok(0, "String length is %u, expected %u\n", String->Length, Length);
51 Result = FALSE;
52 }
53
54 EqualLength = RtlCompareMemory(String->Buffer, Expected, Length);
55 if (EqualLength != Length)
56 {
57 ok(0, "String is '%wZ', expected '%S'\n", String, Expected);
58 Result = FALSE;
59 }
60
61 if (String->Buffer[String->Length / sizeof(WCHAR)] != UNICODE_NULL)
62 {
63 ok(0, "Not null terminated\n");
64 Result = FALSE;
65 }
66
67 /* the function nulls the rest of the buffer! */
68 for (i = String->Length + sizeof(UNICODE_NULL); i < String->MaximumLength; i++)
69 {
70 UCHAR Char = ((PUCHAR)String->Buffer)[i];
71 if (Char != 0)
72 {
73 ok(0, "Found 0x%x at offset %lu, expected 0x%x\n", Char, (ULONG)i, 0);
74 /* don't count this as a failure unless the string was actually wrong */
75 //Result = FALSE;
76 /* don't flood the log */
77 break;
78 }
79 }
80
81 return Result;
82 }
83
84 static
85 BOOLEAN
86 CheckBuffer(
87 PVOID Buffer,
88 SIZE_T Size,
89 UCHAR Value)
90 {
91 PUCHAR Array = Buffer;
92 SIZE_T i;
93
94 for (i = 0; i < Size; i++)
95 if (Array[i] != Value)
96 {
97 trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i);
98 return FALSE;
99 }
100 return TRUE;
101 }
102
103 #define RtlPathTypeNotSet 123
104 #define InvalidPointer ((PVOID)0x0123456789ABCDEFULL)
105
106 /* winetest_platform is "windows" for us, so broken() doesn't do what it should :( */
107 #undef broken
108 #define broken(x) 0
109
110 typedef enum
111 {
112 PrefixNone,
113 PrefixCurrentDrive,
114 PrefixCurrentPath,
115 PrefixCurrentPathWithoutLastPart
116 } PREFIX_TYPE;
117
118 static
119 VOID
120 RunTestCases(VOID)
121 {
122 /* TODO: don't duplicate this in the other tests */
123 /* TODO: Drive Relative tests don't work yet if the current drive isn't C: */
124 struct
125 {
126 PCWSTR FileName;
127 PREFIX_TYPE PrefixType;
128 PCWSTR FullPathName;
129 RTL_PATH_TYPE PathType;
130 PREFIX_TYPE FilePartPrefixType;
131 SIZE_T FilePartSize;
132 } TestCases[] =
133 {
134 { L"C:", PrefixCurrentPath, L"", RtlPathTypeDriveRelative, PrefixCurrentPathWithoutLastPart },
135 { L"C:\\", PrefixNone, L"C:\\", RtlPathTypeDriveAbsolute },
136 { L"C:\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive },
137 { L"C:\\test\\", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute },
138 { L"C:/test/", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute },
139
140 { L"C:\\\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive },
141 { L"test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) },
142 { L"\\test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive },
143 { L"/test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive },
144 { L".\\test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) },
145
146 { L"\\.", PrefixCurrentDrive, L"", RtlPathTypeRooted },
147 { L"\\.\\", PrefixCurrentDrive, L"", RtlPathTypeRooted },
148 { L"\\\\.", PrefixNone, L"\\\\.\\", RtlPathTypeRootLocalDevice },
149 { L"\\\\.\\", PrefixNone, L"\\\\.\\", RtlPathTypeLocalDevice },
150 { L"\\\\.\\Something\\", PrefixNone, L"\\\\.\\Something\\", RtlPathTypeLocalDevice },
151
152 { L"\\??\\", PrefixCurrentDrive, L"??\\", RtlPathTypeRooted },
153 { L"\\??\\C:", PrefixCurrentDrive, L"??\\C:", RtlPathTypeRooted, PrefixCurrentDrive, 3 * sizeof(WCHAR) },
154 { L"\\??\\C:\\", PrefixCurrentDrive, L"??\\C:\\", RtlPathTypeRooted },
155 { L"\\??\\C:\\test", PrefixCurrentDrive, L"??\\C:\\test", RtlPathTypeRooted, PrefixCurrentDrive, 6 * sizeof(WCHAR) },
156 { L"\\??\\C:\\test\\", PrefixCurrentDrive, L"??\\C:\\test\\", RtlPathTypeRooted },
157
158 { L"\\\\??\\", PrefixNone, L"\\\\??\\", RtlPathTypeUncAbsolute },
159 { L"\\\\??\\C:", PrefixNone, L"\\\\??\\C:", RtlPathTypeUncAbsolute },
160 { L"\\\\??\\C:\\", PrefixNone, L"\\\\??\\C:\\", RtlPathTypeUncAbsolute },
161 { L"\\\\??\\C:\\test", PrefixNone, L"\\\\??\\C:\\test", RtlPathTypeUncAbsolute, PrefixNone, sizeof(L"\\\\??\\C:\\") },
162 { L"\\\\??\\C:\\test\\", PrefixNone, L"\\\\??\\C:\\test\\", RtlPathTypeUncAbsolute },
163 };
164 NTSTATUS Status, ExceptionStatus;
165 UNICODE_STRING FileName;
166 UNICODE_STRING FullPathName;
167 WCHAR FullPathNameBuffer[MAX_PATH];
168 UNICODE_STRING TempString;
169 PUNICODE_STRING StringUsed;
170 SIZE_T FilePartSize;
171 BOOLEAN NameInvalid;
172 RTL_PATH_TYPE PathType;
173 SIZE_T LengthNeeded;
174 WCHAR ExpectedPathName[MAX_PATH];
175 SIZE_T ExpectedFilePartSize;
176 const INT TestCount = sizeof(TestCases) / sizeof(TestCases[0]);
177 INT i;
178
179 for (i = 0; i < TestCount; i++)
180 {
181 trace("i = %d\n", i);
182 switch (TestCases[i].PrefixType)
183 {
184 case PrefixNone:
185 ExpectedPathName[0] = UNICODE_NULL;
186 break;
187 case PrefixCurrentDrive:
188 GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
189 ExpectedPathName[3] = UNICODE_NULL;
190 break;
191 case PrefixCurrentPath:
192 {
193 ULONG Length;
194 Length = GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
195 if (Length == 3 && TestCases[i].FullPathName[0])
196 ExpectedPathName[2] = UNICODE_NULL;
197 break;
198 }
199 default:
200 skip(0, "Invalid test!\n");
201 continue;
202 }
203 wcscat(ExpectedPathName, TestCases[i].FullPathName);
204 RtlInitUnicodeString(&FileName, TestCases[i].FileName);
205 RtlInitEmptyUnicodeString(&FullPathName, FullPathNameBuffer, sizeof(FullPathNameBuffer));
206 RtlFillMemory(FullPathName.Buffer, FullPathName.MaximumLength, 0xAA);
207 TempString = FileName;
208 PathType = RtlPathTypeNotSet;
209 StringUsed = InvalidPointer;
210 FilePartSize = 1234;
211 NameInvalid = (BOOLEAN)-1;
212 LengthNeeded = 1234;
213 StartSeh()
214 Status = RtlGetFullPathName_UstrEx(&FileName,
215 &FullPathName,
216 NULL,
217 &StringUsed,
218 &FilePartSize,
219 &NameInvalid,
220 &PathType,
221 &LengthNeeded);
222 ok(Status == STATUS_SUCCESS, "status = %lx\n", Status);
223 EndSeh(STATUS_SUCCESS);
224 ok_eq_ustr(&FileName, &TempString);
225 ok(FullPathName.Buffer == FullPathNameBuffer, "Buffer modified\n");
226 ok(FullPathName.MaximumLength == sizeof(FullPathNameBuffer), "MaximumLength modified\n");
227 ok(CheckStringBuffer(&FullPathName, ExpectedPathName),
228 "Wrong path name '%wZ', expected '%S'\n", &FullPathName, ExpectedPathName);
229 ok(StringUsed == &FullPathName, "StringUsed = %p, expected %p\n", StringUsed, &FullPathName);
230 switch (TestCases[i].FilePartPrefixType)
231 {
232 case PrefixNone:
233 ExpectedFilePartSize = 0;
234 break;
235 case PrefixCurrentDrive:
236 ExpectedFilePartSize = sizeof(L"C:\\");
237 break;
238 case PrefixCurrentPath:
239 ExpectedFilePartSize = GetCurrentDirectoryW(0, NULL) * sizeof(WCHAR);
240 if (ExpectedFilePartSize == sizeof(L"C:\\"))
241 ExpectedFilePartSize -= sizeof(WCHAR);
242 break;
243 case PrefixCurrentPathWithoutLastPart:
244 {
245 WCHAR CurrentPath[MAX_PATH];
246 PCWSTR BackSlash;
247 ExpectedFilePartSize = GetCurrentDirectoryW(sizeof(CurrentPath) / sizeof(WCHAR), CurrentPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
248 if (ExpectedFilePartSize == sizeof(L"C:\\"))
249 ExpectedFilePartSize = 0;
250 else
251 {
252 BackSlash = wcsrchr(CurrentPath, L'\\');
253 if (BackSlash)
254 ExpectedFilePartSize -= wcslen(BackSlash + 1) * sizeof(WCHAR);
255 else
256 ok(0, "GetCurrentDirectory returned %S\n", CurrentPath);
257 }
258 break;
259 }
260 default:
261 skip(0, "Invalid test!\n");
262 continue;
263 }
264 ExpectedFilePartSize += TestCases[i].FilePartSize;
265 if (ExpectedFilePartSize != 0)
266 ExpectedFilePartSize = (ExpectedFilePartSize - sizeof(UNICODE_NULL)) / sizeof(WCHAR);
267 ok(FilePartSize == ExpectedFilePartSize,
268 "FilePartSize = %lu, expected %lu\n", (ULONG)FilePartSize, (ULONG)ExpectedFilePartSize);
269 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
270 ok(PathType == TestCases[i].PathType, "PathType = %d, expected %d\n", PathType, TestCases[i].PathType);
271 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
272 }
273 }
274
275 START_TEST(RtlGetFullPathName_UstrEx)
276 {
277 NTSTATUS Status, ExceptionStatus;
278 UNICODE_STRING FileName;
279 UNICODE_STRING TempString;
280 UNICODE_STRING StaticString;
281 PUNICODE_STRING StringUsed;
282 SIZE_T FilePartSize;
283 BOOLEAN NameInvalid;
284 BOOLEAN NameInvalidArray[sizeof(ULONGLONG)];
285 RTL_PATH_TYPE PathType;
286 SIZE_T LengthNeeded;
287
288 /* NULL parameters */
289 StartSeh()
290 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
291 EndSeh(STATUS_ACCESS_VIOLATION);
292
293 RtlInitUnicodeString(&FileName, NULL);
294 TempString = FileName;
295 StartSeh()
296 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
297 EndSeh(STATUS_ACCESS_VIOLATION);
298 ok_eq_ustr(&FileName, &TempString);
299
300 RtlInitUnicodeString(&FileName, L"");
301 TempString = FileName;
302 StartSeh()
303 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
304 EndSeh(STATUS_ACCESS_VIOLATION);
305 ok_eq_ustr(&FileName, &TempString);
306
307 PathType = RtlPathTypeNotSet;
308 StartSeh()
309 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
310 EndSeh(STATUS_ACCESS_VIOLATION);
311 ok(PathType == RtlPathTypeUnknown ||
312 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
313
314 /* Check what else is initialized before it crashes */
315 PathType = RtlPathTypeNotSet;
316 StringUsed = InvalidPointer;
317 FilePartSize = 1234;
318 NameInvalid = (BOOLEAN)-1;
319 LengthNeeded = 1234;
320 StartSeh()
321 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, &PathType, &LengthNeeded);
322 EndSeh(STATUS_ACCESS_VIOLATION);
323 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
324 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
325 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
326 ok(PathType == RtlPathTypeUnknown ||
327 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
328 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
329
330 RtlInitUnicodeString(&FileName, L"");
331 TempString = FileName;
332 StringUsed = InvalidPointer;
333 FilePartSize = 1234;
334 NameInvalid = (BOOLEAN)-1;
335 LengthNeeded = 1234;
336 StartSeh()
337 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, NULL, &LengthNeeded);
338 EndSeh(STATUS_ACCESS_VIOLATION);
339 ok_eq_ustr(&FileName, &TempString);
340 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
341 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
342 ok(NameInvalid == FALSE ||
343 broken(NameInvalid == (BOOLEAN)-1) /* Win7 */, "NameInvalid = %u\n", NameInvalid);
344 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
345
346 /* This is the first one that doesn't crash. FileName and PathType cannot be NULL */
347 RtlInitUnicodeString(&FileName, NULL);
348 TempString = FileName;
349 PathType = RtlPathTypeNotSet;
350 StartSeh()
351 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
352 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
353 EndSeh(STATUS_SUCCESS);
354 ok_eq_ustr(&FileName, &TempString);
355 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
356
357 RtlInitUnicodeString(&FileName, L"");
358 TempString = FileName;
359 PathType = RtlPathTypeNotSet;
360 StartSeh()
361 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
362 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
363 EndSeh(STATUS_SUCCESS);
364 ok_eq_ustr(&FileName, &TempString);
365 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
366
367 /* Show that NameInvalid is indeed BOOLEAN */
368 RtlInitUnicodeString(&FileName, L"");
369 TempString = FileName;
370 PathType = RtlPathTypeNotSet;
371 RtlFillMemory(NameInvalidArray, sizeof(NameInvalidArray), 0x55);
372 StartSeh()
373 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NameInvalidArray, &PathType, NULL);
374 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
375 EndSeh(STATUS_SUCCESS);
376 ok_eq_ustr(&FileName, &TempString);
377 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
378 ok(NameInvalidArray[0] == FALSE, "NameInvalid = %u\n", NameInvalidArray[0]);
379 ok(CheckBuffer(NameInvalidArray + 1, sizeof(NameInvalidArray) - sizeof(NameInvalidArray[0]), 0x55), "CheckBuffer failed\n");
380
381 /* Give it a valid path */
382 RtlInitUnicodeString(&FileName, L"C:\\test");
383 TempString = FileName;
384 PathType = RtlPathTypeNotSet;
385 StartSeh()
386 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
387 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
388 EndSeh(STATUS_SUCCESS);
389 ok_eq_ustr(&FileName, &TempString);
390 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
391
392 /* Zero-length static string */
393 RtlInitUnicodeString(&FileName, L"C:\\test");
394 TempString = FileName;
395 RtlInitUnicodeString(&StaticString, NULL);
396 PathType = RtlPathTypeNotSet;
397 StartSeh()
398 Status = RtlGetFullPathName_UstrEx(&FileName, &StaticString, NULL, NULL, NULL, NULL, &PathType, NULL);
399 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
400 EndSeh(STATUS_SUCCESS);
401 ok_eq_ustr(&FileName, &TempString);
402 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
403
404 /* TODO: play around with StaticString and DynamicString */
405
406 /* Check the actual functionality with different paths */
407 RunTestCases();
408 }