Newer
Older
/*
* File path.c - managing path in debugging environments
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dbghelp_private.h"
Jacek Caban
committed
#include "image_private.h"
#include "winnls.h"
#include "winternl.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
static const struct machine_dir
{
DWORD machine;
const WCHAR *pe_dir;
const WCHAR *so_dir;
}
all_machine_dir[] =
{
{IMAGE_FILE_MACHINE_I386, L"\\i386-windows\\", L"\\i386-unix\\"},
{IMAGE_FILE_MACHINE_AMD64, L"\\x86_64-windows\\", L"\\x86_64-unix\\"},
{IMAGE_FILE_MACHINE_ARMNT, L"\\arm-windows\\", L"\\arm-unix\\"},
{IMAGE_FILE_MACHINE_ARM64, L"\\aarch64-windows\\", L"\\aarch64-unix\\"},
};

Alexandre Julliard
committed
static inline BOOL is_sepA(char ch) {return ch == '/' || ch == '\\';}
static inline BOOL is_sep(WCHAR ch) {return ch == '/' || ch == '\\';}
const char* file_nameA(const char* str)
const char* p;
for (p = str + strlen(str) - 1; p >= str && !is_sepA(*p); p--);
return p + 1;
}
const WCHAR* file_name(const WCHAR* str)
for (p = str + lstrlenW(str) - 1; p >= str && !is_sep(*p); p--);
static inline void file_pathW(const WCHAR *src, WCHAR *dst)
{
int len;
for (len = lstrlenW(src) - 1; (len > 0) && (!is_sep(src[len])); len--);
memcpy( dst, src, len * sizeof(WCHAR) );
dst[len] = 0;
}
/******************************************************************
* FindDebugInfoFile (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFile(PCSTR FileName, PCSTR SymbolPath, PSTR DebugFilePath)
Eric van Beurden
committed
h = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
{
if (!SearchPathA(SymbolPath, file_nameA(FileName), NULL, MAX_PATH, DebugFilePath, NULL))
return NULL;
h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindDebugInfoFileEx (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFileEx(PCSTR FileName, PCSTR SymbolPath,
PSTR DebugFilePath,
PFIND_DEBUG_FILE_CALLBACK Callback,
PVOID CallerData)
{
FIXME("(%s %s %s %p %p): stub\n", debugstr_a(FileName), debugstr_a(SymbolPath),
debugstr_a(DebugFilePath), Callback, CallerData);
return NULL;
}
/******************************************************************
* FindExecutableImageExW (DBGHELP.@)
HANDLE WINAPI FindExecutableImageExW(PCWSTR FileName, PCWSTR SymbolPath, PWSTR ImageFilePath,
Francois Gouget
committed
PFIND_EXE_FILE_CALLBACKW Callback, PVOID user)
{
HANDLE h;
if (Callback) FIXME("Unsupported callback yet\n");
if (!SearchPathW(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
return NULL;
h = CreateFileW(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindExecutableImageEx (DBGHELP.@)
*
*/
HANDLE WINAPI FindExecutableImageEx(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath,
Francois Gouget
committed
PFIND_EXE_FILE_CALLBACK Callback, PVOID user)
if (Callback) FIXME("Unsupported callback yet\n");
if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
return NULL;
h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindExecutableImage (DBGHELP.@)
*
*/
HANDLE WINAPI FindExecutableImage(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath)
{
return FindExecutableImageEx(FileName, SymbolPath, ImageFilePath, NULL, NULL);
}
/***********************************************************************
* MakeSureDirectoryPathExists (DBGHELP.@)
*/
Francois Gouget
committed
BOOL WINAPI MakeSureDirectoryPathExists(PCSTR DirPath)
char path[MAX_PATH];
const char *p = DirPath;
int n;
if (p[0] && p[1] == ':') p += 2;
while (*p == '\\') p++; /* skip drive root */
while ((p = strchr(p, '\\')) != NULL)
n = p - DirPath + 1;
memcpy(path, DirPath, n);
path[n] = '\0';
if( !CreateDirectoryA(path, NULL) &&
(GetLastError() != ERROR_ALREADY_EXISTS))
return FALSE;
p++;
if (GetLastError() == ERROR_ALREADY_EXISTS)
SetLastError(ERROR_SUCCESS);
return TRUE;
/******************************************************************
* SymMatchFileNameW (DBGHELP.@)
*
*/
Francois Gouget
committed
BOOL WINAPI SymMatchFileNameW(PCWSTR file, PCWSTR match,
PWSTR* filestop, PWSTR* matchstop)
Francois Gouget
committed
PCWSTR fptr;
PCWSTR mptr;
TRACE("(%s %s %p %p)\n",
debugstr_w(file), debugstr_w(match), filestop, matchstop);
fptr = file + lstrlenW(file) - 1;
mptr = match + lstrlenW(match) - 1;
while (fptr >= file && mptr >= match)
{
if (towupper(*fptr) != towupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr)))
Francois Gouget
committed
if (filestop) *filestop = (PWSTR)fptr;
if (matchstop) *matchstop = (PWSTR)mptr;
return mptr == match - 1;
}
/******************************************************************
* SymMatchFileName (DBGHELP.@)
*
*/
Francois Gouget
committed
BOOL WINAPI SymMatchFileName(PCSTR file, PCSTR match,
PSTR* filestop, PSTR* matchstop)
Francois Gouget
committed
PCSTR fptr;
PCSTR mptr;
Eric van Beurden
committed
TRACE("(%s %s %p %p)\n", debugstr_a(file), debugstr_a(match), filestop, matchstop);
fptr = file + strlen(file) - 1;
mptr = match + strlen(match) - 1;
while (fptr >= file && mptr >= match)
{
if (toupper(*fptr) != toupper(*mptr) && !(is_sepA(*fptr) && is_sepA(*mptr)))
break;
fptr--; mptr--;
}
Francois Gouget
committed
if (filestop) *filestop = (PSTR)fptr;
if (matchstop) *matchstop = (PSTR)mptr;
return mptr == match - 1;
}
Francois Gouget
committed
static BOOL do_searchW(PCWSTR file, PWSTR buffer, BOOL recurse,
PENUMDIRTREE_CALLBACKW cb, PVOID user)
{
HANDLE h;
WIN32_FIND_DATAW fd;
unsigned pos;
BOOL found = FALSE;

Rémi Bernon
committed
if (pos == 0) return FALSE;
if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
if ((h = FindFirstFileW(buffer, &fd)) == INVALID_HANDLE_VALUE)
return FALSE;
/* doc doesn't specify how the tree is enumerated...
* doing a depth first based on, but may be wrong
*/
do
{
if (!wcscmp(fd.cFileName, L".") || !wcscmp(fd.cFileName, L"..")) continue;
if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
found = do_searchW(file, buffer, TRUE, cb, user);
else if (SymMatchFileNameW(buffer, file, NULL, NULL))
{
if (!cb || cb(buffer, user)) found = TRUE;
}
} while (!found && FindNextFileW(h, &fd));
if (!found) buffer[--pos] = '\0';
FindClose(h);
return found;
}
/***********************************************************************
* SearchTreeForFileW (DBGHELP.@)
*/
BOOL WINAPI SearchTreeForFileW(PCWSTR root, PCWSTR file, PWSTR buffer)
{
TRACE("(%s, %s, %p)\n",
debugstr_w(root), debugstr_w(file), buffer);
return do_searchW(file, buffer, TRUE, NULL, NULL);
}
/***********************************************************************
* SearchTreeForFile (DBGHELP.@)
*/
BOOL WINAPI SearchTreeForFile(PCSTR root, PCSTR file, PSTR buffer)
WCHAR rootW[MAX_PATH];
WCHAR fileW[MAX_PATH];
WCHAR bufferW[MAX_PATH];
BOOL ret;
MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH);
ret = SearchTreeForFileW(rootW, fileW, bufferW);
if (ret)
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
return ret;
/******************************************************************
* EnumDirTreeW (DBGHELP.@)
*
*
*/
BOOL WINAPI EnumDirTreeW(HANDLE hProcess, PCWSTR root, PCWSTR file,
Francois Gouget
committed
PWSTR buffer, PENUMDIRTREE_CALLBACKW cb, PVOID user)
{
TRACE("(%p %s %s %p %p %p)\n",
hProcess, debugstr_w(root), debugstr_w(file), buffer, cb, user);
return do_searchW(file, buffer, TRUE, cb, user);
}
/******************************************************************
* EnumDirTree (DBGHELP.@)
*
*
*/
struct enum_dir_treeWA
{
PENUMDIRTREE_CALLBACK cb;
void* user;
char name[MAX_PATH];
};
Francois Gouget
committed
static BOOL CALLBACK enum_dir_treeWA(PCWSTR name, PVOID user)
{
struct enum_dir_treeWA* edt = user;
WideCharToMultiByte(CP_ACP, 0, name, -1, edt->name, MAX_PATH, NULL, NULL);
return edt->cb(edt->name, edt->user);
}
BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
Francois Gouget
committed
PSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
WCHAR rootW[MAX_PATH];
WCHAR fileW[MAX_PATH];
WCHAR bufferW[MAX_PATH];
struct enum_dir_treeWA edt;
BOOL ret;
edt.cb = cb;
edt.user = user;
MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH);
if ((ret = EnumDirTreeW(hProcess, rootW, fileW, bufferW, enum_dir_treeWA, &edt)))
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
return ret;
}
struct sffip
{
void* user;
};
/* checks that buffer (as found by matching the name) matches the info
* (information is based on file type)
* returns TRUE when file is found, FALSE to continue searching
Francois Gouget
committed
* (NB this is the opposite convention of SymFindFileInPathProc)
Francois Gouget
committed
static BOOL CALLBACK sffip_cb(PCWSTR buffer, PVOID user)
if (!s->cb) return TRUE;
/* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
* convention to stop/continue enumeration. sigh.
*/
return !(s->cb)(buffer, s->user);
}
/******************************************************************
BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_path,
PVOID id, DWORD two, DWORD three, DWORD flags,
Francois Gouget
committed
PWSTR buffer, PFINDFILEINPATHCALLBACKW cb,
{
struct sffip s;
struct process* pcs = process_find_by_handle(hProcess);
WCHAR tmp[MAX_PATH];
WCHAR* ptr;
const WCHAR* filename;
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",
hProcess, debugstr_w(searchPath), debugstr_w(full_path),
id, two, three, flags, buffer, cb, user);
if (!pcs) return FALSE;
if (!searchPath) searchPath = pcs->search_path;
s.cb = cb;
s.user = user;
filename = file_name(full_path);
while (searchPath)
{
if (ptr)
{
memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR));
tmp[ptr - searchPath] = 0;
searchPath = ptr + 1;
}
else
{
searchPath = NULL;
}
if (do_searchW(filename, tmp, FALSE, sffip_cb, &s))
SetLastError(ERROR_FILE_NOT_FOUND);
/******************************************************************
* SymFindFileInPath (DBGHELP.@)
*
*/
BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path,
PVOID id, DWORD two, DWORD three, DWORD flags,
Francois Gouget
committed
PSTR buffer, PFINDFILEINPATHCALLBACK cb,
PVOID user)
{
WCHAR searchPathW[MAX_PATH];
WCHAR full_pathW[MAX_PATH];
WCHAR bufferW[MAX_PATH];
struct enum_dir_treeWA edt;
BOOL ret;
/* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the
* same signature & semantics, hence we can reuse the EnumDirTree W->A
* conversion helper
*/
edt.cb = cb;
edt.user = user;
if (searchPath)
MultiByteToWideChar(CP_ACP, 0, searchPath, -1, searchPathW, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH);
if ((ret = SymFindFileInPathW(hProcess, searchPath ? searchPathW : NULL, full_pathW,
id, two, three, flags,
bufferW, enum_dir_treeWA, &edt)))
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
return ret;
}
BOOL is_pdb;
/* pdb: guid PDB guid (if DS PDB file)
* or dw1 PDB timestamp (if JG PDB file)
* dw2 PDB age
* dbg: dw1 DWORD:timestamp
* dw2 size of image (from PE header)
*/
const GUID* guid;
DWORD dw1;
DWORD dw2;
SYMSRV_INDEX_INFOW *info;
WCHAR *buffer; /* MAX_PATH + 1 */
unsigned matched;
};
/* checks that buffer (as found by matching the name) matches the info
* (information is based on file type)
* returns TRUE when file is found, FALSE to continue searching
* (NB this is the opposite convention of SymFindFileInPathProc)
*/
static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user)
{
struct module_find* mf = user;
SYMSRV_INDEX_INFOW info;
info.sizeofstruct = sizeof(info);
if (!SymSrvGetFileIndexInfoW(buffer, &info, 0))
return FALSE;
if (!memcmp(&info.guid, mf->guid, sizeof(GUID))) matched++;
if (info.timestamp == mf->dw1) matched++;
if (info.age == mf->dw2) matched++;
size_t len = min(wcslen(buffer), MAX_PATH);
memcpy(mf->buffer, buffer, len * sizeof(WCHAR));
mf->buffer[len] = L'\0';
mf->info->guid = info.guid;
mf->info->timestamp = info.timestamp;
mf->info->age = info.age;
mf->info->sig = info.sig;
}
/* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
* convention to stop/continue enumeration. sigh.
*/
return mf->matched == 4;
BOOL path_find_symbol_file(const struct process* pcs, const struct module* module,
PCSTR full_path, BOOL is_pdb, const GUID* guid, DWORD dw1, DWORD dw2,
SYMSRV_INDEX_INFOW *info, BOOL* is_unmatched)
WCHAR *searchPath = pcs->search_path;
WCHAR buffer[MAX_PATH];
TRACE("(pcs = %p, full_path = %s, guid = %s, dw1 = 0x%08lx, dw2 = 0x%08lx)\n",
pcs, debugstr_a(full_path), debugstr_guid(guid), dw1, dw2);
mf.info = info;
mf.guid = guid;
mf.dw1 = dw1;
mf.dw2 = dw2;
mf.matched = 0;
mf.buffer = is_pdb ? info->pdbfile : info->dbgfile;
MultiByteToWideChar(CP_ACP, 0, full_path, -1, info->file, MAX_PATH);
filename = file_name(info->file);

