|
|
1.1 ! root 1: /* ! 2: * Restore. ! 3: * restor key [args] ! 4: * f [dump] Use this dump, not the default. ! 5: * v Verbose. ! 6: * t Print dates of the dump. ! 7: * x,X Extract. X asks for reel numbers and does ! 8: * a rewind between reels. ! 9: * r,R Mass restore. R asks for reel numbers and does ! 10: * a rewind between reels. ! 11: * ! 12: * Multiple dumps can be put on a single spool of ! 13: * tape by dumping to the no rewind device. The restore is ! 14: * done by positioning the tape using the `skip' command and ! 15: * restoring using the `x' option. ! 16: */ ! 17: #include <stdio.h> ! 18: #include <dumptape.h> ! 19: #include <canon.h> ! 20: #include <sys/filsys.h> ! 21: #include <sys/fblk.h> ! 22: #include <discbuf.h> ! 23: #include <signal.h> ! 24: ! 25: #define NRBUF 10 /* # of restore cache buffers */ ! 26: ! 27: /* ! 28: * This structure is used ! 29: * to remember the names and i numbers ! 30: * of the files being extracted. ! 31: */ ! 32: struct xf ! 33: { ! 34: char *xf_path; /* Path name */ ! 35: ino_t xf_ino; /* The associated inumber */ ! 36: }; ! 37: ! 38: /* ! 39: * Structure used to remember ! 40: * things about the directories that ! 41: * were on the tape. ! 42: */ ! 43: struct dlist ! 44: { ! 45: struct dlist *dl_dlp; /* Link */ ! 46: ino_t dl_ino; /* Inumber of the directory */ ! 47: long dl_seek; /* Temp file seek address */ ! 48: long dl_size; /* Size in bytes */ ! 49: }; ! 50: ! 51: int is_open; /* dump device open? */ ! 52: int key; /* Operation */ ! 53: int vflag; /* A verbose flag */ ! 54: char *dtn = DTAPE; /* Dump file name */ ! 55: FILE *dtp; /* Its file pointer */ ! 56: struct dumpheader dh; /* Header buffer */ ! 57: int reel = 1; /* Reel # */ ! 58: fsize_t length = 512; /* Length of volume */ ! 59: fsize_t nread; /* Bytes read from volume */ ! 60: char tfn[30] = "/tmp/ddxxxxxx"; /* Temp file name */ ! 61: FILE *tfp; /* Its file pointer */ ! 62: struct dlist *dlist; /* List of directory nodes */ ! 63: struct dlist *droot; /* Root (first) directory node */ ! 64: char *ddbuf; /* Big buffer */ ! 65: char *ddend; /* End of the big buffer */ ! 66: int ddnbuf; /* Size of the big buffer */ ! 67: union dumpdata *ddptr; /* Current buffer pointer */ ! 68: char *map; /* Directory map */ ! 69: int nxf; /* # of `x' files */ ! 70: ino_t nindisc; /* # of inodes on the disc */ ! 71: ino_t ningrab; /* # of inodes to grab */ ! 72: struct xf *xfp; /* Pointer for x names */ ! 73: ! 74: /* ! 75: * Block mapping tables. ! 76: */ ! 77: #define LNBN ((daddr_t) NBN) ! 78: ! 79: char offs[] = { ! 80: 0, ! 81: ND, ! 82: ND+1, ! 83: ND+1+1, ! 84: ND+1+1+1 ! 85: }; ! 86: ! 87: daddr_t ranges[] = { ! 88: ND, ! 89: ND + 1*LNBN, ! 90: ND + 1*LNBN + 1*LNBN*LNBN, ! 91: ND + 1*LNBN + 1*LNBN*LNBN + 1*LNBN*LNBN*LNBN ! 92: }; ! 93: ! 94: char shifts[] = { ! 95: 0, ! 96: L2NBN, ! 97: 2*L2NBN, ! 98: 3*L2NBN ! 99: }; ! 100: ! 101: daddr_t masks[] = { ! 102: 0, ! 103: LNBN-1, ! 104: LNBN*LNBN-1, ! 105: LNBN*LNBN*LNBN-1 ! 106: }; ! 107: ! 108: /* ! 109: * Forward references for the ! 110: * one pass compiler. ! 111: */ ! 112: ino_t lookup(); ! 113: ino_t numfile(); ! 114: daddr_t balloc(); ! 115: char *ctime(); ! 116: int cleanup(); ! 117: struct dlist *findnode(); ! 118: union dumpdata *readdump(); ! 119: char *calloc(); ! 120: DISCBUF *dbimap(); ! 121: ! 122: main(argc, argv) ! 123: char *argv[]; ! 124: { ! 125: register char *p; ! 126: register c, i; ! 127: register struct xf *rxfp; ! 128: char *name, *path; ! 129: ino_t ino; ! 130: ! 131: if (argc < 2) ! 132: usage(); ! 133: p = argv[1]; ! 134: i = 1; ! 135: while ((c = *p++) != '\0') { ! 136: switch (c) { ! 137: ! 138: case 'f': ! 139: if (++i >= argc) ! 140: usage(); ! 141: dtn = argv[i]; ! 142: break; ! 143: ! 144: case 'r': ! 145: case 'R': ! 146: case 'x': ! 147: case 'X': ! 148: case 't': ! 149: if (key != 0) ! 150: usage(); ! 151: key = c; ! 152: break; ! 153: ! 154: case 'v': ! 155: vflag = 1; ! 156: break; ! 157: ! 158: case '-': ! 159: { ! 160: /* Cf. nextvol() */ ! 161: extern long RESTMIN, RESTMAX; ! 162: ! 163: if (++i >= argc) ! 164: usage(); ! 165: RESTMIN = atoi(argv[i]); ! 166: if (++i >= argc) ! 167: usage(); ! 168: RESTMAX = atoi(argv[i]); ! 169: break; ! 170: } ! 171: ! 172: default: ! 173: usage(); ! 174: } ! 175: } ! 176: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 177: signal(SIGINT, cleanup); ! 178: switch (key) { ! 179: ! 180: case 'r': ! 181: case 'R': ! 182: if (++i >= argc) ! 183: usage(); ! 184: if ((dbfp = fopen(argv[i], "r+w")) == NULL) ! 185: message(1, "%s: cannot open filesystem", argv[i]); ! 186: dbclaim(NRBUF); ! 187: if (key == 'r') ! 188: nextvol(1); ! 189: else { ! 190: for (;;) { ! 191: reel = getreel(); ! 192: opendump(); ! 193: if (readhead(0) != 0) ! 194: break; ! 195: fclose(dtp); ! 196: } ! 197: } ! 198: restore(); ! 199: dbflush(1); ! 200: break; ! 201: ! 202: case 'x': ! 203: case 'X': ! 204: nextvol(1); ! 205: mktemp(tfn); ! 206: if ((tfp = fopen(tfn, "w")) == NULL ! 207: || (tfp = freopen(tfn, "r+w", tfp)) == NULL) ! 208: message(1, "cannot create temporary file"); ! 209: readdirs(); ! 210: xfp = (struct xf *)malloc((argc-i)*sizeof(struct xf)); ! 211: if (xfp == NULL) ! 212: message(1, "too many restore names"); ! 213: rxfp = xfp; ! 214: while (++i < argc) { ! 215: name = argv[i]; ! 216: if ((ino = numfile(name)) != 0) { ! 217: if (ino<ROOTIN || ino>dh.dh_nino) { ! 218: message(0, "%s: bad inumber", name); ! 219: continue; ! 220: } ! 221: path = "(by ino)"; ! 222: } else if ((ino = lookup(name)) != 0) ! 223: path = name; ! 224: else { ! 225: message(0, "%s: not found", name); ! 226: continue; ! 227: } ! 228: if (getmap(ino) == 0) { ! 229: message(0, "%s: not dumped", name); ! 230: continue; ! 231: } ! 232: rxfp->xf_path = path; ! 233: rxfp->xf_ino = ino; ! 234: rxfp++; ! 235: ++nxf; ! 236: } ! 237: if (nxf == 0) ! 238: break; ! 239: for (i=0; i<nxf; ++i) ! 240: printf("%u\t%s\n", xfp[i].xf_ino, xfp[i].xf_path); ! 241: if (key == 'x') ! 242: readfile(0); ! 243: else { ! 244: for (;;) { ! 245: fclose(dtp); ! 246: reel = getreel(); ! 247: opendump(); ! 248: readfile(1); ! 249: for (i=0; i<nxf && xfp[i].xf_ino==0; ++i) ! 250: ; ! 251: if (i == nxf) ! 252: break; ! 253: } ! 254: } ! 255: fclose(dtp); ! 256: for (i=0; i<nxf; ++i) ! 257: if (xfp[i].xf_ino != 0) ! 258: message(0, "%s: not restored", xfp[i].xf_path); ! 259: break; ! 260: ! 261: case 't': ! 262: opendump(); ! 263: readhead(1); ! 264: fprintf(stderr, "Dump since %s", ctime(&dh.dh_ddate)); ! 265: fprintf(stderr, "Dumped on %s", ctime(&dh.dh_bdate)); ! 266: break; ! 267: ! 268: default: ! 269: usage(); ! 270: } ! 271: delexit(0); ! 272: } ! 273: ! 274: /* ! 275: * If the supplied character string ! 276: * is all number convert it to binary and ! 277: * return it. Otherwise return 0. A ! 278: * file name that is all numeric is taken ! 279: * to be an inumber. ! 280: */ ! 281: ino_t ! 282: numfile(s) ! 283: register char *s; ! 284: { ! 285: register ino_t ino; ! 286: register c; ! 287: ! 288: ino = 0; ! 289: while ((c = *s++)>='0' && c<='9') ! 290: ino = 10*ino + c - '0'; ! 291: if (c != '\0') ! 292: return (0); ! 293: return (ino); ! 294: } ! 295: ! 296: /* ! 297: * Open the dump tape. ! 298: * Die if the tape cannot be opened ! 299: * for any reason. ! 300: */ ! 301: opendump() ! 302: { ! 303: if ((dtp = fopen(dtn, "r")) == NULL) ! 304: message(1, "%s: cannot open dump file", dtn); ! 305: ++is_open; ! 306: } ! 307: ! 308: /* ! 309: * Read reel number. ! 310: */ ! 311: getreel() ! 312: { ! 313: register c, flag, reel; ! 314: ! 315: for (;;) { ! 316: fprintf(stderr, "restor: desired volume? "); ! 317: reel = 0; ! 318: flag = 0; ! 319: while ((c = getchar())>='0' && c<='9') { ! 320: flag = 1; ! 321: reel = 10*reel + c - '0'; ! 322: } ! 323: if (c == EOF) ! 324: delexit(1); ! 325: if (c=='\n' && flag!=0) ! 326: return (reel); ! 327: message(0, "bad reel number"); ! 328: while (c!=EOF && c!='\n') ! 329: c = getchar(); ! 330: if (c == EOF) ! 331: delexit(1); ! 332: } ! 333: } ! 334: ! 335: /* ! 336: * Do the hard work of a ! 337: * restore. ! 338: * (NOTE: I think that the flag is now a fossil). ! 339: */ ! 340: readfile(flag) ! 341: { ! 342: register union dumpdata *ddp; ! 343: register ino_t ino; ! 344: register FILE *rfp; ! 345: register i; ! 346: int bwerror, outsync; ! 347: char rfn[20]; ! 348: ! 349: if (flag) { ! 350: while ((ddp = readdump()) != NULL) ! 351: if (ddp->dd_type != DD_DATA) ! 352: break; ! 353: #if 0 ! 354: if (readhead(0) == 0) ! 355: return; ! 356: while ((ddp = readdump()) != NULL) { ! 357: if (ddp->dd_type != DD_MAP) ! 358: break; ! 359: canino(ddp->dd_ino); ! 360: canint(ddp->dd_nmap); ! 361: setmap(ddp); ! 362: } ! 363: #endif ! 364: } else ! 365: ddp = readdump(); ! 366: if (ddp==NULL || anyfiles()==0) ! 367: return; ! 368: outsync = 0; ! 369: do { ! 370: switch (ddp->dd_type) { ! 371: ! 372: case DD_EOT: ! 373: return; ! 374: ! 375: case DD_INO: ! 376: canino(ddp->dd_ino); ! 377: ino = ddp->dd_ino; ! 378: rfp = NULL; ! 379: bwerror = 0; ! 380: if (outsync == 1) ! 381: message(0, "skipped 1 item"); ! 382: else if (outsync != 0) ! 383: message(0, "skipped %d items", outsync); ! 384: outsync = 0; ! 385: for (i=0; i<nxf && xfp[i].xf_ino!=ino; ++i) ! 386: ; ! 387: if (i != nxf) { ! 388: sprintf(rfn, "%u", ino); ! 389: if ((rfp = fopen(rfn, "w")) == NULL) ! 390: message(0, "%s: cannot create", rfn); ! 391: else ! 392: xfp[i].xf_ino = 0; ! 393: } ! 394: while ((ddp = readdump()) != NULL) { ! 395: if (ddp->dd_type != DD_DATA) ! 396: break; ! 397: canino(ddp->dd_ino); ! 398: if (ddp->dd_ino != ino) { ! 399: if (outsync == 0) ! 400: message(0, "data sync"); ! 401: ++outsync; ! 402: continue; ! 403: } ! 404: if (rfp != NULL) { ! 405: candaddr(ddp->dd_block); ! 406: canint(ddp->dd_size); ! 407: if (bwrite(rfp, ddp) == 0) ! 408: bwerror = 1; ! 409: } ! 410: } ! 411: if (bwerror) ! 412: message("%s: write error", rfn); ! 413: if (rfp != NULL) ! 414: fclose(rfp); ! 415: if (anyfiles() == 0) ! 416: return; ! 417: break; ! 418: ! 419: default: ! 420: if (outsync == 0) ! 421: message(0, "inode sync"); ! 422: ++outsync; ! 423: } ! 424: } while (ddp != NULL); ! 425: } ! 426: ! 427: /* ! 428: * Do a restore. ! 429: * The tape is open and the header ! 430: * has been checked. ! 431: */ ! 432: restore() ! 433: { ! 434: register union dumpdata *ddp; ! 435: register DISCBUF *dbp; ! 436: struct filsys *fsp; ! 437: register ino_t ino; ! 438: struct dinode *dip; ! 439: struct dinode dinode; ! 440: int me, outsync; ! 441: int ifmt, ndeleted; ! 442: ! 443: /* ! 444: * If the target file system is not ! 445: * large enough, complain about it and pretend ! 446: * that all of the inodes that are beyond the ! 447: * end are not there. This may, of course, leave ! 448: * the file system addled. ! 449: */ ! 450: dbp = dbread((long) SUPERI); ! 451: fsp = (struct filsys *) dbp->db_data; ! 452: nindisc = fsp->s_isize; ! 453: canino(nindisc); ! 454: nindisc = INOPB * (nindisc-INODEI); ! 455: ningrab = dh.dh_nino; ! 456: if (ningrab > nindisc) { ! 457: message(0, "I-list too small, some I-nodes may be deleted"); ! 458: ningrab = nindisc; ! 459: } ! 460: /* ! 461: * Read in the map. ! 462: */ ! 463: while ((ddp=readdump()) != NULL) { ! 464: if (ddp->dd_type != DD_MAP) ! 465: break; ! 466: canino(ddp->dd_ino); ! 467: canint(ddp->dd_nmap); ! 468: setmap(ddp); ! 469: } ! 470: /* ! 471: * Do required inode clears. ! 472: * Never clear the badblock inode. ! 473: * Clear only as far as we are restoring; ! 474: * that is, ningrab inodes. ! 475: */ ! 476: for (ino=ROOTIN; ino<=ningrab; ++ino) { ! 477: me = getmap(ino); ! 478: if ((me&DD_BUSY)==0 || (me&DD_HERE)==DD_HERE) { ! 479: if (vflag) ! 480: message(0, "clri I#%u", ino); ! 481: clri(ino); ! 482: } ! 483: } ! 484: /* ! 485: * Read through the tape. ! 486: * Look for files that we are going to ! 487: * restore and do so. ! 488: */ ! 489: outsync = 0; ! 490: ndeleted = 0; ! 491: while (ddp!=NULL && ddp->dd_type!=DD_EOT) { ! 492: if (ddp->dd_type != DD_INO) { ! 493: if (outsync++ == 0) ! 494: message(0, "inode sync"); ! 495: ddp = readdump(); ! 496: continue; ! 497: } ! 498: /* ! 499: * Restore the file. ! 500: * Block by block. ! 501: * Don't move anything. ! 502: */ ! 503: canino(ddp->dd_ino); ! 504: if ((ino=ddp->dd_ino) > ningrab) { ! 505: if (vflag != 0) ! 506: message(0, "deleted I#%u", (unsigned)ino); ! 507: ++ndeleted; ! 508: printskip(outsync); ! 509: outsync = 0; ! 510: while ((ddp=readdump()) != NULL) { ! 511: if (ddp->dd_type != DD_DATA) ! 512: break; ! 513: canino(ddp->dd_ino); ! 514: if (ddp->dd_ino!=ino && outsync++==0) ! 515: message(0, "skip sync"); ! 516: } ! 517: continue; ! 518: } ! 519: if (vflag != 0) ! 520: message(0, "restoring I#%u", (unsigned)ino); ! 521: copyb(&dinode, &ddp->dd_dinode, sizeof(dinode)); ! 522: canshort(ddp->dd_dinode.di_mode); ! 523: ifmt = ddp->dd_dinode.di_mode&IFMT; ! 524: if (ifmt==IFREG || ifmt==IFDIR) ! 525: zerob(dinode.di_addr, sizeof(dinode.di_addr)); ! 526: printskip(outsync); ! 527: outsync = 0; ! 528: while ((ddp=readdump()) != NULL) { ! 529: if (ddp->dd_type != DD_DATA) ! 530: break; ! 531: canino(ddp->dd_ino); ! 532: if (ddp->dd_ino != ino) { ! 533: if (outsync++ == 0) ! 534: message(0, "data sync"); ! 535: continue; ! 536: } ! 537: candaddr(ddp->dd_block); ! 538: canint(ddp->dd_size); ! 539: dbp = dbimap(&dinode, ddp->dd_block); ! 540: copyb(dbp->db_data,ddp->dd_data,ddp->dd_size); ! 541: dbfree(dbp, DB_DIRT); ! 542: } ! 543: dbp = dbread((long) (--ino/INOPB + INODEI)); ! 544: dip = (struct dinode *)(dbp->db_data) + ino%INOPB; ! 545: if (dip->di_mode != 0) { ! 546: message(0, "I#%u busy", (unsigned)ino+1); ! 547: clri(ino+1); ! 548: } ! 549: copyb((char *)dip, (char *)&dinode, sizeof(dinode)); ! 550: dbfree(dbp, DB_DIRT); ! 551: } ! 552: if (ndeleted != 0) ! 553: message(0, "%d I-nodes deleted", ndeleted); ! 554: fixilist(); ! 555: } ! 556: ! 557: /* ! 558: * Print out a message that ! 559: * tells the number of data items that were ! 560: * skipped on the tape. Special stuff for ! 561: * handling 0 and 1 items. ! 562: */ ! 563: printskip(n) ! 564: { ! 565: if (n == 1) ! 566: message(0, "skipped 1 item"); ! 567: else if (n != 0) ! 568: message(0, "skipped %d items", n); ! 569: } ! 570: ! 571: /* ! 572: * Fix the ifree list in ! 573: * the super block. It is safer to ! 574: * always reconstruct it. ! 575: */ ! 576: fixilist() ! 577: { ! 578: DISCBUF *ibp, *sbp; ! 579: register struct filsys *fsp; ! 580: register struct dinode *dip; ! 581: register ino_t ino; ! 582: short ninode, tinode, minode; ! 583: ino_t tmpino; ! 584: ! 585: if (vflag) ! 586: message(0, "building I-free list"); ! 587: sbp = dbread((long) SUPERI); ! 588: fsp = (struct filsys *)(sbp->db_data); ! 589: tinode = 0; ! 590: ninode = 0; ! 591: minode = fsp->s_isize; ! 592: canshort(minode); ! 593: minode = INOPB * (minode-INODEI); ! 594: ibp = NULL; ! 595: for (ino=1; ino<=minode; ++ino) { ! 596: if ((ino-1)%INOPB == 0) { ! 597: if (ibp != NULL) ! 598: dbfree(ibp, 0); ! 599: ibp = dbread((long) ((ino-1)/INOPB + INODEI)); ! 600: dip = (struct dinode *)(ibp->db_data); ! 601: } ! 602: if (dip->di_mode == 0) { ! 603: ++tinode; ! 604: if (ninode < NICINOD) { ! 605: tmpino = ino; ! 606: canino(tmpino); ! 607: fsp->s_inode[ninode++] = tmpino; ! 608: } ! 609: } ! 610: ++dip; ! 611: } ! 612: dbfree(ibp, 0); ! 613: canshort(tinode); ! 614: fsp->s_tinode = tinode; ! 615: canshort(ninode); ! 616: fsp->s_ninode = ninode; ! 617: strncpy(fsp->s_fname, dh.dh_fname, sizeof(dh.dh_fname)); ! 618: strncpy(fsp->s_fpack, dh.dh_fpack, sizeof(dh.dh_fpack)); ! 619: dbfree(sbp, DB_DIRT); ! 620: } ! 621: ! 622: /* ! 623: * Clear an inode. ! 624: * Free all of its blocks and ! 625: * zero the on disc inode. Don't worry about ! 626: * the super block as it is always rebuilt ! 627: * at the end. ! 628: */ ! 629: clri(ino) ! 630: ino_t ino; ! 631: { ! 632: register DISCBUF *dbp; ! 633: register struct dinode *dip; ! 634: register i; ! 635: short dimode; ! 636: daddr_t addr[NADDR]; ! 637: ! 638: dbp = dbread((long) ((ino-1)/INOPB + INODEI)); ! 639: dip = (struct dinode *)(dbp->db_data) + (ino-1)%INOPB; ! 640: dimode = dip->di_mode; ! 641: canshort(dimode); ! 642: if ((dimode&IFMT)==IFDIR || (dimode&IFMT)==IFREG) { ! 643: l3tol(addr, dip->di_addr, NADDR); ! 644: for (i=0; i<NADDR-3; ++i) ! 645: bfree(addr[i], 0); ! 646: bfree(addr[NADDR-3], 1); ! 647: bfree(addr[NADDR-2], 2); ! 648: bfree(addr[NADDR-1], 3); ! 649: } ! 650: zerob((char *) dip, sizeof(struct dinode)); ! 651: dbfree(dbp, DB_DIRT); ! 652: } ! 653: ! 654: /* ! 655: * Free a block. ! 656: * The first argument is the block ! 657: * number. 0 here means no block is allocated ! 658: * and the call is a nop. The second argument ! 659: * is the number of levels of indirect blocks ! 660: * to read through. ! 661: */ ! 662: bfree(bn, nil) ! 663: daddr_t bn; ! 664: { ! 665: register DISCBUF *dbp, *dbp1; ! 666: struct filsys *fsp; ! 667: struct fblk *fbp; ! 668: int dbp1flag; ! 669: int i; ! 670: daddr_t ibn; ! 671: ! 672: if (bn == 0) ! 673: return; ! 674: dbp1 = NULL; ! 675: if (nil != 0) { ! 676: dbp1flag = 0; ! 677: dbp1 = dbread((long) bn); ! 678: for (i=0; i<NBN; ++i) { ! 679: ibn = ((daddr_t *) dbp1->db_data)[i]; ! 680: if (ibn != 0) { ! 681: candaddr(ibn); /* Added by Mike */ ! 682: bfree(ibn, nil-1); ! 683: } ! 684: } ! 685: } ! 686: dbp = dbread((long) SUPERI); ! 687: fsp = (struct filsys *) dbp->db_data; ! 688: canshort(fsp->s_nfree); ! 689: if (fsp->s_nfree == NICFREE) { ! 690: if (dbp1 == NULL) ! 691: dbp1 = dbread((long) bn); ! 692: dbp1flag = DB_DIRT; ! 693: fbp = (struct fblk *) dbp1->db_data; ! 694: fbp->df_nfree = fsp->s_nfree; ! 695: canshort(fbp->df_nfree); ! 696: copyb(fbp->df_free, fsp->s_free, sizeof(fsp->s_free)); ! 697: fsp->s_nfree = 0; ! 698: } ! 699: candaddr(bn); ! 700: fsp->s_free[fsp->s_nfree++] = bn; ! 701: canshort(fsp->s_nfree); ! 702: candaddr(fsp->s_tfree); ! 703: ++fsp->s_tfree; ! 704: candaddr(fsp->s_tfree); ! 705: if (dbp1 != NULL) ! 706: dbfree(dbp1, dbp1flag); ! 707: dbfree(dbp, DB_DIRT); ! 708: } ! 709: ! 710: /* ! 711: * Allocate a block. ! 712: * Return 0 if there are no blocks ! 713: * remaining. ! 714: */ ! 715: daddr_t ! 716: balloc() ! 717: { ! 718: register struct filsys *fsp; ! 719: register DISCBUF *dbp; ! 720: register DISCBUF *dbp1; ! 721: register struct fblk *fbp; ! 722: short nfree; ! 723: daddr_t tfree, bn; ! 724: ! 725: dbp = dbread((long) SUPERI); ! 726: fsp = (struct filsys *) dbp->db_data; ! 727: if ((tfree = fsp->s_tfree) == 0) ! 728: message(1, "out of space"); ! 729: candaddr(tfree); ! 730: nfree = fsp->s_nfree; ! 731: canshort(nfree); ! 732: if ((bn = fsp->s_free[--nfree]) == 0) ! 733: message(1, "out of space and tfree lied"); ! 734: candaddr(bn); ! 735: if (nfree == 0) { ! 736: dbp1 = dbread((long) bn); ! 737: fbp = (struct fblk *) dbp1->db_data; ! 738: nfree = fbp->df_nfree; ! 739: canshort(nfree); ! 740: copyb(fsp->s_free, fbp->df_free, sizeof(fsp->s_free)); ! 741: dbfree(dbp1, 0); ! 742: } ! 743: --tfree; ! 744: canshort(nfree); ! 745: fsp->s_nfree = nfree; ! 746: candaddr(tfree); ! 747: fsp->s_tfree = tfree; ! 748: dbfree(dbp, DB_DIRT); ! 749: return (bn); ! 750: } ! 751: ! 752: /* ! 753: * Quickly zero out a block of ! 754: * memory. Used to clear out disc inodes ! 755: * and other similar things. ! 756: */ ! 757: zerob(ap, an) ! 758: char *ap; ! 759: { ! 760: register char *p; ! 761: register n; ! 762: ! 763: if ((n = an) != 0) { ! 764: p = ap; ! 765: do { ! 766: *p++ = 0; ! 767: } while (--n); ! 768: } ! 769: } ! 770: ! 771: /* ! 772: * Quickly move a block of ! 773: * memory from one place to another ! 774: * place. ! 775: */ ! 776: copyb(atp, afp, an) ! 777: char *atp; ! 778: char *afp; ! 779: { ! 780: register char *tp, *fp; ! 781: register n; ! 782: ! 783: if ((n = an) != 0) { ! 784: tp = atp; ! 785: fp = afp; ! 786: do { ! 787: *tp++ = *fp++; ! 788: } while (--n); ! 789: } ! 790: } ! 791: ! 792: /* ! 793: * Yet another version of ! 794: * the inode mapping code. This version ! 795: * allocates blocks if they are not present ! 796: * in the file. It makes good use of the ! 797: * buffer cache. ! 798: * A pointer to a DISCBUF holding the ! 799: * block is returned. Usually this will be ! 800: * a buffer created by `dbzero'. ! 801: */ ! 802: DISCBUF * ! 803: dbimap(dip, lb) ! 804: struct dinode *dip; ! 805: daddr_t lb; ! 806: { ! 807: register DISCBUF *dbp; ! 808: register il, newblock; ! 809: daddr_t addr[NADDR]; ! 810: daddr_t pb, bpos, *bkp; ! 811: ! 812: l3tol(addr, dip->di_addr, NADDR); ! 813: for (il=0; il<4; ++il) { ! 814: if (lb < ranges[il]) { ! 815: if (il > 0) ! 816: lb -= ranges[il-1]; ! 817: bpos = lb >> shifts[il]; ! 818: lb &= masks[il]; ! 819: bkp = &addr[(int)bpos + offs[il]]; ! 820: newblock = 0; ! 821: if ((pb = *bkp) == 0) { ! 822: newblock = 1; ! 823: *bkp = pb = balloc(); ! 824: ltol3(dip->di_addr, addr, NADDR); ! 825: } ! 826: if (pb != 0) { ! 827: while (il-- > 0) { ! 828: if (newblock) ! 829: dbp = dbzero(pb); else ! 830: dbp = dbread(pb); ! 831: bpos = lb >> shifts[il]; ! 832: lb &= masks[il]; ! 833: bkp = (long *)dbp->db_data + bpos; ! 834: pb = *bkp; ! 835: candaddr(pb); ! 836: if (pb == 0) { ! 837: newblock = 1; ! 838: pb = balloc(); ! 839: *bkp = pb; ! 840: candaddr(*bkp); ! 841: dbfree(dbp, DB_DIRT); ! 842: } else { ! 843: newblock = 0; ! 844: dbfree(dbp, 0); ! 845: } ! 846: if (pb == 0) ! 847: break; ! 848: } ! 849: } ! 850: if (pb != 0) { ! 851: if (newblock) ! 852: dbp = dbzero(pb); else ! 853: dbp = dbread(pb); ! 854: return (dbp); ! 855: } ! 856: return (NULL); ! 857: } ! 858: } ! 859: message(0, "file too large to map"); ! 860: return (NULL); ! 861: } ! 862: ! 863: /* ! 864: * Write a block. ! 865: */ ! 866: bwrite(fp, ddp) ! 867: register FILE *fp; ! 868: register union dumpdata *ddp; ! 869: { ! 870: lseek(fileno(fp), BUFSIZ*ddp->dd_block, 0); ! 871: if (write(fileno(fp), ddp->dd_data, ddp->dd_size) != ddp->dd_size) ! 872: return (0); ! 873: return (1); ! 874: } ! 875: ! 876: /* ! 877: * Check if any files in the ! 878: * `x' file list remain on this ! 879: * tape (as indicated by the ! 880: * map). ! 881: */ ! 882: anyfiles() ! 883: { ! 884: register ino_t ino; ! 885: register i; ! 886: ! 887: for (i=0; i<nxf; ++i) { ! 888: if ((ino = xfp[i].xf_ino)!=0 && getmap(ino)!=0) ! 889: return (1); ! 890: } ! 891: return (0); ! 892: } ! 893: ! 894: /* ! 895: * Read and validate tape header. ! 896: * The `quit' flag is true if errors ! 897: * are fatal. ! 898: * Only allocate the map first time. ! 899: */ ! 900: readhead(quit) ! 901: { ! 902: register char *p; ! 903: register checksum; ! 904: ! 905: if (read(fileno(dtp), &dh, sizeof dh) != sizeof dh) { ! 906: message(quit, "header read error"); ! 907: return (0); ! 908: } ! 909: nread = sizeof dh; ! 910: canint(dh.dh_magic); ! 911: canino(dh.dh_nino); ! 912: cantime(dh.dh_bdate); ! 913: cantime(dh.dh_ddate); ! 914: canint(dh.dh_level); ! 915: canint(dh.dh_reel); ! 916: canint(dh.dh_blocking); ! 917: cansize(dh.dh_nbyte); ! 918: canint(dh.dh_checksum); ! 919: if (dh.dh_magic != DH_MAG) { ! 920: message(quit, "not a dump"); ! 921: return (0); ! 922: } ! 923: p = (char *) &dh; ! 924: checksum = 0; ! 925: while (p < (char *) &dh.dh_checksum) ! 926: checksum += (*p++) & 0377; ! 927: if (checksum != dh.dh_checksum) { ! 928: message(quit, "checksum error"); ! 929: return (0); ! 930: } ! 931: if (dh.dh_reel != reel) { ! 932: message(quit, "wrong reel (is %d, not %d)", dh.dh_reel, reel); ! 933: return (0); ! 934: } ! 935: ++reel; ! 936: length = dh.dh_nbyte; ! 937: if (map == NULL) { ! 938: if ((map = calloc(sizeof(char), dh.dh_nino)) == NULL) ! 939: message(1, "out of memory (map)"); ! 940: } ! 941: if (ddbuf != NULL) ! 942: free(ddbuf); ! 943: ddnbuf = dh.dh_blocking * sizeof(union dumpdata); ! 944: if ((ddbuf = malloc(ddnbuf)) == NULL) ! 945: message(1, "out of memory (big buffer)"); ! 946: ddend = &ddbuf[ddnbuf]; ! 947: ddptr = (union dumpdata *) ddend; ! 948: return (1); ! 949: } ! 950: ! 951: /* ! 952: * Read in directories and set up ! 953: * the map. The last tape record is ungotten ! 954: * so that the extract code can be made a ! 955: * little simpler. ! 956: */ ! 957: readdirs() ! 958: { ! 959: register union dumpdata *ddp; ! 960: register struct dlist *dlp; ! 961: unsigned short mode; ! 962: ! 963: while ((ddp = readdump()) != NULL) { ! 964: switch (ddp->dd_type) { ! 965: ! 966: case DD_EOT: ! 967: --ddptr; ! 968: return; ! 969: ! 970: case DD_MAP: ! 971: canino(ddp->dd_ino); ! 972: canint(ddp->dd_nmap); ! 973: setmap(ddp); ! 974: break; ! 975: ! 976: case DD_INO: ! 977: mode = ddp->dd_dinode.di_mode; ! 978: canshort(mode); ! 979: if ((mode&IFMT) != IFDIR) { ! 980: --ddptr; ! 981: return; ! 982: } ! 983: canino(ddp->dd_ino); ! 984: cansize(ddp->dd_dinode.di_size); ! 985: dlp = (struct dlist *) malloc(sizeof(struct dlist)); ! 986: if (dlp == NULL) ! 987: message(1, "out of memory (dlist)"); ! 988: dlp->dl_dlp = dlist; ! 989: dlist = dlp; ! 990: if (droot == NULL) ! 991: droot = dlp; ! 992: dlp->dl_ino = ddp->dd_ino; ! 993: dlp->dl_seek = ftell(tfp); ! 994: dlp->dl_size = ddp->dd_dinode.di_size; ! 995: break; ! 996: ! 997: case DD_DATA: ! 998: canino(ddp->dd_ino); ! 999: candaddr(ddp->dd_block); ! 1000: canint(ddp->dd_size); ! 1001: if (dlist==NULL || dlist->dl_ino!=ddp->dd_ino) ! 1002: message(1, "directory out of sync"); ! 1003: fseek(tfp, dlp->dl_seek+(BUFSIZ*ddp->dd_block), 0); ! 1004: fwrite(ddp->dd_data, sizeof(char), ddp->dd_size, tfp); ! 1005: if (ferror(tfp)) ! 1006: message(1, "directory write error"); ! 1007: break; ! 1008: ! 1009: default: ! 1010: message(1, "bad type %d", ddp->dd_type); ! 1011: } ! 1012: } ! 1013: } ! 1014: ! 1015: /* ! 1016: * Fill in map. ! 1017: */ ! 1018: setmap(ddp) ! 1019: union dumpdata *ddp; ! 1020: { ! 1021: register char *p1, *p2; ! 1022: register nb; ! 1023: ! 1024: if ((nb = ddp->dd_nmap) != 0) { ! 1025: p1 = &map[ddp->dd_ino-1]; ! 1026: p2 = ddp->dd_map; ! 1027: do { ! 1028: *p1++ = *p2++; ! 1029: } while (--nb); ! 1030: } ! 1031: } ! 1032: ! 1033: /* ! 1034: * Get map item. ! 1035: */ ! 1036: getmap(ino) ! 1037: ino_t ino; ! 1038: { ! 1039: return (map[ino-1]); ! 1040: } ! 1041: ! 1042: /* ! 1043: * Read dump file. ! 1044: * Canonize the type and look after ! 1045: * multi-volume (reel) dumps. ! 1046: */ ! 1047: union dumpdata * ! 1048: readdump() ! 1049: { ! 1050: register nb; ! 1051: ! 1052: while ((char *) ddptr == ddend) { ! 1053: if (length != 0 && (nread+ddnbuf) > length) { ! 1054: nextvol(0); ! 1055: continue; ! 1056: } ! 1057: if ((nb = read(fileno(dtp), ddbuf, ddnbuf)) != ddnbuf) { ! 1058: if (nb != 0) ! 1059: message(1, "dump read error"); ! 1060: nextvol(0); ! 1061: continue; ! 1062: } ! 1063: ddptr = (union dumpdata *) ddbuf; ! 1064: nread += nb; ! 1065: break; ! 1066: } ! 1067: canint(ddptr->dd_type); ! 1068: return (ddptr++); ! 1069: } ! 1070: ! 1071: /* ! 1072: * Read the next volume (reel or diskette) ! 1073: * from the dump. ! 1074: * The flag is passed onto readhead for quiting. ! 1075: * ! 1076: * RESTMIN, RESTMAX, and restime are used to bound the time taken ! 1077: * to restor a volume in hopes of preventing unbounded copies of ! 1078: * Coherent dump distributions. The values are passed with an ! 1079: * undocumented '-' option which specifies RESTMIN and RESTMAX. ! 1080: */ ! 1081: long RESTMIN, RESTMAX, restime, time(); ! 1082: ! 1083: nextvol(flag) ! 1084: int flag; ! 1085: { ! 1086: register int c; ! 1087: register char *vtype = "reel"; ! 1088: ! 1089: restime += time(NULL); ! 1090: /* Spurious error to detect copies of dump volumes ! 1091: * made with ms-dos formatter/copier. Activated by ! 1092: * '-' key modifier in command list. ! 1093: * Not documented in manual. ! 1094: */ ! 1095: if (RESTMIN && reel > 1 && (restime < RESTMIN || restime > RESTMAX)) ! 1096: message(1, "volume sync: %ld", restime); ! 1097: for (;;) { ! 1098: if (is_open) { ! 1099: fclose(dtp); ! 1100: is_open = 0; ! 1101: } ! 1102: if (length != 0) ! 1103: vtype = "volume"; ! 1104: fprintf(stderr, "restor: mount %s %d, type return key...", ! 1105: vtype, reel); ! 1106: while ((c = getchar())!=EOF && c!='\n') ! 1107: ; ! 1108: if (c == EOF) ! 1109: delexit(1); ! 1110: restime = -time(NULL); ! 1111: opendump(); ! 1112: if (readhead(flag) != 0) ! 1113: break; ! 1114: } ! 1115: } ! 1116: ! 1117: /* ! 1118: * Lookup a file, by name. ! 1119: * Return the inumber. ! 1120: * This routine only looks in ! 1121: * directories. The file may ! 1122: * not actually be on the tape. ! 1123: */ ! 1124: ino_t ! 1125: lookup(cp) ! 1126: register char *cp; ! 1127: { ! 1128: char db[DIRSIZ]; ! 1129: struct direct dirbuf; ! 1130: ino_t ino; ! 1131: long seek; ! 1132: struct dlist *dlp; ! 1133: ! 1134: ino = ROOTIN; ! 1135: for (;;) { ! 1136: { ! 1137: register char *dp; ! 1138: register c; ! 1139: ! 1140: while ((c = *cp++) == '/') ! 1141: ; ! 1142: if (c == '\0') ! 1143: return (ino); ! 1144: dp = db; ! 1145: for (;;) { ! 1146: if (dp < &db[DIRSIZ]) ! 1147: *dp++ = c; ! 1148: if ((c = *cp)=='\0' || c=='/') ! 1149: break; ! 1150: ++cp; ! 1151: } ! 1152: while (dp < &db[DIRSIZ]) ! 1153: *dp++ = 0; ! 1154: } ! 1155: if ((dlp = findnode(ino)) == NULL) ! 1156: return (0); ! 1157: seek = dlp->dl_seek; ! 1158: for (;;) { ! 1159: if (seek-dlp->dl_seek >= dlp->dl_size) ! 1160: return (0); ! 1161: fseek(tfp, seek, 0); ! 1162: fread(&dirbuf, sizeof(dirbuf), 1, tfp); ! 1163: if (ferror(tfp)) ! 1164: message(1, "temporary file read error"); ! 1165: canino(dirbuf.d_ino); ! 1166: ino = dirbuf.d_ino; ! 1167: if (ino!=0 && strncmp(db, dirbuf.d_name, DIRSIZ)==0) ! 1168: break; ! 1169: seek += sizeof(struct direct); ! 1170: } ! 1171: } ! 1172: } ! 1173: ! 1174: /* ! 1175: * Look for a directory inode ! 1176: * in the dlist. ! 1177: */ ! 1178: struct dlist * ! 1179: findnode(ino) ! 1180: register ino_t ino; ! 1181: { ! 1182: register struct dlist *dlp; ! 1183: ! 1184: dlp = dlist; ! 1185: while (dlp != NULL) { ! 1186: if (dlp->dl_ino == ino) ! 1187: break; ! 1188: dlp = dlp->dl_dlp; ! 1189: } ! 1190: return (dlp); ! 1191: } ! 1192: ! 1193: /* ! 1194: * Usage message. ! 1195: */ ! 1196: usage() ! 1197: { ! 1198: fprintf(stderr, "Usage: restor key [args]\n"); ! 1199: delexit(1); ! 1200: } ! 1201: ! 1202: /* ! 1203: * Message output. ! 1204: */ ! 1205: message(quit, a) ! 1206: { ! 1207: fprintf(stderr, "restor: %r\n", &a); ! 1208: if (quit) ! 1209: delexit(1); ! 1210: } ! 1211: ! 1212: /* ! 1213: * Cleanup function. ! 1214: * Called from the interrupt signal. ! 1215: */ ! 1216: cleanup() ! 1217: { ! 1218: delexit(1); ! 1219: } ! 1220: ! 1221: /* ! 1222: * Exit. ! 1223: * Delete the temp file, if there. ! 1224: */ ! 1225: delexit(s) ! 1226: { ! 1227: if (tfp != NULL) ! 1228: unlink(tfn); ! 1229: exit(s); ! 1230: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.