1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24 * Glenn Fowler
25 * AT&T Research
26 *
27 * in-place path name canonicalization -- preserves the logical view
28 * pointer to trailing 0 in path returned
29 *
30 * remove redundant .'s and /'s
31 * move ..'s to the front
32 * /.. preserved (for pdu and newcastle hacks)
33 * FS_3D handles ...
34 * if (flags&PATH_PHYSICAL) then symlinks resolved at each component
35 * if (flags&PATH_DOTDOT) then each .. checked for access
36 * if (flags&PATH_EXISTS) then path must exist at each component
37 * if (flags&PATH_VERIFIED(n)) then first n chars of path exist
38 *
39 * longer pathname possible if (flags&PATH_PHYSICAL) or FS_3D ... involved
40 * 0 returned on error and if (flags&(PATH_DOTDOT|PATH_EXISTS)) then path
41 * will contain the components following the failure point
42 */
43
44 #define _AST_API_H 1
45
46 #include <ast.h>
47 #include <ls.h>
48 #include <fs3d.h>
49 #include <error.h>
50
51 char*
pathcanon(char * path,int flags)52 pathcanon(char* path, int flags)
53 {
54 return pathcanon_20100601(path, PATH_MAX, flags);
55 }
56
57 #undef _AST_API_H
58
59 #include <ast_api.h>
60
61 char*
pathcanon_20100601(char * path,size_t size,int flags)62 pathcanon_20100601(char* path, size_t size, int flags)
63 {
64 register char* p;
65 register char* r;
66 register char* s;
67 register char* t;
68 register int dots;
69 char* phys;
70 char* v;
71 int loop;
72 int oerrno;
73 #if defined(FS_3D)
74 long visits = 0;
75 #endif
76
77 oerrno = errno;
78 dots = loop = 0;
79 phys = path;
80 v = path + ((flags >> 5) & 01777);
81 if (!size)
82 size = strlen(path) + 1;
83 if (*path == '/')
84 {
85 if (*(path + 1) == '/' && *astconf("PATH_LEADING_SLASHES", NiL, NiL) == '1')
86 do path++; while (*path == '/' && *(path + 1) == '/');
87 if (!*(path + 1))
88 return path + 1;
89 }
90 p = r = s = t = path;
91 for (;;)
92 switch (*t++ = *s++)
93 {
94 case '.':
95 dots++;
96 break;
97 case 0:
98 s--;
99 /*FALLTHROUGH*/
100 case '/':
101 while (*s == '/') s++;
102 switch (dots)
103 {
104 case 1:
105 t -= 2;
106 break;
107 case 2:
108 if ((flags & (PATH_DOTDOT|PATH_EXISTS)) == PATH_DOTDOT && (t - 2) >= v)
109 {
110 struct stat st;
111
112 *(t - 2) = 0;
113 if (stat(phys, &st))
114 {
115 strcpy(path, s);
116 return 0;
117 }
118 *(t - 2) = '.';
119 }
120 #if PRESERVE_TRAILING_SLASH
121 if (t - 5 < r) r = t;
122 #else
123 if (t - 5 < r)
124 {
125 if (t - 4 == r) t = r + 1;
126 else r = t;
127 }
128 #endif
129 else for (t -= 5; t > r && *(t - 1) != '/'; t--);
130 break;
131 case 3:
132 #if defined(FS_3D)
133 {
134 char* x;
135 char* o;
136 int c;
137
138 o = t;
139 if ((t -= 5) <= path) t = path + 1;
140 c = *t;
141 *t = 0;
142 if (x = pathnext(phys, s - (*s != 0), &visits))
143 {
144 r = path;
145 if (t == r + 1) x = r;
146 v = s = t = x;
147 }
148 else
149 {
150 *t = c;
151 t = o;
152 }
153 }
154 #else
155 r = t;
156 #endif
157 break;
158 default:
159 if ((flags & PATH_PHYSICAL) && loop < 32 && (t - 1) > path)
160 {
161 int c;
162 char buf[PATH_MAX];
163
164 c = *(t - 1);
165 *(t - 1) = 0;
166 dots = pathgetlink(phys, buf, sizeof(buf));
167 *(t - 1) = c;
168 if (dots > 0)
169 {
170 loop++;
171 strcpy(buf + dots, s - (*s != 0));
172 if (*buf == '/') p = r = path;
173 v = s = t = p;
174 strcpy(p, buf);
175 }
176 else if (dots < 0 && errno == ENOENT)
177 {
178 if (flags & PATH_EXISTS)
179 {
180 strcpy(path, s);
181 return 0;
182 }
183 flags &= ~(PATH_PHYSICAL|PATH_DOTDOT);
184 }
185 dots = 4;
186 }
187 break;
188 }
189 if (dots >= 4 && (flags & PATH_EXISTS) && (t - 1) >= v && (t > path + 1 || t > path && *(t - 1) && *(t - 1) != '/'))
190 {
191 struct stat st;
192
193 *(t - 1) = 0;
194 if (stat(phys, &st))
195 {
196 strcpy(path, s);
197 return 0;
198 }
199 v = t;
200 if (*s) *(t - 1) = '/';
201 }
202 if (!*s)
203 {
204 if (t > path && !*(t - 1)) t--;
205 if (t == path) *t++ = '.';
206 #if DONT_PRESERVE_TRAILING_SLASH
207 else if (t > path + 1 && *(t - 1) == '/') t--;
208 #else
209 else if ((s <= path || *(s - 1) != '/') && t > path + 1 && *(t - 1) == '/') t--;
210 #endif
211 *t = 0;
212 errno = oerrno;
213 return t;
214 }
215 dots = 0;
216 p = t;
217 break;
218 default:
219 dots = 4;
220 break;
221 }
222 }
223