eric pouech
committed
*is_unmatched = FALSE;
/* first check full path to file */
if (is_pdb && module_find_cb(info->file, &mf))
wcscpy( info->pdbfile, info->file );
/* FIXME: Use Environment-Variables (see MS docs)
_NT_SYMBOL_PATH and _NT_ALT_SYMBOL_PATH
ext = wcsrchr(module->module.LoadedImageName, L'.');
size_t len;
len = (ptr) ? ptr - searchPath : wcslen(searchPath);
if (len + 1 < ARRAY_SIZE(buffer))
memcpy(buffer, searchPath, len * sizeof(WCHAR));
/* return first fully matched file */
if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE;
len = wcslen(buffer); /* do_searchW removes the trailing \ in buffer when present */
/* check once max size for \symbols\<ext>\ */
if (ext && len + 9 /* \symbols\ */ + wcslen(ext + 1) + 1 + 1 <= ARRAY_SIZE(buffer))
{
buffer[len++] = L'\\';
wcscpy(buffer + len, ext + 1);
wcscat(buffer + len, L"\\");
if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE;
wcscpy(buffer + len, L"symbols\\");
wcscat(buffer + len, ext + 1);
wcscat(buffer + len, L"\\");
if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE;
}
ERR("Too long search element %ls\n", searchPath);
searchPath = ptr ? ptr + 1 : NULL;
/* check module-path */
if (module->real_path)
{
file_pathW(module->real_path, buffer);
if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE;
}
file_pathW(module->module.LoadedImageName, buffer);
if (do_searchW(filename, buffer, FALSE, module_find_cb, &mf)) return TRUE;
/* if no fully matching file is found, return the best matching file if any */
if ((dbghelp_options & SYMOPT_LOAD_ANYTHING) && mf.matched)
{

eric pouech
committed
*is_unmatched = TRUE;
mf.buffer[0] = L'\0';
WCHAR *get_dos_file_name(const WCHAR *filename)
{
WCHAR *dos_path;
size_t len;
if (*filename == '/')
{
char *unix_path;
len = WideCharToMultiByte(CP_UNIXCP, 0, filename, -1, NULL, 0, NULL, NULL);
unix_path = heap_alloc(len * sizeof(WCHAR));
WideCharToMultiByte(CP_UNIXCP, 0, filename, -1, unix_path, len, NULL, NULL);
dos_path = wine_get_dos_file_name(unix_path);
heap_free(unix_path);
}
else
{
len = lstrlenW(filename);
dos_path = heap_alloc((len + 1) * sizeof(WCHAR));
memcpy(dos_path, filename, (len + 1) * sizeof(WCHAR));
}
return dos_path;
}
static inline const WCHAR* get_machine_dir(const struct machine_dir *machine_dir, const WCHAR *name)
{
WCHAR *ptr;
if ((ptr = wcsrchr(name, L'.')) && !lstrcmpW(ptr, L".so"))
return machine_dir->so_dir;
return machine_dir->pe_dir;
}
static BOOL try_match_file(const WCHAR *name, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param)
{
HANDLE file = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file != INVALID_HANDLE_VALUE)
{
BOOL ret = match(param, file, name);
CloseHandle(file);
return ret;
}
return FALSE;
}
BOOL search_dll_path(const struct process *process, const WCHAR *name, WORD machine, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param)
const WCHAR *env;

