[NTDLL_WINETEST]
[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(IN PUNICODE_STRING FileName,
17 IN PUNICODE_STRING StaticString,
18 IN PUNICODE_STRING DynamicString,
19 IN PUNICODE_STRING *StringUsed,
20 IN PSIZE_T FilePartSize OPTIONAL,
21 OUT PBOOLEAN NameInvalid,
22 OUT RTL_PATH_TYPE* PathType,
23 OUT PSIZE_T LengthNeeded OPTIONAL);
24 */
25
26 #define StartSeh() ExceptionStatus = STATUS_SUCCESS; _SEH2_TRY {
27 #define EndSeh(ExpectedStatus) } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { ExceptionStatus = _SEH2_GetExceptionCode(); } _SEH2_END; ok(ExceptionStatus == ExpectedStatus, "Exception %lx, expected %lx\n", ExceptionStatus, ExpectedStatus)
28
29 #define ok_eq_ustr(str1, str2) do { \
30 ok((str1)->Buffer == (str2)->Buffer, "Buffer modified\n"); \
31 ok((str1)->Length == (str2)->Length, "Length modified\n"); \
32 ok((str1)->MaximumLength == (str2)->MaximumLength, "MaximumLength modified\n"); \
33 } while (0)
34
35 static
36 BOOLEAN
37 CheckStringBuffer(
38 PCUNICODE_STRING String,
39 PCWSTR Expected)
40 {
41 USHORT Length = wcslen(Expected) * sizeof(WCHAR);
42 SIZE_T EqualLength;
43 BOOLEAN Result = TRUE;
44 SIZE_T i;
45
46 if (String->Length != Length)
47 {
48 ok(0, "String length is %u, expected %u\n", String->Length, Length);
49 Result = FALSE;
50 }
51
52 EqualLength = RtlCompareMemory(String->Buffer, Expected, Length);
53 if (EqualLength != Length)
54 {
55 ok(0, "String is '%wZ', expected '%S'\n", String, Expected);
56 Result = FALSE;
57 }
58
59 if (String->Buffer[String->Length / sizeof(WCHAR)] != UNICODE_NULL)
60 {
61 ok(0, "Not null terminated\n");
62 Result = FALSE;
63 }
64
65 /* the function nulls the rest of the buffer! */
66 for (i = String->Length + sizeof(UNICODE_NULL); i < String->MaximumLength; i++)
67 {
68 UCHAR Char = ((PUCHAR)String->Buffer)[i];
69 if (Char != 0)
70 {
71 ok(0, "Found 0x%x at offset %lu, expected 0x%x\n", Char, (ULONG)i, 0);
72 /* don't count this as a failure unless the string was actually wrong */
73 //Result = FALSE;
74 /* don't flood the log */
75 break;
76 }
77 }
78
79 return Result;
80 }
81
82 #define RtlPathTypeNotSet 123
83 #define InvalidPointer ((PVOID)0x1234)
84
85 /* winetest_platform is "windows" for us, so broken() doesn't do what it should :( */
86 #undef broken
87 #define broken(x) 0
88
89 typedef enum
90 {
91 PrefixNone,
92 PrefixCurrentDrive,
93 PrefixCurrentPath,
94 PrefixCurrentPathWithoutLastPart
95 } PREFIX_TYPE;
96
97 static
98 VOID
99 RunTestCases(VOID)
100 {
101 /* TODO: don't duplicate this here and in the RtlGetFullPathName_U test */
102 struct
103 {
104 PCWSTR FileName;
105 PREFIX_TYPE PrefixType;
106 PCWSTR FullPathName;
107 RTL_PATH_TYPE PathType;
108 PREFIX_TYPE FilePartPrefixType;
109 SIZE_T FilePartSize;
110 } TestCases[] =
111 {
112 { L"C:", PrefixCurrentPath, L"", RtlPathTypeDriveRelative, PrefixCurrentPathWithoutLastPart },
113 { L"C:\\", PrefixNone, L"C:\\", RtlPathTypeDriveAbsolute },
114 { L"C:\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive },
115 { L"C:\\test\\", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute },
116 { L"C:/test/", PrefixNone, L"C:\\test\\", RtlPathTypeDriveAbsolute },
117
118 { L"C:\\\\test", PrefixNone, L"C:\\test", RtlPathTypeDriveAbsolute, PrefixCurrentDrive },
119 { L"test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) },
120 { L"\\test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive },
121 { L"/test", PrefixCurrentDrive, L"test", RtlPathTypeRooted, PrefixCurrentDrive },
122 { L".\\test", PrefixCurrentPath, L"\\test", RtlPathTypeRelative, PrefixCurrentPath, sizeof(WCHAR) },
123
124 { L"\\.", PrefixCurrentDrive, L"", RtlPathTypeRooted },
125 { L"\\.\\", PrefixCurrentDrive, L"", RtlPathTypeRooted },
126 { L"\\\\.", PrefixNone, L"\\\\.\\", RtlPathTypeRootLocalDevice },
127 { L"\\\\.\\", PrefixNone, L"\\\\.\\", RtlPathTypeLocalDevice },
128 { L"\\\\.\\Something\\", PrefixNone, L"\\\\.\\Something\\", RtlPathTypeLocalDevice },
129
130 { L"\\??\\", PrefixCurrentDrive, L"??\\", RtlPathTypeRooted },
131 { L"\\??\\C:", PrefixCurrentDrive, L"??\\C:", RtlPathTypeRooted, PrefixCurrentDrive, 3 * sizeof(WCHAR) },
132 { L"\\??\\C:\\", PrefixCurrentDrive, L"??\\C:\\", RtlPathTypeRooted },
133 { L"\\??\\C:\\test", PrefixCurrentDrive, L"??\\C:\\test", RtlPathTypeRooted, PrefixCurrentDrive, 6 * sizeof(WCHAR) },
134 { L"\\??\\C:\\test\\", PrefixCurrentDrive, L"??\\C:\\test\\", RtlPathTypeRooted },
135
136 { L"\\\\??\\", PrefixNone, L"\\\\??\\", RtlPathTypeUncAbsolute },
137 { L"\\\\??\\C:", PrefixNone, L"\\\\??\\C:", RtlPathTypeUncAbsolute },
138 { L"\\\\??\\C:\\", PrefixNone, L"\\\\??\\C:\\", RtlPathTypeUncAbsolute },
139 { L"\\\\??\\C:\\test", PrefixNone, L"\\\\??\\C:\\test", RtlPathTypeUncAbsolute, PrefixNone, sizeof(L"\\\\??\\C:\\") },
140 { L"\\\\??\\C:\\test\\", PrefixNone, L"\\\\??\\C:\\test\\", RtlPathTypeUncAbsolute },
141 };
142 NTSTATUS Status, ExceptionStatus;
143 UNICODE_STRING FileName;
144 UNICODE_STRING FullPathName;
145 WCHAR FullPathNameBuffer[MAX_PATH];
146 UNICODE_STRING TempString;
147 PUNICODE_STRING StringUsed;
148 SIZE_T FilePartSize;
149 BOOLEAN NameInvalid;
150 RTL_PATH_TYPE PathType;
151 SIZE_T LengthNeeded;
152 WCHAR ExpectedPathName[MAX_PATH];
153 SIZE_T ExpectedFilePartSize;
154 const INT TestCount = sizeof(TestCases) / sizeof(TestCases[0]);
155 INT i;
156
157 for (i = 0; i < TestCount; i++)
158 {
159 trace("i = %d\n", i);
160 switch (TestCases[i].PrefixType)
161 {
162 case PrefixNone:
163 ExpectedPathName[0] = UNICODE_NULL;
164 break;
165 case PrefixCurrentDrive:
166 GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
167 ExpectedPathName[3] = UNICODE_NULL;
168 break;
169 case PrefixCurrentPath:
170 {
171 ULONG Length;
172 Length = GetCurrentDirectoryW(sizeof(ExpectedPathName) / sizeof(WCHAR), ExpectedPathName);
173 if (Length == 3 && TestCases[i].FullPathName[0])
174 ExpectedPathName[2] = UNICODE_NULL;
175 break;
176 }
177 default:
178 skip(0, "Invalid test!\n");
179 continue;
180 }
181 wcscat(ExpectedPathName, TestCases[i].FullPathName);
182 RtlInitUnicodeString(&FileName, TestCases[i].FileName);
183 RtlInitEmptyUnicodeString(&FullPathName, FullPathNameBuffer, sizeof(FullPathNameBuffer));
184 RtlFillMemory(FullPathName.Buffer, FullPathName.MaximumLength, 0xAA);
185 TempString = FileName;
186 PathType = RtlPathTypeNotSet;
187 StringUsed = InvalidPointer;
188 FilePartSize = 1234;
189 NameInvalid = (BOOLEAN)-1;
190 LengthNeeded = 1234;
191 StartSeh()
192 Status = RtlGetFullPathName_UstrEx(&FileName,
193 &FullPathName,
194 NULL,
195 &StringUsed,
196 &FilePartSize,
197 &NameInvalid,
198 &PathType,
199 &LengthNeeded);
200 ok(Status == STATUS_SUCCESS, "status = %lx\n", Status);
201 EndSeh(STATUS_SUCCESS);
202 ok_eq_ustr(&FileName, &TempString);
203 ok(FullPathName.Buffer == FullPathNameBuffer, "Buffer modified\n");
204 ok(FullPathName.MaximumLength == sizeof(FullPathNameBuffer), "MaximumLength modified\n");
205 /* TODO: remove SEH here */
206 StartSeh()
207 ok(CheckStringBuffer(&FullPathName, ExpectedPathName),
208 "Wrong path name '%wZ', expected '%S'\n", &FullPathName, ExpectedPathName);
209 EndSeh(STATUS_SUCCESS);
210 ok(StringUsed == &FullPathName, "StringUsed = %p, expected %p\n", StringUsed, &FullPathName);
211 switch (TestCases[i].FilePartPrefixType)
212 {
213 case PrefixNone:
214 ExpectedFilePartSize = 0;
215 break;
216 case PrefixCurrentDrive:
217 ExpectedFilePartSize = sizeof(L"C:\\");
218 break;
219 case PrefixCurrentPath:
220 ExpectedFilePartSize = GetCurrentDirectoryW(0, NULL) * sizeof(WCHAR);
221 if (ExpectedFilePartSize == sizeof(L"C:\\"))
222 ExpectedFilePartSize -= sizeof(WCHAR);
223 break;
224 case PrefixCurrentPathWithoutLastPart:
225 {
226 WCHAR CurrentPath[MAX_PATH];
227 PCWSTR BackSlash;
228 ExpectedFilePartSize = GetCurrentDirectoryW(sizeof(CurrentPath) / sizeof(WCHAR), CurrentPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
229 if (ExpectedFilePartSize == sizeof(L"C:\\"))
230 ExpectedFilePartSize = 0;
231 else
232 {
233 BackSlash = wcsrchr(CurrentPath, L'\\');
234 if (BackSlash)
235 ExpectedFilePartSize -= wcslen(BackSlash + 1) * sizeof(WCHAR);
236 else
237 ok(0, "GetCurrentDirectory returned %S\n", CurrentPath);
238 }
239 break;
240 }
241 default:
242 skip(0, "Invalid test!\n");
243 continue;
244 }
245 ExpectedFilePartSize += TestCases[i].FilePartSize;
246 if (ExpectedFilePartSize != 0)
247 ExpectedFilePartSize = (ExpectedFilePartSize - sizeof(UNICODE_NULL)) / sizeof(WCHAR);
248 ok(FilePartSize == ExpectedFilePartSize,
249 "FilePartSize = %lu, expected %lu\n", (ULONG)FilePartSize, (ULONG)ExpectedFilePartSize);
250 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
251 ok(PathType == TestCases[i].PathType, "PathType = %d, expected %d\n", PathType, TestCases[i].PathType);
252 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
253 }
254 }
255
256 START_TEST(RtlGetFullPathName_UstrEx)
257 {
258 NTSTATUS Status, ExceptionStatus;
259 UNICODE_STRING FileName;
260 UNICODE_STRING TempString;
261 UNICODE_STRING StaticString;
262 PUNICODE_STRING StringUsed;
263 SIZE_T FilePartSize;
264 BOOLEAN NameInvalid;
265 RTL_PATH_TYPE PathType;
266 SIZE_T LengthNeeded;
267
268 /* NULL parameters */
269 StartSeh()
270 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
271 EndSeh(STATUS_ACCESS_VIOLATION);
272
273 RtlInitUnicodeString(&FileName, L"");
274 TempString = FileName;
275 StartSeh()
276 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
277 EndSeh(STATUS_ACCESS_VIOLATION);
278 ok_eq_ustr(&FileName, &TempString);
279
280 PathType = RtlPathTypeNotSet;
281 StartSeh()
282 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
283 EndSeh(STATUS_ACCESS_VIOLATION);
284 ok(PathType == RtlPathTypeUnknown ||
285 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
286
287 /* check what else is initialized before it crashes */
288 PathType = RtlPathTypeNotSet;
289 StringUsed = InvalidPointer;
290 FilePartSize = 1234;
291 NameInvalid = (BOOLEAN)-1;
292 LengthNeeded = 1234;
293 StartSeh()
294 RtlGetFullPathName_UstrEx(NULL, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, &PathType, &LengthNeeded);
295 EndSeh(STATUS_ACCESS_VIOLATION);
296 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
297 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
298 ok(NameInvalid == FALSE, "NameInvalid = %u\n", NameInvalid);
299 ok(PathType == RtlPathTypeUnknown ||
300 broken(PathType == RtlPathTypeNotSet) /* Win7 */, "PathType = %d\n", PathType);
301 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
302
303 RtlInitUnicodeString(&FileName, L"");
304 TempString = FileName;
305 StringUsed = InvalidPointer;
306 FilePartSize = 1234;
307 NameInvalid = (BOOLEAN)-1;
308 LengthNeeded = 1234;
309 StartSeh()
310 RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, &StringUsed, &FilePartSize, &NameInvalid, NULL, &LengthNeeded);
311 EndSeh(STATUS_ACCESS_VIOLATION);
312 ok_eq_ustr(&FileName, &TempString);
313 ok(StringUsed == NULL, "StringUsed = %p\n", StringUsed);
314 ok(FilePartSize == 0, "FilePartSize = %lu\n", (ULONG)FilePartSize);
315 ok(NameInvalid == FALSE ||
316 broken(NameInvalid == (BOOLEAN)-1) /* Win7 */, "NameInvalid = %u\n", NameInvalid);
317 ok(LengthNeeded == 0, "LengthNeeded = %lu\n", (ULONG)LengthNeeded);
318
319 /* This is the first one that doesn't crash. FileName and PathType cannot be NULL */
320 RtlInitUnicodeString(&FileName, L"");
321 TempString = FileName;
322 PathType = RtlPathTypeNotSet;
323 StartSeh()
324 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
325 ok(Status == STATUS_OBJECT_NAME_INVALID, "status = %lx\n", Status);
326 EndSeh(STATUS_SUCCESS);
327 ok_eq_ustr(&FileName, &TempString);
328 ok(PathType == RtlPathTypeUnknown, "PathType = %d\n", PathType);
329
330 /* Give it a valid path */
331 RtlInitUnicodeString(&FileName, L"C:\\test");
332 TempString = FileName;
333 PathType = RtlPathTypeNotSet;
334 StartSeh()
335 Status = RtlGetFullPathName_UstrEx(&FileName, NULL, NULL, NULL, NULL, NULL, &PathType, NULL);
336 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
337 EndSeh(STATUS_SUCCESS);
338 ok_eq_ustr(&FileName, &TempString);
339 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
340
341 /* Zero-length static string */
342 RtlInitUnicodeString(&FileName, L"C:\\test");
343 TempString = FileName;
344 RtlInitUnicodeString(&StaticString, NULL);
345 PathType = RtlPathTypeNotSet;
346 StartSeh()
347 Status = RtlGetFullPathName_UstrEx(&FileName, &StaticString, NULL, NULL, NULL, NULL, &PathType, NULL);
348 ok(Status == STATUS_BUFFER_TOO_SMALL, "status = %lx\n", Status);
349 EndSeh(STATUS_SUCCESS);
350 ok_eq_ustr(&FileName, &TempString);
351 ok(PathType == RtlPathTypeDriveAbsolute, "PathType = %d\n", PathType);
352
353 /* TODO: play around with StaticString and DynamicString */
354
355 /* check the actual functionality with different paths */
356 RunTestCases();
357 }