Remove trailing backslash.
[wine.git] / dlls / dbghelp / path.c
blob7358047a72a06326510a0084e707c53ca8fb0f06
1 /*
2 * File path.c - managing path in debugging environments
4 * Copyright (C) 2004, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
26 #include "dbghelp_private.h"
27 #include "ntstatus.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "winternl.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
35 static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';}
37 static inline char* file_name(char* str)
39 char* p;
41 for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--);
42 return p + 1;
45 /******************************************************************
46 * FindDebugInfoFile (DBGHELP.@)
49 HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePath)
51 HANDLE h;
53 h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
54 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
55 if (h == INVALID_HANDLE_VALUE)
57 if (!SearchPathA(SymbolPath, file_name(FileName), NULL, MAX_PATH, DebugFilePath, NULL))
58 return NULL;
59 h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
60 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
62 return (h == INVALID_HANDLE_VALUE) ? NULL : h;
65 /******************************************************************
66 * FindDebugInfoFileEx (DBGHELP.@)
69 HANDLE WINAPI FindDebugInfoFileEx(PSTR FileName, PSTR SymbolPath,
70 PSTR DebugFilePath,
71 PFIND_DEBUG_FILE_CALLBACK Callback,
72 PVOID CallerData)
74 FIXME("(%s %s %p %p %p): stub\n",
75 FileName, SymbolPath, DebugFilePath, Callback, CallerData);
76 return NULL;
79 /******************************************************************
80 * FindExecutableImage (DBGHELP.@)
83 HANDLE WINAPI FindExecutableImage(PSTR FileName, PSTR SymbolPath, PSTR ImageFilePath)
85 HANDLE h;
86 if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
87 return NULL;
88 h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
89 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
90 return (h == INVALID_HANDLE_VALUE) ? NULL : h;
93 /***********************************************************************
94 * MakeSureDirectoryPathExists (DBGHELP.@)
96 BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
98 char path[MAX_PATH];
99 const char *p = DirPath;
100 int n;
102 if (p[0] && p[1] == ':') p += 2;
103 while (*p == '\\') p++; /* skip drive root */
104 while ((p = strchr(p, '\\')) != NULL)
106 n = p - DirPath + 1;
107 memcpy(path, DirPath, n);
108 path[n] = '\0';
109 if( !CreateDirectoryA(path, NULL) &&
110 (GetLastError() != ERROR_ALREADY_EXISTS))
111 return FALSE;
112 p++;
114 if (GetLastError() == ERROR_ALREADY_EXISTS)
115 SetLastError(ERROR_SUCCESS);
117 return TRUE;
120 /******************************************************************
121 * SymMatchFileName (DBGHELP.@)
124 BOOL WINAPI SymMatchFileName(char* file, char* match,
125 char** filestop, char** matchstop)
127 char* fptr;
128 char* mptr;
130 TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop);
132 fptr = file + strlen(file) - 1;
133 mptr = match + strlen(match) - 1;
135 while (fptr >= file && mptr >= match)
137 if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr)))
138 break;
139 fptr--; mptr--;
141 if (filestop) *filestop = fptr;
142 if (matchstop) *matchstop = mptr;
144 return mptr == match - 1;
147 static BOOL do_search(const char* file, char* buffer, BOOL recurse,
148 PENUMDIRTREE_CALLBACK cb, void* user)
150 HANDLE h;
151 WIN32_FIND_DATAA fd;
152 unsigned pos;
153 BOOL found = FALSE;
155 pos = strlen(buffer);
156 if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
157 strcpy(buffer + pos, "*.*");
158 if ((h = FindFirstFileA(buffer, &fd)) == INVALID_HANDLE_VALUE)
159 return FALSE;
160 /* doc doesn't specify how the tree is enumerated...
161 * doing a depth first based on, but may be wrong
165 if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue;
167 strcpy(buffer + pos, fd.cFileName);
168 if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
169 found = do_search(file, buffer, TRUE, cb, user);
170 else if (SymMatchFileName(buffer, (char*)file, NULL, NULL))
172 if (!cb || cb(buffer, user)) found = TRUE;
174 } while (!found && FindNextFileA(h, &fd));
175 if (!found) buffer[--pos] = '\0';
176 FindClose(h);
178 return found;
181 /***********************************************************************
182 * SearchTreeForFile (DBGHELP.@)
184 BOOL WINAPI SearchTreeForFile(LPSTR root, LPSTR file, LPSTR buffer)
186 TRACE("(%s, %s, %p)\n",
187 debugstr_a(root), debugstr_a(file), buffer);
188 strcpy(buffer, root);
189 return do_search(file, buffer, TRUE, NULL, NULL);
192 /******************************************************************
193 * EnumDirTree (DBGHELP.@)
197 BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
198 LPSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
200 TRACE("(%p %s %s %p %p %p)\n", hProcess, root, file, buffer, cb, user);
202 strcpy(buffer, root);
203 return do_search(file, buffer, TRUE, cb, user);
206 struct sffip
208 enum module_type kind;
209 /* pe: id -> DWORD:timestamp
210 * two -> size of image (from PE header)
211 * pdb: id -> PDB signature
212 * I think either DWORD:timestamp or GUID:guid depending on PDB version
213 * two -> PDB age ???
214 * elf: id -> DWORD:CRC 32 of ELF image (Wine only)
216 PVOID id;
217 DWORD two;
218 DWORD three;
219 DWORD flags;
220 PFINDFILEINPATHCALLBACK cb;
221 void* user;
224 static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user)
226 struct sffip* s = (struct sffip*)user;
227 DWORD size, checksum;
228 DWORD_PTR timestamp;
229 /* FIXME: should check that id/two/three match the file pointed
230 * by buffer
232 switch (s->kind)
234 case DMT_PE:
236 HANDLE hFile, hMap;
237 void* mapping;
239 timestamp = ~(DWORD_PTR)s->id;
240 size = ~s->two;
241 hFile = CreateFileA(buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
242 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
243 if (hFile == INVALID_HANDLE_VALUE) return TRUE;
244 if ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
246 if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
248 IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping);
249 timestamp = nth->FileHeader.TimeDateStamp;
250 size = nth->OptionalHeader.SizeOfImage;
251 UnmapViewOfFile(mapping);
253 CloseHandle(hMap);
255 CloseHandle(hFile);
256 if (timestamp != (DWORD_PTR)s->id || size != s->two)
258 WARN("Found %s, but wrong size or timestamp\n", buffer);
259 return TRUE;
262 break;
263 case DMT_ELF:
264 if (elf_fetch_file_info(buffer, 0, &size, &checksum))
266 if (checksum != (DWORD_PTR)s->id)
268 WARN("Found %s, but wrong checksums: %08lx %08lx\n",
269 buffer, checksum, (DWORD_PTR)s->id);
270 return TRUE;
273 else
275 WARN("Couldn't read %s\n", buffer);
276 return TRUE;
278 break;
279 case DMT_PDB:
280 FIXME("NIY on '%s'\n", buffer);
281 break;
282 default:
283 FIXME("What the heck??\n");
284 return TRUE;
286 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
287 * convention to stop/continue enumeration. sigh.
289 return !(s->cb)((char*)buffer, s->user);
292 /******************************************************************
293 * SymFindFileInPath (DBGHELP.@)
296 BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR full_path,
297 PVOID id, DWORD two, DWORD three, DWORD flags,
298 LPSTR buffer, PFINDFILEINPATHCALLBACK cb,
299 PVOID user)
301 struct sffip s;
302 struct process* pcs = process_find_by_handle(hProcess);
303 char tmp[MAX_PATH];
304 char* ptr;
305 char* filename;
307 TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n",
308 hProcess, searchPath, full_path, id, two, three, flags,
309 buffer, cb, user);
311 if (!pcs) return FALSE;
312 if (!searchPath) searchPath = pcs->search_path;
314 s.id = id;
315 s.two = two;
316 s.three = three;
317 s.flags = flags;
318 s.cb = cb;
319 s.user = user;
321 filename = file_name(full_path);
322 s.kind = module_get_type_by_name(filename);
324 /* first check full path to file */
325 if (sffip_cb(full_path, &s))
327 strcpy(buffer, full_path);
328 return TRUE;
331 while (searchPath)
333 ptr = strchr(searchPath, ';');
334 if (ptr)
336 memcpy(tmp, searchPath, ptr - searchPath);
337 tmp[ptr - searchPath] = 0;
338 searchPath = ptr + 1;
340 else
342 strcpy(tmp, searchPath);
343 searchPath = NULL;
345 if (do_search(filename, tmp, FALSE, sffip_cb, &s)) {
346 strcpy(buffer, tmp);
347 return TRUE;
350 return FALSE;