Don't strip the library extension if it's not ".dll".
[wine] / loader / elfdll.c
1 /*
2  * Elf-dll loader functions
3  *
4  * Copyright 1999 Bertho A. Stultiens
5  */
6
7 #include <string.h>
8 #include <ctype.h>
9 #include <stdlib.h>
10
11 #include "config.h"
12 #include "windef.h"
13 #include "global.h"
14 #include "process.h"
15 #include "module.h"
16 #include "neexe.h"
17 #include "heap.h"
18 #include "wine/winbase16.h"
19 #include "elfdll.h"
20 #include "debugtools.h"
21 #include "winerror.h"
22
23 DEFAULT_DEBUG_CHANNEL(elfdll)
24
25 #if defined(HAVE_DL_API)
26 #include <dlfcn.h>
27
28 /*------------------ HACKS -----------------*/
29 extern DWORD fixup_imports(WINE_MODREF *wm);
30 extern void dump_exports(HMODULE hModule);
31 /*---------------- END HACKS ---------------*/
32
33 char *extra_ld_library_path = NULL;     /* The extra search-path set in wine.conf */
34
35 struct elfdll_image
36 {
37         HMODULE         pe_module_start;
38         DWORD           pe_module_size;
39         NE_MODULE       *ne_module_start;
40         DWORD           ne_module_size;
41 };
42
43
44 /****************************************************************************
45  *      ELFDLL_dlopen
46  *
47  * Wrapper for dlopen to search the EXTRA_LD_LIBRARY_PATH from wine.conf
48  * manually because libdl.so caches the environment and does not accept our
49  * changes.
50  */
51 void *ELFDLL_dlopen(const char *libname, int flags)
52 {
53         char buffer[256];
54         int namelen;
55         void *handle;
56         char *ldpath;
57
58         /* First try the default path search of dlopen() */
59         handle = dlopen(libname, flags);
60         /* do NOT call dlerror() here ! (check after return) */
61         if(handle)
62                 return handle;
63
64         /* Now try to construct searches through our extra search-path */
65         namelen = strlen(libname);
66         ldpath = extra_ld_library_path;
67         while(ldpath && *ldpath)
68         {
69                 int len;
70                 char *cptr;
71                 char *from;
72
73                 from = ldpath;
74                 cptr = strchr(ldpath, ':');
75                 if(!cptr)
76                 {
77                         len = strlen(ldpath);
78                         ldpath = NULL;
79                 }
80                 else
81                 {
82                         len = cptr - ldpath;
83                         ldpath = cptr + 1;
84                 }
85
86                 if(len + namelen + 1 >= sizeof(buffer))
87                 {
88                         ERR("Buffer overflow! Check EXTRA_LD_LIBRARY_PATH or increase buffer size.\n");
89                         return NULL;
90                 }
91
92                 strncpy(buffer, from, len);
93                 if(len)
94                 {
95                         buffer[len] = '/';
96                         strcpy(buffer + len + 1, libname);
97                 }
98                 else
99                         strcpy(buffer + len, libname);
100
101                 TRACE("Trying dlopen('%s', %d)\n", buffer, flags);
102
103                 handle = dlopen(buffer, flags);
104                 /* do NOT call dlerror() here ! (check after return) */
105                 if(handle)
106                         return handle;
107         }
108         return NULL;
109 }
110
111
112 /****************************************************************************
113  *      get_sobasename  (internal)
114  *
115  */
116 static LPSTR get_sobasename(LPCSTR path, LPSTR name)
117 {
118         char *cptr;
119
120         /* Strip the path from the library name */
121         if((cptr = strrchr(path, '/')))
122         {
123                 char *cp = strrchr(cptr+1, '\\');
124                 if(cp && cp > cptr)
125                         cptr = cp;
126         }
127         else
128                 cptr = strrchr(path, '\\');
129
130         if(!cptr)
131                 cptr = (char *)path;    /* No '/' nor '\\' in path */
132         else
133                 cptr++;
134
135         strcpy(name, cptr);
136         cptr = strrchr(name, '.');
137         if(cptr && !strcasecmp(cptr,".dll")) *cptr = '\0'; /* Strip extension */
138
139         /* Convert to lower case.
140          * This must be done manually because it is not sure that
141          * other modules are accessible.
142          */
143         for(cptr = name; *cptr; cptr++)
144                 *cptr = tolower(*cptr);
145
146         return name;
147 }
148
149
150 /****************************************************************************
151  *      ELFDLL_LoadLibraryExA   (internal)
152  *
153  * Implementation of elf-dll loading for PE modules
154  */
155 WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags)
156 {
157         LPVOID dlhandle;
158         struct elfdll_image *image;
159         char name[129];
160         char soname[129];
161         WINE_MODREF *wm;
162
163         get_sobasename(path, name);
164         strcpy(soname, name);
165         strcat(soname, ".so");
166
167         /* Try to open the elf-dll */
168         dlhandle = ELFDLL_dlopen(soname, RTLD_LAZY);
169         if(!dlhandle)
170         {
171                 WARN("Could not load %s (%s)\n", soname, dlerror());
172                 SetLastError( ERROR_FILE_NOT_FOUND );
173                 return NULL;
174         }
175
176         /* Get the 'dllname_elfdll_image' variable */
177         strcpy(soname, name);
178         strcat(soname, "_elfdll_image");
179         image = (struct elfdll_image *)dlsym(dlhandle, soname);
180         if(!image) 
181         {
182                 ERR("Could not get elfdll image descriptor %s (%s)\n", soname, dlerror());
183                 dlclose(dlhandle);
184                 SetLastError( ERROR_BAD_FORMAT );
185                 return NULL;
186         }
187
188         wm = PE_CreateModule( image->pe_module_start, path, 0, -1, FALSE );
189         if(!wm)
190         {
191                 ERR("Could not create WINE_MODREF for %s\n", path);
192                 dlclose(dlhandle);
193                 SetLastError( ERROR_OUTOFMEMORY );
194                 return NULL;
195         }
196         wm->dlhandle = dlhandle;
197
198         dump_exports(image->pe_module_start);
199         return wm;
200 }
201
202 #else
203
204 /*
205  * No elfdlls possible 
206  * Just put stubs in here.
207  */
208
209 WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags)
210 {
211         SetLastError( ERROR_FILE_NOT_FOUND );
212         return NULL;
213 }
214
215 #endif