path.c revision 1.1.1.2 1 1.1 jtc #include "sh.h"
2 1.1 jtc #include "ksh_stat.h"
3 1.1 jtc
4 1.1 jtc /*
5 1.1.1.2 hubertf * Contains a routine to search a : separated list of
6 1.1 jtc * paths (a la CDPATH) and make appropiate file names.
7 1.1 jtc * Also contains a routine to simplify .'s and ..'s out of
8 1.1 jtc * a path name.
9 1.1 jtc *
10 1.1 jtc * Larry Bouzane (larry (at) cs.mun.ca)
11 1.1 jtc */
12 1.1 jtc
13 1.1 jtc /*
14 1.1 jtc * $Log: path.c,v $
15 1.1 jtc * Revision 1.1.1.2 1999/10/20 14:27:30 hubertf
16 1.1 jtc * Import pdksh V5.2.14.
17 1.1 jtc * Includes lots of bugfixes.
18 1.1 jtc *
19 1.1 jtc * Revision 1.2 1994/05/19 18:32:40 michael
20 1.1 jtc * Merge complete, stdio replaced, various fixes. (pre autoconf)
21 1.1 jtc *
22 1.1 jtc * Revision 1.1 1994/04/06 13:14:03 michael
23 1.1 jtc * Initial revision
24 1.1 jtc *
25 1.1 jtc * Revision 4.2 1990/12/06 18:05:24 larry
26 1.1 jtc * Updated test code to reflect parameter change.
27 1.1 jtc * Fixed problem with /a/./.dir being simplified to /a and not /a/.dir due
28 1.1 jtc * to *(cur+2) == *f test instead of the correct cur+2 == f
29 1.1 jtc *
30 1.1 jtc * Revision 4.1 90/10/29 14:42:19 larry
31 1.1 jtc * base MUN version
32 1.1 jtc *
33 1.1 jtc * Revision 3.1.0.4 89/02/16 20:28:36 larry
34 1.1 jtc * Forgot to set *pathlist to NULL when last changed make_path().
35 1.1 jtc *
36 1.1 jtc * Revision 3.1.0.3 89/02/13 20:29:55 larry
37 1.1 jtc * Fixed up cd so that it knew when a node from CDPATH was used and would
38 1.1 jtc * print a message only when really necessary.
39 1.1 jtc *
40 1.1 jtc * Revision 3.1.0.2 89/02/13 17:51:22 larry
41 1.1 jtc * Merged with Eric Gisin's version.
42 1.1 jtc *
43 1.1 jtc * Revision 3.1.0.1 89/02/13 17:50:58 larry
44 1.1 jtc * *** empty log message ***
45 1.1 jtc *
46 1.1 jtc * Revision 3.1 89/02/13 17:49:28 larry
47 1.1 jtc * *** empty log message ***
48 1.1 jtc *
49 1.1 jtc */
50 1.1 jtc
51 1.1 jtc #ifdef S_ISLNK
52 1.1 jtc static char *do_phys_path ARGS((XString *xsp, char *xp, const char *path));
53 1.1 jtc #endif /* S_ISLNK */
54 1.1 jtc
55 1.1 jtc /*
56 1.1 jtc * Makes a filename into result using the following algorithm.
57 1.1 jtc * - make result NULL
58 1.1 jtc * - if file starts with '/', append file to result & set cdpathp to NULL
59 1.1 jtc * - if file starts with ./ or ../ append cwd and file to result
60 1.1 jtc * and set cdpathp to NULL
61 1.1 jtc * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx
62 1.1 jtc * then cwd is appended to result.
63 1.1 jtc * - the first element of cdpathp is appended to result
64 1.1 jtc * - file is appended to result
65 1.1 jtc * - cdpathp is set to the start of the next element in cdpathp (or NULL
66 1.1 jtc * if there are no more elements.
67 1.1 jtc * The return value indicates whether a non-null element from cdpathp
68 1.1 jtc * was appened to result.
69 1.1 jtc */
70 1.1.1.2 hubertf int
71 1.1 jtc make_path(cwd, file, cdpathp, xsp, phys_pathp)
72 1.1 jtc const char *cwd;
73 1.1 jtc const char *file;
74 1.1 jtc char **cdpathp; /* & of : separated list */
75 1.1 jtc XString *xsp;
76 1.1 jtc int *phys_pathp;
77 1.1 jtc {
78 1.1 jtc int rval = 0;
79 1.1 jtc int use_cdpath = 1;
80 1.1 jtc char *plist;
81 1.1 jtc int len;
82 1.1 jtc int plen = 0;
83 1.1 jtc char *xp = Xstring(*xsp, xp);
84 1.1 jtc
85 1.1 jtc if (!file)
86 1.1 jtc file = null;
87 1.1 jtc
88 1.1 jtc if (!ISRELPATH(file)) {
89 1.1 jtc *phys_pathp = 0;
90 1.1 jtc use_cdpath = 0;
91 1.1 jtc } else {
92 1.1 jtc if (file[0] == '.') {
93 1.1 jtc char c = file[1];
94 1.1 jtc
95 1.1 jtc if (c == '.')
96 1.1 jtc c = file[2];
97 1.1 jtc if (ISDIRSEP(c) || c == '\0')
98 1.1 jtc use_cdpath = 0;
99 1.1 jtc }
100 1.1 jtc
101 1.1 jtc plist = *cdpathp;
102 1.1 jtc if (!plist)
103 1.1 jtc use_cdpath = 0;
104 1.1 jtc else if (use_cdpath) {
105 1.1 jtc char *pend;
106 1.1 jtc
107 1.1 jtc for (pend = plist; *pend && *pend != PATHSEP; pend++)
108 1.1 jtc ;
109 1.1 jtc plen = pend - plist;
110 1.1 jtc *cdpathp = *pend ? ++pend : (char *) 0;
111 1.1 jtc }
112 1.1 jtc
113 1.1 jtc if ((use_cdpath == 0 || !plen || ISRELPATH(plist))
114 1.1 jtc && (cwd && *cwd))
115 1.1 jtc {
116 1.1 jtc len = strlen(cwd);
117 1.1 jtc XcheckN(*xsp, xp, len);
118 1.1 jtc memcpy(xp, cwd, len);
119 1.1 jtc xp += len;
120 1.1 jtc if (!ISDIRSEP(cwd[len - 1]))
121 1.1 jtc Xput(*xsp, xp, DIRSEP);
122 1.1 jtc }
123 1.1 jtc *phys_pathp = Xlength(*xsp, xp);
124 1.1 jtc if (use_cdpath && plen) {
125 1.1 jtc XcheckN(*xsp, xp, plen);
126 1.1 jtc memcpy(xp, plist, plen);
127 1.1 jtc xp += plen;
128 1.1 jtc if (!ISDIRSEP(plist[plen - 1]))
129 1.1 jtc Xput(*xsp, xp, DIRSEP);
130 1.1 jtc rval = 1;
131 1.1 jtc }
132 1.1 jtc }
133 1.1 jtc
134 1.1 jtc len = strlen(file) + 1;
135 1.1 jtc XcheckN(*xsp, xp, len);
136 1.1 jtc memcpy(xp, file, len);
137 1.1 jtc
138 1.1 jtc if (!use_cdpath)
139 1.1 jtc *cdpathp = (char *) 0;
140 1.1 jtc
141 1.1 jtc return rval;
142 1.1 jtc }
143 1.1 jtc
144 1.1 jtc /*
145 1.1 jtc * Simplify pathnames containing "." and ".." entries.
146 1.1 jtc * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
147 1.1 jtc */
148 1.1 jtc void
149 1.1 jtc simplify_path(path)
150 1.1 jtc char *path;
151 1.1 jtc {
152 1.1 jtc char *cur;
153 1.1 jtc char *t;
154 1.1 jtc int isrooted;
155 1.1 jtc char *very_start = path;
156 1.1 jtc char *start;
157 1.1 jtc
158 1.1 jtc if (!*path)
159 1.1.1.2 hubertf return;
160 1.1 jtc
161 1.1 jtc if ((isrooted = ISROOTEDPATH(path)))
162 1.1.1.2 hubertf very_start++;
163 1.1 jtc #if defined (OS2) || defined (__CYGWIN__)
164 1.1 jtc if (path[0] && path[1] == ':') /* skip a: */
165 1.1 jtc very_start += 2;
166 1.1 jtc #endif /* OS2 || __CYGWIN__ */
167 1.1 jtc
168 1.1 jtc /* Before After
169 1.1 jtc * /foo/ /foo
170 1.1 jtc * /foo/../../bar /bar
171 1.1 jtc * /foo/./blah/.. /foo
172 1.1.1.2 hubertf * . .
173 1.1 jtc * .. ..
174 1.1 jtc * ./foo foo
175 1.1 jtc * foo/../../../bar ../../bar
176 1.1 jtc * OS2 and CYGWIN:
177 1.1 jtc * a:/foo/../.. a:/
178 1.1.1.2 hubertf * a:. a:
179 1.1.1.2 hubertf * a:.. a:..
180 1.1.1.2 hubertf * a:foo/../../blah a:../blah
181 1.1.1.2 hubertf */
182 1.1.1.2 hubertf
183 1.1.1.2 hubertf #ifdef __CYGWIN__
184 1.1 jtc /* preserve leading double-slash on pathnames (for UNC paths) */
185 1.1 jtc if (path[0] && ISDIRSEP(path[0]) && path[1] && ISDIRSEP(path[1]))
186 1.1 jtc very_start++;
187 1.1 jtc #endif /* __CYGWIN__ */
188 1.1 jtc
189 1.1 jtc for (cur = t = start = very_start; ; ) {
190 1.1 jtc /* treat multiple '/'s as one '/' */
191 1.1 jtc while (ISDIRSEP(*t))
192 1.1 jtc t++;
193 1.1 jtc
194 1.1 jtc if (*t == '\0') {
195 1.1 jtc if (cur == path)
196 1.1 jtc /* convert empty path to dot */
197 1.1 jtc *cur++ = '.';
198 1.1 jtc *cur = '\0';
199 1.1 jtc break;
200 1.1 jtc }
201 1.1 jtc
202 1.1 jtc if (t[0] == '.') {
203 1.1 jtc if (!t[1] || ISDIRSEP(t[1])) {
204 1.1 jtc t += 1;
205 1.1 jtc continue;
206 1.1 jtc } else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
207 1.1 jtc if (!isrooted && cur == start) {
208 1.1 jtc if (cur != very_start)
209 1.1 jtc *cur++ = DIRSEP;
210 1.1 jtc *cur++ = '.';
211 1.1 jtc *cur++ = '.';
212 1.1 jtc start = cur;
213 1.1 jtc } else if (cur != start)
214 1.1 jtc while (--cur > start && !ISDIRSEP(*cur))
215 1.1 jtc ;
216 1.1 jtc t += 2;
217 1.1 jtc continue;
218 1.1 jtc }
219 1.1 jtc }
220 1.1 jtc
221 1.1 jtc if (cur != very_start)
222 1.1 jtc *cur++ = DIRSEP;
223 1.1 jtc
224 1.1 jtc /* find/copy next component of pathname */
225 1.1 jtc while (*t && !ISDIRSEP(*t))
226 1.1 jtc *cur++ = *t++;
227 1.1 jtc }
228 1.1 jtc }
229 1.1 jtc
230 1.1 jtc
231 1.1 jtc void
232 1.1 jtc set_current_wd(path)
233 1.1 jtc char *path;
234 1.1 jtc {
235 1.1 jtc int len;
236 1.1 jtc char *p = path;
237 1.1 jtc
238 1.1 jtc if (!p && !(p = ksh_get_wd((char *) 0, 0)))
239 1.1 jtc p = null;
240 1.1 jtc
241 1.1 jtc len = strlen(p) + 1;
242 1.1 jtc
243 1.1 jtc if (len > current_wd_size)
244 1.1 jtc current_wd = aresize(current_wd, current_wd_size = len, APERM);
245 1.1 jtc memcpy(current_wd, p, len);
246 1.1 jtc if (p != path && p != null)
247 1.1 jtc afree(p, ATEMP);
248 1.1 jtc }
249 1.1 jtc
250 1.1 jtc #ifdef S_ISLNK
251 1.1 jtc char *
252 1.1 jtc get_phys_path(path)
253 1.1 jtc const char *path;
254 1.1 jtc {
255 1.1 jtc XString xs;
256 1.1 jtc char *xp;
257 1.1 jtc
258 1.1 jtc Xinit(xs, xp, strlen(path) + 1, ATEMP);
259 1.1 jtc
260 1.1 jtc xp = do_phys_path(&xs, xp, path);
261 1.1 jtc
262 1.1 jtc if (!xp)
263 1.1 jtc return (char *) 0;
264 1.1 jtc
265 1.1 jtc if (Xlength(xs, xp) == 0)
266 1.1 jtc Xput(xs, xp, DIRSEP);
267 1.1 jtc Xput(xs, xp, '\0');
268 1.1 jtc
269 1.1 jtc return Xclose(xs, xp);
270 1.1 jtc }
271 1.1 jtc
272 1.1 jtc static char *
273 1.1 jtc do_phys_path(xsp, xp, path)
274 1.1 jtc XString *xsp;
275 1.1 jtc char *xp;
276 1.1 jtc const char *path;
277 1.1 jtc {
278 1.1 jtc const char *p, *q;
279 1.1 jtc int len, llen;
280 1.1 jtc int savepos;
281 1.1 jtc char lbuf[PATH];
282 1.1 jtc
283 1.1 jtc Xcheck(*xsp, xp);
284 1.1 jtc for (p = path; p; p = q) {
285 1.1 jtc while (ISDIRSEP(*p))
286 1.1 jtc p++;
287 1.1 jtc if (!*p)
288 1.1 jtc break;
289 1.1 jtc len = (q = ksh_strchr_dirsep(p)) ? q - p : strlen(p);
290 1.1 jtc if (len == 1 && p[0] == '.')
291 1.1 jtc continue;
292 1.1 jtc if (len == 2 && p[0] == '.' && p[1] == '.') {
293 1.1 jtc while (xp > Xstring(*xsp, xp)) {
294 1.1 jtc xp--;
295 1.1 jtc if (ISDIRSEP(*xp))
296 1.1 jtc break;
297 1.1 jtc }
298 1.1 jtc continue;
299 1.1 jtc }
300 1.1 jtc
301 1.1 jtc savepos = Xsavepos(*xsp, xp);
302 1.1 jtc Xput(*xsp, xp, DIRSEP);
303 1.1 jtc XcheckN(*xsp, xp, len + 1);
304 1.1 jtc memcpy(xp, p, len);
305 1.1 jtc xp += len;
306 1.1 jtc *xp = '\0';
307 1.1 jtc
308 1.1 jtc llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
309 1.1 jtc if (llen < 0) {
310 1.1 jtc /* EINVAL means it wasn't a symlink... */
311 1.1 jtc if (errno != EINVAL)
312 1.1 jtc return (char *) 0;
313 1.1 jtc continue;
314 1.1 jtc }
315 1.1 jtc lbuf[llen] = '\0';
316 1.1 jtc
317 1.1 jtc /* If absolute path, start from scratch.. */
318 1.1 jtc xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp)
319 1.1 jtc : Xrestpos(*xsp, xp, savepos);
320 1.1 jtc if (!(xp = do_phys_path(xsp, xp, lbuf)))
321 1.1 jtc return (char *) 0;
322 1.1 jtc }
323 1.1 jtc return xp;
324 1.1 jtc }
325 1.1 jtc #endif /* S_ISLNK */
326 1.1 jtc
327 1.1 jtc #ifdef TEST
328 1.1 jtc
329 1.1 jtc main(argc, argv)
330 1.1 jtc {
331 1.1 jtc int rv;
332 1.1 jtc char *cp, cdpath[256], pwd[256], file[256], result[256];
333 1.1 jtc
334 1.1 jtc printf("enter CDPATH: "); gets(cdpath);
335 1.1 jtc printf("enter PWD: "); gets(pwd);
336 1.1 jtc while (1) {
337 1.1 jtc if (printf("Enter file: "), gets(file) == 0)
338 1.1 jtc return 0;
339 1.1 jtc cp = cdpath;
340 1.1 jtc do {
341 1.1 jtc rv = make_path(pwd, file, &cp, result, sizeof(result));
342 1.1 jtc printf("make_path returns (%d), \"%s\" ", rv, result);
343 1.1 jtc simplify_path(result);
344 1.1 jtc printf("(simpifies to \"%s\")\n", result);
345 } while (cp);
346 }
347 }
348 #endif /* TEST */
349