1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for RtlDosSearchPath_U
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 /*
11 ULONG
12 NTAPI
13 RtlDosSearchPath_U(
14 IN PCWSTR Path,
15 IN PCWSTR FileName,
16 IN PCWSTR Extension,
17 IN ULONG BufferSize,
18 OUT PWSTR Buffer,
19 OUT PWSTR *PartName
20 );
21 */
22
23 #define PrintablePointer(p) ((p) == InvalidPointer ? NULL : (p))
24
25 static
26 BOOLEAN
CheckStringBuffer(PCWSTR Buffer,SIZE_T Length,SIZE_T MaximumLength,PCWSTR Expected)27 CheckStringBuffer(
28 PCWSTR Buffer,
29 SIZE_T Length,
30 SIZE_T MaximumLength,
31 PCWSTR Expected)
32 {
33 SIZE_T ExpectedLength = wcslen(Expected) * sizeof(WCHAR);
34 SIZE_T EqualLength;
35 BOOLEAN Result = TRUE;
36 SIZE_T i;
37
38 if (Length != ExpectedLength)
39 {
40 ok(0, "String length is %lu, expected %lu\n", (ULONG)Length, (ULONG)ExpectedLength);
41 Result = FALSE;
42 }
43
44 EqualLength = RtlCompareMemory(Buffer, Expected, Length);
45 if (EqualLength != Length)
46 {
47 ok(0, "String is '%S', expected '%S'\n", Buffer, Expected);
48 Result = FALSE;
49 }
50
51 if (Buffer[Length / sizeof(WCHAR)] != UNICODE_NULL)
52 {
53 ok(0, "Not null terminated\n");
54 Result = FALSE;
55 }
56
57 /* the function nulls the rest of the buffer! */
58 for (i = Length + sizeof(UNICODE_NULL); i < MaximumLength; i++)
59 {
60 UCHAR Char = ((PUCHAR)Buffer)[i];
61 if (Char != 0)
62 {
63 ok(0, "Found 0x%x at offset %lu, expected 0x%x\n", Char, (ULONG)i, 0);
64 /* don't count this as a failure unless the string was actually wrong */
65 //Result = FALSE;
66 /* don't flood the log */
67 break;
68 }
69 }
70
71 return Result;
72 }
73
74 static
75 BOOLEAN
CheckBuffer(PVOID Buffer,SIZE_T Size,UCHAR Value)76 CheckBuffer(
77 PVOID Buffer,
78 SIZE_T Size,
79 UCHAR Value)
80 {
81 PUCHAR Array = Buffer;
82 SIZE_T i;
83
84 for (i = 0; i < Size; i++)
85 if (Array[i] != Value)
86 {
87 trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i);
88 return FALSE;
89 }
90 return TRUE;
91 }
92
93 static
94 VOID
RunTestCases(PCWSTR CustomPath)95 RunTestCases(
96 PCWSTR CustomPath)
97 {
98 struct
99 {
100 PCWSTR SearchPath;
101 PCWSTR FileName;
102 PCWSTR Extension;
103 PCWSTR ResultPath;
104 PCWSTR ResultFileName;
105 } Tests[] =
106 {
107 { L"", L"", NULL, NULL, NULL },
108 { L"C:\\%ls\\Folder1", L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
109 /* No path: current directory */
110 { L"", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
111 /* Full path as FileName */
112 { L"", L"C:\\", NULL, L"C:\\", NULL },
113 { L"", L"C:\\%ls\\Folder1", NULL, L"C:\\%ls\\", L"Folder1" },
114 /* No FileName */
115 { L"C:\\", L"", NULL, L"C:\\", NULL },
116 { L"C:\\%ls\\Folder1", L"", NULL, L"C:\\%ls\\Folder1\\", NULL },
117 /* Full path as FileName */
118 { L"", L"C:\\%ls\\Folder1\\SomeProgram.exe", NULL, L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
119 { L"", L"C:\\%ls\\Folder1\\SomeProgram.exe", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
120 { L"", L"C:\\%ls\\Folder1\\SomeProgram", NULL, NULL, NULL },
121 // 10
122 { L"", L"C:\\%ls\\Folder1\\SomeProgram", L".exe", NULL, NULL },
123 /* Both SearchPath and FileName */
124 { L"C:\\%ls\\Folder1\\", L"SomeProgram.exe", NULL, L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
125 { L"C:\\%ls\\Folder1\\", L"SomeProgram.exe", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
126 { L"C:\\%ls\\Folder1\\", L"SomeProgram", NULL, NULL, NULL },
127 { L"C:\\%ls\\Folder1\\", L"SomeProgram", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
128 { L"C:\\%ls\\Folder1", L"SomeProgram.exe", NULL, L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
129 { L"C:\\%ls\\Folder1", L"SomeProgram.exe", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
130 { L"C:\\%ls\\Folder1", L"SomeProgram", NULL, NULL, NULL },
131 { L"C:\\%ls\\Folder1", L"SomeProgram", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
132 /* Full path to file in SearchPath doesn't work */
133 { L"C:\\%ls\\Folder1\\SomeProgram.exe", L"", NULL, NULL, NULL },
134 // 20
135 { L"C:\\%ls\\Folder1\\SomeProgram.exe", L"", L".exe", NULL, NULL },
136 { L"C:\\%ls\\Folder1\\SomeProgram", L"", NULL, NULL, NULL },
137 { L"C:\\%ls\\Folder1\\SomeProgram", L"", L".exe", NULL, NULL },
138 /* */
139 { L"C:\\%ls\\Folder1", L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
140 { L"C:\\%ls\\CurrentDirectory", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
141 { L"C:\\%ls\\Folder1 ", L"File1", NULL, NULL, NULL },
142 { L"C:\\%ls\\CurrentDirectory ",L"File1", NULL, NULL, NULL },
143 { L" C:\\%ls\\Folder1", L"File1", NULL, NULL, NULL },
144 { L" C:\\%ls\\CurrentDirectory",L"File1", NULL, NULL, NULL },
145 { L" C:\\%ls\\Folder1 ", L"File1", NULL, NULL, NULL },
146 // 30
147 { L" C:\\%ls\\CurrentDirectory ",L"File1", NULL, NULL, NULL },
148 /* Multiple search paths */
149 { L"C:\\%ls\\Folder1;C:\\%ls\\CurrentDirectory",
150 L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
151 { L"C:\\%ls\\CurrentDirectory;C:\\%ls\\Folder1",
152 L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
153 { L"C:\\%ls\\CurrentDirectory ; C:\\%ls\\Folder1",
154 L"File1", NULL, NULL, NULL },
155 { L"C:\\%ls\\CurrentDirectory ;C:\\%ls\\Folder1",
156 L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
157 { L"C:\\%ls\\CurrentDirectory; C:\\%ls\\Folder1",
158 L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
159 { L";C:\\%ls\\Folder1", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
160 { L";C:\\%ls\\Folder1;", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
161 { L";C:\\%ls\\Folder1;", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
162 { L"C:\\%ls\\Folder1", L"OnlyInCurr", NULL, NULL, NULL },
163 // 40
164 { L"", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
165 { L"", L"OnlyInCurr ", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
166 { L"", L" OnlyInCurr", NULL, NULL, NULL },
167 { L" ", L"OnlyInCurr", NULL, NULL, NULL },
168 { L";", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
169 { L"; ", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
170 { L" ;", L"OnlyInCurr", NULL, NULL, NULL },
171 { L" ; ", L"OnlyInCurr", NULL, NULL, NULL },
172 { L";C:\\%ls\\Folder1", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
173 { L"C:\\%ls\\Folder1;", L"OnlyInCurr", NULL, NULL, NULL },
174 // 50
175 { L"C:\\%ls\\Folder1;;", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
176 { L";C:\\%ls\\Folder1;", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
177 { L"C:\\%ls\\Folder1;C:\\%ls\\Folder2",
178 L"OnlyInCurr", NULL, NULL, NULL },
179 { L";C:\\%ls\\Folder1;C:\\%ls\\Folder2",
180 L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
181 { L"C:\\%ls\\Folder1;;C:\\%ls\\Folder2",
182 L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
183 { L"C:\\%ls\\Folder1;C:\\%ls\\Folder2;",
184 L"OnlyInCurr", NULL, NULL, NULL },
185 { L"C:\\%ls\\Folder1;C:\\%ls\\Folder2;;",
186 L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
187 /* Spaces in FileName! */
188 { L"", L"C:\\%ls\\Folder1\\SomeProgram With Spaces",
189 L".exe", NULL, NULL },
190 { L"", L"C:\\%ls\\Folder1\\SomeProgram With Spaces.exe",
191 L".exe", NULL, NULL },
192 { L"", L"C:\\%ls\\Folder1\\Program", L".exe", NULL, NULL },
193 // 60
194 { L"", L"C:\\%ls\\Folder1\\Program.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program.exe" },
195 { L"", L"C:\\%ls\\Folder1\\Program With", L".exe", NULL, NULL },
196 { L"", L"C:\\%ls\\Folder1\\Program With.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program With.exe" },
197 { L"", L"C:\\%ls\\Folder1\\Program With Spaces",L".exe", NULL, NULL },
198 { L"", L"C:\\%ls\\Folder1\\Program With Spaces.exe",
199 L".exe", L"C:\\%ls\\Folder1\\", L"Program With Spaces.exe" },
200 /* Same tests with path in SearchPath - now extensions are appended */
201 { L"C:\\%ls\\Folder1", L"SomeProgram With Spaces",
202 L".exe", NULL, NULL },
203 { L"C:\\%ls\\Folder1", L"SomeProgram With Spaces.exe",
204 L".exe", NULL, NULL },
205 { L"C:\\%ls\\Folder1", L"Program", L".exe", L"C:\\%ls\\Folder1\\", L"Program.exe" },
206 { L"C:\\%ls\\Folder1", L"Program.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program.exe" },
207 { L"C:\\%ls\\Folder1", L"Program With", L".exe", L"C:\\%ls\\Folder1\\", L"Program With.exe" },
208 // 70
209 { L"C:\\%ls\\Folder1", L"Program With.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program With.exe" },
210 { L"C:\\%ls\\Folder1", L"Program With Spaces", L".exe", L"C:\\%ls\\Folder1\\", L"Program With Spaces.exe" },
211 { L"C:\\%ls\\Folder1", L"Program With Spaces.exe",
212 L".exe", L"C:\\%ls\\Folder1\\", L"Program With Spaces.exe" },
213 };
214
215 ULONG i;
216 ULONG Length;
217 PWSTR PartName;
218 WCHAR SearchPath[MAX_PATH];
219 WCHAR FileName[MAX_PATH];
220 WCHAR ResultPath[MAX_PATH];
221 WCHAR Buffer[MAX_PATH];
222 BOOLEAN Okay;
223
224 for (i = 0; i < sizeof(Tests) / sizeof(Tests[0]); i++)
225 {
226 swprintf(SearchPath, Tests[i].SearchPath, CustomPath, CustomPath, CustomPath, CustomPath);
227 swprintf(FileName, Tests[i].FileName, CustomPath, CustomPath, CustomPath, CustomPath);
228 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
229 PartName = InvalidPointer;
230
231 StartSeh()
232 Length = RtlDosSearchPath_U(SearchPath,
233 FileName,
234 Tests[i].Extension,
235 sizeof(Buffer),
236 Buffer,
237 &PartName);
238 EndSeh(STATUS_SUCCESS);
239
240 if (Tests[i].ResultPath)
241 {
242 swprintf(ResultPath, Tests[i].ResultPath, CustomPath, CustomPath, CustomPath, CustomPath);
243 if (Tests[i].ResultFileName)
244 {
245 ok(PartName == &Buffer[wcslen(ResultPath)],
246 "PartName = %p (%ls), expected %p\n",
247 PartName, PrintablePointer(PartName), &Buffer[wcslen(ResultPath)]);
248 wcscat(ResultPath, Tests[i].ResultFileName);
249 }
250 else
251 {
252 ok(PartName == NULL,
253 "PartName = %p (%ls), expected NULL\n",
254 PartName, PrintablePointer(PartName));
255 }
256 Okay = CheckStringBuffer(Buffer, Length, sizeof(Buffer), ResultPath);
257 ok(Okay == TRUE, "CheckStringBuffer failed. Got '%ls', expected '%ls'\n", Buffer, ResultPath);
258 }
259 else
260 {
261 Okay = CheckBuffer(Buffer, sizeof(Buffer), 0x55);
262 ok(Okay == TRUE, "CheckBuffer failed\n");
263 ok(Length == 0, "Length = %lu\n", Length);
264 ok(PartName == InvalidPointer,
265 "PartName = %p (%ls), expected %p\n",
266 PartName, PrintablePointer(PartName), InvalidPointer);
267 }
268 }
269 }
270
271 #define MAKE_DIRECTORY(path) \
272 do { \
273 swprintf(FileName, path, CustomPath); \
274 Success = CreateDirectoryW(FileName, NULL); \
275 ok(Success, "CreateDirectory failed, results might not be accurate\n"); \
276 } while (0)
277
278 #define MAKE_FILE(path) \
279 do { \
280 swprintf(FileName, path, CustomPath); \
281 Handle = CreateFileW(FileName, 0, 0, NULL, CREATE_NEW, 0, NULL); \
282 ok(Handle != INVALID_HANDLE_VALUE, \
283 "CreateFile failed, results might not be accurate\n"); \
284 if (Handle != INVALID_HANDLE_VALUE) CloseHandle(Handle); \
285 } while (0)
286
287 #define DELETE_DIRECTORY(path) \
288 do { \
289 swprintf(FileName, path, CustomPath); \
290 Success = RemoveDirectoryW(FileName); \
291 ok(Success, \
292 "RemoveDirectory failed (%lu), test might leave stale directory\n", \
293 GetLastError()); \
294 } while (0)
295
296 #define DELETE_FILE(path) \
297 do { \
298 swprintf(FileName, path, CustomPath); \
299 Success = DeleteFileW(FileName); \
300 ok(Success, \
301 "DeleteFile failed (%lu), test might leave stale file\n", \
302 GetLastError()); \
303 } while (0)
304
START_TEST(RtlDosSearchPath_U)305 START_TEST(RtlDosSearchPath_U)
306 {
307 ULONG Length = 0;
308 WCHAR Buffer[MAX_PATH];
309 PWSTR PartName;
310 BOOLEAN Okay;
311 BOOL Success;
312 WCHAR FileName[MAX_PATH];
313 WCHAR CustomPath[MAX_PATH] = L"RtlDosSearchPath_U_TestPath";
314 HANDLE Handle;
315
316 swprintf(FileName, L"C:\\%ls", CustomPath);
317 /* Make sure this directory doesn't exist */
318 while (GetFileAttributesW(FileName) != INVALID_FILE_ATTRIBUTES)
319 {
320 wcscat(CustomPath, L"X");
321 swprintf(FileName, L"C:\\%ls", CustomPath);
322 }
323 Success = CreateDirectoryW(FileName, NULL);
324 ok(Success, "CreateDirectory failed, results might not be accurate\n");
325
326 MAKE_DIRECTORY(L"C:\\%ls\\Folder1");
327 MAKE_DIRECTORY(L"C:\\%ls\\Folder2");
328 MAKE_DIRECTORY(L"C:\\%ls\\CurrentDirectory");
329 Success = SetCurrentDirectoryW(FileName);
330 ok(Success, "SetCurrentDirectory failed\n");
331 MAKE_FILE(L"C:\\%ls\\Folder1\\File1");
332 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram.exe");
333 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe");
334 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe.exe");
335 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram3.exe.exe");
336 MAKE_FILE(L"C:\\%ls\\Folder1\\Program.exe");
337 MAKE_FILE(L"C:\\%ls\\Folder1\\Program With.exe");
338 MAKE_FILE(L"C:\\%ls\\Folder1\\Program With Spaces.exe");
339 MAKE_FILE(L"C:\\%ls\\CurrentDirectory\\File1");
340 MAKE_FILE(L"C:\\%ls\\CurrentDirectory\\OnlyInCurr");
341
342 /* NULL parameters */
343 StartSeh() RtlDosSearchPath_U(NULL, NULL, NULL, 0, NULL , NULL); EndSeh(STATUS_ACCESS_VIOLATION);
344 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 0, NULL , NULL); EndSeh(STATUS_ACCESS_VIOLATION);
345 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 0, Buffer, NULL); EndSeh(STATUS_ACCESS_VIOLATION);
346 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 1, Buffer, NULL); EndSeh(STATUS_ACCESS_VIOLATION);
347 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 2, Buffer, NULL); EndSeh(STATUS_ACCESS_VIOLATION);
348 StartSeh() RtlDosSearchPath_U(L"" , NULL, NULL, 0, NULL , NULL); EndSeh(STATUS_ACCESS_VIOLATION);
349
350 /* Empty strings - first one that doesn't crash */
351 StartSeh()
352 Length = RtlDosSearchPath_U(L"", L"", NULL, 0, NULL, NULL);
353 ok(Length == 0, "Length %lu\n", Length);
354 EndSeh(STATUS_SUCCESS);
355
356 /* Check what's initialized */
357 PartName = InvalidPointer;
358 StartSeh()
359 Length = RtlDosSearchPath_U(L"", L"", NULL, 0, NULL, &PartName);
360 ok(Length == 0, "Length = %lu\n", Length);
361 EndSeh(STATUS_SUCCESS);
362 ok(PartName == InvalidPointer, "PartName = %p\n", PartName);
363
364 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
365 StartSeh()
366 Length = RtlDosSearchPath_U(L"", L"", NULL, sizeof(Buffer), Buffer, NULL);
367 ok(Length == 0, "Length %lu\n", Length);
368 EndSeh(STATUS_SUCCESS);
369 Okay = CheckBuffer(Buffer, sizeof(Buffer), 0x55);
370 ok(Okay, "CheckBuffer failed\n");
371
372 PartName = InvalidPointer;
373 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
374 StartSeh()
375 Length = RtlDosSearchPath_U(L"", L"", NULL, sizeof(Buffer), Buffer, &PartName);
376 ok(Length == 0, "Length %lu\n", Length);
377 EndSeh(STATUS_SUCCESS);
378 ok(PartName == InvalidPointer, "PartName = %p\n", PartName);
379 Okay = CheckBuffer(Buffer, sizeof(Buffer), 0x55);
380 ok(Okay, "CheckBuffer failed\n");
381
382 /* Now test the actual functionality */
383 RunTestCases(CustomPath);
384
385 /*
386 * Clean up test folder - We can't delete it
387 * if our current directory is inside.
388 */
389 SetCurrentDirectoryW(L"C:\\");
390 DELETE_FILE(L"C:\\%ls\\CurrentDirectory\\OnlyInCurr");
391 DELETE_FILE(L"C:\\%ls\\CurrentDirectory\\File1");
392 DELETE_FILE(L"C:\\%ls\\Folder1\\Program With Spaces.exe");
393 DELETE_FILE(L"C:\\%ls\\Folder1\\Program With.exe");
394 DELETE_FILE(L"C:\\%ls\\Folder1\\Program.exe");
395 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram3.exe.exe");
396 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe.exe");
397 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe");
398 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram.exe");
399 DELETE_FILE(L"C:\\%ls\\Folder1\\File1");
400 DELETE_DIRECTORY(L"C:\\%ls\\CurrentDirectory");
401 DELETE_DIRECTORY(L"C:\\%ls\\Folder2");
402 DELETE_DIRECTORY(L"C:\\%ls\\Folder1");
403 DELETE_DIRECTORY(L"C:\\%ls");
404 }
405