1 /* Copyright (c) 1981 Regents of the University of California */ 2 3 char version[] = "@(#)main.c 1.14 02/26/82"; 4 5 /* Modified to include h option (recursively extract all files within 6 * a subtree) and m option (recreate the heirarchical structure of 7 * that subtree and move extracted files to their proper homes). 8 * 8/29/80 by Mike Litzkow 9 * 10 * Includes the s (skip files) option for use with multiple dumps on 11 * a single tape. 12 */ 13 14 /* static char *sccsid = "@(#)restor.c 4.3 (Berkeley) 6/3/81"; */ 15 16 #define MAXINO 3000 17 #define BITS 8 18 #define NCACHE 3 19 #define SIZEINC 10 20 21 #ifndef STANDALONE 22 #include <stdio.h> 23 #include <signal.h> 24 #endif 25 #include "../h/param.h" 26 #include "../h/inode.h" 27 #include "../h/fs.h" 28 #include "../h/buf.h" 29 #include "../h/user.h" 30 #include "../h/dumprestor.h" 31 #include <sys/mtio.h> 32 33 #define ODIRSIZ 14 34 struct odirect { 35 u_short d_ino; 36 char d_name[ODIRSIZ]; 37 }; 38 39 #define MWORD(m,i) (m[(unsigned)(i-1)/NBBY]) 40 #define MBIT(i) (1<<((unsigned)(i-1)%NBBY)) 41 #define BIS(i,w) (MWORD(w,i) |= MBIT(i)) 42 #define BIC(i,w) (MWORD(w,i) &= ~MBIT(i)) 43 #define BIT(i,w) (MWORD(w,i) & MBIT(i)) 44 45 ino_t ino, maxi; 46 struct inode *cur_ip; 47 48 int eflag = 0, hflag = 0, mflag = 0, cvtdir = 0; 49 50 char mounted = 0; 51 dev_t dev = 0; 52 struct fs *fsptr; 53 struct inode parentino; 54 char tapename[] = "/dev/rmt8"; 55 char *magtape = tapename; 56 int mt; 57 int dumpnum = 1; 58 int volno = 1; 59 int curblk = 0; 60 int bct = NTREC+1; 61 char tbf[NTREC*TP_BSIZE]; 62 63 #ifdef STANDALONE 64 char mbuf[50]; 65 #endif 66 67 daddr_t seekpt; 68 FILE *df; 69 DIR *dirp; 70 int ofile; 71 char dirfile[] = "rstXXXXXX"; 72 73 #define INOHASH(val) (val % MAXINO) 74 struct inotab { 75 struct inotab *t_next; 76 ino_t t_ino; 77 daddr_t t_seekpt; 78 } *inotab[MAXINO]; 79 80 #define XISDIR 1 81 #define XTRACTD 2 82 #define XINUSE 4 83 #define XLINKED 8 84 struct xtrlist { 85 struct xtrlist *x_next; 86 struct xtrlist *x_linkedto; 87 time_t x_timep[2]; 88 ino_t x_ino; 89 char x_flags; 90 char x_name[1]; 91 /* actually longer */ 92 } *xtrlist[MAXINO]; 93 int xtrcnt = 0; 94 95 #ifdef STANDALONE 96 #define msiz 8192 97 char dumpmap[msiz]; 98 char clrimap[msiz]; 99 #else 100 int msiz; 101 char *dumpmap; 102 char *clrimap; 103 #endif 104 105 char clearedbuf[MAXBSIZE]; 106 107 extern char *ctime(); 108 ino_t search(); 109 int dirwrite(); 110 char **envp; 111 112 main(argc, argv, arge) 113 int argc; 114 char *argv[]; 115 char **arge; 116 { 117 register char *cp; 118 char command; 119 int (*signal())(); 120 int done(); 121 122 if (signal(SIGINT, done) == SIG_IGN) 123 signal(SIGINT, SIG_IGN); 124 if (signal(SIGTERM, done) == SIG_IGN) 125 signal(SIGTERM, SIG_IGN); 126 #ifndef STANDALONE 127 envp = arge; 128 mktmp(dirfile); 129 if (argc < 2) { 130 usage: 131 fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n"); 132 done(1); 133 } 134 argv++; 135 argc -= 2; 136 for (cp = *argv++; *cp; cp++) { 137 switch (*cp) { 138 case '-': 139 break; 140 case 'f': 141 magtape = *argv++; 142 argc--; 143 break; 144 /* s dumpnum (skip to) for multifile dump tapes */ 145 case 's': 146 dumpnum = atoi(*argv++); 147 if(dumpnum <= 0) { 148 fprintf(stderr, "Dump number must be a positive integer\n"); 149 done(1); 150 } 151 argc--; 152 break; 153 case 'h': 154 hflag++; 155 break; 156 case 'm': 157 mflag++; 158 break; 159 case 'r': 160 case 'R': 161 case 't': 162 case 'x': 163 command = *cp; 164 break; 165 default: 166 fprintf(stderr, "Bad key character %c\n", *cp); 167 goto usage; 168 } 169 } 170 if (command == 'x') { 171 df = fopen(dirfile, "w"); 172 if (df == 0) { 173 fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile); 174 done(1); 175 } 176 xmount(envp); 177 mounted++; 178 } 179 doit(command, argc, argv); 180 done(0); 181 #else 182 magtape = "tape"; 183 doit('r', 1, 0); 184 #endif 185 } 186 187 doit(command, argc, argv) 188 char command; 189 int argc; 190 char *argv[]; 191 { 192 struct mtop tcom; 193 194 #ifndef STANDALONE 195 if ((mt = open(magtape, 0)) < 0) { 196 fprintf(stderr, "%s: cannot open tape\n", magtape); 197 done(1); 198 } 199 if (dumpnum != 1) { 200 tcom.mt_op = MTFSF; 201 tcom.mt_count = dumpnum -1; 202 if (ioctl(mt,MTIOCTOP,&tcom) < 0) 203 perror("ioctl MTFSF"); 204 } 205 #else 206 do { 207 fprintf(stderr, "Tape? "); 208 gets(mbuf); 209 mt = open(mbuf, 0); 210 } while (mt == -1); 211 magtape = mbuf; 212 #endif 213 blkclr(clearedbuf, MAXBSIZE); 214 switch(command) { 215 #ifndef STANDALONE 216 case 't': 217 if (readhdr(&spcl) == 0) { 218 fprintf(stderr, "Tape is not a dump tape\n"); 219 done(1); 220 } 221 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 222 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate)); 223 return; 224 case 'x': 225 extractfiles(argc, argv); 226 return; 227 #endif 228 case 'r': 229 case 'R': 230 restorfiles(command, argv); 231 return; 232 } 233 } 234 235 #ifndef STANDALONE 236 extractfiles(argc, argv) 237 int argc; 238 char **argv; 239 { 240 char *ststore(); 241 register struct xtrlist *xp; 242 struct xtrlist **xpp; 243 ino_t d; 244 int xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(), null(); 245 int mode; 246 char name[BUFSIZ + 1]; 247 248 if (readhdr(&spcl) == 0) { 249 fprintf(stderr, "Tape is not a dump tape\n"); 250 done(1); 251 } 252 if (checkvol(&spcl, 1) == 0) { 253 fprintf(stderr, "Tape is not volume 1 of the dump\n"); 254 } 255 fsptr = getfs(dev); 256 msiz = roundup(howmany(fsptr->fs_ipg * fsptr->fs_ncg, NBBY), TP_BSIZE); 257 clrimap = (char *)calloc(msiz, sizeof(char)); 258 dumpmap = (char *)calloc(msiz, sizeof(char)); 259 pass1(1); /* This sets the various maps on the way by */ 260 while (argc--) { 261 if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) { 262 fprintf(stdout, "%s: not on tape\n", *argv++); 263 continue; 264 } 265 if (mflag) 266 checkdir(*argv); 267 if(hflag) 268 getleaves(d, *argv++); 269 else 270 allocxtr(d, *argv++, XINUSE); 271 } 272 if (dumpnum > 1) { 273 /* 274 * if this is a multi-dump tape we always start with 275 * volume 1, so as to avoid accidentally restoring 276 * from a different dump! 277 */ 278 resetmt(); 279 dumpnum = 1; 280 volno = 1; 281 readhdr(&spcl); 282 goto rbits; 283 } 284 newvol: 285 resetmt(); 286 getvol: 287 fprintf(stderr, "Mount desired tape volume; Specify volume #: "); 288 if (gets(tbf) == NULL) 289 return; 290 volno = atoi(tbf); 291 if (volno <= 0) { 292 fprintf(stderr, "Volume numbers are positive numerics\n"); 293 goto getvol; 294 } 295 if (readhdr(&spcl) == 0) { 296 fprintf(stderr, "tape is not dump tape\n"); 297 goto newvol; 298 } 299 if (checkvol(&spcl, volno) == 0) { 300 fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume); 301 goto newvol; 302 } 303 rbits: 304 while (gethead(&spcl) == 0) 305 ; 306 if (checktype(&spcl, TS_INODE) == 1) { 307 fprintf(stderr, "Can't find inode mask!\n"); 308 goto newvol; 309 } 310 if (checktype(&spcl, TS_BITS) == 0) 311 goto rbits; 312 readbits(dumpmap); 313 while (xtrcnt > 0) { 314 again: 315 if (ishead(&spcl) == 0) 316 while(gethead(&spcl) == 0) 317 ; 318 if (checktype(&spcl, TS_END) == 1) { 319 fprintf(stderr, "end of tape\n"); 320 break; 321 } 322 if (checktype(&spcl, TS_INODE) == 0) { 323 gethead(&spcl); 324 goto again; 325 } 326 d = spcl.c_inumber; 327 for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) { 328 if (d != xp->x_ino) 329 continue; 330 if (xp->x_flags & XLINKED) 331 continue; 332 xp->x_timep[0] = spcl.c_dinode.di_atime; 333 xp->x_timep[1] = spcl.c_dinode.di_mtime; 334 mode = spcl.c_dinode.di_mode; 335 if (mflag) 336 strcpy(name, xp->x_name); 337 else 338 sprintf(name, "%u", xp->x_ino); 339 switch (mode & IFMT) { 340 default: 341 fprintf(stderr, "%s: unknown file type\n", name); 342 xp->x_flags |= XTRACTD; 343 xtrcnt--; 344 goto skipfile; 345 case IFCHR: 346 case IFBLK: 347 fprintf(stdout, "extract special file %s\n", name); 348 if (xmknod(name, mode, spcl.c_dinode.di_rdev)) { 349 fprintf(stderr, "%s: cannot create special file\n", name); 350 xp->x_flags |= XTRACTD; 351 xtrcnt--; 352 goto skipfile; 353 } 354 getfile(null, null, spcl.c_dinode.di_size); 355 break; 356 case IFDIR: 357 if (mflag) { 358 fprintf(stdout, "extract directory %s\n", name); 359 strncat(name, "/.", BUFSIZ); 360 checkdir(name); 361 xchown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 362 getfile(null, null, spcl.c_dinode.di_size); 363 break; 364 } 365 fprintf(stdout, "extract file %s\n", name); 366 if ((ofile = xcreat(name, 0666)) < 0) { 367 fprintf(stderr, "%s: cannot create file\n", name); 368 xp->x_flags |= XTRACTD; 369 xtrcnt--; 370 goto skipfile; 371 } 372 xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 373 if (cvtdir) { 374 getfile(xtrcvtdir, xtrcvtskip, 375 spcl.c_dinode.di_size); 376 flushent(xtrfile); 377 } else 378 getfile(xtrfile, xtrskip, 379 spcl.c_dinode.di_size); 380 xclose(ofile); 381 break; 382 case IFREG: 383 fprintf(stdout, "extract file %s\n", name); 384 if ((ofile = xcreat(name, 0666)) < 0) { 385 fprintf(stderr, "%s: cannot create file\n", name); 386 xp->x_flags |= XTRACTD; 387 xtrcnt--; 388 goto skipfile; 389 } 390 xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 391 getfile(xtrfile, xtrskip, spcl.c_dinode.di_size); 392 xclose(ofile); 393 break; 394 } 395 xchmod(name, mode); 396 xutime(name, xp->x_timep); 397 xp->x_flags |= XTRACTD; 398 xtrcnt--; 399 goto finished; 400 } 401 skipfile: 402 getfile(null, null, spcl.c_dinode.di_size); 403 finished: 404 ; 405 } 406 if (xtrcnt == 0 && !mflag) 407 return; 408 for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) { 409 for (xp = *xpp; xp; xp = xp->x_next) { 410 if (mflag && (xp->x_flags & XISDIR)) 411 xutime(xp->x_name, xp->x_timep); 412 if (xp->x_flags & XTRACTD) 413 continue; 414 if ((xp->x_flags & XLINKED) == 0) { 415 fprintf(stderr, "cannot find file %s\n", 416 xp->x_name); 417 continue; 418 } 419 if (!mflag) 420 continue; 421 fprintf(stdout, "link %s to %s\n", 422 xp->x_linkedto->x_name, xp->x_name); 423 if (xlink(xp->x_linkedto->x_name, xp->x_name) < 0) 424 fprintf(stderr, "link %s to %s failed\n", 425 xp->x_linkedto->x_name, xp->x_name); 426 } 427 } 428 } 429 #endif 430 431 restorfiles(command, argv) 432 char command; 433 char **argv; 434 { 435 int null(), rstrfile(), rstrskip(), rstrcvtdir(), rstrcvtskip(); 436 register struct dinode *dp; 437 register struct inode *ip; 438 int mode, type; 439 char mount[BUFSIZ + 1]; 440 char *ptr[2]; 441 442 mount[0] = '\0'; 443 strcpy(mount, "MOUNT="); 444 #ifndef STANDALONE 445 strncat(mount, *argv, BUFSIZ); 446 #else 447 fprintf(stderr, "Disk? "); 448 gets(&mount[6]); 449 #endif 450 ptr[0] = mount; 451 ptr[1] = 0; 452 xmount(ptr); 453 mounted++; 454 iput(u.u_cdir); /* release root inode */ 455 iput(u.u_rdir); /* release root inode */ 456 fsptr = getfs(dev); 457 parentino.i_fs = fsptr; 458 parentino.i_dev = dev; 459 maxi = fsptr->fs_ipg * fsptr->fs_ncg; 460 #ifndef STANDALONE 461 msiz = roundup(howmany(maxi, NBBY), TP_BSIZE); 462 clrimap = (char *)calloc(msiz, sizeof(char)); 463 dumpmap = (char *)calloc(msiz, sizeof(char)); 464 if (command == 'R') { 465 fprintf(stderr, "Enter starting volume number: "); 466 if (gets(tbf) == EOF) { 467 volno = 1; 468 fprintf(stderr, "\n"); 469 } 470 else 471 volno = atoi(tbf); 472 } 473 else 474 #endif 475 volno = 1; 476 fprintf(stderr, "Last chance before scribbling on %s. ", 477 #ifdef STANDALONE 478 "disk"); 479 #else 480 *argv); 481 #endif 482 while (getchar() != '\n'); 483 if (readhdr(&spcl) == 0) { 484 fprintf(stderr, "Missing volume record\n"); 485 done(1); 486 } 487 if (checkvol(&spcl, volno) == 0) { 488 fprintf(stderr, "Tape is not volume %d\n", volno); 489 done(1); 490 } 491 pass1(0); 492 gethead(&spcl); /* volume header already checked above */ 493 gethead(&spcl); 494 for (;;) { 495 if (ishead(&spcl) == 0) { 496 fprintf(stderr, "Missing header block\n"); 497 while (gethead(&spcl) == 0) 498 ; 499 eflag++; 500 } 501 if (checktype(&spcl, TS_END) == 1) { 502 fprintf(stderr, "End of tape\n"); 503 close(mt); 504 return; 505 } 506 if (checktype(&spcl, TS_CLRI) == 1) { 507 readbits(clrimap); 508 /* 509 * if throwing away the root inode, must also 510 * discard the predefined lost+found directory. 511 */ 512 if (BIT(ROOTINO, clrimap)) 513 BIS(LOSTFOUNDINO + 1, clrimap); 514 for (ino = ROOTINO; ino <= maxi; ino++) 515 if (BIT(ino, clrimap) == 0) { 516 if (!iexist(&parentino, ino)) 517 continue; 518 ip = iget(dev, fsptr, ino); 519 if (ip == NULL) { 520 fprintf(stderr, "can't find inode %u\n", ino); 521 done(1); 522 } 523 ip->i_nlink = 0; 524 ip->i_flag |= ICHG; 525 iput(ip); 526 } 527 continue; 528 } 529 if (checktype(&spcl, TS_BITS) == 1) { 530 readbits(dumpmap); 531 continue; 532 } 533 if (checktype(&spcl, TS_INODE) == 0) { 534 fprintf(stderr, "Unknown header type\n"); 535 eflag++; 536 gethead(&spcl); 537 continue; 538 } 539 ino = spcl.c_inumber; 540 if (eflag) 541 fprintf(stderr, "Resynced at inode %u\n", ino); 542 eflag = 0; 543 if (ino > maxi) { 544 fprintf(stderr, "%u: ilist too small\n", ino); 545 gethead(&spcl); 546 continue; 547 } 548 dp = &spcl.c_dinode; 549 if (ino < ROOTINO) { 550 getfile(null, null, dp->di_size); 551 continue; 552 } 553 if (iexist(&parentino, ino)) { 554 ip = iget(dev, fsptr, ino); 555 if (ip == NULL) { 556 fprintf(stderr, "can't find inode %u\n", 557 ino); 558 done(1); 559 } 560 ip->i_nlink = 0; 561 ip->i_flag |= ICHG; 562 iput(ip); 563 } 564 ip = ialloc(&parentino, ino, dp->di_mode); 565 if (ip == NULL || ip->i_number != ino) { 566 fprintf(stderr, "can't create inode %u\n", ino); 567 done(1); 568 } 569 ip->i_mode = mode = dp->di_mode; 570 ip->i_nlink = dp->di_nlink; 571 ip->i_uid = dp->di_uid; 572 ip->i_gid = dp->di_gid; 573 ip->i_atime = dp->di_atime; 574 ip->i_mtime = dp->di_mtime; 575 ip->i_ctime = dp->di_ctime; 576 type = ip->i_mode & IFMT; 577 if (type == IFCHR || type == IFBLK) 578 ip->i_rdev = dp->di_rdev; 579 ip->i_size = 0; 580 cur_ip = ip; 581 u.u_offset = 0; 582 u.u_segflg = 1; 583 if (cvtdir && type == IFDIR) { 584 getfile(rstrcvtdir, rstrcvtskip, dp->di_size); 585 flushent(rstrfile); 586 } else 587 getfile(rstrfile, rstrskip, dp->di_size); 588 ip->i_mode = mode; 589 ip->i_flag &= ~(IUPD|IACC); 590 ip->i_flag |= ICHG; 591 iput(ip); 592 } 593 } 594 595 /* 596 * Read the tape, bulding up a directory structure for extraction 597 * by name 598 */ 599 #ifndef STANDALONE 600 pass1(savedir) 601 int savedir; 602 { 603 register int i; 604 register struct dinode *ip; 605 struct direct nulldir; 606 char buf[TP_BSIZE]; 607 int putdir(), null(), dirwrite(); 608 609 nulldir.d_ino = 1; 610 nulldir.d_namlen = 1; 611 strncpy(nulldir.d_name, "/", nulldir.d_namlen); 612 nulldir.d_reclen = DIRSIZ(&nulldir); 613 while (gethead(&spcl) == 0) { 614 fprintf(stderr, "Can't find directory header!\n"); 615 } 616 for (;;) { 617 if (checktype(&spcl, TS_BITS) == 1) { 618 readbits(dumpmap); 619 continue; 620 } 621 if (checktype(&spcl, TS_CLRI) == 1) { 622 readbits(clrimap); 623 continue; 624 } 625 if (checktype(&spcl, TS_INODE) == 0) { 626 finish: 627 if (savedir) { 628 fclose(df); 629 dirp = opendir(dirfile); 630 if (dirp == NULL) 631 perror("opendir"); 632 } 633 resetmt(); 634 return; 635 } 636 ip = &spcl.c_dinode; 637 i = ip->di_mode & IFMT; 638 if (i != IFDIR) { 639 goto finish; 640 } 641 if (spcl.c_inumber == ROOTINO) { 642 readtape(buf); 643 bct--; /* push back this block */ 644 if (((struct direct *)buf)->d_ino != ROOTINO) { 645 if (((struct odirect *)buf)->d_ino != ROOTINO) { 646 fprintf(stderr, "bad root directory\n"); 647 done(1); 648 } 649 fprintf(stderr, "converting to new directory format\n"); 650 cvtdir = 1; 651 } 652 if (!savedir && !cvtdir) { 653 /* if no conversion, just return */ 654 goto finish; 655 } 656 } 657 allocinotab(spcl.c_inumber, seekpt); 658 if (savedir) { 659 getfile(putdir, null, spcl.c_dinode.di_size); 660 putent(&nulldir, dirwrite); 661 flushent(dirwrite); 662 } else { 663 getfile(null, null, spcl.c_dinode.di_size); 664 } 665 } 666 } 667 #endif 668 669 /* 670 * Put the directory entries in the directory file 671 */ 672 #ifndef STANDALONE 673 putdir(buf, size) 674 char *buf; 675 int size; 676 { 677 struct direct cvtbuf; 678 register struct odirect *odp; 679 struct odirect *eodp; 680 register struct direct *dp; 681 long loc; 682 683 if (cvtdir) { 684 eodp = (struct odirect *)&buf[size]; 685 for (odp = (struct odirect *)buf; odp < eodp; odp++) 686 if (odp->d_ino != 0) { 687 dcvt(odp, &cvtbuf); 688 putent(&cvtbuf, dirwrite); 689 } 690 } else { 691 for (loc = 0; loc < size; ) { 692 dp = (struct direct *)(buf + loc); 693 if (dp->d_ino != 0) 694 putent(dp, dirwrite); 695 } 696 } 697 } 698 699 /* 700 * Recursively find names and inumbers of all files in subtree 701 * pname and put them in xtrlist[] 702 */ 703 getleaves(ino, pname) 704 ino_t ino; 705 char *pname; 706 { 707 register struct inotab *itp; 708 int namelen; 709 long bpt; 710 register struct direct *dp; 711 char locname[BUFSIZ + 1]; 712 713 if (BIT(ino, dumpmap) == 0) { 714 fprintf(stdout, "%s: not on the tape\n", pname); 715 return; 716 } 717 for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) { 718 if (itp->t_ino != ino) 719 continue; 720 /* 721 * pname is a directory name 722 */ 723 allocxtr(ino, pname, XISDIR); 724 /* 725 * begin search through the directory 726 * skipping over "." and ".." 727 */ 728 strncpy(locname, pname, BUFSIZ); 729 strncat(locname, "/", BUFSIZ); 730 namelen = strlen(locname); 731 seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 732 dp = readdir(dirp); 733 dp = readdir(dirp); 734 dp = readdir(dirp); 735 bpt = telldir(dirp); 736 /* 737 * "/" signals end of directory 738 */ 739 while (dp->d_namlen != 1 || dp->d_name[0] != '/') { 740 locname[namelen] = '\0'; 741 if (namelen + dp->d_namlen >= BUFSIZ) { 742 fprintf(stderr, "%s%s: name exceedes %d char\n", 743 locname, dp->d_name, BUFSIZ); 744 continue; 745 } 746 strncat(locname, dp->d_name, dp->d_namlen); 747 getleaves(dp->d_ino, locname); 748 seekdir(dirp, bpt, itp->t_seekpt); 749 dp = readdir(dirp); 750 bpt = telldir(dirp); 751 } 752 return; 753 } 754 /* 755 * locname is name of a simple file 756 */ 757 allocxtr(ino, pname, XINUSE); 758 } 759 760 /* 761 * Search the directory tree rooted at inode ROOTINO 762 * for the path pointed at by n 763 */ 764 psearch(n) 765 char *n; 766 { 767 register char *cp, *cp1; 768 char c; 769 770 ino = ROOTINO; 771 if (*(cp = n) == '/') 772 cp++; 773 next: 774 cp1 = cp + 1; 775 while (*cp1 != '/' && *cp1) 776 cp1++; 777 c = *cp1; 778 *cp1 = 0; 779 ino = search(ino, cp); 780 if (ino == 0) { 781 *cp1 = c; 782 return(0); 783 } 784 *cp1 = c; 785 if (c == '/') { 786 cp = cp1+1; 787 goto next; 788 } 789 return(ino); 790 } 791 792 /* 793 * search the directory inode ino 794 * looking for entry cp 795 */ 796 ino_t 797 search(inum, cp) 798 ino_t inum; 799 char *cp; 800 { 801 register struct direct *dp; 802 register struct inotab *itp; 803 int len; 804 805 for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next) 806 if (itp->t_ino == inum) 807 goto found; 808 return(0); 809 found: 810 seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 811 len = strlen(cp); 812 do { 813 dp = readdir(dirp); 814 if (dp->d_namlen == 1 && dp->d_name[0] == '/') 815 return(0); 816 } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len)); 817 return(dp->d_ino); 818 } 819 #endif 820 821 /* 822 * Do the file extraction, calling the supplied functions 823 * with the blocks 824 */ 825 getfile(f1, f2, size) 826 int (*f2)(), (*f1)(); 827 long size; 828 { 829 register int i; 830 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 831 union u_spcl addrblk; 832 # define addrblock addrblk.s_spcl 833 834 addrblock = spcl; 835 for (;;) { 836 for (i = 0; i < addrblock.c_count; i++) { 837 if (addrblock.c_addr[i]) { 838 readtape(&buf[curblk++][0]); 839 if (curblk == BLKING(fsptr) * fsptr->fs_frag) { 840 (*f1)(buf, size > TP_BSIZE ? 841 (long) (BLKING(fsptr) * fsptr->fs_frag * TP_BSIZE) : 842 (curblk - 1) * TP_BSIZE + size); 843 curblk = 0; 844 } 845 } else { 846 if (curblk > 0) { 847 (*f1)(buf, size > TP_BSIZE ? 848 (long) (curblk * TP_BSIZE) : 849 (curblk - 1) * TP_BSIZE + size); 850 curblk = 0; 851 } 852 (*f2)(clearedbuf, size > TP_BSIZE ? 853 (long) TP_BSIZE : size); 854 } 855 if ((size -= TP_BSIZE) <= 0) { 856 eloop: 857 while (gethead(&spcl) == 0) 858 ; 859 if (checktype(&spcl, TS_ADDR) == 1) 860 goto eloop; 861 goto out; 862 } 863 } 864 if (gethead(&addrblock) == 0) { 865 fprintf(stderr, "Missing address (header) block, ino%u\n", ino); 866 goto eloop; 867 } 868 if (checktype(&addrblock, TS_ADDR) == 0) { 869 spcl = addrblock; 870 goto out; 871 } 872 } 873 out: 874 if (curblk > 0) { 875 (*f1)(buf, (curblk * TP_BSIZE) + size); 876 curblk = 0; 877 } 878 } 879 880 /* 881 * The next routines are called during file extraction to 882 * put the data into the right form and place. 883 */ 884 #ifndef STANDALONE 885 xtrfile(buf, size) 886 char *buf; 887 long size; 888 { 889 if (xwrite(ofile, buf, (int) size) == -1) { 890 perror("extract write"); 891 done(1); 892 } 893 } 894 895 xtrskip(buf, size) 896 char *buf; 897 long size; 898 { 899 if (xseek(ofile, size, 1) == -1) { 900 perror("extract seek"); 901 done(1); 902 } 903 } 904 905 xtrcvtdir(buf, size) 906 struct odirect *buf; 907 long size; 908 { 909 struct odirect *odp, *edp; 910 struct direct *dp, cvtbuf; 911 912 edp = &buf[size / sizeof(struct odirect)]; 913 for (odp = buf; odp < edp; odp++) { 914 dcvt(odp, &cvtbuf); 915 putent(&cvtbuf, xtrfile); 916 } 917 } 918 919 xtrcvtskip(buf, size) 920 char *buf; 921 long size; 922 { 923 fprintf(stderr, "unallocated block in directory\n"); 924 xtrskip(buf, size); 925 } 926 #endif 927 928 rstrfile(buf, size) 929 char *buf; 930 long size; 931 { 932 u.u_base = buf; 933 u.u_count = size; 934 writei(cur_ip); 935 if (u.u_error) { 936 perror("restor write"); 937 done(1); 938 } 939 } 940 941 rstrskip(buf, size) 942 char *buf; 943 long size; 944 { 945 u.u_offset += size; 946 } 947 948 rstrcvtdir(buf, size) 949 struct odirect *buf; 950 long size; 951 { 952 struct odirect *odp, *edp; 953 struct direct *dp, cvtbuf; 954 955 edp = &buf[size / sizeof(struct odirect)]; 956 for (odp = buf; odp < edp; odp++) { 957 dcvt(odp, &cvtbuf); 958 putent(&cvtbuf, rstrfile); 959 } 960 } 961 962 rstrcvtskip(buf, size) 963 char *buf; 964 long size; 965 { 966 fprintf(stderr, "unallocated block in directory\n"); 967 rstrskip(buf, size); 968 } 969 970 null() {;} 971 972 /* 973 * Do the tape i/o, dealing with volume changes 974 * etc.. 975 */ 976 readtape(b) 977 char *b; 978 { 979 register int i; 980 struct s_spcl tmpbuf; 981 982 if (bct >= NTREC) { 983 for (i = 0; i < NTREC; i++) 984 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0; 985 bct = 0; 986 if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) { 987 perror("Tape read error"); 988 eflag++; 989 done(1); 990 } 991 if (i == 0) { 992 bct = NTREC + 1; 993 volno++; 994 loop: 995 flsht(); 996 close(mt); 997 fprintf(stderr, "Mount volume %d\n", volno); 998 while (getchar() != '\n') 999 ; 1000 if ((mt = open(magtape, 0)) == -1) { 1001 fprintf(stderr, "Cannot open tape!\n"); 1002 goto loop; 1003 } 1004 if (readhdr(&tmpbuf) == 0) { 1005 fprintf(stderr, "Not a dump tape.Try again\n"); 1006 goto loop; 1007 } 1008 if (checkvol(&tmpbuf, volno) == 0) { 1009 fprintf(stderr, "Wrong tape. Try again\n"); 1010 goto loop; 1011 } 1012 readtape(b); 1013 return; 1014 } 1015 } 1016 blkcpy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE); 1017 } 1018 1019 flsht() 1020 { 1021 bct = NTREC+1; 1022 } 1023 1024 blkcpy(from, to, size) 1025 char *from, *to; 1026 int size; 1027 { 1028 asm(" movc3 12(ap),*4(ap),*8(ap)"); 1029 } 1030 1031 blkclr(buf, size) 1032 char *buf; 1033 int size; 1034 { 1035 asm("movc5 $0,(r0),$0,8(ap),*4(ap)"); 1036 } 1037 1038 resetmt() 1039 { 1040 struct mtop tcom; 1041 1042 if(dumpnum > 1) 1043 tcom.mt_op = MTBSF; 1044 else 1045 tcom.mt_op = MTREW; 1046 tcom.mt_count = 1; 1047 flsht(); 1048 if (ioctl(mt,MTIOCTOP,&tcom) == -1) { 1049 /* kludge for disk dumps */ 1050 lseek(mt, (long)0, 0); 1051 } 1052 if (dumpnum > 1) { 1053 tcom.mt_op = MTFSF; 1054 tcom.mt_count = 1; 1055 ioctl(mt,MTIOCTOP,&tcom); 1056 } 1057 } 1058 1059 checkvol(b, t) 1060 struct s_spcl *b; 1061 int t; 1062 { 1063 if (b->c_volume == t) 1064 return(1); 1065 return(0); 1066 } 1067 1068 readhdr(b) 1069 struct s_spcl *b; 1070 { 1071 if (gethead(b) == 0) 1072 return(0); 1073 if (checktype(b, TS_TAPE) == 0) 1074 return(0); 1075 return(1); 1076 } 1077 1078 /* 1079 * read the tape into buf, then return whether or 1080 * or not it is a header block. 1081 */ 1082 gethead(buf) 1083 struct s_spcl *buf; 1084 { 1085 readtape((char *)buf); 1086 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0) 1087 return(0); 1088 return(1); 1089 } 1090 1091 /* 1092 * return whether or not the buffer contains a header block 1093 */ 1094 ishead(buf) 1095 struct s_spcl *buf; 1096 { 1097 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0) 1098 return(0); 1099 return(1); 1100 } 1101 1102 checktype(b, t) 1103 struct s_spcl *b; 1104 int t; 1105 { 1106 return(b->c_type == t); 1107 } 1108 1109 /* 1110 * read a bit mask from the tape into m. 1111 */ 1112 readbits(m) 1113 char *m; 1114 { 1115 register int i; 1116 1117 i = spcl.c_count; 1118 1119 while (i--) { 1120 readtape((char *) m); 1121 m += (TP_BSIZE/(NBBY/BITS)); 1122 } 1123 while (gethead(&spcl) == 0) 1124 ; 1125 } 1126 1127 checksum(b) 1128 int *b; 1129 { 1130 register int i, j; 1131 1132 j = sizeof(union u_spcl) / sizeof(int); 1133 i = 0; 1134 do 1135 i += *b++; 1136 while (--j); 1137 if (i != CHECKSUM) { 1138 fprintf(stderr, "Checksum error %o, ino %u\n", i, ino); 1139 return(0); 1140 } 1141 return(1); 1142 } 1143 1144 /* 1145 * Check for access into each directory in the pathname of an extracted 1146 * file and create such a directory if needed in preparation for moving 1147 * the file to its proper home. 1148 */ 1149 checkdir(name) 1150 register char *name; 1151 { 1152 register char *cp; 1153 int i; 1154 1155 for (cp = name; *cp; cp++) { 1156 if (*cp == '/') { 1157 *cp = '\0'; 1158 if (xaccess(name, 01) < 0) { 1159 register int pid, rp; 1160 1161 xumount(); 1162 if ((pid = fork()) == 0) { 1163 execl("/bin/xmkdir", "xmkdir", name, 0); 1164 execl("/usr/bin/xmkdir", "xmkdir", name, 0); 1165 execl("./xmkdir", "xmkdir", name, 0); 1166 fprintf(stderr, "xrestor: cannot find xmkdir!\n"); 1167 done(0); 1168 } 1169 while ((rp = wait(&i)) >= 0 && rp != pid) 1170 ; 1171 xmount(envp); 1172 fsptr = getfs(dev); 1173 parentino.i_fs = fsptr; 1174 } 1175 *cp = '/'; 1176 } 1177 } 1178 } 1179 1180 /* 1181 * These variables are "local" to the following two functions. 1182 */ 1183 char dirbuf[DIRBLKSIZ]; 1184 long dirloc = 0; 1185 long prev = 0; 1186 1187 /* 1188 * add a new directory entry to a file. 1189 */ 1190 putent(dp, wrtfunc) 1191 struct direct *dp; 1192 int (*wrtfunc)(); 1193 { 1194 if (dp->d_ino == 0) 1195 return; 1196 for (;;) { 1197 if (dp->d_reclen < DIRBLKSIZ - dirloc) { 1198 blkcpy(dp, dirbuf + dirloc, dp->d_reclen); 1199 prev = dirloc; 1200 dirloc += dp->d_reclen; 1201 return; 1202 } 1203 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 1204 (*wrtfunc)(dirbuf, DIRBLKSIZ); 1205 dirloc = 0; 1206 } 1207 } 1208 1209 /* 1210 * flush out a directory that is finished. 1211 */ 1212 flushent(wrtfunc) 1213 int (*wrtfunc)(); 1214 { 1215 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 1216 (*wrtfunc)(dirbuf, dirloc); 1217 dirloc = 0; 1218 } 1219 1220 dirwrite(buf, size) 1221 char *buf; 1222 int size; 1223 { 1224 fwrite(buf, 1, size, df); 1225 seekpt = ftell(df); 1226 } 1227 1228 dcvt(odp, ndp) 1229 register struct odirect *odp; 1230 register struct direct *ndp; 1231 { 1232 struct inotab *itp; 1233 1234 blkclr(ndp, sizeof *ndp); 1235 ndp->d_ino = odp->d_ino; 1236 strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 1237 ndp->d_namlen = strlen(ndp->d_name); 1238 ndp->d_reclen = DIRSIZ(ndp); 1239 /* 1240 * this quickly calculates if this inode is a directory. 1241 * Currently not maintained. 1242 * 1243 for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) { 1244 if (itp->t_ino != odp->d_ino) 1245 continue; 1246 ndp->d_fmt = IFDIR; 1247 break; 1248 } 1249 */ 1250 } 1251 1252 /* 1253 * seek to an entry in a directory. 1254 * Only values returned by ``telldir'' should be passed to seekdir. 1255 * Modified to have many directories based in one file. 1256 */ 1257 void 1258 seekdir(dirp, loc, base) 1259 register DIR *dirp; 1260 long loc, base; 1261 { 1262 if (loc == telldir(dirp)) 1263 return; 1264 loc -= base; 1265 if (loc < 0) 1266 fprintf(stderr, "bad seek pointer to seekdir %d\n", loc); 1267 lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 1268 dirp->dd_loc = loc & (DIRBLKSIZ - 1); 1269 if (dirp->dd_loc != 0) 1270 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 1271 } 1272 1273 /* 1274 * tell whether an inode is allocated 1275 * this is drawn from ialloccg in sys/alloc.c 1276 */ 1277 iexist(ip, ino) 1278 struct inode *ip; 1279 ino_t ino; 1280 { 1281 register struct fs *fs; 1282 register struct cg *cgp; 1283 register struct buf *bp; 1284 int cg; 1285 1286 fs = ip->i_fs; 1287 if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 1288 return (0); 1289 cg = itog(fs, ino); 1290 bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize); 1291 if (bp->b_flags & B_ERROR) { 1292 brelse(bp); 1293 return(0); 1294 } 1295 cgp = bp->b_un.b_cg; 1296 ino %= fs->fs_ipg; 1297 if (isclr(cgp->cg_iused, ino)) { 1298 brelse(bp); 1299 return(0); 1300 } 1301 brelse(bp); 1302 return (1); 1303 } 1304 1305 allocinotab(ino, seekpt) 1306 ino_t ino; 1307 daddr_t seekpt; 1308 { 1309 register struct inotab *itp; 1310 1311 itp = (struct inotab *)calloc(1, sizeof(struct inotab)); 1312 itp->t_next = inotab[INOHASH(ino)]; 1313 inotab[INOHASH(ino)] = itp; 1314 itp->t_ino = ino; 1315 itp->t_seekpt = seekpt; 1316 } 1317 1318 allocxtr(ino, name, flags) 1319 ino_t ino; 1320 char *name; 1321 char flags; 1322 { 1323 register struct xtrlist *xp, *pxp; 1324 1325 xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name)); 1326 xp->x_next = xtrlist[INOHASH(ino)]; 1327 xtrlist[INOHASH(ino)] = xp; 1328 xp->x_ino = ino; 1329 strcpy(xp->x_name, name); 1330 xtrcnt++; 1331 xp->x_flags = flags; 1332 for (pxp = xp->x_next; pxp; pxp = pxp->x_next) 1333 if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) { 1334 xp->x_flags |= XLINKED; 1335 xp->x_linkedto = pxp; 1336 xtrcnt--; 1337 break; 1338 } 1339 if (xp->x_flags & XLINKED) 1340 fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name); 1341 else if (xp->x_flags & XISDIR) 1342 fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino); 1343 else 1344 fprintf(stdout, "%s: inode %u\n", xp->x_name, ino); 1345 } 1346 1347 done(exitcode) 1348 int exitcode; 1349 { 1350 #ifndef STANDALONE 1351 unlink(dirfile); 1352 #endif 1353 if (mounted) 1354 xumount(); 1355 exit(exitcode); 1356 } 1357