Function to do runtime relative directory mapping - Mailing list pgsql-patches

From Bruce Momjian
Subject Function to do runtime relative directory mapping
Date
Msg-id 200405041725.i44HPaV24482@candle.pha.pa.us
Whole thread Raw
Responses Re: [pgsql-hackers-win32] Function to do runtime relative directory  (Andrew Dunstan <andrew@dunslane.net>)
List pgsql-patches
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Tom Lane wrote:
> >> I guess what you are saying is we should have a configure-time option to
> >> address configured directories via relative paths from the executable's
> >> directory, rather than absolute paths?  Seems reasonable ...
>
> > Yep.  In fact, why would we not use that by default?
>
> Because it'll be slower.  Instead of
>     /usr/local/pgsql/lib
> we'd be using something like
>     /usr/local/pgsql/bin/../lib
> which is not too bad here but would get worse if the directories are not
> so close.
>
> But perhaps we can arrange for the path to be simplified down to an
> absolute form when it's constructed at backend startup?  You'd need a
> routine anyway to combine the bindir path (determined by FindExec) with
> the relative path provided by configure, so maybe this routine could be
> smart about leading ../ in the configure path.

I wrote relative_path() which does the mapping from compiled src/dst to
a new path.  For example:

    $ tst1 /usr/local/pgsql/bin /usr/local/pgsql/lib /users/fred/pgsql/bin
    /users/fred/pgsql/lib

    $ tst1 /a/b/c /a/d /f/g/h
    /f/d

This can be used in the backend to map from your bindir to a relative
libdir at runtime, and share too.  It returns [mp]alloc'ed values, or
NULL if it can't do the tranformation.

Patch attached.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/include/port.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/port.h,v
retrieving revision 1.27
diff -c -c -r1.27 port.h
*** src/include/port.h    30 Apr 2004 17:52:07 -0000    1.27
--- src/include/port.h    4 May 2004 17:07:30 -0000
***************
*** 26,31 ****
--- 26,32 ----
  extern char *last_path_separator(const char *filename);
  extern void canonicalize_path(char *path);
  extern char *get_progname(char *argv0);
+ extern char *relative_path(const char *src, const char *dst, const char *target);

  /* Portable delay handling */
  extern void pg_usleep(long microsec);
Index: src/port/path.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/port/path.c,v
retrieving revision 1.5
diff -c -c -r1.5 path.c
*** src/port/path.c    9 Mar 2004 04:49:02 -0000    1.5
--- src/port/path.c    4 May 2004 17:07:31 -0000
***************
*** 13,21 ****
--- 13,31 ----
   *-------------------------------------------------------------------------
   */

+ #ifndef FRONTEND
+ #include "postgres.h"
+ #else
  #include "c.h"
+ #endif
  #include <ctype.h>

+ #ifndef WIN32
+ #define ISSEP(c)    ((c) == '/')
+ #else
+ #define ISSEP(c)    ((c) == '/' || (c) == '\\')
+ #endif
+
  /*
   *    is_absolute_path
   */
***************
*** 33,39 ****
  }


-
  /*
   *    first_path_separator
   */
--- 43,48 ----
***************
*** 120,123 ****
--- 129,241 ----
          return argv0;
      else
          return last_path_separator(argv0) + 1;
+ }
+
+
+ /*
+  *    relative_path
+  *
+  *    Determine the relative path for getting from 'src' to 'dst' and
+  *    map that change from 'target' to a new directory.
+  */
+ char *
+ relative_path(const char *src, const char *dst, const char *target)
+ {
+     const char *dst_slash = NULL;
+     char    *ret;
+     int        dirs_up;
+
+ #ifdef WIN32
+     if (isalpha(*src) && src[1] == ':' &&
+         isalpha(*dst) && dst[1] == ':')
+     {
+         if (toupper(*src) != toupper(*src))
+             return NULL;    /* no relative path, can't cross drive letters */
+     }
+
+     /* Move past drive letters */
+     if (isalpha(*src) && src[1] == ':')
+         src += 2;
+     if (isalpha(*dst) && dst[1] == ':')
+         src += 2;
+ #endif
+
+     /* If we don't have two absolute paths, give up */
+     if (!is_absolute_path(src) ||
+         !is_absolute_path(dst))
+         return NULL;
+
+     dst_slash = dst;
+
+     while (1)
+     {
+         /* Move past adjacent slashes like //, and trailing ones */
+         while (ISSEP(*src) && (ISSEP(src[1]) || !src[1]))
+             src++;
+         while (ISSEP(*dst) && (ISSEP(dst[1]) || !dst[1]))
+             dst++;
+
+         /* Paths are done or not equal? */
+         if (!*src || !*dst)
+             break;
+ #ifndef WIN32
+         if (*src != *dst)
+             break;
+ #else
+         /* Win32 filesystem is case insensitive */
+         if (toupper(*src) != toupper(*dst) &&
+             (!ISSEP(*src) || !ISSEP(*dst)))    /* '/' == '\\' */
+             break;
+ #endif
+         if (ISSEP(*dst))
+             dst_slash = dst;
+
+         src++;
+         dst++;
+     }
+
+     /* Did the last part of the path match? */
+     dirs_up = ((*src == '\0' || ISSEP(*src)) &&
+                (*dst == '\0' || ISSEP(*dst))) ? 0 : 1;
+
+     /* How many directories do we have to move up? */
+     while (*src)
+     {
+         if (ISSEP(*src))
+         {
+             while (ISSEP(*src))
+                 src++;
+             if (*src != '\0')    /* skip trailing slash */
+                 dirs_up++;
+         }
+         else
+             src++;
+     }
+
+ #ifndef FRONTEND
+     ret = palloc(strlen(target) + strlen(dst) + 1);
+ #else
+     ret = malloc(strlen(target) + strlen(dst) + 1);
+ #endif
+
+     strcpy(ret, target);
+
+     /* Trim off trailing slash from target */
+     if (strlen(ret) > 0 && ISSEP(ret[strlen(ret)-1]))
+         dirs_up++;
+
+     while (dirs_up--)
+         if (last_path_separator(ret) != NULL)
+             *last_path_separator(ret) = '\0';    /* trim off directory */
+         else
+             return NULL;
+
+     /* Add dst to trimmed target */
+     strcat(ret, dst_slash);
+
+     /* Trim off trailing slash from result */
+     if (strlen(ret) > 0 && ISSEP(ret[strlen(ret)-1]))
+         *last_path_separator(ret) = '\0';    /* trim off slash */
+
+     return ret;
  }

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Run-as-admin warning for win32
Next
From: Andrew Dunstan
Date:
Subject: Re: [pgsql-hackers-win32] Function to do runtime relative directory