1 /* 2 * File path.c - managing path in debugging environments 3 * 4 * Copyright (C) 2004,2008, Eric Pouech 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdlib.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 #include "dbghelp_private.h" 26 #include "image_private.h" 27 #include "winnls.h" 28 #include "winternl.h" 29 #include "wine/debug.h" 30 #include "wine/heap.h" 31 32 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); 33 34 static inline BOOL is_sepA(char ch) {return ch == '/' || ch == '\\';} 35 static inline BOOL is_sep(WCHAR ch) {return ch == '/' || ch == '\\';} 36 37 const char* file_nameA(const char* str) 38 { 39 const char* p; 40 41 for (p = str + strlen(str) - 1; p >= str && !is_sepA(*p); p--); 42 return p + 1; 43 } 44 45 const WCHAR* file_name(const WCHAR* str) 46 { 47 const WCHAR* p; 48 49 for (p = str + lstrlenW(str) - 1; p >= str && !is_sep(*p); p--); 50 return p + 1; 51 } 52 53 static inline void file_pathW(const WCHAR *src, WCHAR *dst) 54 { 55 int len; 56 57 for (len = lstrlenW(src) - 1; (len > 0) && (!is_sep(src[len])); len--); 58 memcpy( dst, src, len * sizeof(WCHAR) ); 59 dst[len] = 0; 60 } 61 62 /****************************************************************** 63 * FindDebugInfoFile (DBGHELP.@) 64 * 65 */ 66 HANDLE WINAPI FindDebugInfoFile(PCSTR FileName, PCSTR SymbolPath, PSTR DebugFilePath) 67 { 68 HANDLE h; 69 70 h = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, 71 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 72 if (h == INVALID_HANDLE_VALUE) 73 { 74 if (!SearchPathA(SymbolPath, file_nameA(FileName), NULL, MAX_PATH, DebugFilePath, NULL)) 75 return NULL; 76 h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, 77 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 78 } 79 return (h == INVALID_HANDLE_VALUE) ? NULL : h; 80 } 81 82 /****************************************************************** 83 * FindDebugInfoFileEx (DBGHELP.@) 84 * 85 */ 86 HANDLE WINAPI FindDebugInfoFileEx(PCSTR FileName, PCSTR SymbolPath, 87 PSTR DebugFilePath, 88 PFIND_DEBUG_FILE_CALLBACK Callback, 89 PVOID CallerData) 90 { 91 FIXME("(%s %s %s %p %p): stub\n", debugstr_a(FileName), debugstr_a(SymbolPath), 92 debugstr_a(DebugFilePath), Callback, CallerData); 93 return NULL; 94 } 95 96 /****************************************************************** 97 * FindExecutableImageExW (DBGHELP.@) 98 * 99 */ 100 HANDLE WINAPI FindExecutableImageExW(PCWSTR FileName, PCWSTR SymbolPath, PWSTR ImageFilePath, 101 PFIND_EXE_FILE_CALLBACKW Callback, PVOID user) 102 { 103 HANDLE h; 104 105 if (Callback) FIXME("Unsupported callback yet\n"); 106 if (!SearchPathW(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL)) 107 return NULL; 108 h = CreateFileW(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, 109 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 110 return (h == INVALID_HANDLE_VALUE) ? NULL : h; 111 } 112 113 /****************************************************************** 114 * FindExecutableImageEx (DBGHELP.@) 115 * 116 */ 117 HANDLE WINAPI FindExecutableImageEx(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath, 118 PFIND_EXE_FILE_CALLBACK Callback, PVOID user) 119 { 120 HANDLE h; 121 122 if (Callback) FIXME("Unsupported callback yet\n"); 123 if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL)) 124 return NULL; 125 h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, 126 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 127 return (h == INVALID_HANDLE_VALUE) ? NULL : h; 128 } 129 130 /****************************************************************** 131 * FindExecutableImage (DBGHELP.@) 132 * 133 */ 134 HANDLE WINAPI FindExecutableImage(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath) 135 { 136 return FindExecutableImageEx(FileName, SymbolPath, ImageFilePath, NULL, NULL); 137 } 138 139 /*********************************************************************** 140 * MakeSureDirectoryPathExists (DBGHELP.@) 141 */ 142 BOOL WINAPI MakeSureDirectoryPathExists(PCSTR DirPath) 143 { 144 char path[MAX_PATH]; 145 const char *p = DirPath; 146 int n; 147 148 if (p[0] && p[1] == ':') p += 2; 149 while (*p == '\\') p++; /* skip drive root */ 150 while ((p = strchr(p, '\\')) != NULL) 151 { 152 n = p - DirPath + 1; 153 memcpy(path, DirPath, n); 154 path[n] = '\0'; 155 if( !CreateDirectoryA(path, NULL) && 156 (GetLastError() != ERROR_ALREADY_EXISTS)) 157 return FALSE; 158 p++; 159 } 160 if (GetLastError() == ERROR_ALREADY_EXISTS) 161 SetLastError(ERROR_SUCCESS); 162 163 return TRUE; 164 } 165 166 /****************************************************************** 167 * SymMatchFileNameW (DBGHELP.@) 168 * 169 */ 170 BOOL WINAPI SymMatchFileNameW(PCWSTR file, PCWSTR match, 171 PWSTR* filestop, PWSTR* matchstop) 172 { 173 PCWSTR fptr; 174 PCWSTR mptr; 175 176 TRACE("(%s %s %p %p)\n", 177 debugstr_w(file), debugstr_w(match), filestop, matchstop); 178 179 fptr = file + lstrlenW(file) - 1; 180 mptr = match + lstrlenW(match) - 1; 181 182 while (fptr >= file && mptr >= match) 183 { 184 if (towupper(*fptr) != towupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr))) 185 break; 186 fptr--; mptr--; 187 } 188 if (filestop) *filestop = (PWSTR)fptr; 189 if (matchstop) *matchstop = (PWSTR)mptr; 190 191 return mptr == match - 1; 192 } 193 194 /****************************************************************** 195 * SymMatchFileName (DBGHELP.@) 196 * 197 */ 198 BOOL WINAPI SymMatchFileName(PCSTR file, PCSTR match, 199 PSTR* filestop, PSTR* matchstop) 200 { 201 PCSTR fptr; 202 PCSTR mptr; 203 204 TRACE("(%s %s %p %p)\n", debugstr_a(file), debugstr_a(match), filestop, matchstop); 205 206 fptr = file + strlen(file) - 1; 207 mptr = match + strlen(match) - 1; 208 209 while (fptr >= file && mptr >= match) 210 { 211 if (toupper(*fptr) != toupper(*mptr) && !(is_sepA(*fptr) && is_sepA(*mptr))) 212 break; 213 fptr--; mptr--; 214 } 215 if (filestop) *filestop = (PSTR)fptr; 216 if (matchstop) *matchstop = (PSTR)mptr; 217 218 return mptr == match - 1; 219 } 220 221 static BOOL do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse, 222 PENUMDIRTREE_CALLBACKW cb, PVOID user) 223 { 224 HANDLE h; 225 WIN32_FIND_DATAW fd; 226 unsigned pos; 227 BOOL found = FALSE; 228 static const WCHAR S_AllW[] = {'*','.','*','\0'}; 229 static const WCHAR S_DotW[] = {'.','\0'}; 230 static const WCHAR S_DotDotW[] = {'.','.','\0'}; 231 232 pos = lstrlenW(buffer); 233 if (pos == 0) return FALSE; 234 if (buffer[pos - 1] != '\\') buffer[pos++] = '\\'; 235 lstrcpyW(buffer + pos, S_AllW); 236 if ((h = FindFirstFileW(buffer, &fd)) == INVALID_HANDLE_VALUE) 237 return FALSE; 238 /* doc doesn't specify how the tree is enumerated... 239 * doing a depth first based on, but may be wrong 240 */ 241 do 242 { 243 if (!wcscmp(fd.cFileName, S_DotW) || !wcscmp(fd.cFileName, S_DotDotW)) continue; 244 245 lstrcpyW(buffer + pos, fd.cFileName); 246 if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 247 found = do_searchW(file, buffer, TRUE, cb, user); 248 else if (SymMatchFileNameW(buffer, file, NULL, NULL)) 249 { 250 if (!cb || cb(buffer, user)) found = TRUE; 251 } 252 } while (!found && FindNextFileW(h, &fd)); 253 if (!found) buffer[--pos] = '\0'; 254 FindClose(h); 255 256 return found; 257 } 258 259 /*********************************************************************** 260 * SearchTreeForFileW (DBGHELP.@) 261 */ 262 BOOL WINAPI SearchTreeForFileW(PCWSTR root, PCWSTR file, PWSTR buffer) 263 { 264 TRACE("(%s, %s, %p)\n", 265 debugstr_w(root), debugstr_w(file), buffer); 266 lstrcpyW(buffer, root); 267 return do_searchW(file, buffer, TRUE, NULL, NULL); 268 } 269 270 /*********************************************************************** 271 * SearchTreeForFile (DBGHELP.@) 272 */ 273 BOOL WINAPI SearchTreeForFile(PCSTR root, PCSTR file, PSTR buffer) 274 { 275 WCHAR rootW[MAX_PATH]; 276 WCHAR fileW[MAX_PATH]; 277 WCHAR bufferW[MAX_PATH]; 278 BOOL ret; 279 280 MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH); 281 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH); 282 ret = SearchTreeForFileW(rootW, fileW, bufferW); 283 if (ret) 284 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); 285 return ret; 286 } 287 288 /****************************************************************** 289 * EnumDirTreeW (DBGHELP.@) 290 * 291 * 292 */ 293 BOOL WINAPI EnumDirTreeW(HANDLE hProcess, PCWSTR root, PCWSTR file, 294 PWSTR buffer, PENUMDIRTREE_CALLBACKW cb, PVOID user) 295 { 296 TRACE("(%p %s %s %p %p %p)\n", 297 hProcess, debugstr_w(root), debugstr_w(file), buffer, cb, user); 298 299 lstrcpyW(buffer, root); 300 return do_searchW(file, buffer, TRUE, cb, user); 301 } 302 303 /****************************************************************** 304 * EnumDirTree (DBGHELP.@) 305 * 306 * 307 */ 308 struct enum_dir_treeWA 309 { 310 PENUMDIRTREE_CALLBACK cb; 311 void* user; 312 char name[MAX_PATH]; 313 }; 314 315 static BOOL CALLBACK enum_dir_treeWA(PCWSTR name, PVOID user) 316 { 317 struct enum_dir_treeWA* edt = user; 318 319 WideCharToMultiByte(CP_ACP, 0, name, -1, edt->name, MAX_PATH, NULL, NULL); 320 return edt->cb(edt->name, edt->user); 321 } 322 323 BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file, 324 PSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user) 325 { 326 WCHAR rootW[MAX_PATH]; 327 WCHAR fileW[MAX_PATH]; 328 WCHAR bufferW[MAX_PATH]; 329 struct enum_dir_treeWA edt; 330 BOOL ret; 331 332 edt.cb = cb; 333 edt.user = user; 334 MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH); 335 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH); 336 if ((ret = EnumDirTreeW(hProcess, rootW, fileW, bufferW, enum_dir_treeWA, &edt))) 337 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); 338 return ret; 339 } 340 341 struct sffip 342 { 343 PFINDFILEINPATHCALLBACKW cb; 344 void* user; 345 }; 346 347 /* checks that buffer (as found by matching the name) matches the info 348 * (information is based on file type) 349 * returns TRUE when file is found, FALSE to continue searching 350 * (NB this is the opposite convention of SymFindFileInPathProc) 351 */ 352 static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user) 353 { 354 struct sffip* s = user; 355 356 if (!s->cb) return TRUE; 357 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite 358 * convention to stop/continue enumeration. sigh. 359 */ 360 return !(s->cb)(buffer, s->user); 361 } 362 363 /****************************************************************** 364 * SymFindFileInPathW (DBGHELP.@) 365 * 366 */ 367 BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_path, 368 PVOID id, DWORD two, DWORD three, DWORD flags, 369 PWSTR buffer, PFINDFILEINPATHCALLBACKW cb, 370 PVOID user) 371 { 372 struct sffip s; 373 struct process* pcs = process_find_by_handle(hProcess); 374 WCHAR tmp[MAX_PATH]; 375 WCHAR* ptr; 376 const WCHAR* filename; 377 378 TRACE("(hProcess = %p, searchPath = %s, full_path = %s, id = %p, two = 0x%08x, three = 0x%08x, flags = 0x%08x, buffer = %p, cb = %p, user = %p)\n", 379 hProcess, debugstr_w(searchPath), debugstr_w(full_path), 380 id, two, three, flags, buffer, cb, user); 381 382 if (!pcs) return FALSE; 383 if (!searchPath) searchPath = pcs->search_path; 384 385 s.cb = cb; 386 s.user = user; 387 388 filename = file_name(full_path); 389 390 /* first check full path to file */ 391 if (sffip_cb(full_path, &s)) 392 { 393 lstrcpyW(buffer, full_path); 394 return TRUE; 395 } 396 397 while (searchPath) 398 { 399 ptr = wcschr(searchPath, ';'); 400 if (ptr) 401 { 402 memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR)); 403 tmp[ptr - searchPath] = 0; 404 searchPath = ptr + 1; 405 } 406 else 407 { 408 lstrcpyW(tmp, searchPath); 409 searchPath = NULL; 410 } 411 if (do_searchW(filename, tmp, FALSE, sffip_cb, &s)) 412 { 413 lstrcpyW(buffer, tmp); 414 return TRUE; 415 } 416 } 417 return FALSE; 418 } 419 420 /****************************************************************** 421 * SymFindFileInPath (DBGHELP.@) 422 * 423 */ 424 BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path, 425 PVOID id, DWORD two, DWORD three, DWORD flags, 426 PSTR buffer, PFINDFILEINPATHCALLBACK cb, 427 PVOID user) 428 { 429 WCHAR searchPathW[MAX_PATH]; 430 WCHAR full_pathW[MAX_PATH]; 431 WCHAR bufferW[MAX_PATH]; 432 struct enum_dir_treeWA edt; 433 BOOL ret; 434 435 /* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the 436 * same signature & semantics, hence we can reuse the EnumDirTree W->A 437 * conversion helper 438 */ 439 edt.cb = cb; 440 edt.user = user; 441 if (searchPath) 442 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, searchPathW, MAX_PATH); 443 MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH); 444 if ((ret = SymFindFileInPathW(hProcess, searchPath ? searchPathW : NULL, full_pathW, 445 id, two, three, flags, 446 bufferW, enum_dir_treeWA, &edt))) 447 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); 448 return ret; 449 } 450 451 struct module_find 452 { 453 enum module_type kind; 454 /* pe: dw1 DWORD:timestamp 455 * dw2 size of image (from PE header) 456 * pdb: guid PDB guid (if DS PDB file) 457 * or dw1 PDB timestamp (if JG PDB file) 458 * dw2 PDB age 459 * elf: dw1 DWORD:CRC 32 of ELF image (Wine only) 460 */ 461 const GUID* guid; 462 DWORD dw1; 463 DWORD dw2; 464 WCHAR filename[MAX_PATH]; 465 unsigned matched; 466 }; 467 468 /* checks that buffer (as found by matching the name) matches the info 469 * (information is based on file type) 470 * returns TRUE when file is found, FALSE to continue searching 471 * (NB this is the opposite convention of SymFindFileInPathProc) 472 */ 473 static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user) 474 { 475 struct module_find* mf = user; 476 DWORD size, timestamp; 477 unsigned matched = 0; 478 479 /* the matching weights: 480 * +1 if a file with same name is found and is a decent file of expected type 481 * +1 if first parameter and second parameter match 482 */ 483 484 /* FIXME: should check that id/two match the file pointed 485 * by buffer 486 */ 487 switch (mf->kind) 488 { 489 case DMT_PE: 490 { 491 HANDLE hFile, hMap; 492 void* mapping; 493 494 timestamp = ~mf->dw1; 495 size = ~mf->dw2; 496 hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, 497 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 498 if (hFile == INVALID_HANDLE_VALUE) return FALSE; 499 if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) 500 { 501 if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) 502 { 503 IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping); 504 if (!nth) 505 { 506 UnmapViewOfFile(mapping); 507 CloseHandle(hMap); 508 CloseHandle(hFile); 509 return FALSE; 510 } 511 matched++; 512 timestamp = nth->FileHeader.TimeDateStamp; 513 size = nth->OptionalHeader.SizeOfImage; 514 UnmapViewOfFile(mapping); 515 } 516 CloseHandle(hMap); 517 } 518 CloseHandle(hFile); 519 if (timestamp != mf->dw1) 520 WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer)); 521 if (size != mf->dw2) 522 WARN("Found %s, but wrong size\n", debugstr_w(buffer)); 523 if (timestamp == mf->dw1 && size == mf->dw2) matched++; 524 } 525 break; 526 case DMT_PDB: 527 { 528 struct pdb_lookup pdb_lookup; 529 char fn[MAX_PATH]; 530 531 WideCharToMultiByte(CP_ACP, 0, buffer, -1, fn, MAX_PATH, NULL, NULL); 532 pdb_lookup.filename = fn; 533 534 if (mf->guid) 535 { 536 pdb_lookup.kind = PDB_DS; 537 pdb_lookup.timestamp = 0; 538 pdb_lookup.guid = *mf->guid; 539 } 540 else 541 { 542 pdb_lookup.kind = PDB_JG; 543 pdb_lookup.timestamp = mf->dw1; 544 /* pdb_loopkup.guid = */ 545 } 546 pdb_lookup.age = mf->dw2; 547 548 if (!pdb_fetch_file_info(&pdb_lookup, &matched)) return FALSE; 549 } 550 break; 551 case DMT_DBG: 552 { 553 HANDLE hFile, hMap; 554 void* mapping; 555 556 timestamp = ~mf->dw1; 557 hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, 558 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 559 if (hFile == INVALID_HANDLE_VALUE) return FALSE; 560 if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) 561 { 562 if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) 563 { 564 const IMAGE_SEPARATE_DEBUG_HEADER* hdr; 565 hdr = mapping; 566 567 if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE) 568 { 569 matched++; 570 timestamp = hdr->TimeDateStamp; 571 } 572 UnmapViewOfFile(mapping); 573 } 574 CloseHandle(hMap); 575 } 576 CloseHandle(hFile); 577 if (timestamp == mf->dw1) matched++; 578 else WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer)); 579 } 580 break; 581 default: 582 FIXME("What the heck??\n"); 583 return FALSE; 584 } 585 if (matched > mf->matched) 586 { 587 lstrcpyW(mf->filename, buffer); 588 mf->matched = matched; 589 } 590 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite 591 * convention to stop/continue enumeration. sigh. 592 */ 593 return mf->matched == 2; 594 } 595 596 BOOL path_find_symbol_file(const struct process* pcs, const struct module* module, 597 PCSTR full_path, enum module_type type, const GUID* guid, DWORD dw1, DWORD dw2, 598 WCHAR *buffer, BOOL* is_unmatched) 599 { 600 struct module_find mf; 601 WCHAR full_pathW[MAX_PATH]; 602 WCHAR* ptr; 603 const WCHAR* filename; 604 WCHAR* searchPath = pcs->search_path; 605 606 TRACE("(pcs = %p, full_path = %s, guid = %s, dw1 = 0x%08x, dw2 = 0x%08x, buffer = %p)\n", 607 pcs, debugstr_a(full_path), debugstr_guid(guid), dw1, dw2, buffer); 608 609 mf.guid = guid; 610 mf.dw1 = dw1; 611 mf.dw2 = dw2; 612 mf.matched = 0; 613 614 MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH); 615 filename = file_name(full_pathW); 616 mf.kind = type; 617 *is_unmatched = FALSE; 618 619 /* first check full path to file */ 620 if (module_find_cb(full_pathW, &mf)) 621 { 622 lstrcpyW( buffer, full_pathW ); 623 return TRUE; 624 } 625 626 /* FIXME: Use Environment-Variables (see MS docs) 627 _NT_SYMBOL_PATH and _NT_ALT_SYMBOL_PATH 628 FIXME: Implement "Standard Path Elements" (Path) ... (see MS docs) 629 do a search for (every?) path-element like this ... 630 <path> 631 <path>\dll 632 <path>\symbols\dll 633 (dll may be exe, or sys depending on the file extension) */ 634 635 /* 2. check module-path */ 636 file_pathW(module->module.LoadedImageName, buffer); 637 if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE; 638 if (module->real_path) 639 { 640 file_pathW(module->real_path, buffer); 641 if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE; 642 } 643 644 while (searchPath) 645 { 646 ptr = wcschr(searchPath, ';'); 647 if (ptr) 648 { 649 memcpy(buffer, searchPath, (ptr - searchPath) * sizeof(WCHAR)); 650 buffer[ptr - searchPath] = '\0'; 651 searchPath = ptr + 1; 652 } 653 else 654 { 655 lstrcpyW(buffer, searchPath); 656 searchPath = NULL; 657 } 658 /* return first fully matched file */ 659 if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE; 660 } 661 /* if no fully matching file is found, return the best matching file if any */ 662 if ((dbghelp_options & SYMOPT_LOAD_ANYTHING) && mf.matched) 663 { 664 lstrcpyW( buffer, mf.filename ); 665 *is_unmatched = TRUE; 666 return TRUE; 667 } 668 return FALSE; 669 } 670 671 WCHAR *get_dos_file_name(const WCHAR *filename) 672 { 673 WCHAR *dos_path; 674 size_t len; 675 676 #ifndef __REACTOS__ 677 if (*filename == '/') 678 { 679 char *unix_path; 680 len = WideCharToMultiByte(CP_UNIXCP, 0, filename, -1, NULL, 0, NULL, NULL); 681 unix_path = heap_alloc(len * sizeof(WCHAR)); 682 WideCharToMultiByte(CP_UNIXCP, 0, filename, -1, unix_path, len, NULL, NULL); 683 dos_path = wine_get_dos_file_name(unix_path); 684 heap_free(unix_path); 685 } 686 else 687 #endif 688 { 689 len = lstrlenW(filename); 690 dos_path = heap_alloc((len + 1) * sizeof(WCHAR)); 691 memcpy(dos_path, filename, (len + 1) * sizeof(WCHAR)); 692 } 693 return dos_path; 694 } 695 696 #ifndef __REACTOS__ 697 BOOL search_dll_path(const struct process *process, const WCHAR *name, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param) 698 { 699 const WCHAR *env; 700 size_t len, i; 701 HANDLE file; 702 WCHAR *buf; 703 BOOL ret; 704 705 name = file_name(name); 706 707 if ((env = process_getenv(process, L"WINEBUILDDIR"))) 708 { 709 WCHAR *p, *end; 710 const WCHAR dllsW[] = { '\\','d','l','l','s','\\' }; 711 const WCHAR programsW[] = { '\\','p','r','o','g','r','a','m','s','\\' }; 712 const WCHAR dot_dllW[] = {'.','d','l','l',0}; 713 const WCHAR dot_exeW[] = {'.','e','x','e',0}; 714 const WCHAR dot_soW[] = {'.','s','o',0}; 715 716 717 len = lstrlenW(env); 718 if (!(buf = heap_alloc((len + 8 + 3 * lstrlenW(name)) * sizeof(WCHAR)))) return FALSE; 719 wcscpy(buf, env); 720 end = buf + len; 721 722 memcpy(end, dllsW, sizeof(dllsW)); 723 lstrcpyW(end + ARRAY_SIZE(dllsW), name); 724 if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, dot_soW)) *p = 0; 725 if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, dot_dllW)) *p = 0; 726 p = end + lstrlenW(end); 727 *p++ = '\\'; 728 lstrcpyW(p, name); 729 file = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 730 if (file != INVALID_HANDLE_VALUE) 731 { 732 ret = match(param, file, buf); 733 CloseHandle(file); 734 if (ret) goto found; 735 } 736 737 memcpy(end, programsW, sizeof(programsW)); 738 end += ARRAY_SIZE(programsW); 739 lstrcpyW(end, name); 740 if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, dot_soW)) *p = 0; 741 if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, dot_exeW)) *p = 0; 742 p = end + lstrlenW(end); 743 *p++ = '\\'; 744 lstrcpyW(p, name); 745 file = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 746 if (file != INVALID_HANDLE_VALUE) 747 { 748 ret = match(param, file, buf); 749 CloseHandle(file); 750 if (ret) goto found; 751 } 752 753 heap_free(buf); 754 } 755 756 for (i = 0;; i++) 757 { 758 WCHAR env_name[64]; 759 swprintf(env_name, ARRAY_SIZE(env_name), L"WINEDLLDIR%u", i); 760 if (!(env = process_getenv(process, env_name))) return FALSE; 761 len = wcslen(env) + wcslen(name) + 2; 762 if (!(buf = heap_alloc(len * sizeof(WCHAR)))) return FALSE; 763 swprintf(buf, len, L"%s\\%s", env, name); 764 file = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 765 if (file != INVALID_HANDLE_VALUE) 766 { 767 ret = match(param, file, buf); 768 CloseHandle(file); 769 if (ret) goto found; 770 } 771 heap_free(buf); 772 } 773 774 return FALSE; 775 776 found: 777 TRACE("found %s\n", debugstr_w(buf)); 778 heap_free(buf); 779 return TRUE; 780 } 781 782 BOOL search_unix_path(const WCHAR *name, const WCHAR *path, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param) 783 { 784 const WCHAR *iter, *next; 785 size_t size, len; 786 WCHAR *dos_path; 787 char *buf; 788 BOOL ret = FALSE; 789 790 if (!path) return FALSE; 791 name = file_name(name); 792 793 size = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL) 794 + WideCharToMultiByte(CP_UNIXCP, 0, path, -1, NULL, 0, NULL, NULL); 795 if (!(buf = heap_alloc(size))) return FALSE; 796 797 for (iter = path;; iter = next + 1) 798 { 799 if (!(next = wcschr(iter, ':'))) next = iter + lstrlenW(iter); 800 if (*iter == '/') 801 { 802 len = WideCharToMultiByte(CP_UNIXCP, 0, iter, next - iter, buf, size, NULL, NULL); 803 if (buf[len - 1] != '/') buf[len++] = '/'; 804 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, buf + len, size - len, NULL, NULL); 805 if ((dos_path = wine_get_dos_file_name(buf))) 806 { 807 HANDLE file = CreateFileW(dos_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 808 if (file != INVALID_HANDLE_VALUE) 809 { 810 ret = match(param, file, dos_path); 811 CloseHandle(file); 812 if (ret) TRACE("found %s\n", debugstr_w(dos_path)); 813 } 814 heap_free(dos_path); 815 if (ret) break; 816 } 817 } 818 if (*next != ':') break; 819 } 820 821 heap_free(buf); 822 return ret; 823 } 824 #endif 825