|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 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[] = "@(#)dirs.c 5.5 (Berkeley) 5/13/88"; ! 9: #endif not lint ! 10: ! 11: #include "restore.h" ! 12: #include <protocols/dumprestore.h> ! 13: #include <sys/file.h> ! 14: ! 15: /* ! 16: * Symbol table of directories read from tape. ! 17: */ ! 18: #define HASHSIZE 1000 ! 19: #define INOHASH(val) (val % HASHSIZE) ! 20: struct inotab { ! 21: struct inotab *t_next; ! 22: ino_t t_ino; ! 23: daddr_t t_seekpt; ! 24: long t_size; ! 25: }; ! 26: static struct inotab *inotab[HASHSIZE]; ! 27: extern struct inotab *inotablookup(); ! 28: extern struct inotab *allocinotab(); ! 29: ! 30: /* ! 31: * Information retained about directories. ! 32: */ ! 33: struct modeinfo { ! 34: ino_t ino; ! 35: time_t timep[2]; ! 36: short mode; ! 37: short uid; ! 38: short gid; ! 39: }; ! 40: ! 41: /* ! 42: * Global variables for this file. ! 43: */ ! 44: static daddr_t seekpt; ! 45: static FILE *df, *mf; ! 46: static DIR *dirp; ! 47: static char dirfile[32] = "#"; /* No file */ ! 48: static char modefile[32] = "#"; /* No file */ ! 49: extern ino_t search(); ! 50: struct direct *rst_readdir(); ! 51: extern void rst_seekdir(); ! 52: ! 53: /* ! 54: * Format of old style directories. ! 55: */ ! 56: #define ODIRSIZ 14 ! 57: struct odirect { ! 58: u_short d_ino; ! 59: char d_name[ODIRSIZ]; ! 60: }; ! 61: ! 62: /* ! 63: * Extract directory contents, building up a directory structure ! 64: * on disk for extraction by name. ! 65: * If genmode is requested, save mode, owner, and times for all ! 66: * directories on the tape. ! 67: */ ! 68: extractdirs(genmode) ! 69: int genmode; ! 70: { ! 71: register int i; ! 72: register struct dinode *ip; ! 73: struct inotab *itp; ! 74: struct direct nulldir; ! 75: int putdir(), null(); ! 76: ! 77: vprintf(stdout, "Extract directories from tape\n"); ! 78: (void) sprintf(dirfile, "/tmp/rstdir%d", dumpdate); ! 79: df = fopen(dirfile, "w"); ! 80: if (df == 0) { ! 81: fprintf(stderr, ! 82: "restore: %s - cannot create directory temporary\n", ! 83: dirfile); ! 84: perror("fopen"); ! 85: done(1); ! 86: } ! 87: if (genmode != 0) { ! 88: (void) sprintf(modefile, "/tmp/rstmode%d", dumpdate); ! 89: mf = fopen(modefile, "w"); ! 90: if (mf == 0) { ! 91: fprintf(stderr, ! 92: "restore: %s - cannot create modefile \n", ! 93: modefile); ! 94: perror("fopen"); ! 95: done(1); ! 96: } ! 97: } ! 98: nulldir.d_ino = 0; ! 99: nulldir.d_namlen = 1; ! 100: (void) strcpy(nulldir.d_name, "/"); ! 101: nulldir.d_reclen = DIRSIZ(&nulldir); ! 102: for (;;) { ! 103: curfile.name = "<directory file - name unknown>"; ! 104: curfile.action = USING; ! 105: ip = curfile.dip; ! 106: if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { ! 107: (void) fclose(df); ! 108: dirp = opendir(dirfile); ! 109: if (dirp == NULL) ! 110: perror("opendir"); ! 111: if (mf != NULL) ! 112: (void) fclose(mf); ! 113: i = dirlookup("."); ! 114: if (i == 0) ! 115: panic("Root directory is not on tape\n"); ! 116: return; ! 117: } ! 118: itp = allocinotab(curfile.ino, ip, seekpt); ! 119: getfile(putdir, null); ! 120: putent(&nulldir); ! 121: flushent(); ! 122: itp->t_size = seekpt - itp->t_seekpt; ! 123: } ! 124: } ! 125: ! 126: /* ! 127: * skip over all the directories on the tape ! 128: */ ! 129: skipdirs() ! 130: { ! 131: ! 132: while ((curfile.dip->di_mode & IFMT) == IFDIR) { ! 133: skipfile(); ! 134: } ! 135: } ! 136: ! 137: /* ! 138: * Recursively find names and inumbers of all files in subtree ! 139: * pname and pass them off to be processed. ! 140: */ ! 141: treescan(pname, ino, todo) ! 142: char *pname; ! 143: ino_t ino; ! 144: long (*todo)(); ! 145: { ! 146: register struct inotab *itp; ! 147: register struct direct *dp; ! 148: register struct entry *np; ! 149: int namelen; ! 150: daddr_t bpt; ! 151: char locname[MAXPATHLEN + 1]; ! 152: ! 153: itp = inotablookup(ino); ! 154: if (itp == NULL) { ! 155: /* ! 156: * Pname is name of a simple file or an unchanged directory. ! 157: */ ! 158: (void) (*todo)(pname, ino, LEAF); ! 159: return; ! 160: } ! 161: /* ! 162: * Pname is a dumped directory name. ! 163: */ ! 164: if ((*todo)(pname, ino, NODE) == FAIL) ! 165: return; ! 166: /* ! 167: * begin search through the directory ! 168: * skipping over "." and ".." ! 169: */ ! 170: (void) strncpy(locname, pname, MAXPATHLEN); ! 171: (void) strncat(locname, "/", MAXPATHLEN); ! 172: namelen = strlen(locname); ! 173: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); ! 174: dp = rst_readdir(dirp); /* "." */ ! 175: if (dp != NULL && strcmp(dp->d_name, ".") == 0) ! 176: dp = rst_readdir(dirp); /* ".." */ ! 177: else ! 178: fprintf(stderr, "Warning: `.' missing from directory %s\n", ! 179: pname); ! 180: if (dp != NULL && strcmp(dp->d_name, "..") == 0) ! 181: dp = rst_readdir(dirp); /* first real entry */ ! 182: else ! 183: fprintf(stderr, "Warning: `..' missing from directory %s\n", ! 184: pname); ! 185: bpt = telldir(dirp); ! 186: /* ! 187: * a zero inode signals end of directory ! 188: */ ! 189: while (dp != NULL && dp->d_ino != 0) { ! 190: locname[namelen] = '\0'; ! 191: if (namelen + dp->d_namlen >= MAXPATHLEN) { ! 192: fprintf(stderr, "%s%s: name exceeds %d char\n", ! 193: locname, dp->d_name, MAXPATHLEN); ! 194: } else { ! 195: (void) strncat(locname, dp->d_name, (int)dp->d_namlen); ! 196: treescan(locname, dp->d_ino, todo); ! 197: rst_seekdir(dirp, bpt, itp->t_seekpt); ! 198: } ! 199: dp = rst_readdir(dirp); ! 200: bpt = telldir(dirp); ! 201: } ! 202: if (dp == NULL) ! 203: fprintf(stderr, "corrupted directory: %s.\n", locname); ! 204: } ! 205: ! 206: /* ! 207: * Search the directory tree rooted at inode ROOTINO ! 208: * for the path pointed at by n ! 209: */ ! 210: ino_t ! 211: psearch(n) ! 212: char *n; ! 213: { ! 214: register char *cp, *cp1; ! 215: ino_t ino; ! 216: char c; ! 217: ! 218: ino = ROOTINO; ! 219: if (*(cp = n) == '/') ! 220: cp++; ! 221: next: ! 222: cp1 = cp + 1; ! 223: while (*cp1 != '/' && *cp1) ! 224: cp1++; ! 225: c = *cp1; ! 226: *cp1 = 0; ! 227: ino = search(ino, cp); ! 228: if (ino == 0) { ! 229: *cp1 = c; ! 230: return(0); ! 231: } ! 232: *cp1 = c; ! 233: if (c == '/') { ! 234: cp = cp1+1; ! 235: goto next; ! 236: } ! 237: return(ino); ! 238: } ! 239: ! 240: /* ! 241: * search the directory inode ino ! 242: * looking for entry cp ! 243: */ ! 244: ino_t ! 245: search(inum, cp) ! 246: ino_t inum; ! 247: char *cp; ! 248: { ! 249: register struct direct *dp; ! 250: register struct inotab *itp; ! 251: int len; ! 252: ! 253: itp = inotablookup(inum); ! 254: if (itp == NULL) ! 255: return(0); ! 256: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); ! 257: len = strlen(cp); ! 258: do { ! 259: dp = rst_readdir(dirp); ! 260: if (dp == NULL || dp->d_ino == 0) ! 261: return (0); ! 262: } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0); ! 263: return(dp->d_ino); ! 264: } ! 265: ! 266: /* ! 267: * Put the directory entries in the directory file ! 268: */ ! 269: putdir(buf, size) ! 270: char *buf; ! 271: int size; ! 272: { ! 273: struct direct cvtbuf; ! 274: register struct odirect *odp; ! 275: struct odirect *eodp; ! 276: register struct direct *dp; ! 277: long loc, i; ! 278: extern int Bcvt; ! 279: ! 280: if (cvtflag) { ! 281: eodp = (struct odirect *)&buf[size]; ! 282: for (odp = (struct odirect *)buf; odp < eodp; odp++) ! 283: if (odp->d_ino != 0) { ! 284: dcvt(odp, &cvtbuf); ! 285: putent(&cvtbuf); ! 286: } ! 287: } else { ! 288: for (loc = 0; loc < size; ) { ! 289: dp = (struct direct *)(buf + loc); ! 290: if (Bcvt) { ! 291: swabst("l2s", (char *) dp); ! 292: } ! 293: i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); ! 294: if (dp->d_reclen == 0 || dp->d_reclen > i) { ! 295: loc += i; ! 296: continue; ! 297: } ! 298: loc += dp->d_reclen; ! 299: if (dp->d_ino != 0) { ! 300: putent(dp); ! 301: } ! 302: } ! 303: } ! 304: } ! 305: ! 306: /* ! 307: * These variables are "local" to the following two functions. ! 308: */ ! 309: char dirbuf[DIRBLKSIZ]; ! 310: long dirloc = 0; ! 311: long prev = 0; ! 312: ! 313: /* ! 314: * add a new directory entry to a file. ! 315: */ ! 316: putent(dp) ! 317: struct direct *dp; ! 318: { ! 319: dp->d_reclen = DIRSIZ(dp); ! 320: if (dirloc + dp->d_reclen > DIRBLKSIZ) { ! 321: ((struct direct *)(dirbuf + prev))->d_reclen = ! 322: DIRBLKSIZ - prev; ! 323: (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); ! 324: dirloc = 0; ! 325: } ! 326: bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); ! 327: prev = dirloc; ! 328: dirloc += dp->d_reclen; ! 329: } ! 330: ! 331: /* ! 332: * flush out a directory that is finished. ! 333: */ ! 334: flushent() ! 335: { ! 336: ! 337: ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; ! 338: (void) fwrite(dirbuf, (int)dirloc, 1, df); ! 339: seekpt = ftell(df); ! 340: dirloc = 0; ! 341: } ! 342: ! 343: dcvt(odp, ndp) ! 344: register struct odirect *odp; ! 345: register struct direct *ndp; ! 346: { ! 347: ! 348: bzero((char *)ndp, (long)(sizeof *ndp)); ! 349: ndp->d_ino = odp->d_ino; ! 350: (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); ! 351: ndp->d_namlen = strlen(ndp->d_name); ! 352: ndp->d_reclen = DIRSIZ(ndp); ! 353: } ! 354: ! 355: /* ! 356: * Seek to an entry in a directory. ! 357: * Only values returned by ``telldir'' should be passed to rst_seekdir. ! 358: * This routine handles many directories in a single file. ! 359: * It takes the base of the directory in the file, plus ! 360: * the desired seek offset into it. ! 361: */ ! 362: void ! 363: rst_seekdir(dirp, loc, base) ! 364: register DIR *dirp; ! 365: daddr_t loc, base; ! 366: { ! 367: ! 368: if (loc == telldir(dirp)) ! 369: return; ! 370: loc -= base; ! 371: if (loc < 0) ! 372: fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); ! 373: (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); ! 374: dirp->dd_loc = loc & (DIRBLKSIZ - 1); ! 375: if (dirp->dd_loc != 0) ! 376: dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); ! 377: } ! 378: ! 379: /* ! 380: * get next entry in a directory. ! 381: */ ! 382: struct direct * ! 383: rst_readdir(dirp) ! 384: register DIR *dirp; ! 385: { ! 386: register struct direct *dp; ! 387: ! 388: for (;;) { ! 389: if (dirp->dd_loc == 0) { ! 390: dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, ! 391: DIRBLKSIZ); ! 392: if (dirp->dd_size <= 0) { ! 393: dprintf(stderr, "error reading directory\n"); ! 394: return NULL; ! 395: } ! 396: } ! 397: if (dirp->dd_loc >= dirp->dd_size) { ! 398: dirp->dd_loc = 0; ! 399: continue; ! 400: } ! 401: dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); ! 402: if (dp->d_reclen == 0 || ! 403: dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { ! 404: dprintf(stderr, "corrupted directory: bad reclen %d\n", ! 405: dp->d_reclen); ! 406: return NULL; ! 407: } ! 408: dirp->dd_loc += dp->d_reclen; ! 409: if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) ! 410: continue; ! 411: if (dp->d_ino >= maxino) { ! 412: dprintf(stderr, "corrupted directory: bad inum %d\n", ! 413: dp->d_ino); ! 414: continue; ! 415: } ! 416: return (dp); ! 417: } ! 418: } ! 419: ! 420: /* ! 421: * Simulate the opening of a directory ! 422: */ ! 423: DIR * ! 424: rst_opendir(name) ! 425: char *name; ! 426: { ! 427: struct inotab *itp; ! 428: ino_t ino; ! 429: ! 430: if ((ino = dirlookup(name)) > 0 && ! 431: (itp = inotablookup(ino)) != NULL) { ! 432: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); ! 433: return (dirp); ! 434: } ! 435: return (0); ! 436: } ! 437: ! 438: /* ! 439: * Set the mode, owner, and times for all new or changed directories ! 440: */ ! 441: setdirmodes() ! 442: { ! 443: FILE *mf; ! 444: struct modeinfo node; ! 445: struct entry *ep; ! 446: char *cp; ! 447: ! 448: vprintf(stdout, "Set directory mode, owner, and times.\n"); ! 449: (void) sprintf(modefile, "/tmp/rstmode%d", dumpdate); ! 450: mf = fopen(modefile, "r"); ! 451: if (mf == NULL) { ! 452: perror("fopen"); ! 453: fprintf(stderr, "cannot open mode file %s\n", modefile); ! 454: fprintf(stderr, "directory mode, owner, and times not set\n"); ! 455: return; ! 456: } ! 457: clearerr(mf); ! 458: for (;;) { ! 459: (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); ! 460: if (feof(mf)) ! 461: break; ! 462: ep = lookupino(node.ino); ! 463: if (command == 'i' || command == 'x') { ! 464: if (ep == NIL) ! 465: continue; ! 466: if (ep->e_flags & EXISTED) { ! 467: ep->e_flags &= ~NEW; ! 468: continue; ! 469: } ! 470: if (node.ino == ROOTINO && ! 471: reply("set owner/mode for '.'") == FAIL) ! 472: continue; ! 473: } ! 474: if (ep == NIL) ! 475: panic("cannot find directory inode %d\n", node.ino); ! 476: cp = myname(ep); ! 477: (void) chown(cp, node.uid, node.gid); ! 478: (void) chmod(cp, node.mode); ! 479: utime(cp, node.timep); ! 480: ep->e_flags &= ~NEW; ! 481: } ! 482: if (ferror(mf)) ! 483: panic("error setting directory modes\n"); ! 484: (void) fclose(mf); ! 485: } ! 486: ! 487: /* ! 488: * Generate a literal copy of a directory. ! 489: */ ! 490: genliteraldir(name, ino) ! 491: char *name; ! 492: ino_t ino; ! 493: { ! 494: register struct inotab *itp; ! 495: int ofile, dp, i, size; ! 496: char buf[BUFSIZ]; ! 497: ! 498: itp = inotablookup(ino); ! 499: if (itp == NULL) ! 500: panic("Cannot find directory inode %d named %s\n", ino, name); ! 501: if ((ofile = creat(name, 0666)) < 0) { ! 502: fprintf(stderr, "%s: ", name); ! 503: (void) fflush(stderr); ! 504: perror("cannot create file"); ! 505: return (FAIL); ! 506: } ! 507: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); ! 508: dp = dup(dirp->dd_fd); ! 509: for (i = itp->t_size; i > 0; i -= BUFSIZ) { ! 510: size = i < BUFSIZ ? i : BUFSIZ; ! 511: if (read(dp, buf, (int) size) == -1) { ! 512: fprintf(stderr, ! 513: "write error extracting inode %d, name %s\n", ! 514: curfile.ino, curfile.name); ! 515: perror("read"); ! 516: done(1); ! 517: } ! 518: if (!Nflag && write(ofile, buf, (int) size) == -1) { ! 519: fprintf(stderr, ! 520: "write error extracting inode %d, name %s\n", ! 521: curfile.ino, curfile.name); ! 522: perror("write"); ! 523: done(1); ! 524: } ! 525: } ! 526: (void) close(dp); ! 527: (void) close(ofile); ! 528: return (GOOD); ! 529: } ! 530: ! 531: /* ! 532: * Determine the type of an inode ! 533: */ ! 534: inodetype(ino) ! 535: ino_t ino; ! 536: { ! 537: struct inotab *itp; ! 538: ! 539: itp = inotablookup(ino); ! 540: if (itp == NULL) ! 541: return (LEAF); ! 542: return (NODE); ! 543: } ! 544: ! 545: /* ! 546: * Allocate and initialize a directory inode entry. ! 547: * If requested, save its pertinent mode, owner, and time info. ! 548: */ ! 549: struct inotab * ! 550: allocinotab(ino, dip, seekpt) ! 551: ino_t ino; ! 552: struct dinode *dip; ! 553: daddr_t seekpt; ! 554: { ! 555: register struct inotab *itp; ! 556: struct modeinfo node; ! 557: ! 558: itp = (struct inotab *)calloc(1, sizeof(struct inotab)); ! 559: if (itp == 0) ! 560: panic("no memory directory table\n"); ! 561: itp->t_next = inotab[INOHASH(ino)]; ! 562: inotab[INOHASH(ino)] = itp; ! 563: itp->t_ino = ino; ! 564: itp->t_seekpt = seekpt; ! 565: if (mf == NULL) ! 566: return(itp); ! 567: node.ino = ino; ! 568: node.timep[0] = dip->di_atime; ! 569: node.timep[1] = dip->di_mtime; ! 570: node.mode = dip->di_mode; ! 571: node.uid = dip->di_uid; ! 572: node.gid = dip->di_gid; ! 573: (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); ! 574: return(itp); ! 575: } ! 576: ! 577: /* ! 578: * Look up an inode in the table of directories ! 579: */ ! 580: struct inotab * ! 581: inotablookup(ino) ! 582: ino_t ino; ! 583: { ! 584: register struct inotab *itp; ! 585: ! 586: for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) ! 587: if (itp->t_ino == ino) ! 588: return(itp); ! 589: return ((struct inotab *)0); ! 590: } ! 591: ! 592: /* ! 593: * Clean up and exit ! 594: */ ! 595: done(exitcode) ! 596: int exitcode; ! 597: { ! 598: ! 599: closemt(); ! 600: if (modefile[0] != '#') ! 601: (void) unlink(modefile); ! 602: if (dirfile[0] != '#') ! 603: (void) unlink(dirfile); ! 604: exit(exitcode); ! 605: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.