b8d49f8f4e6e8555df33bf49e65b42b70c4ece45
[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 #define RtlPathTypeNotSet 123
85 #define InvalidPointer ((PVOID)0x0123456789ABCDEFULL)
86
87 /* winetest_platform is "windows" for us, so broken() doesn't do what it should :( */
88 #undef broken
89 #define broken(x) 0
90
91 typedef enum
92 {
93 PrefixNone,
94 PrefixCurrentDrive,
95 PrefixCurrentPath,
96 PrefixCurrentPathWithoutLastPart
97 } PREFIX_TYPE;
98
99 static
100 VOID
101 RunTestCases(VOID)
102 {
103 /* TODO: don't duplicate this here and in the RtlGetFullPathName_U test */
104 struct
105 {
106 PCWSTR FileName;
107 PREFIX_TYPE PrefixType;
108 PCWSTR FullPathName;
109 RTL_PATH_TYPE PathType;
110 PREFIX_TYPE FilePartPrefixType;
111 SIZE_T FilePartSize;
112 } TestCases[] =
113 {
114 { L"C:", PrefixCurrentPath, L"", RtlPathTypeDriveRelative, PrefixCurrentPathWithoutLastPart },
115 { L"C:\\", PrefixNone, L"C:\\", RtlPathTypeDriveAbsolute },
116 { L"C:\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive },
117 { L"C:\\test\\", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute },
118 { L"C:/test/", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute },
119
120 { L"C:\\\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive },
121 { L"test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) },
122 { L"\\test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive },
123 { L"/test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive },
124 { L".\\test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) },
125
126 { L"\\.", PrefixCurrentDrive, L"", RtlPathTypeRooted },
127 { L"\\.\\", PrefixCurrentDrive, L"", RtlPathTypeRooted },
128 { L"\\\\.", PrefixNone, L"\\\\.\\", RtlPathTypeRootLocalDevice },
129 { L"\\\\.\\", PrefixNone, L"\\\\.\\", RtlPathTypeLocalDevice },
130 { L"\\\\.\\Something\\", PrefixNone, L"\\\\.\\Something\\", RtlPathTypeLocalDevice },
131
132 { L"\\??\\", PrefixCurrentDrive, L"??\\", RtlPathTypeRooted },
133 { L"\\??\\C:", PrefixCurrentDrive, L"??\\C:", RtlPathTypeRooted, PrefixCurrentDrive, 3 * sizeof(WCHAR) },
134 { L"\\??\\C:\\", PrefixCurrentDrive, L"??\\C:\\", RtlPathTypeRooted },
135 { L"\\??\\C:\\test", PrefixCurrentDrive, L"??\\C:\\test", RtlPathTypeRooted, PrefixCurrentDrive, 6 * sizeof(WCHAR) },
136 { L"\\??\\C:\\test\\", PrefixCurrentDrive, L"??\\C:\\test\\", RtlPathTypeRooted },
137
138 { L"\\\\??\\", PrefixNone, L"\\\\??\\", RtlPathTypeUncAbsolute },
139 { L"\\\\??\\C:", PrefixNone, L"\\\\??\\C:", RtlPathTypeUncAbsolute },
140 { L"\\\\??\\C:\\", PrefixNone, L"\\\\??\\C:\\", RtlPathTypeUncAbsolute },
141 { L"\\\\??\\C:\\test", PrefixNone, L"\\\\??\\C:\\test", RtlPathTypeUncAbsolute, PrefixNone, sizeof(L"\\\\??\\C:\\") },
142 { L"\\\\??\\C:\\test\\", PrefixNone, L"\\\\??\\C:\\test\\", RtlPathTypeUncAbsolute },
143 };
144 NTSTATUS Status, ExceptionStatus;
145 UNICODE_STRING FileName;
146 UNICODE_STRING FullPathName;
147 WCHAR FullPathNameBuffer[MAX_PATH];
148 UNICODE_STRING TempString;
149 PUNICODE_STRING StringUsed;
150 SIZE_T FilePartSize;
151 BOOLEAN NameInvalid;
152 RTL_PATH_TYPE PathType;
153 SIZE_T LengthNeeded;
154 WCHAR ExpectedPathName[MAX_PATH];
155 SIZE_T ExpectedFilePartSize;
156 const INT TestCount = sizeof(TestCases) / sizeof(TestCases[0]);
157 INT i;
158
159 for (i = 0; i < TestCount; i++)
160 {
161 trace("i = %d\n", i);
162 switch (TestCases[i].PrefixType)
163 {
164 case PrefixNone:
165 ExpectedPathName[0] = UNICODE_NULL;
166 break;
167 case PrefixCurrentDrive:
168 GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
169 ExpectedPathName[3] = UNICODE_NULL;
170 break;
171 case PrefixCurrentPath:
172 {
173 ULONG Length;
174 Length = GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
175 if (Length == 3 && TestCases[i].FullPathName[0])
176 ExpectedPathName[2] = UNICODE_NULL;
177 break;
178 }
179 default:
180 skip(0, "Invalid test!\n");
181 continue;
182 }
183 wcscat(ExpectedPathName, TestCases[i].FullPathName);
184 RtlInitUnicodeString(&FileName, TestCases[i].FileName);
185 RtlInitEmptyUnicodeString(&FullPathName, FullPathNameBuffer, sizeof(FullPathNameBuffer));
186 RtlFillMemory(FullPathName.Buffer, FullPathName.MaximumLength, 0xAA);
187 TempString = FileName;
188 PathType = RtlPathTypeNotSet;
189 StringUsed = InvalidPointer;
190 FilePartSize = 1234;
191 NameInvalid = (BOOLEAN)-1;
192 LengthNeeded = 1234;
193 StartSeh()
194 Status = RtlGetFullPathName_UstrEx(&FileName,
195 &FullPathName,
196 NULL,
197 &StringUsed,
198 &FilePartSize,
199 &NameInvalid,
200 &PathType,
201 &LengthNeeded);
202 ok(Status == STATUS_SUCCESS, "status = %lx\n", Status);
203 EndSeh(STATUS_SUCCESS);
204 ok_eq_ustr(&FileName, &TempString);
205 ok(FullPathName.Buffer == FullPathNameBuffer, "Buffer modified\n");
206 ok(FullPathName.MaximumLength == sizeof(FullPathNameBuffer), "MaximumLength modified\n");
207 ok(CheckStringBuffer(&FullPathName, ExpectedPathName),
208 "Wrong path name '%wZ', expected '%S'\n", &FullPathName, ExpectedPathName);
209 ok(StringUsed == &FullPathName, "StringUsed = %p, expected %p\n", StringUsed, &FullPathName);
210 switch (TestCases[i].FilePartPrefixType)
211 {
212 case PrefixNone:
213 ExpectedFilePartSize = 0;
214 break;
215 case PrefixCurrentDrive:
216 ExpectedFilePartSize = sizeof(L"C:\\");
217 break;
218 case PrefixCurrentPath:
219 ExpectedFilePartSize = GetCurrentDirectoryW(0, NULL) * sizeof(WCHAR);
220 if (ExpectedFilePartSize == sizeof(L"C:\\"))
221 ExpectedFilePartSize -= sizeof(WCHAR);
222 break;
223 case PrefixCurrentPathWithoutLastPart:
224 {
225 WCHAR CurrentPath[MAX_PATH];
226 PCWSTR BackSlash;
227 ExpectedFilePartSize = GetCurrentDirectoryW(sizeof(CurrentPath) / sizeof(WCHAR), CurrentPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
228 if (ExpectedFilePartSize == sizeof(L"C:\\"))
229 ExpectedFilePartSize = 0;
230 else
231 {
232 BackSlash = wcsrchr(CurrentPath, L'\\');
233 if (BackSlash)
234 ExpectedFilePartSize -= wcslen(BackSlash + 1) * sizeof(WCHAR);
235 else
236 ok(0, "GetCurrentDirectory returned %S\n", CurrentPath);
237 }
238 break;
239 }
240 default:
241 skip(0, "Invalid test!\n");
242 continue;
243 }
244 ExpectedFilePartSize += TestCases[i].FilePartSize;
245 if (ExpectedFilePartSize != 0)
246 ExpectedFilePartSize = (ExpectedFilePartSize - sizeof(UNICODE_NULL)) / sizeof(WCHAR);
247 ok(FilePartSize == ExpectedFilePartSize,
248 "FilePartSize = %lu, expected %lu\n", (ULONG)FilePartSize, (ULONG)ExpectedFilePartSize);
249 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
250 ok(PathType == TestCases[i].PathType, "PathType = %d, expected %d\n", PathType, TestCases[i].PathType);
251 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
252 }
253 }
254
255 START_TEST(RtlGetFullPathName_UstrEx)
256 {
257 NTSTATUS Status, ExceptionStatus;
258 UNICODE_STRING FileName;
259 UNICODE_STRING TempString;
260 UNICODE_STRING StaticString;
261 PUNICODE_STRING StringUsed;
262 SIZE_T FilePartSize;
263 BOOLEAN NameInvalid;
264 RTL_PATH_TYPE PathType;
265 SIZE_T LengthNeeded;
266
267 /* NULL parameters */
268 StartSeh()
269 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
270 EndSeh(STATUS_ACCESS_VIOLATION);
271
272 RtlInitUnicodeString(&FileName, NULL);
273 TempString = FileName;
274 StartSeh()
275 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
276 EndSeh(STATUS_ACCESS_VIOLATION);
277 ok_eq_ustr(&FileName, &TempString);
278
279 RtlInitUnicodeString(&FileName, L"");
280 TempString = FileName;
281 StartSeh()
282 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
283 EndSeh(STATUS_ACCESS_VIOLATION);
284 ok_eq_ustr(&FileName, &TempString);
285
286 PathType = RtlPathTypeNotSet;
287 StartSeh()
288 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
289 EndSeh(STATUS_ACCESS_VIOLATION);
290 ok(PathType == RtlPathTypeUnknown ||
291 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
292
293 /* Check what else is initialized before it crashes */
294 PathType = RtlPathTypeNotSet;
295 StringUsed = InvalidPointer;
296 FilePartSize = 1234;
297 NameInvalid = (BOOLEAN)-1;
298 LengthNeeded = 1234;
299 StartSeh()
300 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, &PathType, &LengthNeeded);
301 EndSeh(STATUS_ACCESS_VIOLATION);
302 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
303 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
304 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
305 ok(PathType == RtlPathTypeUnknown ||
306 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
307 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
308
309 RtlInitUnicodeString(&FileName, L"");
310 TempString = FileName;
311 StringUsed = InvalidPointer;
312 FilePartSize = 1234;
313 NameInvalid = (BOOLEAN)-1;
314 LengthNeeded = 1234;
315 StartSeh()
316 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, NULL, &LengthNeeded);
317 EndSeh(STATUS_ACCESS_VIOLATION);
318 ok_eq_ustr(&FileName, &TempString);
319 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
320 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
321 ok(NameInvalid == FALSE ||
322 broken(NameInvalid == (BOOLEAN)-1) /* Win7 */, "NameInvalid = %u\n", NameInvalid);
323 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
324
325 /* This is the first one that doesn't crash. FileName and PathType cannot be NULL */
326 RtlInitUnicodeString(&FileName, NULL);
327 TempString = FileName;
328 PathType = RtlPathTypeNotSet;
329 StartSeh()
330 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
331 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
332 EndSeh(STATUS_SUCCESS);
333 ok_eq_ustr(&FileName, &TempString);
334 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
335
336 RtlInitUnicodeString(&FileName, L"");
337 TempString = FileName;
338 PathType = RtlPathTypeNotSet;
339 StartSeh()
340 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
341 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
342 EndSeh(STATUS_SUCCESS);
343 ok_eq_ustr(&FileName, &TempString);
344 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
345
346 /* Give it a valid path */
347 RtlInitUnicodeString(&FileName, L"C:\\test");
348 TempString = FileName;
349 PathType = RtlPathTypeNotSet;
350 StartSeh()
351 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
352 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
353 EndSeh(STATUS_SUCCESS);
354 ok_eq_ustr(&FileName, &TempString);
355 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
356
357 /* Zero-length static string */
358 RtlInitUnicodeString(&FileName, L"C:\\test");
359 TempString = FileName;
360 RtlInitUnicodeString(&StaticString, NULL);
361 PathType = RtlPathTypeNotSet;
362 StartSeh()
363 Status = RtlGetFullPathName_UstrEx(&FileName, &StaticString, NULL, NULL, NULL, NULL, &PathType, NULL);
364 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
365 EndSeh(STATUS_SUCCESS);
366 ok_eq_ustr(&FileName, &TempString);
367 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
368
369 /* TODO: play around with StaticString and DynamicString */
370
371 /* Check the actual functionality with different paths */
372 RunTestCases();
373 }