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
26 #include "dbghelp_private.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
)
41 for (p
= str
+ strlen(str
) - 1; p
>= str
&& !is_sep(*p
); p
--);
45 /******************************************************************
46 * FindDebugInfoFile (DBGHELP.@)
49 HANDLE WINAPI
FindDebugInfoFile(PSTR FileName
, PSTR SymbolPath
, PSTR DebugFilePath
)
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
))
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
,
71 PFIND_DEBUG_FILE_CALLBACK Callback
,
74 FIXME("(%s %s %p %p %p): stub\n",
75 FileName
, SymbolPath
, DebugFilePath
, Callback
, CallerData
);
79 /******************************************************************
80 * FindExecutableImage (DBGHELP.@)
83 HANDLE WINAPI
FindExecutableImage(PSTR FileName
, PSTR SymbolPath
, PSTR ImageFilePath
)
86 if (!SearchPathA(SymbolPath
, FileName
, NULL
, MAX_PATH
, ImageFilePath
, 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
)
99 const char *p
= DirPath
;
102 if (p
[0] && p
[1] == ':') p
+= 2;
103 while (*p
== '\\') p
++; /* skip drive root */
104 while ((p
= strchr(p
, '\\')) != NULL
)
107 memcpy(path
, DirPath
, n
);
109 if( !CreateDirectoryA(path
, NULL
) &&
110 (GetLastError() != ERROR_ALREADY_EXISTS
))
114 if (GetLastError() == ERROR_ALREADY_EXISTS
)
115 SetLastError(ERROR_SUCCESS
);
120 /******************************************************************
121 * SymMatchFileName (DBGHELP.@)
124 BOOL WINAPI
SymMatchFileName(char* file
, char* match
,
125 char** filestop
, char** matchstop
)
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
)))
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
)
155 pos
= strlen(buffer
);
156 if (buffer
[pos
- 1] != '\\') buffer
[pos
++] = '\\';
157 strcpy(buffer
+ pos
, "*.*");
158 if ((h
= FindFirstFileA(buffer
, &fd
)) == INVALID_HANDLE_VALUE
)
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';
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
);
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
214 * elf: id -> DWORD:CRC 32 of ELF image (Wine only)
220 PFINDFILEINPATHCALLBACK cb
;
224 static BOOL CALLBACK
sffip_cb(LPCSTR buffer
, void* user
)
226 struct sffip
* s
= (struct sffip
*)user
;
227 DWORD size
, checksum
;
229 /* FIXME: should check that id/two/three match the file pointed
239 timestamp
= ~(DWORD_PTR
)s
->id
;
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
);
256 if (timestamp
!= (DWORD_PTR
)s
->id
|| size
!= s
->two
)
258 WARN("Found %s, but wrong size or timestamp\n", buffer
);
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
);
275 WARN("Couldn't read %s\n", buffer
);
280 FIXME("NIY on '%s'\n", buffer
);
283 FIXME("What the heck??\n");
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
,
302 struct process
* pcs
= process_find_by_handle(hProcess
);
307 TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n",
308 hProcess
, searchPath
, full_path
, id
, two
, three
, flags
,
311 if (!pcs
) return FALSE
;
312 if (!searchPath
) searchPath
= pcs
->search_path
;
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
);
333 ptr
= strchr(searchPath
, ';');
336 memcpy(tmp
, searchPath
, ptr
- searchPath
);
337 tmp
[ptr
- searchPath
] = 0;
338 searchPath
= ptr
+ 1;
342 strcpy(tmp
, searchPath
);
345 if (do_search(filename
, tmp
, FALSE
, sffip_cb
, &s
)) {