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