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