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