1 /*-------------------------------------------------------------------------
4 * portable path handling routines
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
19 #include "postgres_fe.h"
28 #define _WIN32_IE 0x0500
39 #include "pg_config_paths.h"
43 #define IS_PATH_VAR_SEP(ch) ((ch) == ':')
45 #define IS_PATH_VAR_SEP(ch) ((ch) == ';')
48 static void make_relative_path(char *ret_path
, const char *target_path
,
49 const char *bin_path
, const char *my_exec_path
);
50 static char *trim_directory(char *path
);
51 static void trim_trailing_separator(char *path
);
52 static char *append_subdir_to_path(char *path
, char *subdir
);
58 * On Windows, a path may begin with "C:" or "//network/". Advance over
59 * this and point to the effective start of the path.
64 skip_drive(const char *path
)
66 if (IS_DIR_SEP(path
[0]) && IS_DIR_SEP(path
[1]))
69 while (*path
&& !IS_DIR_SEP(*path
))
72 else if (isalpha((unsigned char) path
[0]) && path
[1] == ':')
80 #define skip_drive(path) (path)
86 * Return true if the given pathname has a drive prefix.
89 has_drive_prefix(const char *path
)
92 return skip_drive(path
) != path
;
101 * Find the location of the first directory separator, return
105 first_dir_separator(const char *filename
)
109 for (p
= skip_drive(filename
); *p
; p
++)
111 return unconstify(char *, p
);
116 * first_path_var_separator
118 * Find the location of the first path separator (i.e. ':' on
119 * Unix, ';' on Windows), return NULL if not found.
122 first_path_var_separator(const char *pathlist
)
126 /* skip_drive is not needed */
127 for (p
= pathlist
; *p
; p
++)
128 if (IS_PATH_VAR_SEP(*p
))
129 return unconstify(char *, p
);
136 * Find the location of the last directory separator, return
140 last_dir_separator(const char *filename
)
145 for (p
= skip_drive(filename
); *p
; p
++)
148 return unconstify(char *, ret
);
153 * make_native_path - on WIN32, change / to \ in the path
155 * This effectively undoes canonicalize_path.
157 * This is required because WIN32 COPY is an internal CMD.EXE
158 * command and doesn't process forward slashes in the same way
159 * as external commands. Quoting the first argument to COPY
160 * does not convert forward to backward slashes, but COPY does
161 * properly process quoted forward slashes in the second argument.
163 * COPY works with quoted forward slashes in the first argument
164 * only if the current directory is the same as the directory
165 * of the first argument.
168 make_native_path(char *filename
)
173 for (p
= filename
; *p
; p
++)
181 * This function cleans up the paths for use with either cmd.exe or Msys
182 * on Windows. We need them to use filenames without spaces, for which a
183 * short filename is the safest equivalent, eg:
187 cleanup_path(char *path
)
193 * GetShortPathName() will fail if the path does not exist, or short names
194 * are disabled on this file system. In both cases, we just return the
195 * original path. This is particularly useful for --sysconfdir, which
198 GetShortPathName(path
, path
, MAXPGPATH
- 1);
200 /* Replace '\' with '/' */
201 for (ptr
= path
; *ptr
; ptr
++)
211 * join_path_components - join two path components, inserting a slash
213 * We omit the slash if either given component is empty.
215 * ret_path is the output area (must be of size MAXPGPATH)
217 * ret_path can be the same as head, but not the same as tail.
220 join_path_components(char *ret_path
,
221 const char *head
, const char *tail
)
223 if (ret_path
!= head
)
224 strlcpy(ret_path
, head
, MAXPGPATH
);
227 * We used to try to simplify some cases involving "." and "..", but now
228 * we just leave that to be done by canonicalize_path() later.
233 /* only separate with slash if head wasn't empty */
234 snprintf(ret_path
+ strlen(ret_path
), MAXPGPATH
- strlen(ret_path
),
236 (*(skip_drive(head
)) != '\0') ? "/" : "",
242 /* State-machine states for canonicalize_path */
245 ABSOLUTE_PATH_INIT
, /* Just past the leading '/' (and Windows
246 * drive name if any) of an absolute path */
247 ABSOLUTE_WITH_N_DEPTH
, /* We collected 'pathdepth' directories in an
249 RELATIVE_PATH_INIT
, /* At start of a relative path */
250 RELATIVE_WITH_N_DEPTH
, /* We collected 'pathdepth' directories in a
252 RELATIVE_WITH_PARENT_REF
, /* Relative path containing only double-dots */
253 } canonicalize_state
;
257 * o make Win32 path use Unix slashes
258 * o remove trailing quote on Win32
259 * o remove trailing slash
260 * o remove duplicate (adjacent) separators
261 * o remove '.' (unless path reduces to only '.')
262 * o process '..' ourselves, removing it if possible
265 canonicalize_path(char *path
)
272 bool was_sep
= false;
273 canonicalize_state state
;
274 int pathdepth
= 0; /* counts collected regular directory names */
279 * The Windows command processor will accept suitably quoted paths with
280 * forward slashes, but barfs badly with mixed forward and back slashes.
282 for (p
= path
; *p
; p
++)
289 * In Win32, if you do: prog.exe "a b" "\c\d\" the system will pass \c\d"
290 * as argv[2], so trim off trailing quote.
292 if (p
> path
&& *(p
- 1) == '"')
297 * Removing the trailing slash on a path means we never get ugly double
298 * trailing slashes. Also, Win32 can't stat() a directory with a trailing
299 * slash. Don't remove a leading slash, though.
301 trim_trailing_separator(path
);
304 * Remove duplicate adjacent separators
308 /* Don't remove leading double-slash on Win32 */
313 for (; *p
; p
++, to_p
++)
315 /* Handle many adjacent slashes, like "/a///b" */
316 while (*p
== '/' && was_sep
)
320 was_sep
= (*p
== '/');
325 * Remove any uses of "." and process ".." ourselves
327 * Note that "/../.." should reduce to just "/", while "../.." has to be
328 * kept as-is. Also note that we want a Windows drive spec to be visible
329 * to trim_directory(), but it's not part of the logic that's looking at
330 * the name components; hence distinction between path and spath.
332 * This loop overwrites the path in-place. This is safe since we'll never
333 * make the path longer. "unparse" points to where we are reading the
334 * path, "parse" to where we are writing.
336 spath
= skip_drive(path
);
338 return; /* empty path is returned as-is */
342 state
= ABSOLUTE_PATH_INIT
;
343 /* Skip the leading slash for absolute path */
344 parsed
= unparse
= (spath
+ 1);
348 state
= RELATIVE_PATH_INIT
;
349 parsed
= unparse
= spath
;
352 while (*unparse
!= '\0')
357 /* Split off this dir name, and set unparse_next to the next one */
358 unparse_next
= unparse
;
359 while (*unparse_next
&& *unparse_next
!= '/')
361 if (*unparse_next
!= '\0')
362 *unparse_next
++ = '\0';
364 /* Identify type of this dir name */
365 if (strcmp(unparse
, ".") == 0)
367 /* We can ignore "." components in all cases */
368 unparse
= unparse_next
;
372 if (strcmp(unparse
, "..") == 0)
373 is_double_dot
= true;
376 /* adjacent separators were eliminated above */
377 Assert(*unparse
!= '\0');
378 is_double_dot
= false;
383 case ABSOLUTE_PATH_INIT
:
384 /* We can ignore ".." immediately after / */
387 /* Append first dir name (we already have leading slash) */
388 parsed
= append_subdir_to_path(parsed
, unparse
);
389 state
= ABSOLUTE_WITH_N_DEPTH
;
393 case ABSOLUTE_WITH_N_DEPTH
:
396 /* Remove last parsed dir */
397 /* (trim_directory won't remove the leading slash) */
399 parsed
= trim_directory(path
);
400 if (--pathdepth
== 0)
401 state
= ABSOLUTE_PATH_INIT
;
405 /* Append normal dir */
407 parsed
= append_subdir_to_path(parsed
, unparse
);
411 case RELATIVE_PATH_INIT
:
414 /* Append irreducible double-dot (..) */
415 parsed
= append_subdir_to_path(parsed
, unparse
);
416 state
= RELATIVE_WITH_PARENT_REF
;
420 /* Append normal dir */
421 parsed
= append_subdir_to_path(parsed
, unparse
);
422 state
= RELATIVE_WITH_N_DEPTH
;
426 case RELATIVE_WITH_N_DEPTH
:
429 /* Remove last parsed dir */
431 parsed
= trim_directory(path
);
432 if (--pathdepth
== 0)
435 * If the output path is now empty, we're back to the
436 * INIT state. However, we could have processed a
437 * path like "../dir/.." and now be down to "..", in
438 * which case enter the correct state for that.
441 state
= RELATIVE_PATH_INIT
;
443 state
= RELATIVE_WITH_PARENT_REF
;
448 /* Append normal dir */
450 parsed
= append_subdir_to_path(parsed
, unparse
);
454 case RELATIVE_WITH_PARENT_REF
:
457 /* Append next irreducible double-dot (..) */
459 parsed
= append_subdir_to_path(parsed
, unparse
);
463 /* Append normal dir */
465 parsed
= append_subdir_to_path(parsed
, unparse
);
468 * We can now start counting normal dirs. But if later
469 * double-dots make us remove this dir again, we'd better
470 * revert to RELATIVE_WITH_PARENT_REF not INIT state.
472 state
= RELATIVE_WITH_N_DEPTH
;
478 unparse
= unparse_next
;
482 * If our output path is empty at this point, insert ".". We don't want
483 * to do this any earlier because it'd result in an extra dot in corner
484 * cases such as "../dir/..". Since we rejected the wholly-empty-path
485 * case above, there is certainly room.
490 /* And finally, ensure the output path is nul-terminated. */
495 * Detect whether a path contains any parent-directory references ("..")
497 * The input *must* have been put through canonicalize_path previously.
500 path_contains_parent_reference(const char *path
)
503 * Once canonicalized, an absolute path cannot contain any ".." at all,
504 * while a relative path could contain ".."(s) only at the start. So it
505 * is sufficient to check the start of the path, after skipping any
506 * Windows drive/network specifier.
508 path
= skip_drive(path
); /* C: shouldn't affect our conclusion */
510 if (path
[0] == '.' &&
512 (path
[2] == '\0' || path
[2] == '/'))
519 * Detect whether a path is only in or below the current working directory.
521 * The input *must* have been put through canonicalize_path previously.
523 * An absolute path that matches the current working directory should
524 * return false (we only want relative to the cwd).
527 path_is_relative_and_below_cwd(const char *path
)
529 if (is_absolute_path(path
))
531 /* don't allow anything above the cwd */
532 else if (path_contains_parent_reference(path
))
537 * On Win32, a drive letter _not_ followed by a slash, e.g. 'E:abc', is
538 * relative to the cwd on that drive, or the drive's root directory if
539 * that drive has no cwd. Because the path itself cannot tell us which is
540 * the case, we have to assume the worst, i.e. that it is not below the
541 * cwd. We could use GetFullPathName() to find the full path but that
542 * could change if the current directory for the drive changes underneath
543 * us, so we just disallow it.
545 else if (isalpha((unsigned char) path
[0]) && path
[1] == ':' &&
546 !IS_DIR_SEP(path
[2]))
554 * Detect whether path1 is a prefix of path2 (including equality).
556 * This is pretty trivial, but it seems better to export a function than
557 * to export IS_DIR_SEP.
560 path_is_prefix_of_path(const char *path1
, const char *path2
)
562 int path1_len
= strlen(path1
);
564 if (strncmp(path1
, path2
, path1_len
) == 0 &&
565 (IS_DIR_SEP(path2
[path1_len
]) || path2
[path1_len
] == '\0'))
571 * Extracts the actual name of the program as called -
572 * stripped of .exe suffix if any
575 get_progname(const char *argv0
)
577 const char *nodir_name
;
580 nodir_name
= last_dir_separator(argv0
);
584 nodir_name
= skip_drive(argv0
);
587 * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
590 progname
= strdup(nodir_name
);
591 if (progname
== NULL
)
593 fprintf(stderr
, "%s: out of memory\n", nodir_name
);
594 abort(); /* This could exit the postmaster */
597 #if defined(__CYGWIN__) || defined(WIN32)
598 /* strip ".exe" suffix, regardless of case */
599 if (strlen(progname
) > sizeof(EXE
) - 1 &&
600 pg_strcasecmp(progname
+ strlen(progname
) - (sizeof(EXE
) - 1), EXE
) == 0)
601 progname
[strlen(progname
) - (sizeof(EXE
) - 1)] = '\0';
609 * dir_strcmp: strcmp except any two DIR_SEP characters are considered equal,
610 * and we honor filesystem case insensitivity if known
613 dir_strcmp(const char *s1
, const char *s2
)
621 /* On windows, paths are case-insensitive */
622 pg_tolower((unsigned char) *s1
) != pg_tolower((unsigned char) *s2
)
624 && !(IS_DIR_SEP(*s1
) && IS_DIR_SEP(*s2
)))
625 return (int) *s1
- (int) *s2
;
629 return 1; /* s1 longer */
631 return -1; /* s2 longer */
637 * make_relative_path - make a path relative to the actual binary location
639 * This function exists to support relocation of installation trees.
641 * ret_path is the output area (must be of size MAXPGPATH)
642 * target_path is the compiled-in path to the directory we want to find
643 * bin_path is the compiled-in path to the directory of executables
644 * my_exec_path is the actual location of my executable
646 * We determine the common prefix of target_path and bin_path, then compare
647 * the remainder of bin_path to the last directory component(s) of
648 * my_exec_path. If they match, build the result as the part of my_exec_path
649 * preceding the match, joined to the remainder of target_path. If no match,
650 * return target_path as-is.
653 * target_path = '/usr/local/share/postgresql'
654 * bin_path = '/usr/local/bin'
655 * my_exec_path = '/opt/pgsql/bin/postgres'
656 * Given these inputs, the common prefix is '/usr/local/', the tail of
657 * bin_path is 'bin' which does match the last directory component of
658 * my_exec_path, so we would return '/opt/pgsql/share/postgresql'
661 make_relative_path(char *ret_path
, const char *target_path
,
662 const char *bin_path
, const char *my_exec_path
)
670 * Determine the common prefix --- note we require it to end on a
671 * directory separator, consider eg '/usr/lib' and '/usr/libexec'.
674 for (i
= 0; target_path
[i
] && bin_path
[i
]; i
++)
676 if (IS_DIR_SEP(target_path
[i
]) && IS_DIR_SEP(bin_path
[i
]))
678 else if (target_path
[i
] != bin_path
[i
])
682 goto no_match
; /* no common prefix? */
683 tail_len
= strlen(bin_path
) - prefix_len
;
686 * Set up my_exec_path without the actual executable name, and
687 * canonicalize to simplify comparison to bin_path.
689 strlcpy(ret_path
, my_exec_path
, MAXPGPATH
);
690 trim_directory(ret_path
); /* remove my executable name */
691 canonicalize_path(ret_path
);
696 tail_start
= (int) strlen(ret_path
) - tail_len
;
697 if (tail_start
> 0 &&
698 IS_DIR_SEP(ret_path
[tail_start
- 1]) &&
699 dir_strcmp(ret_path
+ tail_start
, bin_path
+ prefix_len
) == 0)
701 ret_path
[tail_start
] = '\0';
702 trim_trailing_separator(ret_path
);
703 join_path_components(ret_path
, ret_path
, target_path
+ prefix_len
);
704 canonicalize_path(ret_path
);
709 strlcpy(ret_path
, target_path
, MAXPGPATH
);
710 canonicalize_path(ret_path
);
717 * If the given pathname isn't already absolute, make it so, interpreting
718 * it relative to the current working directory.
720 * Also canonicalizes the path. The result is always a malloc'd copy.
722 * In backend, failure cases result in ereport(ERROR); in frontend,
723 * we write a complaint on stderr and return NULL.
725 * Note: interpretation of relative-path arguments during postmaster startup
726 * should happen before doing ChangeToDataDir(), else the user will probably
727 * not like the results.
730 make_absolute_path(const char *path
)
734 /* Returning null for null input is convenient for some callers */
738 if (!is_absolute_path(path
))
746 buf
= malloc(buflen
);
751 (errcode(ERRCODE_OUT_OF_MEMORY
),
752 errmsg("out of memory")));
754 fprintf(stderr
, _("out of memory\n"));
759 if (getcwd(buf
, buflen
))
761 else if (errno
== ERANGE
)
769 int save_errno
= errno
;
774 elog(ERROR
, "could not get current working directory: %m");
776 fprintf(stderr
, _("could not get current working directory: %m\n"));
782 new = malloc(strlen(buf
) + strlen(path
) + 2);
788 (errcode(ERRCODE_OUT_OF_MEMORY
),
789 errmsg("out of memory")));
791 fprintf(stderr
, _("out of memory\n"));
795 sprintf(new, "%s/%s", buf
, path
);
805 (errcode(ERRCODE_OUT_OF_MEMORY
),
806 errmsg("out of memory")));
808 fprintf(stderr
, _("out of memory\n"));
814 /* Make sure punctuation is canonical, too */
815 canonicalize_path(new);
825 get_share_path(const char *my_exec_path
, char *ret_path
)
827 make_relative_path(ret_path
, PGSHAREDIR
, PGBINDIR
, my_exec_path
);
834 get_etc_path(const char *my_exec_path
, char *ret_path
)
836 make_relative_path(ret_path
, SYSCONFDIR
, PGBINDIR
, my_exec_path
);
843 get_include_path(const char *my_exec_path
, char *ret_path
)
845 make_relative_path(ret_path
, INCLUDEDIR
, PGBINDIR
, my_exec_path
);
849 * get_pkginclude_path
852 get_pkginclude_path(const char *my_exec_path
, char *ret_path
)
854 make_relative_path(ret_path
, PKGINCLUDEDIR
, PGBINDIR
, my_exec_path
);
858 * get_includeserver_path
861 get_includeserver_path(const char *my_exec_path
, char *ret_path
)
863 make_relative_path(ret_path
, INCLUDEDIRSERVER
, PGBINDIR
, my_exec_path
);
870 get_lib_path(const char *my_exec_path
, char *ret_path
)
872 make_relative_path(ret_path
, LIBDIR
, PGBINDIR
, my_exec_path
);
879 get_pkglib_path(const char *my_exec_path
, char *ret_path
)
881 make_relative_path(ret_path
, PKGLIBDIR
, PGBINDIR
, my_exec_path
);
888 get_locale_path(const char *my_exec_path
, char *ret_path
)
890 make_relative_path(ret_path
, LOCALEDIR
, PGBINDIR
, my_exec_path
);
897 get_doc_path(const char *my_exec_path
, char *ret_path
)
899 make_relative_path(ret_path
, DOCDIR
, PGBINDIR
, my_exec_path
);
906 get_html_path(const char *my_exec_path
, char *ret_path
)
908 make_relative_path(ret_path
, HTMLDIR
, PGBINDIR
, my_exec_path
);
915 get_man_path(const char *my_exec_path
, char *ret_path
)
917 make_relative_path(ret_path
, MANDIR
, PGBINDIR
, my_exec_path
);
924 * On Unix, this actually returns the user's home directory. On Windows
925 * it returns the PostgreSQL-specific application data folder.
928 get_home_path(char *ret_path
)
932 * We first consult $HOME. If that's unset, try to get the info from
937 home
= getenv("HOME");
940 strlcpy(ret_path
, home
, MAXPGPATH
);
950 rc
= getpwuid_r(geteuid(), &pwbuf
, buf
, sizeof buf
, &pw
);
953 strlcpy(ret_path
, pw
->pw_dir
, MAXPGPATH
);
960 * Note: We use getenv() here because the more modern SHGetFolderPath()
961 * would force the backend to link with shell32.lib, which eats valuable
962 * desktop heap. XXX This function is used only in psql, which already
963 * brings in shell32 via libpq. Moving this function to its own file
964 * would keep it out of the backend, freeing it from this concern.
966 tmppath
= getenv("APPDATA");
969 snprintf(ret_path
, MAXPGPATH
, "%s/postgresql", tmppath
);
976 * get_parent_directory
978 * Modify the given string in-place to name the parent directory of the
981 * If the input is just a file name with no directory part, the result is
982 * an empty string, not ".". This is appropriate when the next step is
983 * join_path_components(), but might need special handling otherwise.
985 * Caution: this will not produce desirable results if the string ends
986 * with "..". For most callers this is not a problem since the string
987 * is already known to name a regular file. If in doubt, apply
988 * canonicalize_path() first.
991 get_parent_directory(char *path
)
993 trim_directory(path
);
1000 * Trim trailing directory from path, that is, remove any trailing slashes,
1001 * the last pathname component, and the slash just ahead of it --- but never
1002 * remove a leading slash.
1004 * For the convenience of canonicalize_path, the path's new end location
1008 trim_directory(char *path
)
1012 path
= skip_drive(path
);
1014 if (path
[0] == '\0')
1017 /* back up over trailing slash(es) */
1018 for (p
= path
+ strlen(path
) - 1; IS_DIR_SEP(*p
) && p
> path
; p
--)
1020 /* back up over directory name */
1021 for (; !IS_DIR_SEP(*p
) && p
> path
; p
--)
1023 /* if multiple slashes before directory name, remove 'em all */
1024 for (; p
> path
&& IS_DIR_SEP(*(p
- 1)); p
--)
1026 /* don't erase a leading slash */
1027 if (p
== path
&& IS_DIR_SEP(*p
))
1035 * trim_trailing_separator
1037 * trim off trailing slashes, but not a leading slash
1040 trim_trailing_separator(char *path
)
1044 path
= skip_drive(path
);
1045 p
= path
+ strlen(path
);
1047 for (p
--; p
> path
&& IS_DIR_SEP(*p
); p
--)
1052 * append_subdir_to_path
1054 * Append the currently-considered subdirectory name to the output
1055 * path in canonicalize_path. Return the new end location of the
1058 * Since canonicalize_path updates the path in-place, we must use
1059 * memmove not memcpy, and we don't yet terminate the path with '\0'.
1062 append_subdir_to_path(char *path
, char *subdir
)
1064 size_t len
= strlen(subdir
);
1066 /* No need to copy data if path and subdir are the same. */
1068 memmove(path
, subdir
, len
);