xref: /titanic_51/usr/src/lib/libast/common/path/pathcanon.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
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