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