|
|
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.