]> granicus.if.org Git - postgresql/blob - src/port/path.c
Centralize single quote escaping in src/port/quotes.c
[postgresql] / src / port / path.c
1 /*-------------------------------------------------------------------------
2  *
3  * path.c
4  *        portable path handling routines
5  *
6  * Portions Copyright (c) 1996-2013, 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 #include "c.h"
17
18 #include <ctype.h>
19 #include <sys/stat.h>
20 #ifdef WIN32
21 #ifdef _WIN32_IE
22 #undef _WIN32_IE
23 #endif
24 #define _WIN32_IE 0x0500
25 #ifdef near
26 #undef near
27 #endif
28 #define near
29 #include <shlobj.h>
30 #else
31 #include <unistd.h>
32 #endif
33
34 #include "pg_config_paths.h"
35
36
37 #ifndef WIN32
38 #define IS_PATH_VAR_SEP(ch) ((ch) == ':')
39 #else
40 #define IS_PATH_VAR_SEP(ch) ((ch) == ';')
41 #endif
42
43 static void make_relative_path(char *ret_path, const char *target_path,
44                                    const char *bin_path, const char *my_exec_path);
45 static void trim_directory(char *path);
46 static void trim_trailing_separator(char *path);
47
48
49 /*
50  * skip_drive
51  *
52  * On Windows, a path may begin with "C:" or "//network/".      Advance over
53  * this and point to the effective start of the path.
54  */
55 #ifdef WIN32
56
57 static char *
58 skip_drive(const char *path)
59 {
60         if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
61         {
62                 path += 2;
63                 while (*path && !IS_DIR_SEP(*path))
64                         path++;
65         }
66         else if (isalpha((unsigned char) path[0]) && path[1] == ':')
67         {
68                 path += 2;
69         }
70         return (char *) path;
71 }
72 #else
73
74 #define skip_drive(path)        (path)
75 #endif
76
77 /*
78  *      has_drive_prefix
79  *
80  * Return true if the given pathname has a drive prefix.
81  */
82 bool
83 has_drive_prefix(const char *path)
84 {
85         return skip_drive(path) != path;
86 }
87
88 /*
89  *      first_dir_separator
90  *
91  * Find the location of the first directory separator, return
92  * NULL if not found.
93  */
94 char *
95 first_dir_separator(const char *filename)
96 {
97         const char *p;
98
99         for (p = skip_drive(filename); *p; p++)
100                 if (IS_DIR_SEP(*p))
101                         return (char *) p;
102         return NULL;
103 }
104
105 /*
106  *      first_path_var_separator
107  *
108  * Find the location of the first path separator (i.e. ':' on
109  * Unix, ';' on Windows), return NULL if not found.
110  */
111 char *
112 first_path_var_separator(const char *pathlist)
113 {
114         const char *p;
115
116         /* skip_drive is not needed */
117         for (p = pathlist; *p; p++)
118                 if (IS_PATH_VAR_SEP(*p))
119                         return (char *) p;
120         return NULL;
121 }
122
123 /*
124  *      last_dir_separator
125  *
126  * Find the location of the last directory separator, return
127  * NULL if not found.
128  */
129 char *
130 last_dir_separator(const char *filename)
131 {
132         const char *p,
133                            *ret = NULL;
134
135         for (p = skip_drive(filename); *p; p++)
136                 if (IS_DIR_SEP(*p))
137                         ret = p;
138         return (char *) ret;
139 }
140
141
142 /*
143  *      make_native_path - on WIN32, change / to \ in the path
144  *
145  *      This effectively undoes canonicalize_path.
146  *
147  *      This is required because WIN32 COPY is an internal CMD.EXE
148  *      command and doesn't process forward slashes in the same way
149  *      as external commands.  Quoting the first argument to COPY
150  *      does not convert forward to backward slashes, but COPY does
151  *      properly process quoted forward slashes in the second argument.
152  *
153  *      COPY works with quoted forward slashes in the first argument
154  *      only if the current directory is the same as the directory
155  *      of the first argument.
156  */
157 void
158 make_native_path(char *filename)
159 {
160 #ifdef WIN32
161         char       *p;
162
163         for (p = filename; *p; p++)
164                 if (*p == '/')
165                         *p = '\\';
166 #endif
167 }
168
169
170 /*
171  * join_path_components - join two path components, inserting a slash
172  *
173  * We omit the slash if either given component is empty.
174  *
175  * ret_path is the output area (must be of size MAXPGPATH)
176  *
177  * ret_path can be the same as head, but not the same as tail.
178  */
179 void
180 join_path_components(char *ret_path,
181                                          const char *head, const char *tail)
182 {
183         if (ret_path != head)
184                 strlcpy(ret_path, head, MAXPGPATH);
185
186         /*
187          * Remove any leading "." in the tail component.
188          *
189          * Note: we used to try to remove ".." as well, but that's tricky to get
190          * right; now we just leave it to be done by canonicalize_path() later.
191          */
192         while (tail[0] == '.' && IS_DIR_SEP(tail[1]))
193                 tail += 2;
194
195         if (*tail)
196         {
197                 /* only separate with slash if head wasn't empty */
198                 snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path),
199                                  "%s%s",
200                                  (*(skip_drive(head)) != '\0') ? "/" : "",
201                                  tail);
202         }
203 }
204
205
206 /*
207  *      Clean up path by:
208  *              o  make Win32 path use Unix slashes
209  *              o  remove trailing quote on Win32
210  *              o  remove trailing slash
211  *              o  remove duplicate adjacent separators
212  *              o  remove trailing '.'
213  *              o  process trailing '..' ourselves
214  */
215 void
216 canonicalize_path(char *path)
217 {
218         char       *p,
219                            *to_p;
220         char       *spath;
221         bool            was_sep = false;
222         int                     pending_strips;
223
224 #ifdef WIN32
225
226         /*
227          * The Windows command processor will accept suitably quoted paths with
228          * forward slashes, but barfs badly with mixed forward and back slashes.
229          */
230         for (p = path; *p; p++)
231         {
232                 if (*p == '\\')
233                         *p = '/';
234         }
235
236         /*
237          * In Win32, if you do: prog.exe "a b" "\c\d\" the system will pass \c\d"
238          * as argv[2], so trim off trailing quote.
239          */
240         if (p > path && *(p - 1) == '"')
241                 *(p - 1) = '/';
242 #endif
243
244         /*
245          * Removing the trailing slash on a path means we never get ugly double
246          * trailing slashes. Also, Win32 can't stat() a directory with a trailing
247          * slash. Don't remove a leading slash, though.
248          */
249         trim_trailing_separator(path);
250
251         /*
252          * Remove duplicate adjacent separators
253          */
254         p = path;
255 #ifdef WIN32
256         /* Don't remove leading double-slash on Win32 */
257         if (*p)
258                 p++;
259 #endif
260         to_p = p;
261         for (; *p; p++, to_p++)
262         {
263                 /* Handle many adjacent slashes, like "/a///b" */
264                 while (*p == '/' && was_sep)
265                         p++;
266                 if (to_p != p)
267                         *to_p = *p;
268                 was_sep = (*p == '/');
269         }
270         *to_p = '\0';
271
272         /*
273          * Remove any trailing uses of "." and process ".." ourselves
274          *
275          * Note that "/../.." should reduce to just "/", while "../.." has to be
276          * kept as-is.  In the latter case we put back mistakenly trimmed ".."
277          * components below.  Also note that we want a Windows drive spec to be
278          * visible to trim_directory(), but it's not part of the logic that's
279          * looking at the name components; hence distinction between path and
280          * spath.
281          */
282         spath = skip_drive(path);
283         pending_strips = 0;
284         for (;;)
285         {
286                 int                     len = strlen(spath);
287
288                 if (len >= 2 && strcmp(spath + len - 2, "/.") == 0)
289                         trim_directory(path);
290                 else if (strcmp(spath, ".") == 0)
291                 {
292                         /* Want to leave "." alone, but "./.." has to become ".." */
293                         if (pending_strips > 0)
294                                 *spath = '\0';
295                         break;
296                 }
297                 else if ((len >= 3 && strcmp(spath + len - 3, "/..") == 0) ||
298                                  strcmp(spath, "..") == 0)
299                 {
300                         trim_directory(path);
301                         pending_strips++;
302                 }
303                 else if (pending_strips > 0 && *spath != '\0')
304                 {
305                         /* trim a regular directory name canceled by ".." */
306                         trim_directory(path);
307                         pending_strips--;
308                         /* foo/.. should become ".", not empty */
309                         if (*spath == '\0')
310                                 strcpy(spath, ".");
311                 }
312                 else
313                         break;
314         }
315
316         if (pending_strips > 0)
317         {
318                 /*
319                  * We could only get here if path is now totally empty (other than a
320                  * possible drive specifier on Windows). We have to put back one or
321                  * more ".."'s that we took off.
322                  */
323                 while (--pending_strips > 0)
324                         strcat(path, "../");
325                 strcat(path, "..");
326         }
327 }
328
329 /*
330  * Detect whether a path contains any parent-directory references ("..")
331  *
332  * The input *must* have been put through canonicalize_path previously.
333  *
334  * This is a bit tricky because we mustn't be fooled by "..a.." (legal)
335  * nor "C:.." (legal on Unix but not Windows).
336  */
337 bool
338 path_contains_parent_reference(const char *path)
339 {
340         int                     path_len;
341
342         path = skip_drive(path);        /* C: shouldn't affect our conclusion */
343
344         path_len = strlen(path);
345
346         /*
347          * ".." could be the whole path; otherwise, if it's present it must be at
348          * the beginning, in the middle, or at the end.
349          */
350         if (strcmp(path, "..") == 0 ||
351                 strncmp(path, "../", 3) == 0 ||
352                 strstr(path, "/../") != NULL ||
353                 (path_len >= 3 && strcmp(path + path_len - 3, "/..") == 0))
354                 return true;
355
356         return false;
357 }
358
359 /*
360  * Detect whether a path is only in or below the current working directory.
361  * An absolute path that matches the current working directory should
362  * return false (we only want relative to the cwd).  We don't allow
363  * "/../" even if that would keep us under the cwd (it is too hard to
364  * track that).
365  */
366 bool
367 path_is_relative_and_below_cwd(const char *path)
368 {
369         if (is_absolute_path(path))
370                 return false;
371         /* don't allow anything above the cwd */
372         else if (path_contains_parent_reference(path))
373                 return false;
374 #ifdef WIN32
375
376         /*
377          * On Win32, a drive letter _not_ followed by a slash, e.g. 'E:abc', is
378          * relative to the cwd on that drive, or the drive's root directory if
379          * that drive has no cwd.  Because the path itself cannot tell us which is
380          * the case, we have to assume the worst, i.e. that it is not below the
381          * cwd.  We could use GetFullPathName() to find the full path but that
382          * could change if the current directory for the drive changes underneath
383          * us, so we just disallow it.
384          */
385         else if (isalpha((unsigned char) path[0]) && path[1] == ':' &&
386                          !IS_DIR_SEP(path[2]))
387                 return false;
388 #endif
389         else
390                 return true;
391 }
392
393 /*
394  * Detect whether path1 is a prefix of path2 (including equality).
395  *
396  * This is pretty trivial, but it seems better to export a function than
397  * to export IS_DIR_SEP.
398  */
399 bool
400 path_is_prefix_of_path(const char *path1, const char *path2)
401 {
402         int                     path1_len = strlen(path1);
403
404         if (strncmp(path1, path2, path1_len) == 0 &&
405                 (IS_DIR_SEP(path2[path1_len]) || path2[path1_len] == '\0'))
406                 return true;
407         return false;
408 }
409
410 /*
411  * Extracts the actual name of the program as called -
412  * stripped of .exe suffix if any
413  */
414 const char *
415 get_progname(const char *argv0)
416 {
417         const char *nodir_name;
418         char       *progname;
419
420         nodir_name = last_dir_separator(argv0);
421         if (nodir_name)
422                 nodir_name++;
423         else
424                 nodir_name = skip_drive(argv0);
425
426         /*
427          * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
428          * called only once.
429          */
430         progname = strdup(nodir_name);
431         if (progname == NULL)
432         {
433                 fprintf(stderr, "%s: out of memory\n", nodir_name);
434                 abort();                                /* This could exit the postmaster */
435         }
436
437 #if defined(__CYGWIN__) || defined(WIN32)
438         /* strip ".exe" suffix, regardless of case */
439         if (strlen(progname) > sizeof(EXE) - 1 &&
440         pg_strcasecmp(progname + strlen(progname) - (sizeof(EXE) - 1), EXE) == 0)
441                 progname[strlen(progname) - (sizeof(EXE) - 1)] = '\0';
442 #endif
443
444         return progname;
445 }
446
447
448 /*
449  * dir_strcmp: strcmp except any two DIR_SEP characters are considered equal,
450  * and we honor filesystem case insensitivity if known
451  */
452 static int
453 dir_strcmp(const char *s1, const char *s2)
454 {
455         while (*s1 && *s2)
456         {
457                 if (
458 #ifndef WIN32
459                         *s1 != *s2
460 #else
461                 /* On windows, paths are case-insensitive */
462                         pg_tolower((unsigned char) *s1) != pg_tolower((unsigned char) *s2)
463 #endif
464                         && !(IS_DIR_SEP(*s1) && IS_DIR_SEP(*s2)))
465                         return (int) *s1 - (int) *s2;
466                 s1++, s2++;
467         }
468         if (*s1)
469                 return 1;                               /* s1 longer */
470         if (*s2)
471                 return -1;                              /* s2 longer */
472         return 0;
473 }
474
475
476 /*
477  * make_relative_path - make a path relative to the actual binary location
478  *
479  * This function exists to support relocation of installation trees.
480  *
481  *      ret_path is the output area (must be of size MAXPGPATH)
482  *      target_path is the compiled-in path to the directory we want to find
483  *      bin_path is the compiled-in path to the directory of executables
484  *      my_exec_path is the actual location of my executable
485  *
486  * We determine the common prefix of target_path and bin_path, then compare
487  * the remainder of bin_path to the last directory component(s) of
488  * my_exec_path.  If they match, build the result as the part of my_exec_path
489  * preceding the match, joined to the remainder of target_path.  If no match,
490  * return target_path as-is.
491  *
492  * For example:
493  *              target_path  = '/usr/local/share/postgresql'
494  *              bin_path         = '/usr/local/bin'
495  *              my_exec_path = '/opt/pgsql/bin/postmaster'
496  * Given these inputs, the common prefix is '/usr/local/', the tail of
497  * bin_path is 'bin' which does match the last directory component of
498  * my_exec_path, so we would return '/opt/pgsql/share/postgresql'
499  */
500 static void
501 make_relative_path(char *ret_path, const char *target_path,
502                                    const char *bin_path, const char *my_exec_path)
503 {
504         int                     prefix_len;
505         int                     tail_start;
506         int                     tail_len;
507         int                     i;
508
509         /*
510          * Determine the common prefix --- note we require it to end on a
511          * directory separator, consider eg '/usr/lib' and '/usr/libexec'.
512          */
513         prefix_len = 0;
514         for (i = 0; target_path[i] && bin_path[i]; i++)
515         {
516                 if (IS_DIR_SEP(target_path[i]) && IS_DIR_SEP(bin_path[i]))
517                         prefix_len = i + 1;
518                 else if (target_path[i] != bin_path[i])
519                         break;
520         }
521         if (prefix_len == 0)
522                 goto no_match;                  /* no common prefix? */
523         tail_len = strlen(bin_path) - prefix_len;
524
525         /*
526          * Set up my_exec_path without the actual executable name, and
527          * canonicalize to simplify comparison to bin_path.
528          */
529         strlcpy(ret_path, my_exec_path, MAXPGPATH);
530         trim_directory(ret_path);       /* remove my executable name */
531         canonicalize_path(ret_path);
532
533         /*
534          * Tail match?
535          */
536         tail_start = (int) strlen(ret_path) - tail_len;
537         if (tail_start > 0 &&
538                 IS_DIR_SEP(ret_path[tail_start - 1]) &&
539                 dir_strcmp(ret_path + tail_start, bin_path + prefix_len) == 0)
540         {
541                 ret_path[tail_start] = '\0';
542                 trim_trailing_separator(ret_path);
543                 join_path_components(ret_path, ret_path, target_path + prefix_len);
544                 canonicalize_path(ret_path);
545                 return;
546         }
547
548 no_match:
549         strlcpy(ret_path, target_path, MAXPGPATH);
550         canonicalize_path(ret_path);
551 }
552
553
554 /*
555  *      get_share_path
556  */
557 void
558 get_share_path(const char *my_exec_path, char *ret_path)
559 {
560         make_relative_path(ret_path, PGSHAREDIR, PGBINDIR, my_exec_path);
561 }
562
563 /*
564  *      get_etc_path
565  */
566 void
567 get_etc_path(const char *my_exec_path, char *ret_path)
568 {
569         make_relative_path(ret_path, SYSCONFDIR, PGBINDIR, my_exec_path);
570 }
571
572 /*
573  *      get_include_path
574  */
575 void
576 get_include_path(const char *my_exec_path, char *ret_path)
577 {
578         make_relative_path(ret_path, INCLUDEDIR, PGBINDIR, my_exec_path);
579 }
580
581 /*
582  *      get_pkginclude_path
583  */
584 void
585 get_pkginclude_path(const char *my_exec_path, char *ret_path)
586 {
587         make_relative_path(ret_path, PKGINCLUDEDIR, PGBINDIR, my_exec_path);
588 }
589
590 /*
591  *      get_includeserver_path
592  */
593 void
594 get_includeserver_path(const char *my_exec_path, char *ret_path)
595 {
596         make_relative_path(ret_path, INCLUDEDIRSERVER, PGBINDIR, my_exec_path);
597 }
598
599 /*
600  *      get_lib_path
601  */
602 void
603 get_lib_path(const char *my_exec_path, char *ret_path)
604 {
605         make_relative_path(ret_path, LIBDIR, PGBINDIR, my_exec_path);
606 }
607
608 /*
609  *      get_pkglib_path
610  */
611 void
612 get_pkglib_path(const char *my_exec_path, char *ret_path)
613 {
614         make_relative_path(ret_path, PKGLIBDIR, PGBINDIR, my_exec_path);
615 }
616
617 /*
618  *      get_locale_path
619  */
620 void
621 get_locale_path(const char *my_exec_path, char *ret_path)
622 {
623         make_relative_path(ret_path, LOCALEDIR, PGBINDIR, my_exec_path);
624 }
625
626 /*
627  *      get_doc_path
628  */
629 void
630 get_doc_path(const char *my_exec_path, char *ret_path)
631 {
632         make_relative_path(ret_path, DOCDIR, PGBINDIR, my_exec_path);
633 }
634
635 /*
636  *      get_html_path
637  */
638 void
639 get_html_path(const char *my_exec_path, char *ret_path)
640 {
641         make_relative_path(ret_path, HTMLDIR, PGBINDIR, my_exec_path);
642 }
643
644 /*
645  *      get_man_path
646  */
647 void
648 get_man_path(const char *my_exec_path, char *ret_path)
649 {
650         make_relative_path(ret_path, MANDIR, PGBINDIR, my_exec_path);
651 }
652
653
654 /*
655  *      get_home_path
656  *
657  * On Unix, this actually returns the user's home directory.  On Windows
658  * it returns the PostgreSQL-specific application data folder.
659  */
660 bool
661 get_home_path(char *ret_path)
662 {
663 #ifndef WIN32
664         char            pwdbuf[BUFSIZ];
665         struct passwd pwdstr;
666         struct passwd *pwd = NULL;
667
668         if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
669                 return false;
670         strlcpy(ret_path, pwd->pw_dir, MAXPGPATH);
671         return true;
672 #else
673         char       *tmppath;
674
675         /*
676          * Note: We use getenv here because the more modern
677          * SHGetSpecialFolderPath() will force us to link with shell32.lib which
678          * eats valuable desktop heap.
679          */
680         tmppath = getenv("APPDATA");
681         if (!tmppath)
682                 return false;
683         snprintf(ret_path, MAXPGPATH, "%s/postgresql", tmppath);
684         return true;
685 #endif
686 }
687
688
689 /*
690  * get_parent_directory
691  *
692  * Modify the given string in-place to name the parent directory of the
693  * named file.
694  *
695  * If the input is just a file name with no directory part, the result is
696  * an empty string, not ".".  This is appropriate when the next step is
697  * join_path_components(), but might need special handling otherwise.
698  *
699  * Caution: this will not produce desirable results if the string ends
700  * with "..".  For most callers this is not a problem since the string
701  * is already known to name a regular file.  If in doubt, apply
702  * canonicalize_path() first.
703  */
704 void
705 get_parent_directory(char *path)
706 {
707         trim_directory(path);
708 }
709
710
711 /*
712  *      trim_directory
713  *
714  *      Trim trailing directory from path, that is, remove any trailing slashes,
715  *      the last pathname component, and the slash just ahead of it --- but never
716  *      remove a leading slash.
717  */
718 static void
719 trim_directory(char *path)
720 {
721         char       *p;
722
723         path = skip_drive(path);
724
725         if (path[0] == '\0')
726                 return;
727
728         /* back up over trailing slash(es) */
729         for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--)
730                 ;
731         /* back up over directory name */
732         for (; !IS_DIR_SEP(*p) && p > path; p--)
733                 ;
734         /* if multiple slashes before directory name, remove 'em all */
735         for (; p > path && IS_DIR_SEP(*(p - 1)); p--)
736                 ;
737         /* don't erase a leading slash */
738         if (p == path && IS_DIR_SEP(*p))
739                 p++;
740         *p = '\0';
741 }
742
743
744 /*
745  *      trim_trailing_separator
746  *
747  * trim off trailing slashes, but not a leading slash
748  */
749 static void
750 trim_trailing_separator(char *path)
751 {
752         char       *p;
753
754         path = skip_drive(path);
755         p = path + strlen(path);
756         if (p > path)
757                 for (p--; p > path && IS_DIR_SEP(*p); p--)
758                         *p = '\0';
759 }