4 * $Header: /cvsroot/pgpool/pgpool-II/pool_path.c,v 1.2.2.1 2009/08/22 04:19:49 t-ishii Exp $
6 * pgpool: a language independent connection pool server for PostgreSQL
7 * written by Tatsuo Ishii
9 * Portions Copyright (c) 2003-2008, PgPool Global Development Group
10 * Portions Copyright (c) 2004, PostgreSQL Global Development Group
12 * Permission to use, copy, modify, and distribute this software and
13 * its documentation for any purpose and without fee is hereby
14 * granted, provided that the above copyright notice appear in all
15 * copies and that both that copyright notice and this permission
16 * notice appear in supporting documentation, and that the name of the
17 * author not be used in advertising or publicity pertaining to
18 * distribution of the software without specific, written prior
19 * permission. The author makes no representations about the
20 * suitability of this software for any purpose. It is provided "as
21 * is" without express or implied warranty.
23 * pool_path.c.: small functions to manipulate paths
27 #include "pool_type.h"
28 #include "pool_path.h"
32 static void trim_directory(char *path);
33 static void trim_trailing_separator(char *path);
36 * get_parent_directory
38 * Modify the given string in-place to name the parent directory of the
41 void get_parent_directory(char *path)
50 * Trim trailing directory from path, that is, remove any trailing slashes,
51 * the last pathname component, and the slash just ahead of it --- but never
52 * remove a leading slash.
54 static void trim_directory(char *path)
61 /* back up over trailing slash(es) */
62 for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--);
64 /* back up over directory name */
65 for (; !IS_DIR_SEP(*p) && p > path; p--);
67 /* if multiple slashes before directory name, remove 'em all */
68 for (; p > path && IS_DIR_SEP(*(p - 1)); p--);
70 /* don't erase a leading slash */
71 if (p == path && IS_DIR_SEP(*p))
79 * join_path_components - join two path components, inserting a slash
81 * ret_path is the output area (must be of size MAXPGPATH)
83 * ret_path can be the same as head, but not the same as tail.
85 void join_path_components(char *ret_path, const char *head, const char *tail)
88 StrNCpy(ret_path, head, MAXPGPATH);
91 * Remove any leading "." and ".." in the tail component,
92 * adjusting head as needed.
96 if (tail[0] == '.' && IS_DIR_SEP(tail[1]))
100 else if (tail[0] == '.' && tail[1] == '\0')
105 else if (tail[0] == '.' && tail[1] == '.' && IS_DIR_SEP(tail[2]))
107 trim_directory(ret_path);
110 else if (tail[0] == '.' && tail[1] == '.' && tail[2] == '\0')
112 trim_directory(ret_path);
121 snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path), "/%s", tail);
127 * o remove trailing slash
128 * o remove duplicate adjacent separators
129 * o remove trailing '.'
130 * o process trailing '..' ourselves
132 void canonicalize_path(char *path)
135 bool was_sep = false;
138 * Removing the trailing slash on a path means we never get ugly
139 * double trailing slashes.
141 trim_trailing_separator(path);
144 * Remove duplicate adjacent separators
148 for (; *p; p++, to_p++)
150 /* Handle many adjacent slashes, like "/a///b" */
151 while (*p == '/' && was_sep)
155 was_sep = (*p == '/');
160 * Remove any trailing uses of "." and process ".." ourselves
164 int len = strlen(path);
166 if (len > 2 && strcmp(path + len - 2, "/.") == 0)
167 trim_directory(path);
168 else if (len > 3 && strcmp(path + len - 3, "/..") == 0)
170 trim_directory(path);
171 trim_directory(path);
172 /* remove directory above */
181 * trim_trailing_separator
183 * trim off trailing slashes, but not a leading slash
185 static void trim_trailing_separator(char *path)
189 p = path + strlen(path);
191 for (p--; p > path && IS_DIR_SEP(*p); p--)