Thread: Re: [pgsql-hackers-win32] Data directory with trailing [back]slash

Re: [pgsql-hackers-win32] Data directory with trailing [back]slash

From
Andrew Dunstan
Date:

Tom Lane wrote:

>"Magnus Hagander" <mha@sollentuna.net> writes:
>
>
>>It's not possible to start the postmaster on win32 with:
>>postmaster -D d:\pgdata\
>>or
>>postmaster -D d:/pgdata/
>>
>>
>
>Sounds like canonicalize_path() needs to be applied a bit sooner than
>it is.
>
>BTW I think canonicalize_path() is a few bricks shy of a load yet:
>I'm not sure it works well with Windows drive-letters, and it definitely
>will strip significant slashes when given input like '/' or 'C:\'.
>Feel free to fix those problems while at it...
>
>

Or use the attached patch, which I think does it right.

cheers

andrew
Index: src/port/path.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/port/path.c,v
retrieving revision 1.20
diff -c -r1.20 path.c
*** src/port/path.c    11 Jun 2004 17:09:13 -0000    1.20
--- src/port/path.c    21 Jun 2004 00:19:27 -0000
***************
*** 115,121 ****
--- 115,144 ----
          if (*p == '\\')
              *p = '/';
      }
+
+     /* skip network and drive specifiers for win32 */
+     if (strlen(path) >= 2)
+     {
+         if (path[0] == '/' && path[1] == '/')
+         {
+             /* network drive */
+             path = strstr(path + 2, "/");
+             if (path == NULL)
+                 return;
+         }
+         else if (path[1] == ':' &&
+                  ((path[0] >= 'a' && path[0] <= 'z') ||
+                   (path[0] >= 'A' && path[0] <= 'Z')))
+         {
+             /* local drive */
+             path += 2;
+         }
+     }
+
  #endif
+
+     if (path[0] == '/')            /* don't trim leading '/'. */
+         ++path;

      trim_trailing_separator(path);
  }

Re: [pgsql-hackers-win32] Data directory with trailing [back]slash

From
Bruce Momjian
Date:
OK, I have fixed the problem.  While your patch got close, it is best to
fix the problem in trim_trailing_separator() rather than above.

Tom already fixed the Unix case by preventing a path of '/' from being
stripped.  This patch prevents c:/ and //network/ from being stripped
too.  (Tom already mentioned Win32 would need work.)

---------------------------------------------------------------------------

Andrew Dunstan wrote:
>
>
> Tom Lane wrote:
>
> >"Magnus Hagander" <mha@sollentuna.net> writes:
> >
> >
> >>It's not possible to start the postmaster on win32 with:
> >>postmaster -D d:\pgdata\
> >>or
> >>postmaster -D d:/pgdata/
> >>
> >>
> >
> >Sounds like canonicalize_path() needs to be applied a bit sooner than
> >it is.
> >
> >BTW I think canonicalize_path() is a few bricks shy of a load yet:
> >I'm not sure it works well with Windows drive-letters, and it definitely
> >will strip significant slashes when given input like '/' or 'C:\'.
> >Feel free to fix those problems while at it...
> >
> >
>
> Or use the attached patch, which I think does it right.
>
> cheers
>
> andrew


>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: the planner will ignore your desire to choose an index scan if your
>       joining column's datatypes do not match

--
  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/port/path.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/port/path.c,v
