relocatable.c | relocatable.c | |||
---|---|---|---|---|
/* Provide relocatable packages. | /* Provide relocatable packages. | |||
Copyright (C) 2003-2006, 2008-2010 Free Software Foundation, Inc. | Copyright (C) 2003-2006, 2008-2014 Free Software Foundation, Inc. | |||
Written by Bruno Haible <bruno@clisp.org>, 2003. | Written by Bruno Haible <bruno@clisp.org>, 2003. | |||
This program is free software; you can redistribute it and/or modify it | This program is free software: you can redistribute it and/or modify | |||
under the terms of the GNU Library General Public License as published | it under the terms of the GNU Lesser General Public License as published | |||
by the Free Software Foundation; either version 2, or (at your option) | by | |||
any later version. | the Free Software Foundation; either version 2.1 of the License, or | |||
(at your option) any later version. | ||||
This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
Library General Public License for more details. | GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Library General Public | You should have received a copy of the GNU Lesser General Public License | |||
License along with this program; if not, write to the Free Software | along with this program. If not, see <http://www.gnu.org/licenses/>. * | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | / | |||
, | ||||
USA. */ | ||||
/* Tell glibc's <stdio.h> to provide a prototype for getline(). | /* Tell glibc's <stdio.h> to provide a prototype for getline(). | |||
This must come before <config.h> because <config.h> may include | This must come before <config.h> because <config.h> may include | |||
<features.h>, and once <features.h> has been included, it's too late. * / | <features.h>, and once <features.h> has been included, it's too late. * / | |||
#ifndef _GNU_SOURCE | #ifndef _GNU_SOURCE | |||
# define _GNU_SOURCE 1 | # define _GNU_SOURCE 1 | |||
#endif | #endif | |||
#define _GL_USE_STDLIB_ALLOC 1 | ||||
#include <config.h> | #include <config.h> | |||
/* Specification. */ | /* Specification. */ | |||
#include "relocatable.h" | #include "relocatable.h" | |||
#if ENABLE_RELOCATABLE | #if ENABLE_RELOCATABLE | |||
#include <stddef.h> | #include <stddef.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <string.h> | #include <string.h> | |||
#ifdef NO_XMALLOC | #ifdef NO_XMALLOC | |||
# define xmalloc malloc | # define xmalloc malloc | |||
#else | #else | |||
# include "xalloc.h" | # include "xalloc.h" | |||
#endif | #endif | |||
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ | #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ | |||
# define WIN32_LEAN_AND_MEAN | # define WIN32_LEAN_AND_MEAN | |||
# include <windows.h> | # include <windows.h> | |||
#endif | #endif | |||
#if DEPENDS_ON_LIBCHARSET | #if DEPENDS_ON_LIBCHARSET | |||
# include <libcharset.h> | # include <libcharset.h> | |||
#endif | #endif | |||
#if DEPENDS_ON_LIBICONV && HAVE_ICONV | #if DEPENDS_ON_LIBICONV && HAVE_ICONV | |||
# include <iconv.h> | # include <iconv.h> | |||
#endif | #endif | |||
skipping to change at line 72 | skipping to change at line 71 | |||
#undef false | #undef false | |||
#undef true | #undef true | |||
#define bool int | #define bool int | |||
#define false 0 | #define false 0 | |||
#define true 1 | #define true 1 | |||
/* Pathname support. | /* Pathname support. | |||
ISSLASH(C) tests whether C is a directory separator character. | ISSLASH(C) tests whether C is a directory separator character. | |||
IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. | IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. | |||
*/ | */ | |||
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __ | #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defin | |||
EMX__ || defined __DJGPP__ | ed __EMX__ || defined __DJGPP__ | |||
/* Win32, Cygwin, OS/2, DOS */ | /* Native Windows, OS/2, DOS */ | |||
# define ISSLASH(C) ((C) == '/' || (C) == '\\') | # define ISSLASH(C) ((C) == '/' || (C) == '\\') | |||
# define HAS_DEVICE(P) \ | # define HAS_DEVICE(P) \ | |||
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ | ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ | |||
&& (P)[1] == ':') | && (P)[1] == ':') | |||
# define IS_PATH_WITH_DIR(P) \ | # define IS_PATH_WITH_DIR(P) \ | |||
(strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) | (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) | |||
# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) | # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) | |||
#else | #else | |||
/* Unix */ | /* Unix */ | |||
# define ISSLASH(C) ((C) == '/') | # define ISSLASH(C) ((C) == '/') | |||
# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) | # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) | |||
# define FILE_SYSTEM_PREFIX_LEN(P) 0 | # define FILE_SYSTEM_PREFIX_LEN(P) 0 | |||
#endif | #endif | |||
/* Whether to enable the more costly support for relocatable libraries. | ||||
It allows libraries to be have been installed with a different original | ||||
prefix than the program. But it is quite costly, especially on Cygwin | ||||
platforms, see below. Therefore we enable it by default only on native | ||||
Windows platforms. */ | ||||
#ifndef ENABLE_COSTLY_RELOCATABLE | ||||
# if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ | ||||
# define ENABLE_COSTLY_RELOCATABLE 1 | ||||
# else | ||||
# define ENABLE_COSTLY_RELOCATABLE 0 | ||||
# endif | ||||
#endif | ||||
/* Original installation prefix. */ | /* Original installation prefix. */ | |||
static char *orig_prefix; | static char *orig_prefix; | |||
static size_t orig_prefix_len; | static size_t orig_prefix_len; | |||
/* Current installation prefix. */ | /* Current installation prefix. */ | |||
static char *curr_prefix; | static char *curr_prefix; | |||
static size_t curr_prefix_len; | static size_t curr_prefix_len; | |||
/* These prefixes do not end in a slash. Anything that will be concatenate d | /* These prefixes do not end in a slash. Anything that will be concatenate d | |||
to them must start with a slash. */ | to them must start with a slash. */ | |||
/* Sets the original and the current installation prefix of this module. | /* Sets the original and the current installation prefix of this module. | |||
skipping to change at line 157 | skipping to change at line 169 | |||
libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | |||
#endif | #endif | |||
#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109 | #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109 | |||
libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | |||
#endif | #endif | |||
#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_pref ix | #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_pref ix | |||
libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); | |||
#endif | #endif | |||
} | } | |||
#if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR) | #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COS TLY_RELOCATABLE) | |||
/* Convenience function: | /* Convenience function: | |||
Computes the current installation prefix, based on the original | Computes the current installation prefix, based on the original | |||
installation prefix, the original installation directory of a particular | installation prefix, the original installation directory of a particular | |||
file, and the current pathname of this file. | file, and the current pathname of this file. | |||
Returns it, freshly allocated. Returns NULL upon failure. */ | Returns it, freshly allocated. Returns NULL upon failure. */ | |||
#ifdef IN_LIBRARY | #ifdef IN_LIBRARY | |||
#define compute_curr_prefix local_compute_curr_prefix | #define compute_curr_prefix local_compute_curr_prefix | |||
static | static | |||
#endif | #endif | |||
skipping to change at line 239 | skipping to change at line 251 | |||
if (ISSLASH (*rpi) || ISSLASH (*cpi)) | if (ISSLASH (*rpi) || ISSLASH (*cpi)) | |||
{ | { | |||
if (ISSLASH (*rpi) && ISSLASH (*cpi)) | if (ISSLASH (*rpi) && ISSLASH (*cpi)) | |||
same = true; | same = true; | |||
break; | break; | |||
} | } | |||
/* Do case-insensitive comparison if the file system is always or | /* Do case-insensitive comparison if the file system is always or | |||
often case-insensitive. It's better to accept the compariso n | often case-insensitive. It's better to accept the compariso n | |||
if the difference is only in case, rather than to fail. */ | if the difference is only in case, rather than to fail. */ | |||
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __ EMX__ || defined __DJGPP__ | #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __ EMX__ || defined __DJGPP__ | |||
/* Win32, Cygwin, OS/2, DOS - case insignificant file system */ | /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */ | |||
if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi) | if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi) | |||
!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi)) | != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi)) | |||
break; | break; | |||
#else | #else | |||
if (*rpi != *cpi) | if (*rpi != *cpi) | |||
break; | break; | |||
#endif | #endif | |||
} | } | |||
if (!same) | if (!same) | |||
break; | break; | |||
skipping to change at line 287 | skipping to change at line 299 | |||
free (curr_installdir); | free (curr_installdir); | |||
return curr_prefix; | return curr_prefix; | |||
} | } | |||
} | } | |||
} | } | |||
#endif /* !IN_LIBRARY || PIC */ | #endif /* !IN_LIBRARY || PIC */ | |||
#if defined PIC && defined INSTALLDIR | #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE | |||
/* Full pathname of shared library, or NULL. */ | /* Full pathname of shared library, or NULL. */ | |||
static char *shared_library_fullname; | static char *shared_library_fullname; | |||
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ | #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ | |||
/* Native Windows only. | ||||
On Cygwin, it is better to use the Cygwin provided /proc interface, than | ||||
to use native Windows API and cygwin_conv_to_posix_path, because it | ||||
supports longer file names | ||||
(see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */ | ||||
/* Determine the full pathname of the shared library when it is loaded. */ | /* Determine the full pathname of the shared library when it is loaded. */ | |||
BOOL WINAPI | BOOL WINAPI | |||
DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved) | DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved) | |||
{ | { | |||
(void) reserved; | (void) reserved; | |||
if (event == DLL_PROCESS_ATTACH) | if (event == DLL_PROCESS_ATTACH) | |||
{ | { | |||
skipping to change at line 314 | skipping to change at line 331 | |||
static char location[MAX_PATH]; | static char location[MAX_PATH]; | |||
if (!GetModuleFileName (module_handle, location, sizeof (location))) | if (!GetModuleFileName (module_handle, location, sizeof (location))) | |||
/* Shouldn't happen. */ | /* Shouldn't happen. */ | |||
return FALSE; | return FALSE; | |||
if (!IS_PATH_WITH_DIR (location)) | if (!IS_PATH_WITH_DIR (location)) | |||
/* Shouldn't happen. */ | /* Shouldn't happen. */ | |||
return FALSE; | return FALSE; | |||
{ | shared_library_fullname = strdup (location); | |||
#if defined __CYGWIN__ | ||||
/* On Cygwin, we need to convert paths coming from Win32 system cal | ||||
ls | ||||
to the Unix-like slashified notation. */ | ||||
static char location_as_posix_path[2 * MAX_PATH]; | ||||
/* There's no error return defined for cygwin_conv_to_posix_path. | ||||
See cygwin-api/func-cygwin-conv-to-posix-path.html. | ||||
Does it overflow the buffer of expected size MAX_PATH or does it | ||||
truncate the path? I don't know. Let's catch both. */ | ||||
cygwin_conv_to_posix_path (location, location_as_posix_path); | ||||
location_as_posix_path[MAX_PATH - 1] = '\0'; | ||||
if (strlen (location_as_posix_path) >= MAX_PATH - 1) | ||||
/* A sign of buffer overflow or path truncation. */ | ||||
return FALSE; | ||||
shared_library_fullname = strdup (location_as_posix_path); | ||||
#else | ||||
shared_library_fullname = strdup (location); | ||||
#endif | ||||
} | ||||
} | } | |||
return TRUE; | return TRUE; | |||
} | } | |||
#else /* Unix except Cygwin */ | #else /* Unix */ | |||
static void | static void | |||
find_shared_library_fullname () | find_shared_library_fullname () | |||
{ | { | |||
#if defined __linux__ && __GLIBC__ >= 2 | #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || define | |||
/* Linux has /proc/self/maps. glibc 2 has the getline() function. */ | d __CYGWIN__ | |||
/* Linux has /proc/self/maps. glibc 2 and uClibc have the getline() | ||||
function. | ||||
Cygwin >= 1.5 has /proc/self/maps and the getline() function too. | ||||
But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on | ||||
Cygwin 1.7. */ | ||||
FILE *fp; | FILE *fp; | |||
/* Open the current process' maps file. It describes one VMA per line. */ | /* Open the current process' maps file. It describes one VMA per line. */ | |||
fp = fopen ("/proc/self/maps", "r"); | fp = fopen ("/proc/self/maps", "r"); | |||
if (fp) | if (fp) | |||
{ | { | |||
unsigned long address = (unsigned long) &find_shared_library_fullname ; | unsigned long address = (unsigned long) &find_shared_library_fullname ; | |||
for (;;) | for (;;) | |||
{ | { | |||
unsigned long start, end; | unsigned long start, end; | |||
skipping to change at line 389 | skipping to change at line 392 | |||
break; | break; | |||
} | } | |||
while (c = getc (fp), c != EOF && c != '\n') | while (c = getc (fp), c != EOF && c != '\n') | |||
continue; | continue; | |||
} | } | |||
fclose (fp); | fclose (fp); | |||
} | } | |||
#endif | #endif | |||
} | } | |||
#endif /* (WIN32 or Cygwin) / (Unix except Cygwin) */ | #endif /* Native Windows / Unix */ | |||
/* Return the full pathname of the current shared library. | /* Return the full pathname of the current shared library. | |||
Return NULL if unknown. | Return NULL if unknown. | |||
Guaranteed to work only on Linux, Cygwin and Woe32. */ | Guaranteed to work only on Linux, Cygwin, and native Windows. */ | |||
static char * | static char * | |||
get_shared_library_fullname () | get_shared_library_fullname () | |||
{ | { | |||
#if !(defined _WIN32 || defined __WIN32__ || defined __CYGWIN__) | #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) | |||
static bool tried_find_shared_library_fullname; | static bool tried_find_shared_library_fullname; | |||
if (!tried_find_shared_library_fullname) | if (!tried_find_shared_library_fullname) | |||
{ | { | |||
find_shared_library_fullname (); | find_shared_library_fullname (); | |||
tried_find_shared_library_fullname = true; | tried_find_shared_library_fullname = true; | |||
} | } | |||
#endif | #endif | |||
return shared_library_fullname; | return shared_library_fullname; | |||
} | } | |||
#endif /* PIC */ | #endif /* PIC */ | |||
/* Returns the pathname, relocated according to the current installation | /* Returns the pathname, relocated according to the current installation | |||
directory. | directory. | |||
The returned string is either PATHNAME unmodified or a freshly allocated | The returned string is either PATHNAME unmodified or a freshly allocated | |||
string that you can free with free() after casting it to 'char *'. */ | string that you can free with free() after casting it to 'char *'. */ | |||
const char * | const char * | |||
relocate (const char *pathname) | relocate (const char *pathname) | |||
{ | { | |||
#if defined PIC && defined INSTALLDIR | #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE | |||
static int initialized; | static int initialized; | |||
/* Initialization code for a shared library. */ | /* Initialization code for a shared library. */ | |||
if (!initialized) | if (!initialized) | |||
{ | { | |||
/* At this point, orig_prefix and curr_prefix likely have already bee n | /* At this point, orig_prefix and curr_prefix likely have already bee n | |||
set through the main program's set_program_name_and_installdir | set through the main program's set_program_name_and_installdir | |||
function. This is sufficient in the case that the library has | function. This is sufficient in the case that the library has | |||
initially been installed in the same orig_prefix. But we can do | initially been installed in the same orig_prefix. But we can do | |||
better, to also cover the cases that 1. it has been installed | better, to also cover the cases that 1. it has been installed | |||
End of changes. 19 change blocks. | ||||
47 lines changed or deleted | 51 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |