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 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 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 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 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