retrieving revision 1.21
diff -c -c -r1.21 path.c
*** src/port/path.c    10 Jul 2004 22:58:42 -0000    1.21
--- src/port/path.c    11 Jul 2004 02:50:49 -0000
***************
*** 389,395 ****
  trim_trailing_separator(char *path)
  {
      char *p = path + strlen(path);
!
      /* trim off trailing slashes */
      if (p > path)
          for (p--; p > path && IS_DIR_SEP(*p); p--)
--- 389,414 ----
  trim_trailing_separator(char *path)
  {
      char *p = path + strlen(path);
!
! #ifdef WIN32
!     /* Skip over network and drive specifiers for win32 */
!     if (strlen(path) >= 2)
!     {
!         if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
!         {
!             path += 2;
!             while (*path && !IS_DIR_SEP(*path))
!                 path++;
!         }
!         else if (isalpha(path[0]) && path[1] == ':')
!         {
!             path++;
!             if (IS_DIR_SEP(path[1]))
!                 path++;
!         }
!     }
! #endif
!
      /* trim off trailing slashes */
      if (p > path)
          for (p--; p > path && IS_DIR_SEP(*p); p--)

Re: [pgsql-hackers-win32] Data directory with trailing [back]slash

From
Bruce Momjian
Date:
I am now confused about the original report.  I don't see how my fix
would correct the reported problem.  trim_trailing_separator() would
have handled d:\pgdata\ and d:\pgdata just fine.  The fix only corrects
d:\.

Magnus, does current CVS fix the problem?

---------------------------------------------------------------------------

Andrew Dunstan wrote:
>
>
> Tom Lane wrote:
>
> >"Magnus Hagander" <mha@sollentuna.net> writes:
> >
> >
> >>It's not possible to start the postmaster on win32 with:
> >>postmaster -D d:\pgdata\
> >>or
> >>postmaster -D d:/pgdata/
> >>
> >>
> >
> >Sounds like canonicalize_path() needs to be applied a bit sooner than
> >it is.
> >
> >BTW I think canonicalize_path() is a few bricks shy of a load yet:
> >I'm not sure it works well with Windows drive-letters, and it definitely
> >will strip significant slashes when given input like '/' or 'C:\'.
> >Feel free to fix those problems while at it...
> >
> >
>
> Or use the attached patch, which I think does it right.
>
> cheers
>
> andrew


>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: the planner will ignore your desire to choose an index scan if your
>       joining column's datatypes do not match

--
  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

Re: [pgsql-hackers-win32] Data directory with trailing [back]slash

From
Bruce Momjian
Date:
I think this still is not fixed.  I think we need to add a call to
trim_trailing_separator() in checkDataDir().  Magnus, can you confirm
this will fix it?

---------------------------------------------------------------------------

Bruce Momjian wrote:
>
> I am now confused about the original report.  I don't see how my fix
> would correct the reported problem.  trim_trailing_separator() would
> have handled d:\pgdata\ and d:\pgdata just fine.  The fix only corrects
> d:\.
>
> Magnus, does current CVS fix the problem?
>
> ---------------------------------------------------------------------------
>
> Andrew Dunstan wrote:
> >
> >
> > Tom Lane wrote:
> >
> > >"Magnus Hagander" <mha@sollentuna.net> writes:
> > >
> > >
> > >>It's not possible to start the postmaster on win32 with:
> > >>postmaster -D d:\pgdata\
> > >>or
> > >>postmaster -D d:/pgdata/
> > >>
> > >>
> > >
> > >Sounds like canonicalize_path() needs to be applied a bit sooner than
> > >it is.
> > >
> > >BTW I think canonicalize_path() is a few bricks shy of a load yet:
> > >I'm not sure it works well with Windows drive-letters, and it definitely
> > >will strip significant slashes when given input like '/' or 'C:\'.
> > >Feel free to fix those problems while at it...
> > >
> > >
> >
> > Or use the attached patch, which I think does it right.
> >
> > cheers
> >
> > andrew
>
>
> >
> > ---------------------------(end of broadcast)---------------------------
> > TIP 9: the planner will ignore your desire to choose an index scan if your
> >       joining column's datatypes do not match
>
> --
>   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
>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
>

--
  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

Re: [pgsql-hackers-win32] Data directory with trailing [back]slash

From
Bruce Momjian
Date:
OK, I found the problem.  While we did canonicalize_path for client apps
like initdb, we didn't do it for server-side paths, for the most part.

This applied patch does canonicalize_path for -D, GUC variables, and
environment variables supplying paths.  This should fix the Win32
problem you saw.

Are there other places where paths come into the system?

---------------------------------------------------------------------------

Bruce Momjian wrote:
>
> I think this still is not fixed.  I think we need to add a call to
> trim_trailing_separator() in checkDataDir().  Magnus, can you confirm
> this will fix it?
>
> ---------------------------------------------------------------------------
>
> Bruce Momjian wrote:
> >
> > I am now confused about the original report.  I don't see how my fix
> > would correct the reported problem.  trim_trailing_separator() would
> > have handled d:\pgdata\ and d:\pgdata just fine.  The fix only corrects
> > d:\.
> >
> > Magnus, does current CVS fix the problem?
> >
> > ---------------------------------------------------------------------------
> >
> > Andrew Dunstan wrote:
> > >
> > >
> > > Tom Lane wrote:
> > >
> > > >"Magnus Hagander" <mha@sollentuna.net> writes:
> > > >
> > > >
> > > >>It's not possible to start the postmaster on win32 with:
> > > >>postmaster -D d:\pgdata\
> > > >>or
> > > >>postmaster -D d:/pgdata/
> > > >>
> > > >>
> > > >
> > > >Sounds like canonicalize_path() needs to be applied a bit sooner than
> > > >it is.
> > > >
> > > >BTW I think canonicalize_path() is a few bricks shy of a load yet:
> > > >I'm not sure it works well with Windows drive-letters, and it definitely
> > > >will strip significant slashes when given input like '/' or 'C:\'.
> > > >Feel free to fix those problems while at it...
> > > >
> > > >
> > >
> > > Or use the attached patch, which I think does it right.
> > >
> > > cheers
> > >
> > > andrew
> >
> >
> > >
> > > ---------------------------(end of broadcast)---------------------------
> > > TIP 9: the planner will ignore your desire to choose an index scan if your
> > >       joining column's datatypes do not match
> >
> > --
> >   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
> >
> > ---------------------------(end of broadcast)---------------------------
> > TIP 2: you can get off all lists at once with the unregister command
> >     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
> >
>
> --
>   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
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: the planner will ignore your desire to choose an index scan if your
>       joining column's datatypes do not match
>

--
  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

Re: [pgsql-hackers-win32] Data directory with trailing [back]slash

From
Bruce Momjian
Date:
Oops, path patch attached.

---------------------------------------------------------------------------

Bruce Momjian wrote:
>
> I think this still is not fixed.  I think we need to add a call to
> trim_trailing_separator() in checkDataDir().  Magnus, can you confirm
> this will fix it?
>
> ---------------------------------------------------------------------------
>
> Bruce Momjian wrote:
> >
> > I am now confused about the original report.  I don't see how my fix
> > would correct the reported problem.  trim_trailing_separator() would
> > have handled d:\pgdata\ and d:\pgdata just fine.  The fix only corrects
> > d:\.
> >
> > Magnus, does current CVS fix the problem?
> >
> > ---------------------------------------------------------------------------
> >
> > Andrew Dunstan wrote:
> > >
> > >
> > > Tom Lane wrote:
> > >
> > > >"Magnus Hagander" <mha@sollentuna.net> writes:
> > > >
> > > >
> > > >>It's not possible to start the postmaster on win32 with:
> > > >>postmaster -D d:\pgdata\
> > > >>or
> > > >>postmaster -D d:/pgdata/
> > > >>
> > > >>
> > > >
> > > >Sounds like canonicalize_path() needs to be applied a bit sooner than
> > > >it is.
> > > >
> > > >BTW I think canonicalize_path() is a few bricks shy of a load yet:
> > > >I'm not sure it works well with Windows drive-letters, and it definitely
> > > >will strip significant slashes when given input like '/' or 'C:\'.
> > > >Feel free to fix those problems while at it...
> > > >
> > > >
> > >
> > > Or use the attached patch, which I think does it right.
> > >
> > > cheers
> > >
> > > andrew
> >
> >
> > >
> > > ---------------------------(end of broadcast)---------------------------
> > > TIP 9: the planner will ignore your desire to choose an index scan if your
> > >       joining column's datatypes do not match
> >
> > --
> >   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
> >
> > ---------------------------(end of broadcast)---------------------------
> > TIP 2: you can get off all lists at once with the unregister command
> >     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
> >
>
> --
>   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
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: the planner will ignore your desire to choose an index scan if your
>       joining column's datatypes do not match
>

--
  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/backend/postmaster/postmaster.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v
retrieving revision 1.407
diff -c -c -r1.407 postmaster.c
*** src/backend/postmaster/postmaster.c    11 Jul 2004 00:18:43 -0000    1.407
--- src/backend/postmaster/postmaster.c    11 Jul 2004 21:29:16 -0000
***************
*** 372,378 ****
      InitializeGUCOptions();

      userPGDATA = getenv("PGDATA");        /* default value */
!
      opterr = 1;

      while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:")) != -1)
--- 372,379 ----
      InitializeGUCOptions();

      userPGDATA = getenv("PGDATA");        /* default value */
!     canonicalize_path(userPGDATA);
!
      opterr = 1;

      while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:")) != -1)
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.214
diff -c -c -r1.214 guc.c
*** src/backend/utils/misc/guc.c    11 Jul 2004 00:18:44 -0000    1.214
--- src/backend/utils/misc/guc.c    11 Jul 2004 21:29:19 -0000
***************
*** 113,118 ****
--- 113,119 ----
  static bool assign_stage_log_stats(bool newval, bool doit, GucSource source);
  static bool assign_log_stats(bool newval, bool doit, GucSource source);
  static bool assign_transaction_read_only(bool newval, bool doit, GucSource source);
+ static const char *assign_canonical_path(const char *newval, bool doit, GucSource source);

  static void ReadConfigFile(char *filename, GucContext context);

***************
*** 1470,1476 ****
                           "the specified file.")
          },
          &Dynamic_library_path,
