Home | History | Annotate | Line # | Download | only in lib
      1  1.1  christos /* Provide relocatable packages.
      2  1.1  christos    Copyright (C) 2003-2006 Free Software Foundation, Inc.
      3  1.1  christos    Written by Bruno Haible <bruno (at) clisp.org>, 2003.
      4  1.1  christos 
      5  1.1  christos    This program is free software; you can redistribute it and/or modify it
      6  1.1  christos    under the terms of the GNU Library General Public License as published
      7  1.1  christos    by the Free Software Foundation; either version 2, or (at your option)
      8  1.1  christos    any later version.
      9  1.1  christos 
     10  1.1  christos    This program is distributed in the hope that it will be useful,
     11  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  1.1  christos    Library General Public License for more details.
     14  1.1  christos 
     15  1.1  christos    You should have received a copy of the GNU Library General Public
     16  1.1  christos    License along with this program; if not, write to the Free Software
     17  1.1  christos    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
     18  1.1  christos    USA.  */
     19  1.1  christos 
     20  1.1  christos 
     21  1.1  christos /* Tell glibc's <stdio.h> to provide a prototype for getline().
     22  1.1  christos    This must come before <config.h> because <config.h> may include
     23  1.1  christos    <features.h>, and once <features.h> has been included, it's too late.  */
     24  1.1  christos #ifndef _GNU_SOURCE
     25  1.1  christos # define _GNU_SOURCE	1
     26  1.1  christos #endif
     27  1.1  christos 
     28  1.1  christos #include <config.h>
     29  1.1  christos 
     30  1.1  christos /* Specification.  */
     31  1.1  christos #include "relocatable.h"
     32  1.1  christos 
     33  1.1  christos #if ENABLE_RELOCATABLE
     34  1.1  christos 
     35  1.1  christos #include <stddef.h>
     36  1.1  christos #include <stdio.h>
     37  1.1  christos #include <stdlib.h>
     38  1.1  christos #include <string.h>
     39  1.1  christos 
     40  1.1  christos #ifdef NO_XMALLOC
     41  1.1  christos # define xmalloc malloc
     42  1.1  christos #else
     43  1.1  christos # include "xalloc.h"
     44  1.1  christos #endif
     45  1.1  christos 
     46  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
     47  1.1  christos # define WIN32_LEAN_AND_MEAN
     48  1.1  christos # include <windows.h>
     49  1.1  christos #endif
     50  1.1  christos 
     51  1.1  christos #if DEPENDS_ON_LIBCHARSET
     52  1.1  christos # include <libcharset.h>
     53  1.1  christos #endif
     54  1.1  christos #if DEPENDS_ON_LIBICONV && HAVE_ICONV
     55  1.1  christos # include <iconv.h>
     56  1.1  christos #endif
     57  1.1  christos #if DEPENDS_ON_LIBINTL && ENABLE_NLS
     58  1.1  christos # include <libintl.h>
     59  1.1  christos #endif
     60  1.1  christos 
     61  1.1  christos /* Faked cheap 'bool'.  */
     62  1.1  christos #undef bool
     63  1.1  christos #undef false
     64  1.1  christos #undef true
     65  1.1  christos #define bool int
     66  1.1  christos #define false 0
     67  1.1  christos #define true 1
     68  1.1  christos 
     69  1.1  christos /* Pathname support.
     70  1.1  christos    ISSLASH(C)           tests whether C is a directory separator character.
     71  1.1  christos    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
     72  1.1  christos  */
     73  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
     74  1.1  christos   /* Win32, Cygwin, OS/2, DOS */
     75  1.1  christos # define ISSLASH(C) ((C) == '/' || (C) == '\\')
     76  1.1  christos # define HAS_DEVICE(P) \
     77  1.1  christos     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
     78  1.1  christos      && (P)[1] == ':')
     79  1.1  christos # define IS_PATH_WITH_DIR(P) \
     80  1.1  christos     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
     81  1.1  christos # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
     82  1.1  christos #else
     83  1.1  christos   /* Unix */
     84  1.1  christos # define ISSLASH(C) ((C) == '/')
     85  1.1  christos # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
     86  1.1  christos # define FILE_SYSTEM_PREFIX_LEN(P) 0
     87  1.1  christos #endif
     88  1.1  christos 
     89  1.1  christos /* Original installation prefix.  */
     90  1.1  christos static char *orig_prefix;
     91  1.1  christos static size_t orig_prefix_len;
     92  1.1  christos /* Current installation prefix.  */
     93  1.1  christos static char *curr_prefix;
     94  1.1  christos static size_t curr_prefix_len;
     95  1.1  christos /* These prefixes do not end in a slash.  Anything that will be concatenated
     96  1.1  christos    to them must start with a slash.  */
     97  1.1  christos 
     98  1.1  christos /* Sets the original and the current installation prefix of this module.
     99  1.1  christos    Relocation simply replaces a pathname starting with the original prefix
    100  1.1  christos    by the corresponding pathname with the current prefix instead.  Both
    101  1.1  christos    prefixes should be directory names without trailing slash (i.e. use ""
    102  1.1  christos    instead of "/").  */
    103  1.1  christos static void
    104  1.1  christos set_this_relocation_prefix (const char *orig_prefix_arg,
    105  1.1  christos 			    const char *curr_prefix_arg)
    106  1.1  christos {
    107  1.1  christos   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
    108  1.1  christos       /* Optimization: if orig_prefix and curr_prefix are equal, the
    109  1.1  christos 	 relocation is a nop.  */
    110  1.1  christos       && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
    111  1.1  christos     {
    112  1.1  christos       /* Duplicate the argument strings.  */
    113  1.1  christos       char *memory;
    114  1.1  christos 
    115  1.1  christos       orig_prefix_len = strlen (orig_prefix_arg);
    116  1.1  christos       curr_prefix_len = strlen (curr_prefix_arg);
    117  1.1  christos       memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
    118  1.1  christos #ifdef NO_XMALLOC
    119  1.1  christos       if (memory != NULL)
    120  1.1  christos #endif
    121  1.1  christos 	{
    122  1.1  christos 	  memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
    123  1.1  christos 	  orig_prefix = memory;
    124  1.1  christos 	  memory += orig_prefix_len + 1;
    125  1.1  christos 	  memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
    126  1.1  christos 	  curr_prefix = memory;
    127  1.1  christos 	  return;
    128  1.1  christos 	}
    129  1.1  christos     }
    130  1.1  christos   orig_prefix = NULL;
    131  1.1  christos   curr_prefix = NULL;
    132  1.1  christos   /* Don't worry about wasted memory here - this function is usually only
    133  1.1  christos      called once.  */
    134  1.1  christos }
    135  1.1  christos 
    136  1.1  christos /* Sets the original and the current installation prefix of the package.
    137  1.1  christos    Relocation simply replaces a pathname starting with the original prefix
    138  1.1  christos    by the corresponding pathname with the current prefix instead.  Both
    139  1.1  christos    prefixes should be directory names without trailing slash (i.e. use ""
    140  1.1  christos    instead of "/").  */
    141  1.1  christos void
    142  1.1  christos set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
    143  1.1  christos {
    144  1.1  christos   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    145  1.1  christos 
    146  1.1  christos   /* Now notify all dependent libraries.  */
    147  1.1  christos #if DEPENDS_ON_LIBCHARSET
    148  1.1  christos   libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    149  1.1  christos #endif
    150  1.1  christos #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
    151  1.1  christos   libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    152  1.1  christos #endif
    153  1.1  christos #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
    154  1.1  christos   libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
    155  1.1  christos #endif
    156  1.1  christos }
    157  1.1  christos 
    158  1.1  christos #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
    159  1.1  christos 
    160  1.1  christos /* Convenience function:
    161  1.1  christos    Computes the current installation prefix, based on the original
    162  1.1  christos    installation prefix, the original installation directory of a particular
    163  1.1  christos    file, and the current pathname of this file.  Returns NULL upon failure.  */
    164  1.1  christos #ifdef IN_LIBRARY
    165  1.1  christos #define compute_curr_prefix local_compute_curr_prefix
    166  1.1  christos static
    167  1.1  christos #endif
    168  1.1  christos const char *
    169  1.1  christos compute_curr_prefix (const char *orig_installprefix,
    170  1.1  christos 		     const char *orig_installdir,
    171  1.1  christos 		     const char *curr_pathname)
    172  1.1  christos {
    173  1.1  christos   const char *curr_installdir;
    174  1.1  christos   const char *rel_installdir;
    175  1.1  christos 
    176  1.1  christos   if (curr_pathname == NULL)
    177  1.1  christos     return NULL;
    178  1.1  christos 
    179  1.1  christos   /* Determine the relative installation directory, relative to the prefix.
    180  1.1  christos      This is simply the difference between orig_installprefix and
    181  1.1  christos      orig_installdir.  */
    182  1.1  christos   if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
    183  1.1  christos       != 0)
    184  1.1  christos     /* Shouldn't happen - nothing should be installed outside $(prefix).  */
    185  1.1  christos     return NULL;
    186  1.1  christos   rel_installdir = orig_installdir + strlen (orig_installprefix);
    187  1.1  christos 
    188  1.1  christos   /* Determine the current installation directory.  */
    189  1.1  christos   {
    190  1.1  christos     const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
    191  1.1  christos     const char *p = curr_pathname + strlen (curr_pathname);
    192  1.1  christos     char *q;
    193  1.1  christos 
    194  1.1  christos     while (p > p_base)
    195  1.1  christos       {
    196  1.1  christos 	p--;
    197  1.1  christos 	if (ISSLASH (*p))
    198  1.1  christos 	  break;
    199  1.1  christos       }
    200  1.1  christos 
    201  1.1  christos     q = (char *) xmalloc (p - curr_pathname + 1);
    202  1.1  christos #ifdef NO_XMALLOC
    203  1.1  christos     if (q == NULL)
    204  1.1  christos       return NULL;
    205  1.1  christos #endif
    206  1.1  christos     memcpy (q, curr_pathname, p - curr_pathname);
    207  1.1  christos     q[p - curr_pathname] = '\0';
    208  1.1  christos     curr_installdir = q;
    209  1.1  christos   }
    210  1.1  christos 
    211  1.1  christos   /* Compute the current installation prefix by removing the trailing
    212  1.1  christos      rel_installdir from it.  */
    213  1.1  christos   {
    214  1.1  christos     const char *rp = rel_installdir + strlen (rel_installdir);
    215  1.1  christos     const char *cp = curr_installdir + strlen (curr_installdir);
    216  1.1  christos     const char *cp_base =
    217  1.1  christos       curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
    218  1.1  christos 
    219  1.1  christos     while (rp > rel_installdir && cp > cp_base)
    220  1.1  christos       {
    221  1.1  christos 	bool same = false;
    222  1.1  christos 	const char *rpi = rp;
    223  1.1  christos 	const char *cpi = cp;
    224  1.1  christos 
    225  1.1  christos 	while (rpi > rel_installdir && cpi > cp_base)
    226  1.1  christos 	  {
    227  1.1  christos 	    rpi--;
    228  1.1  christos 	    cpi--;
    229  1.1  christos 	    if (ISSLASH (*rpi) || ISSLASH (*cpi))
    230  1.1  christos 	      {
    231  1.1  christos 		if (ISSLASH (*rpi) && ISSLASH (*cpi))
    232  1.1  christos 		  same = true;
    233  1.1  christos 		break;
    234  1.1  christos 	      }
    235  1.1  christos 	    /* Do case-insensitive comparison if the filesystem is always or
    236  1.1  christos 	       often case-insensitive.  It's better to accept the comparison
    237  1.1  christos 	       if the difference is only in case, rather than to fail.  */
    238  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
    239  1.1  christos 	    /* Win32, Cygwin, OS/2, DOS - case insignificant filesystem */
    240  1.1  christos 	    if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
    241  1.1  christos 		!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
    242  1.1  christos 	      break;
    243  1.1  christos #else
    244  1.1  christos 	    if (*rpi != *cpi)
    245  1.1  christos 	      break;
    246  1.1  christos #endif
    247  1.1  christos 	  }
    248  1.1  christos 	if (!same)
    249  1.1  christos 	  break;
    250  1.1  christos 	/* The last pathname component was the same.  opi and cpi now point
    251  1.1  christos 	   to the slash before it.  */
    252  1.1  christos 	rp = rpi;
    253  1.1  christos 	cp = cpi;
    254  1.1  christos       }
    255  1.1  christos 
    256  1.1  christos     if (rp > rel_installdir)
    257  1.1  christos       /* Unexpected: The curr_installdir does not end with rel_installdir.  */
    258  1.1  christos       return NULL;
    259  1.1  christos 
    260  1.1  christos     {
    261  1.1  christos       size_t curr_prefix_len = cp - curr_installdir;
    262  1.1  christos       char *curr_prefix;
    263  1.1  christos 
    264  1.1  christos       curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
    265  1.1  christos #ifdef NO_XMALLOC
    266  1.1  christos       if (curr_prefix == NULL)
    267  1.1  christos 	return NULL;
    268  1.1  christos #endif
    269  1.1  christos       memcpy (curr_prefix, curr_installdir, curr_prefix_len);
    270  1.1  christos       curr_prefix[curr_prefix_len] = '\0';
    271  1.1  christos 
    272  1.1  christos       return curr_prefix;
    273  1.1  christos     }
    274  1.1  christos   }
    275  1.1  christos }
    276  1.1  christos 
    277  1.1  christos #endif /* !IN_LIBRARY || PIC */
    278  1.1  christos 
    279  1.1  christos #if defined PIC && defined INSTALLDIR
    280  1.1  christos 
    281  1.1  christos /* Full pathname of shared library, or NULL.  */
    282  1.1  christos static char *shared_library_fullname;
    283  1.1  christos 
    284  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
    285  1.1  christos 
    286  1.1  christos /* Determine the full pathname of the shared library when it is loaded.  */
    287  1.1  christos 
    288  1.1  christos BOOL WINAPI
    289  1.1  christos DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
    290  1.1  christos {
    291  1.1  christos   (void) reserved;
    292  1.1  christos 
    293  1.1  christos   if (event == DLL_PROCESS_ATTACH)
    294  1.1  christos     {
    295  1.1  christos       /* The DLL is being loaded into an application's address range.  */
    296  1.1  christos       static char location[MAX_PATH];
    297  1.1  christos 
    298  1.1  christos       if (!GetModuleFileName (module_handle, location, sizeof (location)))
    299  1.1  christos 	/* Shouldn't happen.  */
    300  1.1  christos 	return FALSE;
    301  1.1  christos 
    302  1.1  christos       if (!IS_PATH_WITH_DIR (location))
    303  1.1  christos 	/* Shouldn't happen.  */
    304  1.1  christos 	return FALSE;
    305  1.1  christos 
    306  1.1  christos       {
    307  1.1  christos #if defined __CYGWIN__
    308  1.1  christos 	/* On Cygwin, we need to convert paths coming from Win32 system calls
    309  1.1  christos 	   to the Unix-like slashified notation.  */
    310  1.1  christos 	static char location_as_posix_path[2 * MAX_PATH];
    311  1.1  christos 	/* There's no error return defined for cygwin_conv_to_posix_path.
    312  1.1  christos 	   See cygwin-api/func-cygwin-conv-to-posix-path.html.
    313  1.1  christos 	   Does it overflow the buffer of expected size MAX_PATH or does it
    314  1.1  christos 	   truncate the path?  I don't know.  Let's catch both.  */
    315  1.1  christos 	cygwin_conv_to_posix_path (location, location_as_posix_path);
    316  1.1  christos 	location_as_posix_path[MAX_PATH - 1] = '\0';
    317  1.1  christos 	if (strlen (location_as_posix_path) >= MAX_PATH - 1)
    318  1.1  christos 	  /* A sign of buffer overflow or path truncation.  */
    319  1.1  christos 	  return FALSE;
    320  1.1  christos 	shared_library_fullname = strdup (location_as_posix_path);
    321  1.1  christos #else
    322  1.1  christos 	shared_library_fullname = strdup (location);
    323  1.1  christos #endif
    324  1.1  christos       }
    325  1.1  christos     }
    326  1.1  christos 
    327  1.1  christos   return TRUE;
    328  1.1  christos }
    329  1.1  christos 
    330  1.1  christos #else /* Unix except Cygwin */
    331  1.1  christos 
    332  1.1  christos static void
    333  1.1  christos find_shared_library_fullname ()
    334  1.1  christos {
    335  1.1  christos #if defined __linux__ && __GLIBC__ >= 2
    336  1.1  christos   /* Linux has /proc/self/maps. glibc 2 has the getline() function.  */
    337  1.1  christos   FILE *fp;
    338  1.1  christos 
    339  1.1  christos   /* Open the current process' maps file.  It describes one VMA per line.  */
    340  1.1  christos   fp = fopen ("/proc/self/maps", "r");
    341  1.1  christos   if (fp)
    342  1.1  christos     {
    343  1.1  christos       unsigned long address = (unsigned long) &find_shared_library_fullname;
    344  1.1  christos       for (;;)
    345  1.1  christos 	{
    346  1.1  christos 	  unsigned long start, end;
    347  1.1  christos 	  int c;
    348  1.1  christos 
    349  1.1  christos 	  if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
    350  1.1  christos 	    break;
    351  1.1  christos 	  if (address >= start && address <= end - 1)
    352  1.1  christos 	    {
    353  1.1  christos 	      /* Found it.  Now see if this line contains a filename.  */
    354  1.1  christos 	      while (c = getc (fp), c != EOF && c != '\n' && c != '/')
    355  1.1  christos 		continue;
    356  1.1  christos 	      if (c == '/')
    357  1.1  christos 		{
    358  1.1  christos 		  size_t size;
    359  1.1  christos 		  int len;
    360  1.1  christos 
    361  1.1  christos 		  ungetc (c, fp);
    362  1.1  christos 		  shared_library_fullname = NULL; size = 0;
    363  1.1  christos 		  len = getline (&shared_library_fullname, &size, fp);
    364  1.1  christos 		  if (len >= 0)
    365  1.1  christos 		    {
    366  1.1  christos 		      /* Success: filled shared_library_fullname.  */
    367  1.1  christos 		      if (len > 0 && shared_library_fullname[len - 1] == '\n')
    368  1.1  christos 			shared_library_fullname[len - 1] = '\0';
    369  1.1  christos 		    }
    370  1.1  christos 		}
    371  1.1  christos 	      break;
    372  1.1  christos 	    }
    373  1.1  christos 	  while (c = getc (fp), c != EOF && c != '\n')
    374  1.1  christos 	    continue;
    375  1.1  christos 	}
    376  1.1  christos       fclose (fp);
    377  1.1  christos     }
    378  1.1  christos #endif
    379  1.1  christos }
    380  1.1  christos 
    381  1.1  christos #endif /* (WIN32 or Cygwin) / (Unix except Cygwin) */
    382  1.1  christos 
    383  1.1  christos /* Return the full pathname of the current shared library.
    384  1.1  christos    Return NULL if unknown.
    385  1.1  christos    Guaranteed to work only on Linux, Cygwin and Woe32.  */
    386  1.1  christos static char *
    387  1.1  christos get_shared_library_fullname ()
    388  1.1  christos {
    389  1.1  christos #if !(defined _WIN32 || defined __WIN32__ || defined __CYGWIN__)
    390  1.1  christos   static bool tried_find_shared_library_fullname;
    391  1.1  christos   if (!tried_find_shared_library_fullname)
    392  1.1  christos     {
    393  1.1  christos       find_shared_library_fullname ();
    394  1.1  christos       tried_find_shared_library_fullname = true;
    395  1.1  christos     }
    396  1.1  christos #endif
    397  1.1  christos   return shared_library_fullname;
    398  1.1  christos }
    399  1.1  christos 
    400  1.1  christos #endif /* PIC */
    401  1.1  christos 
    402  1.1  christos /* Returns the pathname, relocated according to the current installation
    403  1.1  christos    directory.  */
    404  1.1  christos const char *
    405  1.1  christos relocate (const char *pathname)
    406  1.1  christos {
    407  1.1  christos #if defined PIC && defined INSTALLDIR
    408  1.1  christos   static int initialized;
    409  1.1  christos 
    410  1.1  christos   /* Initialization code for a shared library.  */
    411  1.1  christos   if (!initialized)
    412  1.1  christos     {
    413  1.1  christos       /* At this point, orig_prefix and curr_prefix likely have already been
    414  1.1  christos 	 set through the main program's set_program_name_and_installdir
    415  1.1  christos 	 function.  This is sufficient in the case that the library has
    416  1.1  christos 	 initially been installed in the same orig_prefix.  But we can do
    417  1.1  christos 	 better, to also cover the cases that 1. it has been installed
    418  1.1  christos 	 in a different prefix before being moved to orig_prefix and (later)
    419  1.1  christos 	 to curr_prefix, 2. unlike the program, it has not moved away from
    420  1.1  christos 	 orig_prefix.  */
    421  1.1  christos       const char *orig_installprefix = INSTALLPREFIX;
    422  1.1  christos       const char *orig_installdir = INSTALLDIR;
    423  1.1  christos       const char *curr_prefix_better;
    424  1.1  christos 
    425  1.1  christos       curr_prefix_better =
    426  1.1  christos 	compute_curr_prefix (orig_installprefix, orig_installdir,
    427  1.1  christos 			     get_shared_library_fullname ());
    428  1.1  christos       if (curr_prefix_better == NULL)
    429  1.1  christos 	curr_prefix_better = curr_prefix;
    430  1.1  christos 
    431  1.1  christos       set_relocation_prefix (orig_installprefix, curr_prefix_better);
    432  1.1  christos 
    433  1.1  christos       initialized = 1;
    434  1.1  christos     }
    435  1.1  christos #endif
    436  1.1  christos 
    437  1.1  christos   /* Note: It is not necessary to perform case insensitive comparison here,
    438  1.1  christos      even for DOS-like filesystems, because the pathname argument was
    439  1.1  christos      typically created from the same Makefile variable as orig_prefix came
    440  1.1  christos      from.  */
    441  1.1  christos   if (orig_prefix != NULL && curr_prefix != NULL
    442  1.1  christos       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
    443  1.1  christos     {
    444  1.1  christos       if (pathname[orig_prefix_len] == '\0')
    445  1.1  christos 	/* pathname equals orig_prefix.  */
    446  1.1  christos 	return curr_prefix;
    447  1.1  christos       if (ISSLASH (pathname[orig_prefix_len]))
    448  1.1  christos 	{
    449  1.1  christos 	  /* pathname starts with orig_prefix.  */
    450  1.1  christos 	  const char *pathname_tail = &pathname[orig_prefix_len];
    451  1.1  christos 	  char *result =
    452  1.1  christos 	    (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
    453  1.1  christos 
    454  1.1  christos #ifdef NO_XMALLOC
    455  1.1  christos 	  if (result != NULL)
    456  1.1  christos #endif
    457  1.1  christos 	    {
    458  1.1  christos 	      memcpy (result, curr_prefix, curr_prefix_len);
    459  1.1  christos 	      strcpy (result + curr_prefix_len, pathname_tail);
    460  1.1  christos 	      return result;
    461  1.1  christos 	    }
    462  1.1  christos 	}
    463  1.1  christos     }
    464  1.1  christos   /* Nothing to relocate.  */
    465  1.1  christos   return pathname;
    466  1.1  christos }
    467  1.1  christos 
    468  1.1  christos #endif
    469