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