Alexandre Julliard
committed
WCHAR *p, *end;
size_t len, i, machine_dir_len;
const struct cpu* cpu;
const struct machine_dir* machine_dir;
name = file_name(name);
cpu = machine == IMAGE_FILE_MACHINE_UNKNOWN ? process_get_cpu(process) : cpu_find(machine);
for (machine_dir = all_machine_dir; machine_dir < all_machine_dir + ARRAY_SIZE(all_machine_dir); machine_dir++)
if (machine_dir->machine == cpu->machine) break;
if (machine_dir >= all_machine_dir + ARRAY_SIZE(all_machine_dir)) return FALSE;
machine_dir_len = max(wcslen(machine_dir->pe_dir), wcslen(machine_dir->so_dir));
if ((env = process_getenv(process, L"WINEBUILDDIR")))
len = lstrlenW(env);
if (!(buf = heap_alloc((len + wcslen(L"\\programs\\") + machine_dir_len +
2 * lstrlenW(name) + 1) * sizeof(WCHAR)))) return FALSE;
wcscpy(buf, env);
end = buf + len;
wcscpy(end, L"\\dlls\\");
wcscat(end, name);
if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, L".so")) *p = 0;
if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, L".dll")) *p = 0;
/* try multi-arch first */
wcscpy(p, get_machine_dir(machine_dir, name));
wcscpy(p + wcslen(p), name);
if (try_match_file(buf, match, param)) goto found;
/* then old mono-arch */
*p++ = '\\';
if (try_match_file(buf, match, param)) goto found;
wcscpy(end, L"\\programs\\");
end += wcslen(end);
wcscpy(end, name);
if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, L".so")) *p = 0;
if ((p = wcsrchr(end, '.')) && !lstrcmpW(p, L".exe")) *p = 0;
/* try multi-arch first */
wcscpy(p, get_machine_dir(machine_dir, name));
wcscpy(p + wcslen(p), name);
if (try_match_file(buf, match, param)) goto found;
/* then old mono-arch */
*p++ = '\\';
if (try_match_file(buf, match, param)) goto found;
heap_free(buf);
}
for (i = 0;; i++)
{
WCHAR env_name[64];
swprintf(env_name, ARRAY_SIZE(env_name), L"WINEDLLDIR%u", i);
if (!(env = process_getenv(process, env_name))) return FALSE;
len = wcslen(env) + machine_dir_len + wcslen(name) + 1;
Zebediah Figura
committed
if (!(buf = heap_alloc(len * sizeof(WCHAR)))) return FALSE;
swprintf(buf, len, L"%s%s%s", env, get_machine_dir(machine_dir, name), name);
if (try_match_file(buf, match, param)) goto found;
Zebediah Figura
committed
swprintf(buf, len, L"%s\\%s", env, name);
if (try_match_file(buf, match, param)) goto found;
heap_free(buf);
}
return FALSE;
found:
TRACE("found %s\n", debugstr_w(buf));
heap_free(buf);
return TRUE;
}
Jacek Caban
committed
BOOL search_unix_path(const WCHAR *name, const WCHAR *path, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param)
Jacek Caban
committed
{
const WCHAR *iter, *next;
Jacek Caban
committed
size_t size, len;
WCHAR *dos_path;
char *buf;
BOOL ret = FALSE;
if (!path) return FALSE;
name = file_name(name);
size = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL)
+ WideCharToMultiByte(CP_UNIXCP, 0, path, -1, NULL, 0, NULL, NULL);
Jacek Caban
committed
if (!(buf = heap_alloc(size))) return FALSE;
for (iter = path;; iter = next + 1)
{
if (!(next = wcschr(iter, ':'))) next = iter + lstrlenW(iter);
Jacek Caban
committed
if (*iter == '/')
{
len = WideCharToMultiByte(CP_UNIXCP, 0, iter, next - iter, buf, size, NULL, NULL);
Jacek Caban
committed
if (buf[len - 1] != '/') buf[len++] = '/';
WideCharToMultiByte(CP_UNIXCP, 0, name, -1, buf + len, size - len, NULL, NULL);
if ((dos_path = wine_get_dos_file_name(buf)))
{
ret = try_match_file(dos_path, match, param);
if (ret) TRACE("found %s\n", debugstr_w(dos_path));
Jacek Caban
committed
heap_free(dos_path);
if (ret) break;
}
}
if (*next != ':') break;
}
heap_free(buf);
return ret;
}
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
/******************************************************************
* SymSrvGetFileIndexInfo (DBGHELP.@)
*
*/
BOOL WINAPI SymSrvGetFileIndexInfo(const char *file, SYMSRV_INDEX_INFO* info, DWORD flags)
{
SYMSRV_INDEX_INFOW infoW;
WCHAR fileW[MAX_PATH];
BOOL ret;
TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(file), info, flags);
if (info->sizeofstruct < sizeof(*info))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, ARRAY_SIZE(fileW));
infoW.sizeofstruct = sizeof(infoW);
ret = SymSrvGetFileIndexInfoW(fileW, &infoW, flags);
if (ret)
{
WideCharToMultiByte(CP_ACP, 0, infoW.file, -1, info->file, ARRAY_SIZE(info->file), NULL, NULL);
info->stripped = infoW.stripped;
info->timestamp = infoW.timestamp;
info->size = infoW.size;
WideCharToMultiByte(CP_ACP, 0, infoW.dbgfile, -1, info->dbgfile, ARRAY_SIZE(info->dbgfile), NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, infoW.pdbfile, -1, info->pdbfile, ARRAY_SIZE(info->pdbfile), NULL, NULL);
info->guid = infoW.guid;
info->sig = infoW.sig;
info->age = infoW.age;
}
return ret;
}
/******************************************************************
* SymSrvGetFileIndexInfoW (DBGHELP.@)
*
*/
BOOL WINAPI SymSrvGetFileIndexInfoW(const WCHAR *file, SYMSRV_INDEX_INFOW* info, DWORD flags)
{
HANDLE hFile, hMap = NULL;
void* image = NULL;
DWORD fsize, ret;
TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(file), info, flags);
if (info->sizeofstruct < sizeof(*info))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE &&
((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) &&
((image = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
{
/* must handle PE, or .dbg or .pdb files. So each helper will return:
* - ERROR_SUCCESS: if the file format is recognized and index info filled,
* - ERROR_BAD_FORMAT: if the file doesn't match the expected format,
* - any other error: if the file has expected format, but internal errors
*/
fsize = GetFileSize(hFile, NULL);
/* try PE module first */
ret = pe_get_file_indexinfo(image, fsize, info);
if (ret == ERROR_BAD_FORMAT)
ret = pdb_get_file_indexinfo(image, fsize, info);
if (ret == ERROR_BAD_FORMAT)
ret = dbg_get_file_indexinfo(image, fsize, info);
}
else ret = ERROR_FILE_NOT_FOUND;
if (image) UnmapViewOfFile(image);
if (hMap) CloseHandle(hMap);
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
if (ret == ERROR_SUCCESS) wcscpy(info->file, file_name(file)); /* overflow? */
SetLastError(ret);
return ret == ERROR_SUCCESS;
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
}
/******************************************************************
* SymSrvGetFileIndexes (DBGHELP.@)
*
*/
BOOL WINAPI SymSrvGetFileIndexes(PCSTR file, GUID* guid, PDWORD pdw1, PDWORD pdw2, DWORD flags)
{
WCHAR fileW[MAX_PATH];
TRACE("(%s, %p, %p, %p, 0x%08lx)\n", debugstr_a(file), guid, pdw1, pdw2, flags);
MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, ARRAY_SIZE(fileW));
return SymSrvGetFileIndexesW(fileW, guid, pdw1, pdw2, flags);
}
/******************************************************************
* SymSrvGetFileIndexesW (DBGHELP.@)
*
*/
BOOL WINAPI SymSrvGetFileIndexesW(PCWSTR file, GUID* guid, PDWORD pdw1, PDWORD pdw2, DWORD flags)
{
FIXME("(%s, %p, %p, %p, 0x%08lx): stub!\n", debugstr_w(file), guid, pdw1, pdw2, flags);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}