xref: /illumos-gate/usr/src/contrib/ast/src/lib/libast/path/pathcanon.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
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