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