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