source: squid-ssl/trunk/fuentes/libltdl/loaders/loadlibrary.c @ 5496

Last change on this file since 5496 was 5496, checked in by Juanma, 22 months ago

Initial release

File size: 10.6 KB
Line 
1/* loader-loadlibrary.c --  dynamic linking for Win32
2
3   Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006,
4                 2007, 2008, 2010 Free Software Foundation, Inc.
5   Written by Thomas Tanner, 1998
6
7   NOTE: The canonical source of this file is maintained with the
8   GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
9
10GNU Libltdl is free software; you can redistribute it and/or
11modify it under the terms of the GNU Lesser General Public
12License as published by the Free Software Foundation; either
13version 2 of the License, or (at your option) any later version.
14
15As a special exception to the GNU Lesser General Public License,
16if you distribute this file as part of a program or library that
17is built using GNU Libtool, you may include this file under the
18same distribution terms that you use for the rest of that program.
19
20GNU Libltdl is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23GNU Lesser General Public License for more details.
24
25You should have received a copy of the GNU Lesser General Public
26License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
27copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
28or obtained by writing to the Free Software Foundation, Inc.,
2951 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30*/
31
32#include "lt__private.h"
33#include "lt_dlloader.h"
34
35#if defined(__CYGWIN__)
36# include <sys/cygwin.h>
37#endif
38
39/* Use the preprocessor to rename non-static symbols to avoid namespace
40   collisions when the loader code is statically linked into libltdl.
41   Use the "<module_name>_LTX_" prefix so that the symbol addresses can
42   be fetched from the preloaded symbol list by lt_dlsym():  */
43#define get_vtable      loadlibrary_LTX_get_vtable
44
45LT_BEGIN_C_DECLS
46LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
47LT_END_C_DECLS
48
49
50/* Boilerplate code to set up the vtable for hooking this loader into
51   libltdl's loader list:  */
52static int       vl_exit  (lt_user_data loader_data);
53static lt_module vm_open  (lt_user_data loader_data, const char *filename,
54                           lt_dladvise advise);
55static int       vm_close (lt_user_data loader_data, lt_module module);
56static void *    vm_sym   (lt_user_data loader_data, lt_module module,
57                          const char *symbolname);
58
59static lt_dlinterface_id iface_id = 0;
60static lt_dlvtable *vtable = 0;
61
62/* Return the vtable for this loader, only the name and sym_prefix
63   attributes (plus the virtual function implementations, obviously)
64   change between loaders.  */
65lt_dlvtable *
66get_vtable (lt_user_data loader_data)
67{
68  if (!vtable)
69    {
70      vtable = (lt_dlvtable *) lt__zalloc (sizeof *vtable);
71      iface_id = lt_dlinterface_register ("ltdl loadlibrary", NULL);
72    }
73
74  if (vtable && !vtable->name)
75    {
76      vtable->name              = "lt_loadlibrary";
77      vtable->module_open       = vm_open;
78      vtable->module_close      = vm_close;
79      vtable->find_sym          = vm_sym;
80      vtable->dlloader_exit     = vl_exit;
81      vtable->dlloader_data     = loader_data;
82      vtable->priority          = LT_DLLOADER_APPEND;
83    }
84
85  if (vtable && (vtable->dlloader_data != loader_data))
86    {
87      LT__SETERROR (INIT_LOADER);
88      return 0;
89    }
90
91  return vtable;
92}
93
94
95
96/* --- IMPLEMENTATION --- */
97
98
99#include <windows.h>
100
101#define LOCALFREE(mem)                                       LT_STMT_START { \
102        if (mem) { LocalFree ((void *)mem); mem = NULL; }    } LT_STMT_END
103#define LOADLIB__SETERROR(errmsg) LT__SETERRORSTR (loadlibraryerror (errmsg))
104#define LOADLIB_SETERROR(errcode) LOADLIB__SETERROR (LT__STRERROR (errcode))
105
106static const char *loadlibraryerror (const char *default_errmsg);
107static DWORD WINAPI wrap_getthreaderrormode (void);
108static DWORD WINAPI fallback_getthreaderrormode (void);
109static BOOL WINAPI wrap_setthreaderrormode (DWORD mode, DWORD *oldmode);
110static BOOL WINAPI fallback_setthreaderrormode (DWORD mode, DWORD *oldmode);
111
112typedef DWORD (WINAPI getthreaderrormode_type) (void);
113typedef BOOL (WINAPI setthreaderrormode_type) (DWORD, DWORD *);
114
115static getthreaderrormode_type *getthreaderrormode = wrap_getthreaderrormode;
116static setthreaderrormode_type *setthreaderrormode = wrap_setthreaderrormode;
117static char *error_message = 0;
118
119
120/* A function called through the vtable when this loader is no
121   longer needed by the application.  */
122static int
123vl_exit (lt_user_data LT__UNUSED loader_data)
124{
125  vtable = NULL;
126  LOCALFREE (error_message);
127  return 0;
128}
129
130/* A function called through the vtable to open a module with this
131   loader.  Returns an opaque representation of the newly opened
132   module for processing with this loader's other vtable functions.  */
133static lt_module
134vm_open (lt_user_data LT__UNUSED loader_data, const char *filename,
135         lt_dladvise LT__UNUSED advise)
136{
137  lt_module     module     = 0;
138  char          *ext;
139  char          wpath[MAX_PATH];
140  size_t        len;
141
142  if (!filename)
143    {
144      /* Get the name of main module */
145      *wpath = 0;
146      GetModuleFileName (NULL, wpath, sizeof (wpath));
147      filename = wpath;
148    }
149  else
150    {
151      len = LT_STRLEN (filename);
152
153      if (len >= MAX_PATH)
154        {
155          LT__SETERROR (CANNOT_OPEN);
156          return 0;
157        }
158
159#if HAVE_DECL_CYGWIN_CONV_PATH
160      if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, filename, wpath, MAX_PATH))
161        {
162          LT__SETERROR (CANNOT_OPEN);
163          return 0;
164        }
165      len = 0;
166#elif defined(__CYGWIN__)
167      cygwin_conv_to_full_win32_path (filename, wpath);
168      len = 0;
169#else
170      strcpy(wpath, filename);
171#endif
172
173      ext = strrchr (wpath, '.');
174      if (!ext)
175        {
176          /* Append a `.' to stop Windows from adding an
177             implicit `.dll' extension. */
178          if (!len)
179            len = strlen (wpath);
180
181          if (len + 1 >= MAX_PATH)
182            {
183              LT__SETERROR (CANNOT_OPEN);
184              return 0;
185            }
186
187          wpath[len] = '.';
188          wpath[len+1] = '\0';
189        }
190    }
191
192  {
193    /* Silence dialog from LoadLibrary on some failures. */
194    DWORD errormode = getthreaderrormode ();
195    DWORD last_error;
196
197    setthreaderrormode (errormode | SEM_FAILCRITICALERRORS, NULL);
198
199    module = LoadLibrary (wpath);
200
201    /* Restore the error mode. */
202    last_error = GetLastError ();
203    setthreaderrormode (errormode, NULL);
204    SetLastError (last_error);
205  }
206
207  /* libltdl expects this function to fail if it is unable
208     to physically load the library.  Sadly, LoadLibrary
209     will search the loaded libraries for a match and return
210     one of them if the path search load fails.
211
212     We check whether LoadLibrary is returning a handle to
213     an already loaded module, and simulate failure if we
214     find one. */
215  {
216    lt_dlhandle cur = 0;
217
218    while ((cur = lt_dlhandle_iterate (iface_id, cur)))
219      {
220        if (!cur->module)
221          {
222            cur = 0;
223            break;
224          }
225
226        if (cur->module == module)
227          {
228            break;
229          }
230      }
231
232    if (!module)
233      LOADLIB_SETERROR (CANNOT_OPEN);
234    else if (cur)
235      {
236        LT__SETERROR (CANNOT_OPEN);
237        module = 0;
238      }
239  }
240
241  return module;
242}
243
244
245/* A function called through the vtable when a particular module
246   should be unloaded.  */
247static int
248vm_close (lt_user_data LT__UNUSED loader_data, lt_module module)
249{
250  int errors = 0;
251
252  if (FreeLibrary ((HMODULE) module) == 0)
253    {
254      LOADLIB_SETERROR (CANNOT_CLOSE);
255      ++errors;
256    }
257
258  return errors;
259}
260
261
262/* A function called through the vtable to get the address of
263   a symbol loaded from a particular module.  */
264static void *
265vm_sym (lt_user_data LT__UNUSED loader_data, lt_module module, const char *name)
266{
267  void *address = (void *) GetProcAddress ((HMODULE) module, name);
268
269  if (!address)
270    {
271      LOADLIB_SETERROR (SYMBOL_NOT_FOUND);
272    }
273
274  return address;
275}
276
277
278
279/* --- HELPER FUNCTIONS --- */
280
281
282/* Return the windows error message, or the passed in error message on
283   failure. */
284static const char *
285loadlibraryerror (const char *default_errmsg)
286{
287  size_t len;
288  LOCALFREE (error_message);
289
290  FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
291                  FORMAT_MESSAGE_FROM_SYSTEM |
292                  FORMAT_MESSAGE_IGNORE_INSERTS,
293                  NULL,
294                  GetLastError (),
295                  0,
296                  (char *) &error_message,
297                  0, NULL);
298
299  /* Remove trailing CRNL */
300  len = LT_STRLEN (error_message);
301  if (len && error_message[len - 1] == '\n')
302    error_message[--len] = LT_EOS_CHAR;
303  if (len && error_message[len - 1] == '\r')
304    error_message[--len] = LT_EOS_CHAR;
305
306  return len ? error_message : default_errmsg;
307}
308
309/* A function called through the getthreaderrormode variable which checks
310   if the system supports GetThreadErrorMode (or GetErrorMode) and arranges
311   for it or a fallback implementation to be called directly in the future.
312   The selected version is then called. */
313static DWORD WINAPI
314wrap_getthreaderrormode (void)
315{
316  HMODULE kernel32 = GetModuleHandleA ("kernel32.dll");
317  getthreaderrormode
318    = (getthreaderrormode_type *) GetProcAddress (kernel32,
319                                                  "GetThreadErrorMode");
320  if (!getthreaderrormode)
321    getthreaderrormode
322      = (getthreaderrormode_type *) GetProcAddress (kernel32,
323                                                    "GetErrorMode");
324  if (!getthreaderrormode)
325    getthreaderrormode = fallback_getthreaderrormode;
326  return getthreaderrormode ();
327}
328
329/* A function called through the getthreaderrormode variable for cases
330   where the system does not support GetThreadErrorMode or GetErrorMode */
331static DWORD WINAPI
332fallback_getthreaderrormode (void)
333{
334  /* Prior to Windows Vista, the only way to get the current error
335     mode was to set a new one. In our case, we are setting a new
336     error mode right after "getting" it while ignoring the error
337     mode in effect when setting the new error mode, so that's
338     fairly ok. */
339  return (DWORD) SetErrorMode (SEM_FAILCRITICALERRORS);
340}
341
342/* A function called through the setthreaderrormode variable which checks
343   if the system supports SetThreadErrorMode and arranges for it or a
344   fallback implementation to be called directly in the future.
345   The selected version is then called. */
346static BOOL WINAPI
347wrap_setthreaderrormode (DWORD mode, DWORD *oldmode)
348{
349  HMODULE kernel32 = GetModuleHandleA ("kernel32.dll");
350  setthreaderrormode
351    = (setthreaderrormode_type *) GetProcAddress (kernel32,
352                                                  "SetThreadErrorMode");
353  if (!setthreaderrormode)
354    setthreaderrormode = fallback_setthreaderrormode;
355  return setthreaderrormode (mode, oldmode);
356}
357
358/* A function called through the setthreaderrormode variable for cases
359   where the system does not support SetThreadErrorMode. */
360static BOOL WINAPI
361fallback_setthreaderrormode (DWORD mode, DWORD *oldmode)
362{
363  /* Prior to Windows 7, there was no way to set the thread local error
364     mode, so set the process global error mode instead. */
365  DWORD old = (DWORD) SetErrorMode (mode);
366  if (oldmode)
367    *oldmode = old;
368  return TRUE;
369}
Note: See TracBrowser for help on using the repository browser.