1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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 #include <ast.h>
45 #include <ls.h>
46 #include <fs3d.h>
47 #include <error.h>
48
49 char*
pathcanon(char * path,int flags)50 pathcanon(char* path, int flags)
51 {
52 register char* p;
53 register char* r;
54 register char* s;
55 register char* t;
56 register int dots;
57 char* phys;
58 char* v;
59 int loop;
60 int oerrno;
61 #if defined(FS_3D)
62 long visits = 0;
63 #endif
64
65 oerrno = errno;
66 dots = loop = 0;
67 phys = path;
68 v = path + ((flags >> 5) & 01777);
69 if (*path == '/')
70 {
71 if (*(path + 1) == '/' && *astconf("PATH_LEADING_SLASHES", NiL, NiL) == '1')
72 do path++; while (*path == '/' && *(path + 1) == '/');
73 if (!*(path + 1))
74 return path + 1;
75 }
76 p = r = s = t = path;
77 for (;;) switch (*t++ = *s++)
78 {
79 case '.':
80 dots++;
81 break;
82 case 0:
83 s--;
84 /*FALLTHROUGH*/
85 case '/':
86 while (*s == '/') s++;
87 switch (dots)
88 {
89 case 1:
90 t -= 2;
91 break;
92 case 2:
93 if ((flags & (PATH_DOTDOT|PATH_EXISTS)) == PATH_DOTDOT && (t - 2) >= v)
94 {
95 struct stat st;
96
97 *(t - 2) = 0;
98 if (stat(phys, &st))
99 {
100 strcpy(path, s);
101 return 0;
102 }
103 *(t - 2) = '.';
104 }
105 #if PRESERVE_TRAILING_SLASH
106 if (t - 5 < r) r = t;
107 #else
108 if (t - 5 < r)
109 {
110 if (t - 4 == r) t = r + 1;
111 else r = t;
112 }
113 #endif
114 else for (t -= 5; t > r && *(t - 1) != '/'; t--);
115 break;
116 case 3:
117 #if defined(FS_3D)
118 {
119 char* x;
120 char* o;
121 int c;
122
123 o = t;
124 if ((t -= 5) <= path) t = path + 1;
125 c = *t;
126 *t = 0;
127 if (x = pathnext(phys, s - (*s != 0), &visits))
128 {
129 r = path;
130 if (t == r + 1) x = r;
131 v = s = t = x;
132 }
133 else
134 {
135 *t = c;
136 t = o;
137 }
138 }
139 #else
140 r = t;
141 #endif
142 break;
143 default:
144 if ((flags & PATH_PHYSICAL) && loop < 32 && (t - 1) > path)
145 {
146 int c;
147 char buf[PATH_MAX];
148
149 c = *(t - 1);
150 *(t - 1) = 0;
151 dots = pathgetlink(phys, buf, sizeof(buf));
152 *(t - 1) = c;
153 if (dots > 0)
154 {
155 loop++;
156 strcpy(buf + dots, s - (*s != 0));
157 if (*buf == '/') p = r = path;
158 v = s = t = p;
159 strcpy(p, buf);
160 }
161 else if (dots < 0 && errno == ENOENT)
162 {
163 if (flags & PATH_EXISTS)
164 {
165 strcpy(path, s);
166 return 0;
167 }
168 flags &= ~(PATH_PHYSICAL|PATH_DOTDOT);
169 }
170 dots = 4;
171 }
172 break;
173 }
174 if (dots >= 4 && (flags & PATH_EXISTS) && (t - 1) >= v && (t > path + 1 || t > path && *(t - 1) && *(t - 1) != '/'))
175 {
176 struct stat st;
177
178 *(t - 1) = 0;
179 if (stat(phys, &st))
180 {
181 strcpy(path, s);
182 return 0;
183 }
184 v = t;
185 if (*s) *(t - 1) = '/';
186 }
187 if (!*s)
188 {
189 if (t > path && !*(t - 1)) t--;
190 if (t == path) *t++ = '.';
191 #if DONT_PRESERVE_TRAILING_SLASH
192 else if (t > path + 1 && *(t - 1) == '/') t--;
193 #else
194 else if ((s <= path || *(s - 1) != '/') && t > path + 1 && *(t - 1) == '/') t--;
195 #endif
196 *t = 0;
197 errno = oerrno;
198 return t;
199 }
200 dots = 0;
201 p = t;
202 break;
203 default:
204 dots = 4;
205 break;
206 }
207 }
208