604998fde3e754d0d68d14afcb438e9f16427b0e
[reactos.git] / reactos / lib / dbghelp / path.c
1 /*
2 * File path.c - managing path in debugging environments
3 *
4 * Copyright (C) 2004, Eric Pouech
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config.h"
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "dbghelp_private.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
30
31 static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';}
32
33 static inline char* file_name(char* str)
34 {
35 char* p;
36
37 for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--);
38 return p + 1;
39 }
40
41 /******************************************************************
42 * FindDebugInfoFile (DBGHELP.@)
43 *
44 */
45 HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePath)
46 {
47 HANDLE h;
48
49 h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
50 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
51 if (h == INVALID_HANDLE_VALUE)
52 {
53 if (!SearchPathA(SymbolPath, file_name(FileName), NULL, MAX_PATH, DebugFilePath, NULL))
54 return NULL;
55 h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
56 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
57 }
58 return (h == INVALID_HANDLE_VALUE) ? NULL : h;
59 }
60
61 /******************************************************************
62 * FindDebugInfoFileEx (DBGHELP.@)
63 *
64 */
65 HANDLE WINAPI FindDebugInfoFileEx(PSTR FileName, PSTR SymbolPath,
66 PSTR DebugFilePath,
67 PFIND_DEBUG_FILE_CALLBACK Callback,
68 PVOID CallerData)
69 {
70 FIXME("(%s %s %p %p %p): stub\n",
71 FileName, SymbolPath, DebugFilePath, Callback, CallerData);
72 return NULL;
73 }
74
75 /******************************************************************
76 * FindExecutableImage (DBGHELP.@)
77 *
78 */
79 HANDLE WINAPI FindExecutableImage(PSTR FileName, PSTR SymbolPath, PSTR ImageFilePath)
80 {
81 HANDLE h;
82 if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
83 return NULL;
84 h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
85 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
86 return (h == INVALID_HANDLE_VALUE) ? NULL : h;
87 }
88
89 /***********************************************************************
90 * MakeSureDirectoryPathExists (DBGHELP.@)
91 */
92 BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
93 {
94 char path[MAX_PATH];
95 const char *p = DirPath;
96 int n;
97
98 if (p[0] && p[1] == ':') p += 2;
99 while (*p == '\\') p++; /* skip drive root */
100 while ((p = strchr(p, '\\')) != NULL)
101 {
102 n = p - DirPath + 1;
103 memcpy(path, DirPath, n);
104 path[n] = '\0';
105 if( !CreateDirectoryA(path, NULL) &&
106 (GetLastError() != ERROR_ALREADY_EXISTS))
107 return FALSE;
108 p++;
109 }
110 if (GetLastError() == ERROR_ALREADY_EXISTS)
111 SetLastError(ERROR_SUCCESS);
112
113 return TRUE;
114 }
115
116 /******************************************************************
117 * SymMatchFileName (DBGHELP.@)
118 *
119 */
120 BOOL WINAPI SymMatchFileName(char* file, char* match,
121 char** filestop, char** matchstop)
122 {
123 char* fptr;
124 char* mptr;
125
126 TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop);
127
128 fptr = file + strlen(file) - 1;
129 mptr = match + strlen(match) - 1;
130
131 while (fptr >= file && mptr >= match)
132 {
133 if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr)))
134 break;
135 fptr--; mptr--;
136 }
137 if (filestop) *filestop = fptr;
138 if (matchstop) *matchstop = mptr;
139
140 return mptr == match - 1;
141 }
142
143 static BOOL do_search(const char* file, char* buffer,
144 PENUMDIRTREE_CALLBACK cb, void* user)
145 {
146 HANDLE h;
147 WIN32_FIND_DATAA fd;
148 unsigned pos;
149 BOOL found = FALSE;
150
151 pos = strlen(buffer);
152 if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
153 strcpy(buffer + pos, "*.*");
154 if ((h = FindFirstFileA(buffer, &fd)) == INVALID_HANDLE_VALUE)
155 return FALSE;
156 /* doc doesn't specify how the tree is enumerated...
157 * doing a depth first based on, but may be wrong
158 */
159 do
160 {
161 if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue;
162
163 strcpy(buffer + pos, fd.cFileName);
164 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
165 found = do_search(file, buffer, cb, user);
166 else if (SymMatchFileName(buffer, (char*)file, NULL, NULL))
167 {
168 if (!cb || cb(buffer, user)) found = TRUE;
169 }
170 } while (!found && FindNextFileA(h, &fd));
171 if (!found) buffer[--pos] = '\0';
172 FindClose(h);
173
174 return found;
175 }
176
177 /***********************************************************************
178 * SearchTreeForFile (DBGHELP.@)
179 */
180 BOOL WINAPI SearchTreeForFile(LPSTR root, LPSTR file, LPSTR buffer)
181 {
182 TRACE("(%s, %s, %p)\n",
183 debugstr_a(root), debugstr_a(file), buffer);
184 strcpy(buffer, root);
185 return do_search(file, buffer, NULL, NULL);
186 }
187
188 /******************************************************************
189 * EnumDirTree (DBGHELP.@)
190 *
191 *
192 */
193 BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
194 LPSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
195 {
196 TRACE("(%p %s %s %p %p %p)\n", hProcess, root, file, buffer, cb, user);
197
198 strcpy(buffer, root);
199 return do_search(file, buffer, cb, user);
200 }
201
202 struct sffip
203 {
204 PVOID id;
205 DWORD two;
206 DWORD three;
207 DWORD flags;
208 PFINDFILEINPATHCALLBACK cb;
209 void* user;
210 };
211
212 static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user)
213 {
214 struct sffip* s = (struct sffip*)user;
215
216 /* FIXME: should check that id/two/three match the file pointed
217 * by buffer
218 */
219 /* yes, EnumDirTree and SymFindFileInPath callbacks use the opposite
220 * convention to stop/continue enumeration. sigh.
221 */
222 return !(s->cb)((char*)buffer, s->user);
223 }
224
225 /******************************************************************
226 * SymFindFileInPath (DBGHELP.@)
227 *
228 */
229 BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file,
230 PVOID id, DWORD two, DWORD three, DWORD flags,
231 LPSTR buffer, PFINDFILEINPATHCALLBACK cb,
232 PVOID user)
233 {
234 struct sffip s;
235 struct process* pcs = process_find_by_handle(hProcess);
236 char tmp[MAX_PATH];
237 char* ptr;
238
239 TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n",
240 hProcess, searchPath, file, id, two, three, flags,
241 buffer, cb, user);
242
243 if (!pcs) return FALSE;
244 if (!searchPath) searchPath = pcs->search_path;
245
246 s.id = id;
247 s.two = two;
248 s.three = three;
249 s.flags = flags;
250 s.cb = cb;
251 s.user = user;
252
253 file = file_name(file);
254
255 while (searchPath)
256 {
257 ptr = strchr(searchPath, ';');
258 if (ptr)
259 {
260 memcpy(tmp, searchPath, ptr - searchPath);
261 tmp[ptr - searchPath] = 0;
262 searchPath = ptr + 1;
263 }
264 else
265 {
266 strcpy(tmp, searchPath);
267 searchPath = NULL;
268 }
269 if (EnumDirTree(hProcess, tmp, file, buffer, sffip_cb, &s)) return TRUE;
270 }
271 return FALSE;
272 }