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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "dbghelp_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
34 static inline BOOL
is_sep(char ch
) {return ch
== '/' || ch
== '\\';}
36 static inline const char* file_name(const char* str
)
40 for (p
= str
+ strlen(str
) - 1; p
>= str
&& !is_sep(*p
); p
--);
44 /******************************************************************
45 * FindDebugInfoFile (DBGHELP.@)
48 HANDLE WINAPI
FindDebugInfoFile(PCSTR FileName
, PCSTR SymbolPath
, PSTR DebugFilePath
)
52 h
= CreateFileA(DebugFilePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
53 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
54 if (h
== INVALID_HANDLE_VALUE
)
56 if (!SearchPathA(SymbolPath
, file_name(FileName
), NULL
, MAX_PATH
, DebugFilePath
, NULL
))
58 h
= CreateFileA(DebugFilePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
59 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
61 return (h
== INVALID_HANDLE_VALUE
) ? NULL
: h
;
64 /******************************************************************
65 * FindDebugInfoFileEx (DBGHELP.@)
68 HANDLE WINAPI
FindDebugInfoFileEx(PCSTR FileName
, PCSTR SymbolPath
,
70 PFIND_DEBUG_FILE_CALLBACK Callback
,
73 FIXME("(%s %s %p %p %p): stub\n",
74 FileName
, SymbolPath
, DebugFilePath
, Callback
, CallerData
);
78 /******************************************************************
79 * FindExecutableImage (DBGHELP.@)
82 HANDLE WINAPI
FindExecutableImage(PCSTR FileName
, PCSTR SymbolPath
, PSTR ImageFilePath
)
85 if (!SearchPathA(SymbolPath
, FileName
, NULL
, MAX_PATH
, ImageFilePath
, NULL
))
87 h
= CreateFileA(ImageFilePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
88 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
89 return (h
== INVALID_HANDLE_VALUE
) ? NULL
: h
;
92 /***********************************************************************
93 * MakeSureDirectoryPathExists (DBGHELP.@)
95 BOOL WINAPI
MakeSureDirectoryPathExists(LPCSTR DirPath
)
98 const char *p
= DirPath
;
101 if (p
[0] && p
[1] == ':') p
+= 2;
102 while (*p
== '\\') p
++; /* skip drive root */
103 while ((p
= strchr(p
, '\\')) != NULL
)
106 memcpy(path
, DirPath
, n
);
108 if( !CreateDirectoryA(path
, NULL
) &&
109 (GetLastError() != ERROR_ALREADY_EXISTS
))
113 if (GetLastError() == ERROR_ALREADY_EXISTS
)
114 SetLastError(ERROR_SUCCESS
);
119 /******************************************************************
120 * SymMatchFileName (DBGHELP.@)
123 BOOL WINAPI
SymMatchFileName(char* file
, char* match
,
124 char** filestop
, char** matchstop
)
129 TRACE("(%s %s %p %p)\n", file
, match
, filestop
, matchstop
);
131 fptr
= file
+ strlen(file
) - 1;
132 mptr
= match
+ strlen(match
) - 1;
134 while (fptr
>= file
&& mptr
>= match
)
136 if (toupper(*fptr
) != toupper(*mptr
) && !(is_sep(*fptr
) && is_sep(*mptr
)))
140 if (filestop
) *filestop
= fptr
;
141 if (matchstop
) *matchstop
= mptr
;
143 return mptr
== match
- 1;
146 static BOOL
do_search(const char* file
, char* buffer
, BOOL recurse
,
147 PENUMDIRTREE_CALLBACK cb
, void* user
)
154 pos
= strlen(buffer
);
155 if (buffer
[pos
- 1] != '\\') buffer
[pos
++] = '\\';
156 strcpy(buffer
+ pos
, "*.*");
157 if ((h
= FindFirstFileA(buffer
, &fd
)) == INVALID_HANDLE_VALUE
)
159 /* doc doesn't specify how the tree is enumerated...
160 * doing a depth first based on, but may be wrong
164 if (!strcmp(fd
.cFileName
, ".") || !strcmp(fd
.cFileName
, "..")) continue;
166 strcpy(buffer
+ pos
, fd
.cFileName
);
167 if (recurse
&& (fd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
168 found
= do_search(file
, buffer
, TRUE
, cb
, user
);
169 else if (SymMatchFileName(buffer
, (char*)file
, NULL
, NULL
))
171 if (!cb
|| cb(buffer
, user
)) found
= TRUE
;
173 } while (!found
&& FindNextFileA(h
, &fd
));
174 if (!found
) buffer
[--pos
] = '\0';
180 /***********************************************************************
181 * SearchTreeForFile (DBGHELP.@)
183 BOOL WINAPI
SearchTreeForFile(PCSTR root
, PCSTR file
, PSTR buffer
)
185 TRACE("(%s, %s, %p)\n",
186 debugstr_a(root
), debugstr_a(file
), buffer
);
187 strcpy(buffer
, root
);
188 return do_search(file
, buffer
, TRUE
, NULL
, NULL
);
191 /******************************************************************
192 * EnumDirTree (DBGHELP.@)
196 BOOL WINAPI
EnumDirTree(HANDLE hProcess
, PCSTR root
, PCSTR file
,
197 LPSTR buffer
, PENUMDIRTREE_CALLBACK cb
, PVOID user
)
199 TRACE("(%p %s %s %p %p %p)\n", hProcess
, root
, file
, buffer
, cb
, user
);
201 strcpy(buffer
, root
);
202 return do_search(file
, buffer
, TRUE
, cb
, user
);
207 enum module_type kind
;
208 /* pe: id -> DWORD:timestamp
209 * two -> size of image (from PE header)
210 * pdb: id -> PDB signature
211 * I think either DWORD:timestamp or GUID:guid depending on PDB version
213 * elf: id -> DWORD:CRC 32 of ELF image (Wine only)
219 PFINDFILEINPATHCALLBACK cb
;
223 /* checks that buffer (as found by matching the name) matches the info
224 * (information is based on file type)
225 * returns TRUE when file is found, FALSE to continue searching
226 * (NB this is the opposite conventions as for SymFindFileInPathProc)
228 static BOOL CALLBACK
sffip_cb(LPCSTR buffer
, void* user
)
230 struct sffip
* s
= (struct sffip
*)user
;
231 DWORD size
, checksum
;
233 /* FIXME: should check that id/two/three match the file pointed
244 timestamp
= ~(DWORD_PTR
)s
->id
;
246 hFile
= CreateFileA(buffer
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
247 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
248 if (hFile
== INVALID_HANDLE_VALUE
) return FALSE
;
249 if ((hMap
= CreateFileMappingA(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
)) != NULL
)
251 if ((mapping
= MapViewOfFile(hMap
, FILE_MAP_READ
, 0, 0, 0)) != NULL
)
253 IMAGE_NT_HEADERS
* nth
= RtlImageNtHeader(mapping
);
254 timestamp
= nth
->FileHeader
.TimeDateStamp
;
255 size
= nth
->OptionalHeader
.SizeOfImage
;
256 UnmapViewOfFile(mapping
);
261 if (timestamp
!= (DWORD_PTR
)s
->id
|| size
!= s
->two
)
263 WARN("Found %s, but wrong size or timestamp\n", buffer
);
269 if (elf_fetch_file_info(buffer
, 0, &size
, &checksum
))
271 if (checksum
!= (DWORD_PTR
)s
->id
)
273 WARN("Found %s, but wrong checksums: %08lx %08lx\n",
274 buffer
, checksum
, (DWORD_PTR
)s
->id
);
280 WARN("Couldn't read %s\n", buffer
);
286 struct pdb_lookup pdb_lookup
;
288 pdb_lookup
.filename
= buffer
;
290 if (!pdb_fetch_file_info(&pdb_lookup
)) return FALSE
;
291 switch (pdb_lookup
.kind
)
294 if (s
->flags
& SSRVOPT_GUIDPTR
)
296 WARN("Found %s, but wrong PDB version\n", buffer
);
299 if (pdb_lookup
.u
.jg
.timestamp
!= (DWORD_PTR
)s
->id
)
301 WARN("Found %s, but wrong signature: %08lx %08lx\n",
302 buffer
, pdb_lookup
.u
.jg
.timestamp
, (DWORD_PTR
)s
->id
);
307 if (!(s
->flags
& SSRVOPT_GUIDPTR
))
309 WARN("Found %s, but wrong PDB version\n", buffer
);
312 if (memcmp(&pdb_lookup
.u
.ds
.guid
, (GUID
*)s
->id
, sizeof(GUID
)))
314 WARN("Found %s, but wrong GUID: %s %s\n",
315 buffer
, debugstr_guid(&pdb_lookup
.u
.ds
.guid
),
316 debugstr_guid((GUID
*)s
->id
));
321 if (pdb_lookup
.age
!= s
->two
)
323 WARN("Found %s, but wrong age: %08lx %08lx\n",
324 buffer
, pdb_lookup
.age
, s
->two
);
330 FIXME("What the heck??\n");
333 /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
334 * convention to stop/continue enumeration. sigh.
336 return !(s
->cb
)((char*)buffer
, s
->user
);
339 /******************************************************************
340 * SymFindFileInPath (DBGHELP.@)
343 BOOL WINAPI
SymFindFileInPath(HANDLE hProcess
, PCSTR inSearchPath
, PCSTR full_path
,
344 PVOID id
, DWORD two
, DWORD three
, DWORD flags
,
345 LPSTR buffer
, PFINDFILEINPATHCALLBACK cb
,
349 struct process
* pcs
= process_find_by_handle(hProcess
);
352 const char* filename
;
353 const char* searchPath
= inSearchPath
;
355 TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n",
356 hProcess
, searchPath
, full_path
, id
, two
, three
, flags
,
359 if (!pcs
) return FALSE
;
362 unsigned len
= WideCharToMultiByte(CP_ACP
, 0, pcs
->search_path
, -1, NULL
, 0, NULL
, NULL
);
365 searchPath
= buf
= HeapAlloc(GetProcessHeap(), 0, len
);
366 if (!searchPath
) return FALSE
;
367 WideCharToMultiByte(CP_ACP
, 0, pcs
->search_path
, -1, buf
, len
, NULL
, NULL
);
377 filename
= file_name(full_path
);
378 s
.kind
= module_get_type_by_name(filename
);
380 /* first check full path to file */
381 if (sffip_cb(full_path
, &s
))
383 strcpy(buffer
, full_path
);
384 if (searchPath
!= inSearchPath
)
385 HeapFree(GetProcessHeap(), 0, (char*)searchPath
);
391 ptr
= strchr(searchPath
, ';');
394 memcpy(tmp
, searchPath
, ptr
- searchPath
);
395 tmp
[ptr
- searchPath
] = 0;
396 searchPath
= ptr
+ 1;
400 strcpy(tmp
, searchPath
);
403 if (do_search(filename
, tmp
, FALSE
, sffip_cb
, &s
))
406 if (searchPath
!= inSearchPath
)
407 HeapFree(GetProcessHeap(), 0, (char*)searchPath
);
411 if (searchPath
!= inSearchPath
)
412 HeapFree(GetProcessHeap(), 0, (char*)searchPath
);