2 * File path.c - managing path in debugging environments
4 * Copyright (C) 2004,2008, Eric Pouech
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.
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.
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
25 #include "dbghelp_private.h"
26 #include "image_private.h"
29 #include "wine/debug.h"
30 #include "wine/heap.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
34 static const struct machine_dir
42 {IMAGE_FILE_MACHINE_I386
, L
"\\i386-windows\\", L
"\\i386-unix\\"},
43 {IMAGE_FILE_MACHINE_AMD64
, L
"\\x86_64-windows\\", L
"\\x86_64-unix\\"},
44 {IMAGE_FILE_MACHINE_ARMNT
, L
"\\arm-windows\\", L
"\\arm-unix\\"},
45 {IMAGE_FILE_MACHINE_ARM64
, L
"\\aarch64-windows\\", L
"\\aarch64-unix\\"},
48 static inline BOOL
is_sepA(char ch
) {return ch
== '/' || ch
== '\\';}
49 static inline BOOL
is_sep(WCHAR ch
) {return ch
== '/' || ch
== '\\';}
51 const char* file_nameA(const char* str
)
55 for (p
= str
+ strlen(str
) - 1; p
>= str
&& !is_sepA(*p
); p
--);
59 const WCHAR
* file_name(const WCHAR
* str
)
63 for (p
= str
+ lstrlenW(str
) - 1; p
>= str
&& !is_sep(*p
); p
--);
67 static inline void file_pathW(const WCHAR
*src
, WCHAR
*dst
)
71 for (len
= lstrlenW(src
) - 1; (len
> 0) && (!is_sep(src
[len
])); len
--);
72 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
76 /******************************************************************
77 * FindDebugInfoFile (DBGHELP.@)
80 HANDLE WINAPI
FindDebugInfoFile(PCSTR FileName
, PCSTR SymbolPath
, PSTR DebugFilePath
)
84 h
= CreateFileA(FileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
85 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
86 if (h
== INVALID_HANDLE_VALUE
)
88 if (!SearchPathA(SymbolPath
, file_nameA(FileName
), NULL
, MAX_PATH
, DebugFilePath
, NULL
))
90 h
= CreateFileA(DebugFilePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
91 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
93 return (h
== INVALID_HANDLE_VALUE
) ? NULL
: h
;
96 /******************************************************************
97 * FindDebugInfoFileEx (DBGHELP.@)
100 HANDLE WINAPI
FindDebugInfoFileEx(PCSTR FileName
, PCSTR SymbolPath
,
102 PFIND_DEBUG_FILE_CALLBACK Callback
,
105 FIXME("(%s %s %s %p %p): stub\n", debugstr_a(FileName
), debugstr_a(SymbolPath
),
106 debugstr_a(DebugFilePath
), Callback
, CallerData
);
110 /******************************************************************
111 * FindExecutableImageExW (DBGHELP.@)
114 HANDLE WINAPI
FindExecutableImageExW(PCWSTR FileName
, PCWSTR SymbolPath
, PWSTR ImageFilePath
,
115 PFIND_EXE_FILE_CALLBACKW Callback
, PVOID user
)
119 if (Callback
) FIXME("Unsupported callback yet\n");
120 if (!SearchPathW(SymbolPath
, FileName
, NULL
, MAX_PATH
, ImageFilePath
, NULL
))
122 h
= CreateFileW(ImageFilePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
123 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
124 return (h
== INVALID_HANDLE_VALUE
) ? NULL
: h
;
127 /******************************************************************
128 * FindExecutableImageEx (DBGHELP.@)
131 HANDLE WINAPI
FindExecutableImageEx(PCSTR FileName
, PCSTR SymbolPath
, PSTR ImageFilePath
,
132 PFIND_EXE_FILE_CALLBACK Callback
, PVOID user
)
136 if (Callback
) FIXME("Unsupported callback yet\n");
137 if (!SearchPathA(SymbolPath
, FileName
, NULL
, MAX_PATH
, ImageFilePath
, NULL
))
139 h
= CreateFileA(ImageFilePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
140 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
141 return (h
== INVALID_HANDLE_VALUE
) ? NULL
: h
;
144 /******************************************************************
145 * FindExecutableImage (DBGHELP.@)
148 HANDLE WINAPI
FindExecutableImage(PCSTR FileName
, PCSTR SymbolPath
, PSTR ImageFilePath
)
150 return FindExecutableImageEx(FileName
, SymbolPath
, ImageFilePath
, NULL
, NULL
);
153 /***********************************************************************
154 * MakeSureDirectoryPathExists (DBGHELP.@)
156 BOOL WINAPI
MakeSureDirectoryPathExists(PCSTR DirPath
)
159 const char *p
= DirPath
;
162 if (p
[0] && p
[1] == ':') p
+= 2;
163 while (*p
== '\\') p
++; /* skip drive root */
164 while ((p
= strchr(p
, '\\')) != NULL
)
167 memcpy(path
, DirPath
, n
);
169 if( !CreateDirectoryA(path
, NULL
) &&
170 (GetLastError() != ERROR_ALREADY_EXISTS
))
174 if (GetLastError() == ERROR_ALREADY_EXISTS
)
175 SetLastError(ERROR_SUCCESS
);
180 /******************************************************************
181 * SymMatchFileNameW (DBGHELP.@)
184 BOOL WINAPI
SymMatchFileNameW(PCWSTR file
, PCWSTR match
,
185 PWSTR
* filestop
, PWSTR
* matchstop
)
190 TRACE("(%s %s %p %p)\n",
191 debugstr_w(file
), debugstr_w(match
), filestop
, matchstop
);
193 fptr
= file
+ lstrlenW(file
) - 1;
194 mptr
= match
+ lstrlenW(match
) - 1;
196 while (fptr
>= file
&& mptr
>= match
)
198 if (towupper(*fptr
) != towupper(*mptr
) && !(is_sep(*fptr
) && is_sep(*mptr
)))
202 if (filestop
) *filestop
= (PWSTR
)fptr
;
203 if (matchstop
) *matchstop
= (PWSTR
)mptr
;
205 return mptr
== match
- 1;
208 /******************************************************************
209 * SymMatchFileName (DBGHELP.@)
212 BOOL WINAPI
SymMatchFileName(PCSTR file
, PCSTR match
,
213 PSTR
* filestop
, PSTR
* matchstop
)
218 TRACE("(%s %s %p %p)\n", debugstr_a(file
), debugstr_a(match
), filestop
, matchstop
);
220 fptr
= file
+ strlen(file
) - 1;
221 mptr
= match
+ strlen(match
) - 1;
223 while (fptr
>= file
&& mptr
>= match
)
225 if (toupper(*fptr
) != toupper(*mptr
) && !(is_sepA(*fptr
) && is_sepA(*mptr
)))
229 if (filestop
) *filestop
= (PSTR
)fptr
;
230 if (matchstop
) *matchstop
= (PSTR
)mptr
;
232 return mptr
== match
- 1;
235 static BOOL
do_searchW(PCWSTR file
, PWSTR buffer
, BOOL recurse
,
236 PENUMDIRTREE_CALLBACKW cb
, PVOID user
)
243 pos
= lstrlenW(buffer
);
244 if (pos
== 0) return FALSE
;
245 if (buffer
[pos
- 1] != '\\') buffer
[pos
++] = '\\';
246 lstrcpyW(buffer
+ pos
, L
"*.*");
247 if ((h
= FindFirstFileW(buffer
, &fd
)) == INVALID_HANDLE_VALUE
)
249 /* doc doesn't specify how the tree is enumerated...
250 * doing a depth first based on, but may be wrong
254 if (!wcscmp(fd
.cFileName
, L
".") || !wcscmp(fd
.cFileName
, L
"..")) continue;
256 lstrcpyW(buffer
+ pos
, fd
.cFileName
);
257 if (recurse
&& (fd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
258 found
= do_searchW(file
, buffer
, TRUE
, cb
, user
);
259 else if (SymMatchFileNameW(buffer
, file
, NULL
, NULL
))
261 if (!cb
|| cb(buffer
, user
)) found
= TRUE
;
263 } while (!found
&& FindNextFileW(h
, &fd
));
264 if (!found
) buffer
[--pos
] = '\0';
270 /***********************************************************************
271 * SearchTreeForFileW (DBGHELP.@)
273 BOOL WINAPI
SearchTreeForFileW(PCWSTR root
, PCWSTR file
, PWSTR buffer
)
275 TRACE("(%s, %s, %p)\n",
276 debugstr_w(root
), debugstr_w(file
), buffer
);
277 lstrcpyW(buffer
, root
);
278 return do_searchW(file
, buffer
, TRUE
, NULL
, NULL
);
281 /***********************************************************************
282 * SearchTreeForFile (DBGHELP.@)
284 BOOL WINAPI
SearchTreeForFile(PCSTR root
, PCSTR file
, PSTR buffer
)
286 WCHAR rootW
[MAX_PATH
];
287 WCHAR fileW
[MAX_PATH
];
288 WCHAR bufferW
[MAX_PATH
];
291 MultiByteToWideChar(CP_ACP
, 0, root
, -1, rootW
, MAX_PATH
);
292 MultiByteToWideChar(CP_ACP
, 0, file
, -1, fileW
, MAX_PATH
);
293 ret
= SearchTreeForFileW(rootW
, fileW
, bufferW
);
295 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
299 /******************************************************************
300 * EnumDirTreeW (DBGHELP.@)
304 BOOL WINAPI
EnumDirTreeW(HANDLE hProcess
, PCWSTR root
, PCWSTR file
,
305 PWSTR buffer
, PENUMDIRTREE_CALLBACKW cb
, PVOID user
)
307 TRACE("(%p %s %s %p %p %p)\n",
308 hProcess
, debugstr_w(root
), debugstr_w(file
), buffer
, cb
, user
);
310 lstrcpyW(buffer
, root
);
311 return do_searchW(file
, buffer
, TRUE
, cb
, user
);
314 /******************************************************************
315 * EnumDirTree (DBGHELP.@)
319 struct enum_dir_treeWA
321 PENUMDIRTREE_CALLBACK cb
;
326 static BOOL CALLBACK
enum_dir_treeWA(PCWSTR name
, PVOID user
)
328 struct enum_dir_treeWA
* edt
= user
;
330 WideCharToMultiByte(CP_ACP
, 0, name
, -1, edt
->name
, MAX_PATH
, NULL
, NULL
);
331 return edt
->cb(edt
->name
, edt
->user
);
334 BOOL WINAPI
EnumDirTree(HANDLE hProcess
, PCSTR root
, PCSTR file
,
335 PSTR buffer
, PENUMDIRTREE_CALLBACK cb
, PVOID user
)
337 WCHAR rootW
[MAX_PATH
];
338 WCHAR fileW
[MAX_PATH
];
339 WCHAR bufferW
[MAX_PATH
];
340 struct enum_dir_treeWA edt
;
345 MultiByteToWideChar(CP_ACP
, 0, root
, -1, rootW
, MAX_PATH
);
346 MultiByteToWideChar(CP_ACP
, 0, file
, -1, fileW
, MAX_PATH
);
347 if ((ret
= EnumDirTreeW(hProcess
, rootW
, fileW
, bufferW
, enum_dir_treeWA
, &edt
)))
348 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
354 PFINDFILEINPATHCALLBACKW cb
;
358 /* checks that buffer (as found by matching the name) matches the info
359 * (information is based on file type)
360 * returns TRUE when file is found, FALSE to continue searching
361 * (NB this is the opposite convention of SymFindFileInPathProc)
363 static BOOL CALLBACK
sffip_cb(PCWSTR buffer
, PVOID user
)
365 struct sffip
* s
= user
;
367 if (!s
->cb
) return TRUE
;
368 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
369 * convention to stop/continue enumeration. sigh.
371 return !(s
->cb
)(buffer
, s
->user
);
374 /******************************************************************
375 * SymFindFileInPathW (DBGHELP.@)
378 BOOL WINAPI
SymFindFileInPathW(HANDLE hProcess
, PCWSTR searchPath
, PCWSTR full_path
,
379 PVOID id
, DWORD two
, DWORD three
, DWORD flags
,
380 PWSTR buffer
, PFINDFILEINPATHCALLBACKW cb
,
384 struct process
* pcs
= process_find_by_handle(hProcess
);
387 const WCHAR
* filename
;
389 TRACE("(hProcess = %p, searchPath = %s, full_path = %s, id = %p, two = 0x%08lx, three = 0x%08lx, flags = 0x%08lx, buffer = %p, cb = %p, user = %p)\n",
390 hProcess
, debugstr_w(searchPath
), debugstr_w(full_path
),
391 id
, two
, three
, flags
, buffer
, cb
, user
);
393 if (!pcs
) return FALSE
;
394 if (!searchPath
) searchPath
= pcs
->search_path
;
399 filename
= file_name(full_path
);
401 /* first check full path to file */
402 if (sffip_cb(full_path
, &s
))
404 lstrcpyW(buffer
, full_path
);
410 ptr
= wcschr(searchPath
, ';');
413 memcpy(tmp
, searchPath
, (ptr
- searchPath
) * sizeof(WCHAR
));
414 tmp
[ptr
- searchPath
] = 0;
415 searchPath
= ptr
+ 1;
419 lstrcpyW(tmp
, searchPath
);
422 if (do_searchW(filename
, tmp
, FALSE
, sffip_cb
, &s
))
424 lstrcpyW(buffer
, tmp
);
431 /******************************************************************
432 * SymFindFileInPath (DBGHELP.@)
435 BOOL WINAPI
SymFindFileInPath(HANDLE hProcess
, PCSTR searchPath
, PCSTR full_path
,
436 PVOID id
, DWORD two
, DWORD three
, DWORD flags
,
437 PSTR buffer
, PFINDFILEINPATHCALLBACK cb
,
440 WCHAR searchPathW
[MAX_PATH
];
441 WCHAR full_pathW
[MAX_PATH
];
442 WCHAR bufferW
[MAX_PATH
];
443 struct enum_dir_treeWA edt
;
446 /* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the
447 * same signature & semantics, hence we can reuse the EnumDirTree W->A
453 MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, searchPathW
, MAX_PATH
);
454 MultiByteToWideChar(CP_ACP
, 0, full_path
, -1, full_pathW
, MAX_PATH
);
455 if ((ret
= SymFindFileInPathW(hProcess
, searchPath
? searchPathW
: NULL
, full_pathW
,
456 id
, two
, three
, flags
,
457 bufferW
, enum_dir_treeWA
, &edt
)))
458 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
465 /* pdb: guid PDB guid (if DS PDB file)
466 * or dw1 PDB timestamp (if JG PDB file)
468 * dbg: dw1 DWORD:timestamp
469 * dw2 size of image (from PE header)
474 WCHAR filename
[MAX_PATH
];
478 /* checks that buffer (as found by matching the name) matches the info
479 * (information is based on file type)
480 * returns TRUE when file is found, FALSE to continue searching
481 * (NB this is the opposite convention of SymFindFileInPathProc)
483 static BOOL CALLBACK
module_find_cb(PCWSTR buffer
, PVOID user
)
485 struct module_find
* mf
= user
;
487 unsigned matched
= 0;
489 /* the matching weights:
490 * +1 if a file with same name is found and is a decent file of expected type
491 * +1 if first parameter and second parameter match
496 struct pdb_lookup pdb_lookup
;
499 WideCharToMultiByte(CP_ACP
, 0, buffer
, -1, fn
, MAX_PATH
, NULL
, NULL
);
500 pdb_lookup
.filename
= fn
;
504 pdb_lookup
.kind
= PDB_DS
;
505 pdb_lookup
.timestamp
= 0;
506 pdb_lookup
.guid
= *mf
->guid
;
510 pdb_lookup
.kind
= PDB_JG
;
511 pdb_lookup
.timestamp
= mf
->dw1
;
512 /* pdb_loopkup.guid = */
514 pdb_lookup
.age
= mf
->dw2
;
516 if (!pdb_fetch_file_info(&pdb_lookup
, &matched
)) return FALSE
;
523 timestamp
= ~mf
->dw1
;
524 hFile
= CreateFileW(buffer
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
525 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
526 if (hFile
== INVALID_HANDLE_VALUE
) return FALSE
;
527 if ((hMap
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
)) != NULL
)
529 if ((mapping
= MapViewOfFile(hMap
, FILE_MAP_READ
, 0, 0, 0)) != NULL
)
531 const IMAGE_SEPARATE_DEBUG_HEADER
* hdr
;
534 if (hdr
->Signature
== IMAGE_SEPARATE_DEBUG_SIGNATURE
)
537 timestamp
= hdr
->TimeDateStamp
;
539 UnmapViewOfFile(mapping
);
544 if (timestamp
== mf
->dw1
) matched
++;
545 else WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer
));
548 if (matched
> mf
->matched
)
550 lstrcpyW(mf
->filename
, buffer
);
551 mf
->matched
= matched
;
553 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
554 * convention to stop/continue enumeration. sigh.
556 return mf
->matched
== 2;
559 BOOL
path_find_symbol_file(const struct process
* pcs
, const struct module
* module
,
560 PCSTR full_path
, BOOL is_pdb
, const GUID
* guid
, DWORD dw1
, DWORD dw2
,
561 WCHAR
*buffer
, BOOL
* is_unmatched
)
563 struct module_find mf
;
564 WCHAR full_pathW
[MAX_PATH
];
566 const WCHAR
* filename
;
567 WCHAR
* searchPath
= pcs
->search_path
;
569 TRACE("(pcs = %p, full_path = %s, guid = %s, dw1 = 0x%08lx, dw2 = 0x%08lx, buffer = %p)\n",
570 pcs
, debugstr_a(full_path
), debugstr_guid(guid
), dw1
, dw2
, buffer
);
577 MultiByteToWideChar(CP_ACP
, 0, full_path
, -1, full_pathW
, MAX_PATH
);
578 filename
= file_name(full_pathW
);
580 *is_unmatched
= FALSE
;
582 /* first check full path to file */
583 if (module_find_cb(full_pathW
, &mf
))
585 lstrcpyW( buffer
, full_pathW
);
589 /* FIXME: Use Environment-Variables (see MS docs)
590 _NT_SYMBOL_PATH and _NT_ALT_SYMBOL_PATH
591 FIXME: Implement "Standard Path Elements" (Path) ... (see MS docs)
592 do a search for (every?) path-element like this ...
596 (dll may be exe, or sys depending on the file extension) */
598 /* 2. check module-path */
599 file_pathW(module
->module
.LoadedImageName
, buffer
);
600 if (do_searchW(filename
, buffer
, FALSE
, module_find_cb
, &mf
)) return TRUE
;
601 if (module
->real_path
)
603 file_pathW(module
->real_path
, buffer
);
604 if (do_searchW(filename
, buffer
, FALSE
, module_find_cb
, &mf
)) return TRUE
;
609 ptr
= wcschr(searchPath
, ';');
612 memcpy(buffer
, searchPath
, (ptr
- searchPath
) * sizeof(WCHAR
));
613 buffer
[ptr
- searchPath
] = '\0';
614 searchPath
= ptr
+ 1;
618 lstrcpyW(buffer
, searchPath
);
621 /* return first fully matched file */
622 if (do_searchW(filename
, buffer
, FALSE
, module_find_cb
, &mf
)) return TRUE
;
624 /* if no fully matching file is found, return the best matching file if any */
625 if ((dbghelp_options
& SYMOPT_LOAD_ANYTHING
) && mf
.matched
)
627 lstrcpyW( buffer
, mf
.filename
);
628 *is_unmatched
= TRUE
;
634 WCHAR
*get_dos_file_name(const WCHAR
*filename
)
639 if (*filename
== '/')
642 len
= WideCharToMultiByte(CP_UNIXCP
, 0, filename
, -1, NULL
, 0, NULL
, NULL
);
643 unix_path
= heap_alloc(len
* sizeof(WCHAR
));
644 WideCharToMultiByte(CP_UNIXCP
, 0, filename
, -1, unix_path
, len
, NULL
, NULL
);
645 dos_path
= wine_get_dos_file_name(unix_path
);
646 heap_free(unix_path
);
650 len
= lstrlenW(filename
);
651 dos_path
= heap_alloc((len
+ 1) * sizeof(WCHAR
));
652 memcpy(dos_path
, filename
, (len
+ 1) * sizeof(WCHAR
));
657 static inline const WCHAR
* get_machine_dir(const struct machine_dir
*machine_dir
, const WCHAR
*name
)
660 if ((ptr
= wcsrchr(name
, L
'.')) && !lstrcmpW(ptr
, L
".so"))
661 return machine_dir
->so_dir
;
662 return machine_dir
->pe_dir
;
665 static BOOL
try_match_file(const WCHAR
*name
, BOOL (*match
)(void*, HANDLE
, const WCHAR
*), void *param
)
667 HANDLE file
= CreateFileW(name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
668 if (file
!= INVALID_HANDLE_VALUE
)
670 BOOL ret
= match(param
, file
, name
);
677 BOOL
search_dll_path(const struct process
*process
, const WCHAR
*name
, WORD machine
, BOOL (*match
)(void*, HANDLE
, const WCHAR
*), void *param
)
681 size_t len
, i
, machine_dir_len
;
683 const struct cpu
* cpu
;
684 const struct machine_dir
* machine_dir
;
686 name
= file_name(name
);
688 cpu
= machine
== IMAGE_FILE_MACHINE_UNKNOWN
? process_get_cpu(process
) : cpu_find(machine
);
690 for (machine_dir
= all_machine_dir
; machine_dir
< all_machine_dir
+ ARRAY_SIZE(all_machine_dir
); machine_dir
++)
691 if (machine_dir
->machine
== cpu
->machine
) break;
692 if (machine_dir
>= all_machine_dir
+ ARRAY_SIZE(all_machine_dir
)) return FALSE
;
693 machine_dir_len
= max(wcslen(machine_dir
->pe_dir
), wcslen(machine_dir
->so_dir
));
695 if ((env
= process_getenv(process
, L
"WINEBUILDDIR")))
698 if (!(buf
= heap_alloc((len
+ wcslen(L
"\\programs\\") + machine_dir_len
+
699 2 * lstrlenW(name
) + 1) * sizeof(WCHAR
)))) return FALSE
;
703 wcscpy(end
, L
"\\dlls\\");
705 if ((p
= wcsrchr(end
, '.')) && !lstrcmpW(p
, L
".so")) *p
= 0;
706 if ((p
= wcsrchr(end
, '.')) && !lstrcmpW(p
, L
".dll")) *p
= 0;
707 p
= end
+ lstrlenW(end
);
708 /* try multi-arch first */
709 wcscpy(p
, get_machine_dir(machine_dir
, name
));
710 wcscpy(p
+ wcslen(p
), name
);
711 if (try_match_file(buf
, match
, param
)) goto found
;
712 /* then old mono-arch */
715 if (try_match_file(buf
, match
, param
)) goto found
;
717 wcscpy(end
, L
"\\programs\\");
720 if ((p
= wcsrchr(end
, '.')) && !lstrcmpW(p
, L
".so")) *p
= 0;
721 if ((p
= wcsrchr(end
, '.')) && !lstrcmpW(p
, L
".exe")) *p
= 0;
722 p
= end
+ lstrlenW(end
);
723 /* try multi-arch first */
724 wcscpy(p
, get_machine_dir(machine_dir
, name
));
725 wcscpy(p
+ wcslen(p
), name
);
726 if (try_match_file(buf
, match
, param
)) goto found
;
727 /* then old mono-arch */
730 if (try_match_file(buf
, match
, param
)) goto found
;
738 swprintf(env_name
, ARRAY_SIZE(env_name
), L
"WINEDLLDIR%u", i
);
739 if (!(env
= process_getenv(process
, env_name
))) return FALSE
;
740 len
= wcslen(env
) + machine_dir_len
+ wcslen(name
) + 1;
741 if (!(buf
= heap_alloc(len
* sizeof(WCHAR
)))) return FALSE
;
742 swprintf(buf
, len
, L
"%s%s%s", env
, get_machine_dir(machine_dir
, name
), name
);
743 if (try_match_file(buf
, match
, param
)) goto found
;
744 swprintf(buf
, len
, L
"%s\\%s", env
, name
);
745 if (try_match_file(buf
, match
, param
)) goto found
;
752 TRACE("found %s\n", debugstr_w(buf
));
757 BOOL
search_unix_path(const WCHAR
*name
, const WCHAR
*path
, BOOL (*match
)(void*, HANDLE
, const WCHAR
*), void *param
)
759 const WCHAR
*iter
, *next
;
765 if (!path
) return FALSE
;
766 name
= file_name(name
);
768 size
= WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
)
769 + WideCharToMultiByte(CP_UNIXCP
, 0, path
, -1, NULL
, 0, NULL
, NULL
);
770 if (!(buf
= heap_alloc(size
))) return FALSE
;
772 for (iter
= path
;; iter
= next
+ 1)
774 if (!(next
= wcschr(iter
, ':'))) next
= iter
+ lstrlenW(iter
);
777 len
= WideCharToMultiByte(CP_UNIXCP
, 0, iter
, next
- iter
, buf
, size
, NULL
, NULL
);
778 if (buf
[len
- 1] != '/') buf
[len
++] = '/';
779 WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, buf
+ len
, size
- len
, NULL
, NULL
);
780 if ((dos_path
= wine_get_dos_file_name(buf
)))
782 ret
= try_match_file(dos_path
, match
, param
);
783 if (ret
) TRACE("found %s\n", debugstr_w(dos_path
));
788 if (*next
!= ':') break;
795 /******************************************************************
796 * SymSrvGetFileIndexInfo (DBGHELP.@)
799 BOOL WINAPI
SymSrvGetFileIndexInfo(const char *file
, SYMSRV_INDEX_INFO
* info
, DWORD flags
)
801 SYMSRV_INDEX_INFOW infoW
;
802 WCHAR fileW
[MAX_PATH
];
805 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(file
), info
, flags
);
807 if (info
->sizeofstruct
< sizeof(*info
))
809 SetLastError(ERROR_INVALID_PARAMETER
);
812 MultiByteToWideChar(CP_ACP
, 0, file
, -1, fileW
, ARRAY_SIZE(fileW
));
813 infoW
.sizeofstruct
= sizeof(infoW
);
814 ret
= SymSrvGetFileIndexInfoW(fileW
, &infoW
, flags
);
817 WideCharToMultiByte(CP_ACP
, 0, infoW
.file
, -1, info
->file
, ARRAY_SIZE(info
->file
), NULL
, NULL
);
818 info
->stripped
= infoW
.stripped
;
819 info
->timestamp
= infoW
.timestamp
;
820 info
->size
= infoW
.size
;
821 WideCharToMultiByte(CP_ACP
, 0, infoW
.dbgfile
, -1, info
->dbgfile
, ARRAY_SIZE(info
->dbgfile
), NULL
, NULL
);
822 WideCharToMultiByte(CP_ACP
, 0, infoW
.pdbfile
, -1, info
->pdbfile
, ARRAY_SIZE(info
->pdbfile
), NULL
, NULL
);
823 info
->guid
= infoW
.guid
;
824 info
->sig
= infoW
.sig
;
825 info
->age
= infoW
.age
;
830 /******************************************************************
831 * SymSrvGetFileIndexInfoW (DBGHELP.@)
834 BOOL WINAPI
SymSrvGetFileIndexInfoW(const WCHAR
*file
, SYMSRV_INDEX_INFOW
* info
, DWORD flags
)
836 HANDLE hFile
, hMap
= NULL
;
840 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(file
), info
, flags
);
842 if (info
->sizeofstruct
< sizeof(*info
))
844 SetLastError(ERROR_INVALID_PARAMETER
);
848 if ((hFile
= CreateFileW(file
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
849 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
)) != INVALID_HANDLE_VALUE
&&
850 ((hMap
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
)) != NULL
) &&
851 ((image
= MapViewOfFile(hMap
, FILE_MAP_READ
, 0, 0, 0)) != NULL
))
853 /* must handle PE, or .dbg or .pdb files. So each helper will return:
854 * - ERROR_SUCCESS: if the file format is recognized and index info filled,
855 * - ERROR_BAD_FORMAT: if the file doesn't match the expected format,
856 * - any other error: if the file has expected format, but internal errors
858 fsize
= GetFileSize(hFile
, NULL
);
859 /* try PE module first */
860 ret
= pe_get_file_indexinfo(image
, fsize
, info
);
861 if (ret
== ERROR_BAD_FORMAT
)
862 ret
= pdb_get_file_indexinfo(image
, fsize
, info
);
864 else ret
= ERROR_FILE_NOT_FOUND
;
866 if (image
) UnmapViewOfFile(image
);
867 if (hMap
) CloseHandle(hMap
);
868 if (hFile
!= INVALID_HANDLE_VALUE
) CloseHandle(hFile
);
870 if (ret
== ERROR_SUCCESS
) wcscpy(info
->file
, file_name(file
)); /* overflow? */
872 return ret
== ERROR_SUCCESS
;
875 /******************************************************************
876 * SymSrvGetFileIndexes (DBGHELP.@)
879 BOOL WINAPI
SymSrvGetFileIndexes(PCSTR file
, GUID
* guid
, PDWORD pdw1
, PDWORD pdw2
, DWORD flags
)
881 WCHAR fileW
[MAX_PATH
];
883 TRACE("(%s, %p, %p, %p, 0x%08lx)\n", debugstr_a(file
), guid
, pdw1
, pdw2
, flags
);
885 MultiByteToWideChar(CP_ACP
, 0, file
, -1, fileW
, ARRAY_SIZE(fileW
));
886 return SymSrvGetFileIndexesW(fileW
, guid
, pdw1
, pdw2
, flags
);
889 /******************************************************************
890 * SymSrvGetFileIndexesW (DBGHELP.@)
893 BOOL WINAPI
SymSrvGetFileIndexesW(PCWSTR file
, GUID
* guid
, PDWORD pdw1
, PDWORD pdw2
, DWORD flags
)
895 FIXME("(%s, %p, %p, %p, 0x%08lx): stub!\n", debugstr_w(file
), guid
, pdw1
, pdw2
, flags
);
897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);