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