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