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