|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley Software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char *sccsid = "@(#)sh.dir.c 5.3 (Berkeley) 6/11/85";
9: #endif
10:
11: #include "sh.h"
12: #include "sh.dir.h"
13:
14: /*
15: * C Shell - directory management
16: */
17:
18: struct directory *dfind();
19: char *dfollow();
20: char *dcanon();
21: struct directory dhead; /* "head" of loop */
22: int printd; /* force name to be printed */
23: static char *fakev[] = { "dirs", NOSTR };
24:
25: /*
26: * dinit - initialize current working directory
27: */
28: dinit(hp)
29: char *hp;
30: {
31: register char *cp;
32: register struct directory *dp;
33: char path[MAXPATHLEN];
34:
35: if (loginsh && hp)
36: cp = hp;
37: else {
38: cp = getwd(path);
39: if (cp == NULL) {
40: (void) write(2, path, strlen(path));
41: exit(1);
42: }
43: }
44: dp = (struct directory *)calloc(sizeof (struct directory), 1);
45: dp->di_name = savestr(cp);
46: dp->di_count = 0;
47: dhead.di_next = dhead.di_prev = dp;
48: dp->di_next = dp->di_prev = &dhead;
49: printd = 0;
50: dnewcwd(dp);
51: }
52:
53: /*
54: * dodirs - list all directories in directory loop
55: */
56: dodirs(v)
57: char **v;
58: {
59: register struct directory *dp;
60: bool lflag;
61: char *hp = value("home");
62:
63: if (*hp == '\0')
64: hp = NOSTR;
65: if (*++v != NOSTR)
66: if (eq(*v, "-l") && *++v == NOSTR)
67: lflag = 1;
68: else
69: error("Usage: dirs [ -l ]");
70: else
71: lflag = 0;
72: dp = dcwd;
73: do {
74: if (dp == &dhead)
75: continue;
76: if (!lflag && hp != NOSTR) {
77: dtildepr(hp, dp->di_name);
78: } else
79: printf("%s", dp->di_name);
80: printf(" ");
81: } while ((dp = dp->di_prev) != dcwd);
82: printf("\n");
83: }
84:
85: dtildepr(home, dir)
86: register char *home, *dir;
87: {
88:
89: if (!eq(home, "/") && prefix(home, dir))
90: printf("~%s", dir + strlen(home));
91: else
92: printf("%s", dir);
93: }
94:
95: /*
96: * dochngd - implement chdir command.
97: */
98: dochngd(v)
99: char **v;
100: {
101: register char *cp;
102: register struct directory *dp;
103:
104: printd = 0;
105: if (*++v == NOSTR) {
106: if ((cp = value("home")) == NOSTR || *cp == 0)
107: bferr("No home directory");
108: if (chdir(cp) < 0)
109: bferr("Can't change to home directory");
110: cp = savestr(cp);
111: } else if ((dp = dfind(*v)) != 0) {
112: printd = 1;
113: if (chdir(dp->di_name) < 0)
114: Perror(dp->di_name);
115: dcwd->di_prev->di_next = dcwd->di_next;
116: dcwd->di_next->di_prev = dcwd->di_prev;
117: goto flushcwd;
118: } else
119: cp = dfollow(*v);
120: dp = (struct directory *)calloc(sizeof (struct directory), 1);
121: dp->di_name = cp;
122: dp->di_count = 0;
123: dp->di_next = dcwd->di_next;
124: dp->di_prev = dcwd->di_prev;
125: dp->di_prev->di_next = dp;
126: dp->di_next->di_prev = dp;
127: flushcwd:
128: dfree(dcwd);
129: dnewcwd(dp);
130: }
131:
132: /*
133: * dfollow - change to arg directory; fall back on cdpath if not valid
134: */
135: char *
136: dfollow(cp)
137: register char *cp;
138: {
139: register char *dp;
140: struct varent *c;
141:
142: cp = globone(cp);
143: if (chdir(cp) >= 0)
144: goto gotcha;
145: if (cp[0] != '/' && !prefix("./", cp) && !prefix("../", cp)
146: && (c = adrof("cdpath"))) {
147: char **cdp;
148: register char *p;
149: char buf[MAXPATHLEN];
150:
151: for (cdp = c->vec; *cdp; cdp++) {
152: for (dp = buf, p = *cdp; *dp++ = *p++;)
153: ;
154: dp[-1] = '/';
155: for (p = cp; *dp++ = *p++;)
156: ;
157: if (chdir(buf) >= 0) {
158: printd = 1;
159: xfree(cp);
160: cp = savestr(buf);
161: goto gotcha;
162: }
163: }
164: }
165: dp = value(cp);
166: if ((dp[0] == '/' || dp[0] == '.') && chdir(dp) >= 0) {
167: xfree(cp);
168: cp = savestr(dp);
169: printd = 1;
170: goto gotcha;
171: }
172: xfree(cp); /* XXX, use after free */
173: Perror(cp);
174:
175: gotcha:
176: if (*cp != '/') {
177: register char *p, *q;
178: int cwdlen;
179:
180: /*
181: * All in the name of efficiency?
182: */
183: for (p = dcwd->di_name; *p++;)
184: ;
185: if ((cwdlen = p - dcwd->di_name - 1) == 1) /* root */
186: cwdlen = 0;
187: for (p = cp; *p++;)
188: ;
189: dp = xalloc((unsigned) (cwdlen + (p - cp) + 1));
190: for (p = dp, q = dcwd->di_name; *p++ = *q++;)
191: ;
192: if (cwdlen)
193: p[-1] = '/';
194: else
195: p--; /* don't add a / after root */
196: for (q = cp; *p++ = *q++;)
197: ;
198: xfree(cp);
199: cp = dp;
200: dp += cwdlen;
201: } else
202: dp = cp;
203: return dcanon(cp, dp);
204: }
205:
206: /*
207: * dopushd - push new directory onto directory stack.
208: * with no arguments exchange top and second.
209: * with numeric argument (+n) bring it to top.
210: */
211: dopushd(v)
212: char **v;
213: {
214: register struct directory *dp;
215:
216: printd = 1;
217: if (*++v == NOSTR) {
218: if ((dp = dcwd->di_prev) == &dhead)
219: dp = dhead.di_prev;
220: if (dp == dcwd)
221: bferr("No other directory");
222: if (chdir(dp->di_name) < 0)
223: Perror(dp->di_name);
224: dp->di_prev->di_next = dp->di_next;
225: dp->di_next->di_prev = dp->di_prev;
226: dp->di_next = dcwd->di_next;
227: dp->di_prev = dcwd;
228: dcwd->di_next->di_prev = dp;
229: dcwd->di_next = dp;
230: } else if (dp = dfind(*v)) {
231: if (chdir(dp->di_name) < 0)
232: Perror(dp->di_name);
233: } else {
234: register char *cp;
235:
236: cp = dfollow(*v);
237: dp = (struct directory *)calloc(sizeof (struct directory), 1);
238: dp->di_name = cp;
239: dp->di_count = 0;
240: dp->di_prev = dcwd;
241: dp->di_next = dcwd->di_next;
242: dcwd->di_next = dp;
243: dp->di_next->di_prev = dp;
244: }
245: dnewcwd(dp);
246: }
247:
248: /*
249: * dfind - find a directory if specified by numeric (+n) argument
250: */
251: struct directory *
252: dfind(cp)
253: register char *cp;
254: {
255: register struct directory *dp;
256: register int i;
257: register char *ep;
258:
259: if (*cp++ != '+')
260: return (0);
261: for (ep = cp; digit(*ep); ep++)
262: continue;
263: if (*ep)
264: return (0);
265: i = getn(cp);
266: if (i <= 0)
267: return (0);
268: for (dp = dcwd; i != 0; i--) {
269: if ((dp = dp->di_prev) == &dhead)
270: dp = dp->di_prev;
271: if (dp == dcwd)
272: bferr("Directory stack not that deep");
273: }
274: return (dp);
275: }
276:
277: /*
278: * dopopd - pop a directory out of the directory stack
279: * with a numeric argument just discard it.
280: */
281: dopopd(v)
282: char **v;
283: {
284: register struct directory *dp, *p;
285:
286: printd = 1;
287: if (*++v == NOSTR)
288: dp = dcwd;
289: else if ((dp = dfind(*v)) == 0)
290: bferr("Bad directory");
291: if (dp->di_prev == &dhead && dp->di_next == &dhead)
292: bferr("Directory stack empty");
293: if (dp == dcwd) {
294: if ((p = dp->di_prev) == &dhead)
295: p = dhead.di_prev;
296: if (chdir(p->di_name) < 0)
297: Perror(p->di_name);
298: }
299: dp->di_prev->di_next = dp->di_next;
300: dp->di_next->di_prev = dp->di_prev;
301: if (dp == dcwd)
302: dnewcwd(p);
303: else
304: dodirs(fakev);
305: dfree(dp);
306: }
307:
308: /*
309: * dfree - free the directory (or keep it if it still has ref count)
310: */
311: dfree(dp)
312: register struct directory *dp;
313: {
314:
315: if (dp->di_count != 0)
316: dp->di_next = dp->di_prev = 0;
317: else
318: xfree(dp->di_name), xfree((char *)dp);
319: }
320:
321: /*
322: * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
323: * we are of course assuming that the file system is standardly
324: * constructed (always have ..'s, directories have links)
325: */
326: char *
327: dcanon(cp, p)
328: register char *cp, *p;
329: {
330: register char *sp;
331: register char *p1, *p2; /* general purpose */
332: bool slash;
333:
334: if (*cp != '/')
335: abort();
336: while (*p) { /* for each component */
337: sp = p; /* save slash address */
338: while (*++p == '/') /* flush extra slashes */
339: ;
340: if (p != ++sp)
341: for (p1 = sp, p2 = p; *p1++ = *p2++;)
342: ;
343: p = sp; /* save start of component */
344: slash = 0;
345: while (*++p) /* find next slash or end of path */
346: if (*p == '/') {
347: slash = 1;
348: *p = 0;
349: break;
350: }
351: if (*sp == '\0') /* if component is null */
352: if (--sp == cp) /* if path is one char (i.e. /) */
353: break;
354: else
355: *sp = '\0';
356: else if (sp[0] == '.' && sp[1] == 0) {
357: if (slash) {
358: for (p1 = sp, p2 = p + 1; *p1++ = *p2++;)
359: ;
360: p = --sp;
361: } else if (--sp != cp)
362: *sp = '\0';
363: } else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
364: char link[MAXPATHLEN];
365: int cc;
366: char *newcp;
367:
368: /*
369: * We have something like "yyy/xxx/..", where "yyy"
370: * can be null or a path starting at /, and "xxx"
371: * is a single component.
372: * Before compressing "xxx/..", we want to expand
373: * "yyy/xxx", if it is a symbolic link.
374: */
375: *--sp = 0; /* form the pathname for readlink */
376: if (sp != cp &&
377: (cc = readlink(cp, link, sizeof link)) >= 0) {
378: link[cc] = '\0';
379: if (slash)
380: *p = '/';
381: /*
382: * Point p to the '/' in "/..", and restore
383: * the '/'.
384: */
385: *(p = sp) = '/';
386: /*
387: * find length of p
388: */
389: for (p1 = p; *p1++;)
390: ;
391: if (*link != '/') {
392: /*
393: * Relative path, expand it between
394: * the "yyy/" and the "/..".
395: * First, back sp up to the character
396: * past "yyy/".
397: */
398: while (*--sp != '/')
399: ;
400: sp++;
401: *sp = 0;
402: /*
403: * New length is
404: * "yyy/" + link + "/.." and rest
405: */
406: p1 = newcp = xalloc((unsigned)
407: ((sp - cp) + cc + (p1 - p)));
408: /*
409: * Copy new path into newcp
410: */
411: for (p2 = cp; *p1++ = *p2++;)
412: ;
413: for (p1--, p2 = link; *p1++ = *p2++;)
414: ;
415: for (p1--, p2 = p; *p1++ = *p2++;)
416: ;
417: /*
418: * Restart canonicalization at
419: * expanded "/xxx".
420: */
421: p = sp - cp - 1 + newcp;
422: } else {
423: /*
424: * New length is link + "/.." and rest
425: */
426: p1 = newcp = xalloc((unsigned)
427: (cc + (p1 - p)));
428: /*
429: * Copy new path into newcp
430: */
431: for (p2 = link; *p1++ = *p2++;)
432: ;
433: for (p1--, p2 = p; *p1++ = *p2++;)
434: ;
435: /*
436: * Restart canonicalization at beginning
437: */
438: p = newcp;
439: }
440: xfree(cp);
441: cp = newcp;
442: continue; /* canonicalize the link */
443: }
444: *sp = '/';
445: if (sp != cp)
446: while (*--sp != '/')
447: ;
448: if (slash) {
449: for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;)
450: ;
451: p = sp;
452: } else if (cp == sp)
453: *++sp = '\0';
454: else
455: *sp = '\0';
456: } else if (slash)
457: *p = '/';
458: }
459: return cp;
460: }
461:
462: /*
463: * dnewcwd - make a new directory in the loop the current one
464: */
465: dnewcwd(dp)
466: register struct directory *dp;
467: {
468:
469: dcwd = dp;
470: set("cwd", savestr(dcwd->di_name));
471: if (printd)
472: dodirs(fakev);
473: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.