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