PostgreSQL Source Code  git master
path.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * path.c
4  * portable path handling routines
5  *
6  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/port/path.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #ifndef FRONTEND
17 #include "postgres.h"
18 #else
19 #include "postgres_fe.h"
20 #endif
21 
22 #include <ctype.h>
23 #include <sys/stat.h>
24 #ifdef WIN32
25 #ifdef _WIN32_IE
26 #undef _WIN32_IE
27 #endif
28 #define _WIN32_IE 0x0500
29 #ifdef near
30 #undef near
31 #endif
32 #define near
33 #include <shlobj.h>
34 #else
35 #include <unistd.h>
36 #endif
37 
38 #include "pg_config_paths.h"
39 
40 
41 #ifndef WIN32
42 #define IS_PATH_VAR_SEP(ch) ((ch) == ':')
43 #else
44 #define IS_PATH_VAR_SEP(ch) ((ch) == ';')
45 #endif
46 
47 static void make_relative_path(char *ret_path, const char *target_path,
48  const char *bin_path, const char *my_exec_path);
49 static char *trim_directory(char *path);
50 static void trim_trailing_separator(char *path);
51 static char *append_subdir_to_path(char *path, char *subdir);
52 
53 
54 /*
55  * skip_drive
56  *
57  * On Windows, a path may begin with "C:" or "//network/". Advance over
58  * this and point to the effective start of the path.
59  */
60 #ifdef WIN32
61 
62 static char *
63 skip_drive(const char *path)
64 {
65  if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
66  {
67  path += 2;
68  while (*path && !IS_DIR_SEP(*path))
69  path++;
70  }
71  else if (isalpha((unsigned char) path[0]) && path[1] == ':')
72  {
73  path += 2;
74  }
75  return (char *) path;
76 }
77 #else
78 
79 #define skip_drive(path) (path)
80 #endif
81 
82 /*
83  * has_drive_prefix
84  *
85  * Return true if the given pathname has a drive prefix.
86  */
87 bool
88 has_drive_prefix(const char *path)
89 {
90 #ifdef WIN32
91  return skip_drive(path) != path;
92 #else
93  return false;
94 #endif
95 }
96 
97 /*
98  * first_dir_separator
99  *
100  * Find the location of the first directory separator, return
101  * NULL if not found.
102  */
103 char *
105 {
106  const char *p;
107 
108  for (p = skip_drive(filename); *p; p++)
109  if (IS_DIR_SEP(*p))
110  return unconstify(char *, p);
111  return NULL;
112 }
113 
114 /*
115  * first_path_var_separator
116  *
117  * Find the location of the first path separator (i.e. ':' on
118  * Unix, ';' on Windows), return NULL if not found.
119  */
120 char *
121 first_path_var_separator(const char *pathlist)
122 {
123  const char *p;
124 
125  /* skip_drive is not needed */
126  for (p = pathlist; *p; p++)
127  if (IS_PATH_VAR_SEP(*p))
128  return unconstify(char *, p);
129  return NULL;
130 }
131 
132 /*
133  * last_dir_separator
134  *
135  * Find the location of the last directory separator, return
136  * NULL if not found.
137  */
138 char *
140 {
141  const char *p,
142  *ret = NULL;
143 
144  for (p = skip_drive(filename); *p; p++)
145  if (IS_DIR_SEP(*p))
146  ret = p;
147  return unconstify(char *, ret);
148 }
149 
150 
151 /*
152  * make_native_path - on WIN32, change / to \ in the path
153  *
154  * This effectively undoes canonicalize_path.
155  *
156  * This is required because WIN32 COPY is an internal CMD.EXE
157  * command and doesn't process forward slashes in the same way
158  * as external commands. Quoting the first argument to COPY
159  * does not convert forward to backward slashes, but COPY does
160  * properly process quoted forward slashes in the second argument.
161  *
162  * COPY works with quoted forward slashes in the first argument
163  * only if the current directory is the same as the directory
164  * of the first argument.
165  */
166 void
168 {
169 #ifdef WIN32
170  char *p;
171 
172  for (p = filename; *p; p++)
173  if (*p == '/')
174  *p = '\\';
175 #endif
176 }
177 
178 
179 /*
180  * This function cleans up the paths for use with either cmd.exe or Msys
181  * on Windows. We need them to use filenames without spaces, for which a
182  * short filename is the safest equivalent, eg:
183  * C:/Progra~1/
184  */
185 void
186 cleanup_path(char *path)
187 {
188 #ifdef WIN32
189  char *ptr;
190 
191  /*
192  * GetShortPathName() will fail if the path does not exist, or short names
193  * are disabled on this file system. In both cases, we just return the
194  * original path. This is particularly useful for --sysconfdir, which
195  * might not exist.
196  */
197  GetShortPathName(path, path, MAXPGPATH - 1);
198 
199  /* Replace '\' with '/' */
200  for (ptr = path; *ptr; ptr++)
201  {
202  if (*ptr == '\\')
203  *ptr = '/';
204  }
205 #endif
206 }
207 
208 
209 /*
210  * join_path_components - join two path components, inserting a slash
211  *
212  * We omit the slash if either given component is empty.
213  *
214  * ret_path is the output area (must be of size MAXPGPATH)
215  *
216  * ret_path can be the same as head, but not the same as tail.
217  */
218 void
219 join_path_components(char *ret_path,
220  const char *head, const char *tail)
221 {
222  if (ret_path != head)
223  strlcpy(ret_path, head, MAXPGPATH);
224 
225  /*
226  * We used to try to simplify some cases involving "." and "..", but now
227  * we just leave that to be done by canonicalize_path() later.
228  */
229 
230  if (*tail)
231  {
232  /* only separate with slash if head wasn't empty */
233  snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path),
234  "%s%s",
235  (*(skip_drive(head)) != '\0') ? "/" : "",
236  tail);
237  }
238 }
239 
240 
241 /* State-machine states for canonicalize_path */
242 typedef enum
243 {
244  ABSOLUTE_PATH_INIT, /* Just past the leading '/' (and Windows
245  * drive name if any) of an absolute path */
246  ABSOLUTE_WITH_N_DEPTH, /* We collected 'pathdepth' directories in an
247  * absolute path */
248  RELATIVE_PATH_INIT, /* At start of a relative path */
249  RELATIVE_WITH_N_DEPTH, /* We collected 'pathdepth' directories in a
250  * relative path */
251  RELATIVE_WITH_PARENT_REF /* Relative path containing only double-dots */
253 
254 /*
255  * Clean up path by:
256  * o make Win32 path use Unix slashes
257  * o remove trailing quote on Win32
258  * o remove trailing slash
259  * o remove duplicate (adjacent) separators
260  * o remove '.' (unless path reduces to only '.')
261  * o process '..' ourselves, removing it if possible
262  */
263 void
264 canonicalize_path(char *path)
265 {
266  char *p,
267  *to_p;
268  char *spath;
269  char *parsed;
270  char *unparse;
271  bool was_sep = false;
273  int pathdepth = 0; /* counts collected regular directory names */
274 
275 #ifdef WIN32
276 
277  /*
278  * The Windows command processor will accept suitably quoted paths with
279  * forward slashes, but barfs badly with mixed forward and back slashes.
280  */
281  for (p = path; *p; p++)
282  {
283  if (*p == '\\')
284  *p = '/';
285  }
286 
287  /*
288  * In Win32, if you do: prog.exe "a b" "\c\d\" the system will pass \c\d"
289  * as argv[2], so trim off trailing quote.
290  */
291  if (p > path && *(p - 1) == '"')
292  *(p - 1) = '/';
293 #endif
294 
295  /*
296  * Removing the trailing slash on a path means we never get ugly double
297  * trailing slashes. Also, Win32 can't stat() a directory with a trailing
298  * slash. Don't remove a leading slash, though.
299  */
301 
302  /*
303  * Remove duplicate adjacent separators
304  */
305  p = path;
306 #ifdef WIN32
307  /* Don't remove leading double-slash on Win32 */
308  if (*p)
309  p++;
310 #endif
311  to_p = p;
312  for (; *p; p++, to_p++)
313  {
314  /* Handle many adjacent slashes, like "/a///b" */
315  while (*p == '/' && was_sep)
316  p++;
317  if (to_p != p)
318  *to_p = *p;
319  was_sep = (*p == '/');
320  }
321  *to_p = '\0';
322 
323  /*
324  * Remove any uses of "." and process ".." ourselves
325  *
326  * Note that "/../.." should reduce to just "/", while "../.." has to be
327  * kept as-is. Also note that we want a Windows drive spec to be visible
328  * to trim_directory(), but it's not part of the logic that's looking at
329  * the name components; hence distinction between path and spath.
330  *
331  * This loop overwrites the path in-place. This is safe since we'll never
332  * make the path longer. "unparse" points to where we are reading the
333  * path, "parse" to where we are writing.
334  */
335  spath = skip_drive(path);
336  if (*spath == '\0')
337  return; /* empty path is returned as-is */
338 
339  if (*spath == '/')
340  {
342  /* Skip the leading slash for absolute path */
343  parsed = unparse = (spath + 1);
344  }
345  else
346  {
348  parsed = unparse = spath;
349  }
350 
351  while (*unparse != '\0')
352  {
353  char *unparse_next;
354  bool is_double_dot;
355 
356  /* Split off this dir name, and set unparse_next to the next one */
357  unparse_next = unparse;
358  while (*unparse_next && *unparse_next != '/')
359  unparse_next++;
360  if (*unparse_next != '\0')
361  *unparse_next++ = '\0';
362 
363  /* Identify type of this dir name */
364  if (strcmp(unparse, ".") == 0)
365  {
366  /* We can ignore "." components in all cases */
367  unparse = unparse_next;
368  continue;
369  }
370 
371  if (strcmp(unparse, "..") == 0)
372  is_double_dot = true;
373  else
374  {
375  /* adjacent separators were eliminated above */
376  Assert(*unparse != '\0');
377  is_double_dot = false;
378  }
379 
380  switch (state)
381  {
382  case ABSOLUTE_PATH_INIT:
383  /* We can ignore ".." immediately after / */
384  if (!is_double_dot)
385  {
386  /* Append first dir name (we already have leading slash) */
387  parsed = append_subdir_to_path(parsed, unparse);
389  pathdepth++;
390  }
391  break;
393  if (is_double_dot)
394  {
395  /* Remove last parsed dir */
396  /* (trim_directory won't remove the leading slash) */
397  *parsed = '\0';
398  parsed = trim_directory(path);
399  if (--pathdepth == 0)
401  }
402  else
403  {
404  /* Append normal dir */
405  *parsed++ = '/';
406  parsed = append_subdir_to_path(parsed, unparse);
407  pathdepth++;
408  }
409  break;
410  case RELATIVE_PATH_INIT:
411  if (is_double_dot)
412  {
413  /* Append irreducible double-dot (..) */
414  parsed = append_subdir_to_path(parsed, unparse);
416  }
417  else
418  {
419  /* Append normal dir */
420  parsed = append_subdir_to_path(parsed, unparse);
422  pathdepth++;
423  }
424  break;
426  if (is_double_dot)
427  {
428  /* Remove last parsed dir */
429  *parsed = '\0';
430  parsed = trim_directory(path);
431  if (--pathdepth == 0)
432  {
433  /*
434  * If the output path is now empty, we're back to the
435  * INIT state. However, we could have processed a
436  * path like "../dir/.." and now be down to "..", in
437  * which case enter the correct state for that.
438  */
439  if (parsed == spath)
441  else
443  }
444  }
445  else
446  {
447  /* Append normal dir */
448  *parsed++ = '/';
449  parsed = append_subdir_to_path(parsed, unparse);
450  pathdepth++;
451  }
452  break;
454  if (is_double_dot)
455  {
456  /* Append next irreducible double-dot (..) */
457  *parsed++ = '/';
458  parsed = append_subdir_to_path(parsed, unparse);
459  }
460  else
461  {
462  /* Append normal dir */
463  *parsed++ = '/';
464  parsed = append_subdir_to_path(parsed, unparse);
465 
466  /*
467  * We can now start counting normal dirs. But if later
468  * double-dots make us remove this dir again, we'd better
469  * revert to RELATIVE_WITH_PARENT_REF not INIT state.
470  */
472  pathdepth = 1;
473  }
474  break;
475  }
476 
477  unparse = unparse_next;
478  }
479 
480  /*
481  * If our output path is empty at this point, insert ".". We don't want
482  * to do this any earlier because it'd result in an extra dot in corner
483  * cases such as "../dir/..". Since we rejected the wholly-empty-path
484  * case above, there is certainly room.
485  */
486  if (parsed == spath)
487  *parsed++ = '.';
488 
489  /* And finally, ensure the output path is nul-terminated. */
490  *parsed = '\0';
491 }
492 
493 /*
494  * Detect whether a path contains any parent-directory references ("..")
495  *
496  * The input *must* have been put through canonicalize_path previously.
497  */
498 bool
500 {
501  /*
502  * Once canonicalized, an absolute path cannot contain any ".." at all,
503  * while a relative path could contain ".."(s) only at the start. So it
504  * is sufficient to check the start of the path, after skipping any
505  * Windows drive/network specifier.
506  */
507  path = skip_drive(path); /* C: shouldn't affect our conclusion */
508 
509  if (path[0] == '.' &&
510  path[1] == '.' &&
511  (path[2] == '\0' || path[2] == '/'))
512  return true;
513 
514  return false;
515 }
516 
517 /*
518  * Detect whether a path is only in or below the current working directory.
519  *
520  * The input *must* have been put through canonicalize_path previously.
521  *
522  * An absolute path that matches the current working directory should
523  * return false (we only want relative to the cwd).
524  */
525 bool
527 {
528  if (is_absolute_path(path))
529  return false;
530  /* don't allow anything above the cwd */
531  else if (path_contains_parent_reference(path))
532  return false;
533 #ifdef WIN32
534 
535  /*
536  * On Win32, a drive letter _not_ followed by a slash, e.g. 'E:abc', is
537  * relative to the cwd on that drive, or the drive's root directory if
538  * that drive has no cwd. Because the path itself cannot tell us which is
539  * the case, we have to assume the worst, i.e. that it is not below the
540  * cwd. We could use GetFullPathName() to find the full path but that
541  * could change if the current directory for the drive changes underneath
542  * us, so we just disallow it.
543  */
544  else if (isalpha((unsigned char) path[0]) && path[1] == ':' &&
545  !IS_DIR_SEP(path[2]))
546  return false;
547 #endif
548  else
549  return true;
550 }
551 
552 /*
553  * Detect whether path1 is a prefix of path2 (including equality).
554  *
555  * This is pretty trivial, but it seems better to export a function than
556  * to export IS_DIR_SEP.
557  */
558 bool
559 path_is_prefix_of_path(const char *path1, const char *path2)
560 {
561  int path1_len = strlen(path1);
562 
563  if (strncmp(path1, path2, path1_len) == 0 &&
564  (IS_DIR_SEP(path2[path1_len]) || path2[path1_len] == '\0'))
565  return true;
566  return false;
567 }
568 
569 /*
570  * Extracts the actual name of the program as called -
571  * stripped of .exe suffix if any
572  */
573 const char *
574 get_progname(const char *argv0)
575 {
576  const char *nodir_name;
577  char *progname;
578 
579  nodir_name = last_dir_separator(argv0);
580  if (nodir_name)
581  nodir_name++;
582  else
583  nodir_name = skip_drive(argv0);
584 
585  /*
586  * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
587  * called only once.
588  */
589  progname = strdup(nodir_name);
590  if (progname == NULL)
591  {
592  fprintf(stderr, "%s: out of memory\n", nodir_name);
593  abort(); /* This could exit the postmaster */
594  }
595 
596 #if defined(__CYGWIN__) || defined(WIN32)
597  /* strip ".exe" suffix, regardless of case */
598  if (strlen(progname) > sizeof(EXE) - 1 &&
599  pg_strcasecmp(progname + strlen(progname) - (sizeof(EXE) - 1), EXE) == 0)
600  progname[strlen(progname) - (sizeof(EXE) - 1)] = '\0';
601 #endif
602 
603  return progname;
604 }
605 
606 
607 /*
608  * dir_strcmp: strcmp except any two DIR_SEP characters are considered equal,
609  * and we honor filesystem case insensitivity if known
610  */
611 static int
612 dir_strcmp(const char *s1, const char *s2)
613 {
614  while (*s1 && *s2)
615  {
616  if (
617 #ifndef WIN32
618  *s1 != *s2
619 #else
620  /* On windows, paths are case-insensitive */
621  pg_tolower((unsigned char) *s1) != pg_tolower((unsigned char) *s2)
622 #endif
623  && !(IS_DIR_SEP(*s1) && IS_DIR_SEP(*s2)))
624  return (int) *s1 - (int) *s2;
625  s1++, s2++;
626  }
627  if (*s1)
628  return 1; /* s1 longer */
629  if (*s2)
630  return -1; /* s2 longer */
631  return 0;
632 }
633 
634 
635 /*
636  * make_relative_path - make a path relative to the actual binary location
637  *
638  * This function exists to support relocation of installation trees.
639  *
640  * ret_path is the output area (must be of size MAXPGPATH)
641  * target_path is the compiled-in path to the directory we want to find
642  * bin_path is the compiled-in path to the directory of executables
643  * my_exec_path is the actual location of my executable
644  *
645  * We determine the common prefix of target_path and bin_path, then compare
646  * the remainder of bin_path to the last directory component(s) of
647  * my_exec_path. If they match, build the result as the part of my_exec_path
648  * preceding the match, joined to the remainder of target_path. If no match,
649  * return target_path as-is.
650  *
651  * For example:
652  * target_path = '/usr/local/share/postgresql'
653  * bin_path = '/usr/local/bin'
654  * my_exec_path = '/opt/pgsql/bin/postgres'
655  * Given these inputs, the common prefix is '/usr/local/', the tail of
656  * bin_path is 'bin' which does match the last directory component of
657  * my_exec_path, so we would return '/opt/pgsql/share/postgresql'
658  */
659 static void
660 make_relative_path(char *ret_path, const char *target_path,
661  const char *bin_path, const char *my_exec_path)
662 {
663  int prefix_len;
664  int tail_start;
665  int tail_len;
666  int i;
667 
668  /*
669  * Determine the common prefix --- note we require it to end on a
670  * directory separator, consider eg '/usr/lib' and '/usr/libexec'.
671  */
672  prefix_len = 0;
673  for (i = 0; target_path[i] && bin_path[i]; i++)
674  {
675  if (IS_DIR_SEP(target_path[i]) && IS_DIR_SEP(bin_path[i]))
676  prefix_len = i + 1;
677  else if (target_path[i] != bin_path[i])
678  break;
679  }
680  if (prefix_len == 0)
681  goto no_match; /* no common prefix? */
682  tail_len = strlen(bin_path) - prefix_len;
683 
684  /*
685  * Set up my_exec_path without the actual executable name, and
686  * canonicalize to simplify comparison to bin_path.
687  */
688  strlcpy(ret_path, my_exec_path, MAXPGPATH);
689  trim_directory(ret_path); /* remove my executable name */
690  canonicalize_path(ret_path);
691 
692  /*
693  * Tail match?
694  */
695  tail_start = (int) strlen(ret_path) - tail_len;
696  if (tail_start > 0 &&
697  IS_DIR_SEP(ret_path[tail_start - 1]) &&
698  dir_strcmp(ret_path + tail_start, bin_path + prefix_len) == 0)
699  {
700  ret_path[tail_start] = '\0';
701  trim_trailing_separator(ret_path);
702  join_path_components(ret_path, ret_path, target_path + prefix_len);
703  canonicalize_path(ret_path);
704  return;
705  }
706 
707 no_match:
708  strlcpy(ret_path, target_path, MAXPGPATH);
709  canonicalize_path(ret_path);
710 }
711 
712 
713 /*
714  * make_absolute_path
715  *
716  * If the given pathname isn't already absolute, make it so, interpreting
717  * it relative to the current working directory.
718  *
719  * Also canonicalizes the path. The result is always a malloc'd copy.
720  *
721  * In backend, failure cases result in ereport(ERROR); in frontend,
722  * we write a complaint on stderr and return NULL.
723  *
724  * Note: interpretation of relative-path arguments during postmaster startup
725  * should happen before doing ChangeToDataDir(), else the user will probably
726  * not like the results.
727  */
728 char *
729 make_absolute_path(const char *path)
730 {
731  char *new;
732 
733  /* Returning null for null input is convenient for some callers */
734  if (path == NULL)
735  return NULL;
736 
737  if (!is_absolute_path(path))
738  {
739  char *buf;
740  size_t buflen;
741 
742  buflen = MAXPGPATH;
743  for (;;)
744  {
745  buf = malloc(buflen);
746  if (!buf)
747  {
748 #ifndef FRONTEND
749  ereport(ERROR,
750  (errcode(ERRCODE_OUT_OF_MEMORY),
751  errmsg("out of memory")));
752 #else
753  fprintf(stderr, _("out of memory\n"));
754  return NULL;
755 #endif
756  }
757 
758  if (getcwd(buf, buflen))
759  break;
760  else if (errno == ERANGE)
761  {
762  free(buf);
763  buflen *= 2;
764  continue;
765  }
766  else
767  {
768  int save_errno = errno;
769 
770  free(buf);
771  errno = save_errno;
772 #ifndef FRONTEND
773  elog(ERROR, "could not get current working directory: %m");
774 #else
775  fprintf(stderr, _("could not get current working directory: %s\n"),
776  strerror(errno));
777  return NULL;
778 #endif
779  }
780  }
781 
782  new = malloc(strlen(buf) + strlen(path) + 2);
783  if (!new)
784  {
785  free(buf);
786 #ifndef FRONTEND
787  ereport(ERROR,
788  (errcode(ERRCODE_OUT_OF_MEMORY),
789  errmsg("out of memory")));
790 #else
791  fprintf(stderr, _("out of memory\n"));
792  return NULL;
793 #endif
794  }
795  sprintf(new, "%s/%s", buf, path);
796  free(buf);
797  }
798  else
799  {
800  new = strdup(path);
801  if (!new)
802  {
803 #ifndef FRONTEND
804  ereport(ERROR,
805  (errcode(ERRCODE_OUT_OF_MEMORY),
806  errmsg("out of memory")));
807 #else
808  fprintf(stderr, _("out of memory\n"));
809  return NULL;
810 #endif
811  }
812  }
813 
814  /* Make sure punctuation is canonical, too */
815  canonicalize_path(new);
816 
817  return new;
818 }
819 
820 
821 /*
822  * get_share_path
823  */
824 void
825 get_share_path(const char *my_exec_path, char *ret_path)
826 {
827  make_relative_path(ret_path, PGSHAREDIR, PGBINDIR, my_exec_path);
828 }
829 
830 /*
831  * get_etc_path
832  */
833 void
834 get_etc_path(const char *my_exec_path, char *ret_path)
835 {
836  make_relative_path(ret_path, SYSCONFDIR, PGBINDIR, my_exec_path);
837 }
838 
839 /*
840  * get_include_path
841  */
842 void
843 get_include_path(const char *my_exec_path, char *ret_path)
844 {
845  make_relative_path(ret_path, INCLUDEDIR, PGBINDIR, my_exec_path);
846 }
847 
848 /*
849  * get_pkginclude_path
850  */
851 void
852 get_pkginclude_path(const char *my_exec_path, char *ret_path)
853 {
854  make_relative_path(ret_path, PKGINCLUDEDIR, PGBINDIR, my_exec_path);
855 }
856 
857 /*
858  * get_includeserver_path
859  */
860 void
861 get_includeserver_path(const char *my_exec_path, char *ret_path)
862 {
863  make_relative_path(ret_path, INCLUDEDIRSERVER, PGBINDIR, my_exec_path);
864 }
865 
866 /*
867  * get_lib_path
868  */
869 void
870 get_lib_path(const char *my_exec_path, char *ret_path)
871 {
872  make_relative_path(ret_path, LIBDIR, PGBINDIR, my_exec_path);
873 }
874 
875 /*
876  * get_pkglib_path
877  */
878 void
879 get_pkglib_path(const char *my_exec_path, char *ret_path)
880 {
881  make_relative_path(ret_path, PKGLIBDIR, PGBINDIR, my_exec_path);
882 }
883 
884 /*
885  * get_locale_path
886  */
887 void
888 get_locale_path(const char *my_exec_path, char *ret_path)
889 {
890  make_relative_path(ret_path, LOCALEDIR, PGBINDIR, my_exec_path);
891 }
892 
893 /*
894  * get_doc_path
895  */
896 void
897 get_doc_path(const char *my_exec_path, char *ret_path)
898 {
899  make_relative_path(ret_path, DOCDIR, PGBINDIR, my_exec_path);
900 }
901 
902 /*
903  * get_html_path
904  */
905 void
906 get_html_path(const char *my_exec_path, char *ret_path)
907 {
908  make_relative_path(ret_path, HTMLDIR, PGBINDIR, my_exec_path);
909 }
910 
911 /*
912  * get_man_path
913  */
914 void
915 get_man_path(const char *my_exec_path, char *ret_path)
916 {
917  make_relative_path(ret_path, MANDIR, PGBINDIR, my_exec_path);
918 }
919 
920 
921 /*
922  * get_home_path
923  *
924  * On Unix, this actually returns the user's home directory. On Windows
925  * it returns the PostgreSQL-specific application data folder.
926  */
927 bool
928 get_home_path(char *ret_path)
929 {
930 #ifndef WIN32
931  /*
932  * We first consult $HOME. If that's unset, try to get the info from
933  * <pwd.h>.
934  */
935  const char *home;
936 
937  home = getenv("HOME");
938  if (home == NULL || home[0] == '\0')
939  return pg_get_user_home_dir(geteuid(), ret_path, MAXPGPATH);
940  strlcpy(ret_path, home, MAXPGPATH);
941  return true;
942 #else
943  char *tmppath;
944 
945  /*
946  * Note: We use getenv() here because the more modern SHGetFolderPath()
947  * would force the backend to link with shell32.lib, which eats valuable
948  * desktop heap. XXX This function is used only in psql, which already
949  * brings in shell32 via libpq. Moving this function to its own file
950  * would keep it out of the backend, freeing it from this concern.
951  */
952  tmppath = getenv("APPDATA");
953  if (!tmppath)
954  return false;
955  snprintf(ret_path, MAXPGPATH, "%s/postgresql", tmppath);
956  return true;
957 #endif
958 }
959 
960 
961 /*
962  * get_parent_directory
963  *
964  * Modify the given string in-place to name the parent directory of the
965  * named file.
966  *
967  * If the input is just a file name with no directory part, the result is
968  * an empty string, not ".". This is appropriate when the next step is
969  * join_path_components(), but might need special handling otherwise.
970  *
971  * Caution: this will not produce desirable results if the string ends
972  * with "..". For most callers this is not a problem since the string
973  * is already known to name a regular file. If in doubt, apply
974  * canonicalize_path() first.
975  */
976 void
978 {
979  trim_directory(path);
980 }
981 
982 
983 /*
984  * trim_directory
985  *
986  * Trim trailing directory from path, that is, remove any trailing slashes,
987  * the last pathname component, and the slash just ahead of it --- but never
988  * remove a leading slash.
989  *
990  * For the convenience of canonicalize_path, the path's new end location
991  * is returned.
992  */
993 static char *
994 trim_directory(char *path)
995 {
996  char *p;
997 
998  path = skip_drive(path);
999 
1000  if (path[0] == '\0')
1001  return path;
1002 
1003  /* back up over trailing slash(es) */
1004  for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--)
1005  ;
1006  /* back up over directory name */
1007  for (; !IS_DIR_SEP(*p) && p > path; p--)
1008  ;
1009  /* if multiple slashes before directory name, remove 'em all */
1010  for (; p > path && IS_DIR_SEP(*(p - 1)); p--)
1011  ;
1012  /* don't erase a leading slash */
1013  if (p == path && IS_DIR_SEP(*p))
1014  p++;
1015  *p = '\0';
1016  return p;
1017 }
1018 
1019 
1020 /*
1021  * trim_trailing_separator
1022  *
1023  * trim off trailing slashes, but not a leading slash
1024  */
1025 static void
1027 {
1028  char *p;
1029 
1030  path = skip_drive(path);
1031  p = path + strlen(path);
1032  if (p > path)
1033  for (p--; p > path && IS_DIR_SEP(*p); p--)
1034  *p = '\0';
1035 }
1036 
1037 /*
1038  * append_subdir_to_path
1039  *
1040  * Append the currently-considered subdirectory name to the output
1041  * path in canonicalize_path. Return the new end location of the
1042  * output path.
1043  *
1044  * Since canonicalize_path updates the path in-place, we must use
1045  * memmove not memcpy, and we don't yet terminate the path with '\0'.
1046  */
1047 static char *
1048 append_subdir_to_path(char *path, char *subdir)
1049 {
1050  size_t len = strlen(subdir);
1051 
1052  /* No need to copy data if path and subdir are the same. */
1053  if (path != subdir)
1054  memmove(path, subdir, len);
1055 
1056  return path + len;
1057 }
#define unconstify(underlying_type, expr)
Definition: c.h:1255
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define _(x)
Definition: elog.c:91
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
char my_exec_path[MAXPGPATH]
Definition: globals.c:76
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
static char bin_path[MAXPGPATH]
Definition: initdb.c:254
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
const char * progname
Definition: main.c:45
void cleanup_path(char *path)
Definition: path.c:186
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:825
void get_pkglib_path(const char *my_exec_path, char *ret_path)
Definition: path.c:879
void get_locale_path(const char *my_exec_path, char *ret_path)
Definition: path.c:888
void join_path_components(char *ret_path, const char *head, const char *tail)
Definition: path.c:219
#define IS_PATH_VAR_SEP(ch)
Definition: path.c:42
char * last_dir_separator(const char *filename)
Definition: path.c:139
void get_man_path(const char *my_exec_path, char *ret_path)
Definition: path.c:915
bool get_home_path(char *ret_path)
Definition: path.c:928
char * make_absolute_path(const char *path)
Definition: path.c:729
void get_include_path(const char *my_exec_path, char *ret_path)
Definition: path.c:843
static char * append_subdir_to_path(char *path, char *subdir)
Definition: path.c:1048
bool path_is_prefix_of_path(const char *path1, const char *path2)
Definition: path.c:559
char * first_dir_separator(const char *filename)
Definition: path.c:104
bool path_is_relative_and_below_cwd(const char *path)
Definition: path.c:526
void get_lib_path(const char *my_exec_path, char *ret_path)
Definition: path.c:870
void canonicalize_path(char *path)
Definition: path.c:264
void get_parent_directory(char *path)
Definition: path.c:977
const char * get_progname(const char *argv0)
Definition: path.c:574
static void trim_trailing_separator(char *path)
Definition: path.c:1026
static char * trim_directory(char *path)
Definition: path.c:994
static void make_relative_path(char *ret_path, const char *target_path, const char *bin_path, const char *my_exec_path)
Definition: path.c:660
#define skip_drive(path)
Definition: path.c:79
void get_etc_path(const char *my_exec_path, char *ret_path)
Definition: path.c:834
static int dir_strcmp(const char *s1, const char *s2)
Definition: path.c:612
bool path_contains_parent_reference(const char *path)
Definition: path.c:499
char * first_path_var_separator(const char *pathlist)
Definition: path.c:121
void make_native_path(char *filename)
Definition: path.c:167
void get_doc_path(const char *my_exec_path, char *ret_path)
Definition: path.c:897
void get_html_path(const char *my_exec_path, char *ret_path)
Definition: path.c:906
void get_pkginclude_path(const char *my_exec_path, char *ret_path)
Definition: path.c:852
bool has_drive_prefix(const char *path)
Definition: path.c:88
void get_includeserver_path(const char *my_exec_path, char *ret_path)
Definition: path.c:861
canonicalize_state
Definition: path.c:243
@ ABSOLUTE_WITH_N_DEPTH
Definition: path.c:246
@ RELATIVE_WITH_N_DEPTH
Definition: path.c:249
@ ABSOLUTE_PATH_INIT
Definition: path.c:244
@ RELATIVE_PATH_INIT
Definition: path.c:248
@ RELATIVE_WITH_PARENT_REF
Definition: path.c:251
#define MAXPGPATH
const void size_t len
static char * argv0
Definition: pg_ctl.c:92
static char * filename
Definition: pg_dumpall.c:119
static char * buf
Definition: pg_test_fsync.c:67
#define is_absolute_path(filename)
Definition: port.h:103
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define sprintf
Definition: port.h:240
bool pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen)
Definition: user.c:64
#define strerror
Definition: port.h:251
#define snprintf
Definition: port.h:238
#define fprintf
Definition: port.h:242
unsigned char pg_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:122
#define IS_DIR_SEP(ch)
Definition: port.h:102
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define EXE
Definition: port.h:154
char * s1
char * s2
Definition: regguts.h:323