c81e59749d174f0ec00e29051d7aff5797710c25
[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 SIZE_T ExpectedLength = wcslen(Expected) * sizeof(WCHAR);
44 SIZE_T EqualLength;
45 BOOLEAN Result = TRUE;
46 SIZE_T i;
47
48 if (String->Length != ExpectedLength)
49 {
50 ok(0, "String length is %u, expected %lu\n", String->Length, (ULONG)ExpectedLength);
51 Result = FALSE;
52 }
53
54 EqualLength = RtlCompareMemory(String->Buffer, Expected, ExpectedLength);
55 if (EqualLength != ExpectedLength)
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 BOOLEAN Okay;
179
180 for (i = 0; i < TestCount; i++)
181 {
182 trace("i = %d\n", i);
183 switch (TestCases[i].PrefixType)
184 {
185 case PrefixNone:
186 ExpectedPathName[0] = UNICODE_NULL;
187 break;
188 case PrefixCurrentDrive:
189 GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
190 ExpectedPathName[3] = UNICODE_NULL;
191 break;
192 case PrefixCurrentPath:
193 {
194 ULONG Length;
195 Length = GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
196 if (Length == 3 && TestCases[i].FullPathName[0])
197 ExpectedPathName[2] = UNICODE_NULL;
198 break;
199 }
200 default:
201 skip(0, "Invalid test!\n");
202 continue;
203 }
204 wcscat(ExpectedPathName, TestCases[i].FullPathName);
205 RtlInitUnicodeString(&FileName, TestCases[i].FileName);
206 RtlInitEmptyUnicodeString(&FullPathName, FullPathNameBuffer, sizeof(FullPathNameBuffer));
207 RtlFillMemory(FullPathName.Buffer, FullPathName.MaximumLength, 0xAA);
208 TempString = FileName;
209 PathType = RtlPathTypeNotSet;
210 StringUsed = InvalidPointer;
211 FilePartSize = 1234;
212 NameInvalid = (BOOLEAN)-1;
213 LengthNeeded = 1234;
214 StartSeh()
215 Status = RtlGetFullPathName_UstrEx(&FileName,
216 &FullPathName,
217 NULL,
218 &StringUsed,
219 &FilePartSize,
220 &NameInvalid,
221 &PathType,
222 &LengthNeeded);
223 ok(Status == STATUS_SUCCESS, "status = %lx\n", Status);
224 EndSeh(STATUS_SUCCESS);
225 ok_eq_ustr(&FileName, &TempString);
226 ok(FullPathName.Buffer == FullPathNameBuffer, "Buffer modified\n");
227 ok(FullPathName.MaximumLength == sizeof(FullPathNameBuffer), "MaximumLength modified\n");
228 Okay = CheckStringBuffer(&FullPathName, ExpectedPathName);
229 ok(Okay, "Wrong path name '%wZ', expected '%S'\n", &FullPathName, ExpectedPathName);
230 ok(StringUsed == &FullPathName, "StringUsed = %p, expected %p\n", StringUsed, &FullPathName);
231 switch (TestCases[i].FilePartPrefixType)
232 {
233 case PrefixNone:
234 ExpectedFilePartSize = 0;
235 break;
236 case PrefixCurrentDrive:
237 ExpectedFilePartSize = sizeof(L"C:\\");
238 break;
239 case PrefixCurrentPath:
240 ExpectedFilePartSize = GetCurrentDirectoryW(0, NULL) * sizeof(WCHAR);
241 if (ExpectedFilePartSize == sizeof(L"C:\\"))
242 ExpectedFilePartSize -= sizeof(WCHAR);
243 break;
244 case PrefixCurrentPathWithoutLastPart:
245 {
246 WCHAR CurrentPath[MAX_PATH];
247 PCWSTR BackSlash;
248 ExpectedFilePartSize = GetCurrentDirectoryW(sizeof(CurrentPath) / sizeof(WCHAR), CurrentPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
249 if (ExpectedFilePartSize == sizeof(L"C:\\"))
250 ExpectedFilePartSize = 0;
251 else
252 {
253 BackSlash = wcsrchr(CurrentPath, L'\\');
254 if (BackSlash)
255 ExpectedFilePartSize -= wcslen(BackSlash + 1) * sizeof(WCHAR);
256 else
257 ok(0, "GetCurrentDirectory returned %S\n", CurrentPath);
258 }
259 break;
260 }
261 default:
262 skip(0, "Invalid test!\n");
263 continue;
264 }
265 ExpectedFilePartSize += TestCases[i].FilePartSize;
266 if (ExpectedFilePartSize != 0)
267 ExpectedFilePartSize = (ExpectedFilePartSize - sizeof(UNICODE_NULL)) / sizeof(WCHAR);
268 ok(FilePartSize == ExpectedFilePartSize,
269 "FilePartSize = %lu, expected %lu\n", (ULONG)FilePartSize, (ULONG)ExpectedFilePartSize);
270 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
271 ok(PathType == TestCases[i].PathType, "PathType = %d, expected %d\n", PathType, TestCases[i].PathType);
272 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
273 }
274 }
275
276 START_TEST(RtlGetFullPathName_UstrEx)
277 {
278 NTSTATUS Status, ExceptionStatus;
279 UNICODE_STRING FileName;
280 UNICODE_STRING TempString;
281 UNICODE_STRING StaticString;
282 PUNICODE_STRING StringUsed;
283 SIZE_T FilePartSize;
284 BOOLEAN NameInvalid;
285 BOOLEAN NameInvalidArray[sizeof(ULONGLONG)];
286 RTL_PATH_TYPE PathType;
287 SIZE_T LengthNeeded;
288 BOOLEAN Okay;
289
290 /* NULL parameters */
291 StartSeh()
292 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
293 EndSeh(STATUS_ACCESS_VIOLATION);
294
295 RtlInitUnicodeString(&FileName, NULL);
296 TempString = FileName;
297 StartSeh()
298 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
299 EndSeh(STATUS_ACCESS_VIOLATION);
300 ok_eq_ustr(&FileName, &TempString);
301
302 RtlInitUnicodeString(&FileName, L"");
303 TempString = FileName;
304 StartSeh()
305 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
306 EndSeh(STATUS_ACCESS_VIOLATION);
307 ok_eq_ustr(&FileName, &TempString);
308
309 PathType = RtlPathTypeNotSet;
310 StartSeh()
311 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
312 EndSeh(STATUS_ACCESS_VIOLATION);
313 ok(PathType == RtlPathTypeUnknown ||
314 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
315
316 /* Check what else is initialized before it crashes */
317 PathType = RtlPathTypeNotSet;
318 StringUsed = InvalidPointer;
319 FilePartSize = 1234;
320 NameInvalid = (BOOLEAN)-1;
321 LengthNeeded = 1234;
322 StartSeh()
323 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, &PathType, &LengthNeeded);
324 EndSeh(STATUS_ACCESS_VIOLATION);
325 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
326 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
327 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
328 ok(PathType == RtlPathTypeUnknown ||
329 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
330 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
331
332 RtlInitUnicodeString(&FileName, L"");
333 TempString = FileName;
334 StringUsed = InvalidPointer;
335 FilePartSize = 1234;
336 NameInvalid = (BOOLEAN)-1;
337 LengthNeeded = 1234;
338 StartSeh()
339 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, NULL, &LengthNeeded);
340 EndSeh(STATUS_ACCESS_VIOLATION);
341 ok_eq_ustr(&FileName, &TempString);
342 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
343 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
344 ok(NameInvalid == FALSE ||
345 broken(NameInvalid == (BOOLEAN)-1) /* Win7 */, "NameInvalid = %u\n", NameInvalid);
346 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
347
348 /* This is the first one that doesn't crash. FileName and PathType cannot be NULL */
349 RtlInitUnicodeString(&FileName, NULL);
350 TempString = FileName;
351 PathType = RtlPathTypeNotSet;
352 StartSeh()
353 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
354 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
355 EndSeh(STATUS_SUCCESS);
356 ok_eq_ustr(&FileName, &TempString);
357 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
358
359 RtlInitUnicodeString(&FileName, L"");
360 TempString = FileName;
361 PathType = RtlPathTypeNotSet;
362 StartSeh()
363 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
364 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
365 EndSeh(STATUS_SUCCESS);
366 ok_eq_ustr(&FileName, &TempString);
367 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
368
369 /* Show that NameInvalid is indeed BOOLEAN */
370 RtlInitUnicodeString(&FileName, L"");
371 TempString = FileName;
372 PathType = RtlPathTypeNotSet;
373 RtlFillMemory(NameInvalidArray, sizeof(NameInvalidArray), 0x55);
374 StartSeh()
375 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NameInvalidArray, &PathType, NULL);
376 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
377 EndSeh(STATUS_SUCCESS);
378 ok_eq_ustr(&FileName, &TempString);
379 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
380 ok(NameInvalidArray[0] == FALSE, "NameInvalid = %u\n", NameInvalidArray[0]);
381 Okay = CheckBuffer(NameInvalidArray + 1, sizeof(NameInvalidArray) - sizeof(NameInvalidArray[0]), 0x55);
382 ok(Okay, "CheckBuffer failed\n");
383
384 /* Give it a valid path */
385 RtlInitUnicodeString(&FileName, L"C:\\test");
386 TempString = FileName;
387 PathType = RtlPathTypeNotSet;
388 StartSeh()
389 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
390 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
391 EndSeh(STATUS_SUCCESS);
392 ok_eq_ustr(&FileName, &TempString);
393 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
394
395 /* Zero-length static string */
396 RtlInitUnicodeString(&FileName, L"C:\\test");
397 TempString = FileName;
398 RtlInitUnicodeString(&StaticString, NULL);
399 PathType = RtlPathTypeNotSet;
400 StartSeh()
401 Status = RtlGetFullPathName_UstrEx(&FileName, &StaticString, NULL, NULL, NULL, NULL, &PathType, NULL);
402 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
403 EndSeh(STATUS_SUCCESS);
404 ok_eq_ustr(&FileName, &TempString);
405 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
406
407 /* TODO: play around with StaticString and DynamicString */
408
409 /* Check the actual functionality with different paths */
410 RunTestCases();
411 }