!         "$libdir", NULL, NULL
      },

      {
--- 1471,1477 ----
                           "the specified file.")
          },
          &Dynamic_library_path,
!         "$libdir", assign_canonical_path, NULL
      },

      {
***************
*** 1556,1562 ****
              GUC_LIST_INPUT | GUC_LIST_QUOTE
          },
          &preload_libraries_string,
!         "", NULL, NULL
      },

      {
--- 1557,1563 ----
              GUC_LIST_INPUT | GUC_LIST_QUOTE
          },
          &preload_libraries_string,
!         "", assign_canonical_path, NULL
      },

      {
***************
*** 1678,1684 ****
              NULL
          },
          &UnixSocketDir,
!         "", NULL, NULL
      },

      {
--- 1679,1685 ----
              NULL
          },
          &UnixSocketDir,
!         "", assign_canonical_path, NULL
      },

      {
***************
*** 1712,1736 ****
      {
          {"pgdata", PGC_POSTMASTER, 0, gettext_noop("Sets the location of the data directory"), NULL},
          &guc_pgdata,
!         NULL, NULL, NULL
      },

      {
          {"hba_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"hba\" configuration file"), NULL},
          &guc_hbafile,
!         NULL, NULL, NULL
      },

      {
          {"ident_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"ident\" configuration file"), NULL},
          &guc_identfile,
!         NULL, NULL, NULL
      },

      {
          {"external_pidfile", PGC_POSTMASTER, 0, gettext_noop("Writes the postmaster PID to the specified file"),
NULL},
          &external_pidfile,
!         NULL, NULL, NULL
      },

      /* End-of-list marker */
--- 1713,1737 ----
      {
          {"pgdata", PGC_POSTMASTER, 0, gettext_noop("Sets the location of the data directory"), NULL},
          &guc_pgdata,
!         NULL, assign_canonical_path, NULL
      },

      {
          {"hba_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"hba\" configuration file"), NULL},
          &guc_hbafile,
!         NULL, assign_canonical_path, NULL
      },

      {
          {"ident_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"ident\" configuration file"), NULL},
          &guc_identfile,
!         NULL, assign_canonical_path, NULL
      },

      {
          {"external_pidfile", PGC_POSTMASTER, 0, gettext_noop("Writes the postmaster PID to the specified file"),
NULL},
          &external_pidfile,
!         NULL, assign_canonical_path, NULL
      },

      /* End-of-list marker */
***************
*** 5160,5167 ****
  }

  static const char *
! assign_client_min_messages(const char *newval,
!                            bool doit, GucSource source)
  {
      return (assign_msglvl(&client_min_messages, newval, doit, source));
  }
--- 5161,5167 ----
  }

  static const char *
! assign_client_min_messages(const char *newval, bool doit, GucSource source)
  {
      return (assign_msglvl(&client_min_messages, newval, doit, source));
  }
***************
*** 5428,5433 ****
--- 5428,5448 ----
                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                   errmsg("cannot set transaction read only mode inside a subtransaction")));
      return true;
+ }
+
+ static const char *
+ assign_canonical_path(const char *newval, bool doit, GucSource source)
+ {
+
+     if (doit)
+     {
+         /* We have to create a new pointer to force the change */
+         char *canon_val = guc_strdup(FATAL, newval);
+         canonicalize_path(canon_val);
+         return canon_val;
+     }
+     else
+         return newval;
  }

  #include "guc-file.c"
Index: src/bin/psql/command.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/command.c,v
retrieving revision 1.119
diff -c -c -r1.119 command.c
*** src/bin/psql/command.c    11 Jul 2004 13:29:15 -0000    1.119
--- src/bin/psql/command.c    11 Jul 2004 21:29:22 -0000
***************
*** 375,380 ****
--- 375,381 ----
              fname = psql_scan_slash_option(scan_state,
                                             OT_NORMAL, NULL, true);
              expand_tilde(&fname);
+             canonicalize_path(fname);
              status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
              free(fname);
          }
***************
*** 777,784 ****
                      fd = popen(&fname[1], "w");
                  }
                  else
                      fd = fopen(fname, "w");
!
                  if (!fd)
                  {
                      psql_error("%s: %s\n", fname, strerror(errno));
--- 778,787 ----
                      fd = popen(&fname[1], "w");
                  }
                  else
+                 {
+                     canonicalize_path(fname);
                      fd = fopen(fname, "w");
!                 }
                  if (!fd)
                  {
                      psql_error("%s: %s\n", fname, strerror(errno));
***************
*** 1122,1128 ****

      if (filename_arg)
          fname = filename_arg;
-
      else
      {
          /* make a temp file to edit */
--- 1125,1130 ----
***************
*** 1262,1267 ****
--- 1264,1270 ----
      if (!filename)
          return false;

+     canonicalize_path(filename);
      fd = fopen(filename, PG_BINARY_R);

      if (!fd)
Index: src/bin/psql/copy.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/psql/copy.c,v
retrieving revision 1.49
diff -c -c -r1.49 copy.c
*** src/bin/psql/copy.c    11 Jul 2004 13:29:15 -0000    1.49
--- src/bin/psql/copy.c    11 Jul 2004 21:29:22 -0000
***************
*** 513,518 ****
--- 513,520 ----
          appendPQExpBuffer(&query, " FORCE NOT NULL %s", options->force_notnull_list);
      }

+     canonicalize_path(options->file);
+
      if (options->from)
      {
          if (options->file)
Index: src/port/path.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/port/path.c,v
retrieving revision 1.22
diff -c -c -r1.22 path.c
*** src/port/path.c    11 Jul 2004 02:59:42 -0000    1.22
--- src/port/path.c    11 Jul 2004 21:29:23 -0000
***************
*** 33,38 ****
--- 33,39 ----
  #endif

  const static char *relative_path(const char *bin_path, const char *other_path);
+ static void make_relative(const char *my_exec_path, const char *p, char *ret_path);
  static void trim_directory(char *path);
  static void trim_trailing_separator(char *path);

***************
*** 43,57 ****
          (p)++; \
  }

- /* Macro creates a relative path */
- #define MAKE_RELATIVE \
- do { \
-         StrNCpy(path, my_exec_path, MAXPGPATH); \
-         trim_directory(path); \
-         trim_directory(path); \
-         snprintf(ret_path, MAXPGPATH, "%s/%s", path, p); \
- } while (0)
-
  /*
   *    first_dir_separator
   */
--- 44,49 ----
***************
*** 140,152 ****
  void
  get_share_path(const char *my_exec_path, char *ret_path)
  {
-     char path[MAXPGPATH];
      const char *p;

      if ((p = relative_path(PGBINDIR, PGSHAREDIR)))
!         MAKE_RELATIVE;
      else
          StrNCpy(ret_path, PGSHAREDIR, MAXPGPATH);
  }


--- 132,144 ----
  void
  get_share_path(const char *my_exec_path, char *ret_path)
  {
      const char *p;

      if ((p = relative_path(PGBINDIR, PGSHAREDIR)))
!         make_relative(my_exec_path, p, ret_path);
      else
          StrNCpy(ret_path, PGSHAREDIR, MAXPGPATH);
+     canonicalize_path(ret_path);
  }


***************
*** 157,169 ****
  void
  get_etc_path(const char *my_exec_path, char *ret_path)
  {
-     char path[MAXPGPATH];
      const char *p;

      if ((p = relative_path(PGBINDIR, SYSCONFDIR)))
!         MAKE_RELATIVE;
      else
          StrNCpy(ret_path, SYSCONFDIR, MAXPGPATH);
  }


--- 149,161 ----
  void
  get_etc_path(const char *my_exec_path, char *ret_path)
  {
      const char *p;

      if ((p = relative_path(PGBINDIR, SYSCONFDIR)))
!         make_relative(my_exec_path, p, ret_path);
      else
          StrNCpy(ret_path, SYSCONFDIR, MAXPGPATH);
+     canonicalize_path(ret_path);
  }


***************
*** 174,186 ****
  void
  get_include_path(const char *my_exec_path, char *ret_path)
  {
-     char path[MAXPGPATH];
      const char *p;

      if ((p = relative_path(PGBINDIR, INCLUDEDIR)))
!         MAKE_RELATIVE;
      else
          StrNCpy(ret_path, INCLUDEDIR, MAXPGPATH);
  }


--- 166,178 ----
  void
  get_include_path(const char *my_exec_path, char *ret_path)
  {
      const char *p;

      if ((p = relative_path(PGBINDIR, INCLUDEDIR)))
!         make_relative(my_exec_path, p, ret_path);
      else
          StrNCpy(ret_path, INCLUDEDIR, MAXPGPATH);
+     canonicalize_path(ret_path);
  }


***************
*** 191,203 ****
  void
  get_pkginclude_path(const char *my_exec_path, char *ret_path)
  {
-     char path[MAXPGPATH];
      const char *p;

      if ((p = relative_path(PGBINDIR, PKGINCLUDEDIR)))
!         MAKE_RELATIVE;
      else
          StrNCpy(ret_path, PKGINCLUDEDIR, MAXPGPATH);
  }


--- 183,195 ----
  void
  get_pkginclude_path(const char *my_exec_path, char *ret_path)
  {
      const char *p;

      if ((p = relative_path(PGBINDIR, PKGINCLUDEDIR)))
!         make_relative(my_exec_path, p, ret_path);
      else
          StrNCpy(ret_path, PKGINCLUDEDIR, MAXPGPATH);
+     canonicalize_path(ret_path);
  }


***************
*** 210,222 ****
  void
  get_pkglib_path(const char *my_exec_path, char *ret_path)
  {
-     char path[MAXPGPATH];
      const char *p;

      if ((p = relative_path(PGBINDIR, PKGLIBDIR)))
!         MAKE_RELATIVE;
      else
          StrNCpy(ret_path, PKGLIBDIR, MAXPGPATH);
  }


--- 202,214 ----
  void
  get_pkglib_path(const char *my_exec_path, char *ret_path)
  {
      const char *p;

      if ((p = relative_path(PGBINDIR, PKGLIBDIR)))
!         make_relative(my_exec_path, p, ret_path);
      else
          StrNCpy(ret_path, PKGLIBDIR, MAXPGPATH);
+     canonicalize_path(ret_path);
  }


***************
*** 229,241 ****
  void
  get_locale_path(const char *my_exec_path, char *ret_path)
  {
-     char path[MAXPGPATH];
      const char *p;

      if ((p = relative_path(PGBINDIR, LOCALEDIR)))
!         MAKE_RELATIVE;
      else
          StrNCpy(ret_path, LOCALEDIR, MAXPGPATH);
  }


--- 221,233 ----
  void
  get_locale_path(const char *my_exec_path, char *ret_path)
  {
      const char *p;

      if ((p = relative_path(PGBINDIR, LOCALEDIR)))
!         make_relative(my_exec_path, p, ret_path);
      else
          StrNCpy(ret_path, LOCALEDIR, MAXPGPATH);
+     canonicalize_path(ret_path);
  }


***************
*** 270,275 ****
--- 262,268 ----
      {
          /* set for libpq to use */
          snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path);
+         canonicalize_path(env_path);
          putenv(strdup(env_path));
      }
  #endif
***************
*** 280,290 ****
--- 273,298 ----

          /* set for libpq to use */
          snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path);
+         canonicalize_path(env_path);
          putenv(strdup(env_path));
      }
  }


+ /*
+  *    make_relative - adjust path to be relative to bin/
+  */
+ static void
+ make_relative(const char *my_exec_path, const char *p, char *ret_path)
+ {
+     char path[MAXPGPATH];
+
+     StrNCpy(path, my_exec_path, MAXPGPATH);
+     trim_directory(path);
+     trim_directory(path);
+     snprintf(ret_path, MAXPGPATH, "%s/%s", path, p);
+ }
+

  /*
   *    relative_path
***************
*** 391,397 ****
      char *p = path + strlen(path);

  #ifdef WIN32
!     /* Skip over network and drive specifiers for win32 */
      if (strlen(path) >= 2)
      {
          if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
--- 399,408 ----
      char *p = path + strlen(path);

  #ifdef WIN32
!     /*
!      *    Skip over network and drive specifiers for win32.
!      *    Set 'path' to point to the last character to keep.
!      */
      if (strlen(path) >= 2)
      {
          if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))