Annotation of sql/pgsql/libltdl/loaders/loadlibrary.c, revision 1.1
1.1 ! moko 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:
! 10: GNU Libltdl is free software; you can redistribute it and/or
! 11: modify it under the terms of the GNU Lesser General Public
! 12: License as published by the Free Software Foundation; either
! 13: version 2 of the License, or (at your option) any later version.
! 14:
! 15: As a special exception to the GNU Lesser General Public License,
! 16: if you distribute this file as part of a program or library that
! 17: is built using GNU Libtool, you may include this file under the
! 18: same distribution terms that you use for the rest of that program.
! 19:
! 20: GNU Libltdl is distributed in the hope that it will be useful,
! 21: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 22: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 23: GNU Lesser General Public License for more details.
! 24:
! 25: You should have received a copy of the GNU Lesser General Public
! 26: License along with GNU Libltdl; see the file COPYING.LIB. If not, a
! 27: copy can be downloaded from http://www.gnu.org/licenses/lgpl.html,
! 28: or obtained by writing to the Free Software Foundation, Inc.,
! 29: 51 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:
! 45: LT_BEGIN_C_DECLS
! 46: LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
! 47: LT_END_C_DECLS
! 48:
! 49:
! 50: /* Boilerplate code to set up the vtable for hooking this loader into
! 51: libltdl's loader list: */
! 52: static int vl_exit (lt_user_data loader_data);
! 53: static lt_module vm_open (lt_user_data loader_data, const char *filename,
! 54: lt_dladvise advise);
! 55: static int vm_close (lt_user_data loader_data, lt_module module);
! 56: static void * vm_sym (lt_user_data loader_data, lt_module module,
! 57: const char *symbolname);
! 58:
! 59: static lt_dlinterface_id iface_id = 0;
! 60: static 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. */
! 65: lt_dlvtable *
! 66: get_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:
! 106: static const char *loadlibraryerror (const char *default_errmsg);
! 107: static DWORD WINAPI wrap_getthreaderrormode (void);
! 108: static DWORD WINAPI fallback_getthreaderrormode (void);
! 109: static BOOL WINAPI wrap_setthreaderrormode (DWORD mode, DWORD *oldmode);
! 110: static BOOL WINAPI fallback_setthreaderrormode (DWORD mode, DWORD *oldmode);
! 111:
! 112: typedef DWORD (WINAPI getthreaderrormode_type) (void);
! 113: typedef BOOL (WINAPI setthreaderrormode_type) (DWORD, DWORD *);
! 114:
! 115: static getthreaderrormode_type *getthreaderrormode = wrap_getthreaderrormode;
! 116: static setthreaderrormode_type *setthreaderrormode = wrap_setthreaderrormode;
! 117: static char *error_message = 0;
! 118:
! 119:
! 120: /* A function called through the vtable when this loader is no
! 121: longer needed by the application. */
! 122: static int
! 123: vl_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. */
! 133: static lt_module
! 134: vm_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. */
! 247: static int
! 248: vm_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. */
! 264: static void *
! 265: vm_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. */
! 284: static const char *
! 285: loadlibraryerror (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. */
! 313: static DWORD WINAPI
! 314: wrap_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 */
! 331: static DWORD WINAPI
! 332: fallback_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. */
! 346: static BOOL WINAPI
! 347: wrap_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. */
! 360: static BOOL WINAPI
! 361: fallback_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: }
E-mail: