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