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/