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