wined3d: Improve/implement D3DSIO_TEX.
[wine] / dlls / 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 "winnls.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
33
34 static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';}
35
36 static inline const char* file_name(const char* str)
37 {
38     const char*       p;
39
40     for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--);
41     return p + 1;
42 }
43
44 /******************************************************************
45  *              FindDebugInfoFile (DBGHELP.@)
46  *
47  */
48 HANDLE WINAPI FindDebugInfoFile(PCSTR FileName, PCSTR SymbolPath, PSTR DebugFilePath)
49 {
50     HANDLE      h;
51
52     h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
53                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
54     if (h == INVALID_HANDLE_VALUE)
55     {
56         if (!SearchPathA(SymbolPath, file_name(FileName), NULL, MAX_PATH, DebugFilePath, NULL))
57             return NULL;
58         h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
59                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
60     }
61     return (h == INVALID_HANDLE_VALUE) ? NULL : h;
62 }
63  
64 /******************************************************************
65  *              FindDebugInfoFileEx (DBGHELP.@)
66  *
67  */
68 HANDLE WINAPI FindDebugInfoFileEx(PCSTR FileName, PCSTR SymbolPath,
69                                   PSTR DebugFilePath, 
70                                   PFIND_DEBUG_FILE_CALLBACK Callback,
71                                   PVOID CallerData)
72 {
73     FIXME("(%s %s %p %p %p): stub\n", 
74           FileName, SymbolPath, DebugFilePath, Callback, CallerData);
75     return NULL;
76 }
77
78 /******************************************************************
79  *              FindExecutableImage (DBGHELP.@)
80  *
81  */
82 HANDLE WINAPI FindExecutableImage(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath)
83 {
84     HANDLE h;
85     if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
86         return 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;
90 }
91
92 /***********************************************************************
93  *           MakeSureDirectoryPathExists (DBGHELP.@)
94  */
95 BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
96 {
97     char path[MAX_PATH];
98     const char *p = DirPath;
99     int  n;
100
101     if (p[0] && p[1] == ':') p += 2;
102     while (*p == '\\') p++; /* skip drive root */
103     while ((p = strchr(p, '\\')) != NULL)
104     {
105        n = p - DirPath + 1;
106        memcpy(path, DirPath, n);
107        path[n] = '\0';
108        if( !CreateDirectoryA(path, NULL)            &&
109            (GetLastError() != ERROR_ALREADY_EXISTS))
110            return FALSE;
111        p++;
112     }
113     if (GetLastError() == ERROR_ALREADY_EXISTS)
114        SetLastError(ERROR_SUCCESS);
115
116     return TRUE;
117 }
118
119 /******************************************************************
120  *              SymMatchFileName (DBGHELP.@)
121  *
122  */
123 BOOL WINAPI SymMatchFileName(char* file, char* match,
124                              char** filestop, char** matchstop)
125 {
126     char*       fptr;
127     char*       mptr;
128
129     TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop);
130
131     fptr = file + strlen(file) - 1;
132     mptr = match + strlen(match) - 1;
133
134     while (fptr >= file && mptr >= match)
135     {
136         if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr)))
137             break;
138         fptr--; mptr--;
139     }
140     if (filestop) *filestop = fptr;
141     if (matchstop) *matchstop = mptr;
142
143     return mptr == match - 1;
144 }
145
146 static BOOL do_search(const char* file, char* buffer, BOOL recurse,
147                       PENUMDIRTREE_CALLBACK cb, void* user)
148 {
149     HANDLE              h;
150     WIN32_FIND_DATAA    fd;
151     unsigned            pos;
152     BOOL                found = FALSE;
153
154     pos = strlen(buffer);
155     if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
156     strcpy(buffer + pos, "*.*");
157     if ((h = FindFirstFileA(buffer, &fd)) == INVALID_HANDLE_VALUE)
158         return FALSE;
159     /* doc doesn't specify how the tree is enumerated... 
160      * doing a depth first based on, but may be wrong
161      */
162     do
163     {
164         if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue;
165
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))
170         {
171             if (!cb || cb(buffer, user)) found = TRUE;
172         }
173     } while (!found && FindNextFileA(h, &fd));
174     if (!found) buffer[--pos] = '\0';
175     FindClose(h);
176
177     return found;
178 }
179
180 /***********************************************************************
181  *           SearchTreeForFile (DBGHELP.@)
182  */
183 BOOL WINAPI SearchTreeForFile(PCSTR root, PCSTR file, PSTR buffer)
184 {
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);
189 }
190
191 /******************************************************************
192  *              EnumDirTree (DBGHELP.@)
193  *
194  *
195  */
196 BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
197                         LPSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
198 {
199     TRACE("(%p %s %s %p %p %p)\n", hProcess, root, file, buffer, cb, user);
200
201     strcpy(buffer, root);
202     return do_search(file, buffer, TRUE, cb, user);
203 }
204
205 struct sffip
206 {
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
212      *      two -> PDB age ???
213      * elf: id  -> DWORD:CRC 32 of ELF image (Wine only)
214      */
215     PVOID                       id;
216     DWORD                       two;
217     DWORD                       three;
218     DWORD                       flags;
219     PFINDFILEINPATHCALLBACK     cb;
220     void*                       user;
221 };
222
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)
227  */
228 static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user)
229 {
230     struct sffip*       s = (struct sffip*)user;
231     DWORD               size, checksum;
232     DWORD_PTR           timestamp;
233
234     /* FIXME: should check that id/two/three match the file pointed
235      * by buffer
236      */
237     switch (s->kind)
238     {
239     case DMT_PE:
240         {
241             HANDLE  hFile, hMap;
242             void*   mapping;
243
244             timestamp = ~(DWORD_PTR)s->id;
245             size = ~s->two;
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)
250             {
251                 if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
252                 {
253                     IMAGE_NT_HEADERS*   nth = RtlImageNtHeader(mapping);
254                     timestamp = nth->FileHeader.TimeDateStamp;
255                     size = nth->OptionalHeader.SizeOfImage;
256                     UnmapViewOfFile(mapping);
257                 }
258                 CloseHandle(hMap);
259             }
260             CloseHandle(hFile);
261             if (timestamp != (DWORD_PTR)s->id || size != s->two)
262             {
263                 WARN("Found %s, but wrong size or timestamp\n", buffer);
264                 return FALSE;
265             }
266         }
267         break;
268     case DMT_ELF:
269         if (elf_fetch_file_info(buffer, 0, &size, &checksum))
270         {
271             if (checksum != (DWORD_PTR)s->id)
272             {
273                 WARN("Found %s, but wrong checksums: %08lx %08lx\n",
274                       buffer, checksum, (DWORD_PTR)s->id);
275                 return FALSE;
276             }
277         }
278         else
279         {
280             WARN("Couldn't read %s\n", buffer);
281             return FALSE;
282         }
283         break;
284     case DMT_PDB:
285         FIXME("NIY on '%s'\n", buffer);
286         break;
287     default:
288         FIXME("What the heck??\n");
289         return FALSE;
290     }
291     /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
292      * convention to stop/continue enumeration. sigh.
293      */
294     return !(s->cb)((char*)buffer, s->user);
295 }
296
297 /******************************************************************
298  *              SymFindFileInPath (DBGHELP.@)
299  *
300  */
301 BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path,
302                               PVOID id, DWORD two, DWORD three, DWORD flags,
303                               LPSTR buffer, PFINDFILEINPATHCALLBACK cb,
304                               PVOID user)
305 {
306     struct sffip        s;
307     struct process*     pcs = process_find_by_handle(hProcess);
308     char                tmp[MAX_PATH];
309     char*               ptr;
310     const char*         filename;
311
312     TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n",
313           hProcess, searchPath, full_path, id, two, three, flags, 
314           buffer, cb, user);
315
316     if (!pcs) return FALSE;
317     if (!searchPath) searchPath = pcs->search_path;
318
319     s.id = id;
320     s.two = two;
321     s.three = three;
322     s.flags = flags;
323     s.cb = cb;
324     s.user = user;
325
326     filename = file_name(full_path);
327     s.kind = module_get_type_by_name(filename);
328
329     /* first check full path to file */
330     if (sffip_cb(full_path, &s))
331     {
332         strcpy(buffer, full_path);
333         return TRUE;
334     }
335
336     while (searchPath)
337     {
338         ptr = strchr(searchPath, ';');
339         if (ptr)
340         {
341             memcpy(tmp, searchPath, ptr - searchPath);
342             tmp[ptr - searchPath] = 0;
343             searchPath = ptr + 1;
344         }
345         else
346         {
347             strcpy(tmp, searchPath);
348             searchPath = NULL;
349         }
350         if (do_search(filename, tmp, FALSE, sffip_cb, &s))
351         {
352             strcpy(buffer, tmp);
353             return TRUE;
354         }
355     }
356     return FALSE;
357 }