1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)restore.c 8.1 (Berkeley) 06/05/93"; 10 #endif /* not lint */ 11 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 15 #include <ufs/ufs/dinode.h> 16 17 #include <stdio.h> 18 #include <string.h> 19 20 #include "restore.h" 21 #include "extern.h" 22 23 static char *keyval __P((int)); 24 25 /* 26 * This implements the 't' option. 27 * List entries on the tape. 28 */ 29 long 30 listfile(name, ino, type) 31 char *name; 32 ino_t ino; 33 int type; 34 { 35 long descend = hflag ? GOOD : FAIL; 36 37 if (TSTINO(ino, dumpmap) == 0) 38 return (descend); 39 vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir "); 40 fprintf(stdout, "%10d\t%s\n", ino, name); 41 return (descend); 42 } 43 44 /* 45 * This implements the 'x' option. 46 * Request that new entries be extracted. 47 */ 48 long 49 addfile(name, ino, type) 50 char *name; 51 ino_t ino; 52 int type; 53 { 54 register struct entry *ep; 55 long descend = hflag ? GOOD : FAIL; 56 char buf[100]; 57 58 if (TSTINO(ino, dumpmap) == 0) { 59 dprintf(stdout, "%s: not on the tape\n", name); 60 return (descend); 61 } 62 if (!mflag) { 63 (void) sprintf(buf, "./%u", ino); 64 name = buf; 65 if (type == NODE) { 66 (void) genliteraldir(name, ino); 67 return (descend); 68 } 69 } 70 ep = lookupino(ino); 71 if (ep != NULL) { 72 if (strcmp(name, myname(ep)) == 0) { 73 ep->e_flags |= NEW; 74 return (descend); 75 } 76 type |= LINK; 77 } 78 ep = addentry(name, ino, type); 79 if (type == NODE) 80 newnode(ep); 81 ep->e_flags |= NEW; 82 return (descend); 83 } 84 85 /* 86 * This is used by the 'i' option to undo previous requests made by addfile. 87 * Delete entries from the request queue. 88 */ 89 /* ARGSUSED */ 90 long 91 deletefile(name, ino, type) 92 char *name; 93 ino_t ino; 94 int type; 95 { 96 long descend = hflag ? GOOD : FAIL; 97 struct entry *ep; 98 99 if (TSTINO(ino, dumpmap) == 0) 100 return (descend); 101 ep = lookupino(ino); 102 if (ep != NULL) 103 ep->e_flags &= ~NEW; 104 return (descend); 105 } 106 107 /* 108 * The following four routines implement the incremental 109 * restore algorithm. The first removes old entries, the second 110 * does renames and calculates the extraction list, the third 111 * cleans up link names missed by the first two, and the final 112 * one deletes old directories. 113 * 114 * Directories cannot be immediately deleted, as they may have 115 * other files in them which need to be moved out first. As 116 * directories to be deleted are found, they are put on the 117 * following deletion list. After all deletions and renames 118 * are done, this list is actually deleted. 119 */ 120 static struct entry *removelist; 121 122 /* 123 * Remove unneeded leaves from the old tree. 124 * Remove directories from the lookup chains. 125 */ 126 void 127 removeoldleaves() 128 { 129 register struct entry *ep; 130 register ino_t i; 131 132 vprintf(stdout, "Mark entries to be removed.\n"); 133 for (i = ROOTINO + 1; i < maxino; i++) { 134 ep = lookupino(i); 135 if (ep == NULL) 136 continue; 137 if (TSTINO(i, clrimap)) 138 continue; 139 for ( ; ep != NULL; ep = ep->e_links) { 140 dprintf(stdout, "%s: REMOVE\n", myname(ep)); 141 if (ep->e_type == LEAF) { 142 removeleaf(ep); 143 freeentry(ep); 144 } else { 145 mktempname(ep); 146 deleteino(ep->e_ino); 147 ep->e_next = removelist; 148 removelist = ep; 149 } 150 } 151 } 152 } 153 154 /* 155 * For each directory entry on the incremental tape, determine which 156 * category it falls into as follows: 157 * KEEP - entries that are to be left alone. 158 * NEW - new entries to be added. 159 * EXTRACT - files that must be updated with new contents. 160 * LINK - new links to be added. 161 * Renames are done at the same time. 162 */ 163 long 164 nodeupdates(name, ino, type) 165 char *name; 166 ino_t ino; 167 int type; 168 { 169 register struct entry *ep, *np, *ip; 170 long descend = GOOD; 171 int lookuptype = 0; 172 int key = 0; 173 /* key values */ 174 # define ONTAPE 0x1 /* inode is on the tape */ 175 # define INOFND 0x2 /* inode already exists */ 176 # define NAMEFND 0x4 /* name already exists */ 177 # define MODECHG 0x8 /* mode of inode changed */ 178 179 /* 180 * This routine is called once for each element in the 181 * directory hierarchy, with a full path name. 182 * The "type" value is incorrectly specified as LEAF for 183 * directories that are not on the dump tape. 184 * 185 * Check to see if the file is on the tape. 186 */ 187 if (TSTINO(ino, dumpmap)) 188 key |= ONTAPE; 189 /* 190 * Check to see if the name exists, and if the name is a link. 191 */ 192 np = lookupname(name); 193 if (np != NULL) { 194 key |= NAMEFND; 195 ip = lookupino(np->e_ino); 196 if (ip == NULL) 197 panic("corrupted symbol table\n"); 198 if (ip != np) 199 lookuptype = LINK; 200 } 201 /* 202 * Check to see if the inode exists, and if one of its links 203 * corresponds to the name (if one was found). 204 */ 205 ip = lookupino(ino); 206 if (ip != NULL) { 207 key |= INOFND; 208 for (ep = ip->e_links; ep != NULL; ep = ep->e_links) { 209 if (ep == np) { 210 ip = ep; 211 break; 212 } 213 } 214 } 215 /* 216 * If both a name and an inode are found, but they do not 217 * correspond to the same file, then both the inode that has 218 * been found and the inode corresponding to the name that 219 * has been found need to be renamed. The current pathname 220 * is the new name for the inode that has been found. Since 221 * all files to be deleted have already been removed, the 222 * named file is either a now unneeded link, or it must live 223 * under a new name in this dump level. If it is a link, it 224 * can be removed. If it is not a link, it is given a 225 * temporary name in anticipation that it will be renamed 226 * when it is later found by inode number. 227 */ 228 if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) { 229 if (lookuptype == LINK) { 230 removeleaf(np); 231 freeentry(np); 232 } else { 233 dprintf(stdout, "name/inode conflict, mktempname %s\n", 234 myname(np)); 235 mktempname(np); 236 } 237 np = NULL; 238 key &= ~NAMEFND; 239 } 240 if ((key & ONTAPE) && 241 (((key & INOFND) && ip->e_type != type) || 242 ((key & NAMEFND) && np->e_type != type))) 243 key |= MODECHG; 244 245 /* 246 * Decide on the disposition of the file based on its flags. 247 * Note that we have already handled the case in which 248 * a name and inode are found that correspond to different files. 249 * Thus if both NAMEFND and INOFND are set then ip == np. 250 */ 251 switch (key) { 252 253 /* 254 * A previously existing file has been found. 255 * Mark it as KEEP so that other links to the inode can be 256 * detected, and so that it will not be reclaimed by the search 257 * for unreferenced names. 258 */ 259 case INOFND|NAMEFND: 260 ip->e_flags |= KEEP; 261 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 262 flagvalues(ip)); 263 break; 264 265 /* 266 * A file on the tape has a name which is the same as a name 267 * corresponding to a different file in the previous dump. 268 * Since all files to be deleted have already been removed, 269 * this file is either a now unneeded link, or it must live 270 * under a new name in this dump level. If it is a link, it 271 * can simply be removed. If it is not a link, it is given a 272 * temporary name in anticipation that it will be renamed 273 * when it is later found by inode number (see INOFND case 274 * below). The entry is then treated as a new file. 275 */ 276 case ONTAPE|NAMEFND: 277 case ONTAPE|NAMEFND|MODECHG: 278 if (lookuptype == LINK) { 279 removeleaf(np); 280 freeentry(np); 281 } else { 282 mktempname(np); 283 } 284 /* fall through */ 285 286 /* 287 * A previously non-existent file. 288 * Add it to the file system, and request its extraction. 289 * If it is a directory, create it immediately. 290 * (Since the name is unused there can be no conflict) 291 */ 292 case ONTAPE: 293 ep = addentry(name, ino, type); 294 if (type == NODE) 295 newnode(ep); 296 ep->e_flags |= NEW|KEEP; 297 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 298 flagvalues(ep)); 299 break; 300 301 /* 302 * A file with the same inode number, but a different 303 * name has been found. If the other name has not already 304 * been found (indicated by the KEEP flag, see above) then 305 * this must be a new name for the file, and it is renamed. 306 * If the other name has been found then this must be a 307 * link to the file. Hard links to directories are not 308 * permitted, and are either deleted or converted to 309 * symbolic links. Finally, if the file is on the tape, 310 * a request is made to extract it. 311 */ 312 case ONTAPE|INOFND: 313 if (type == LEAF && (ip->e_flags & KEEP) == 0) 314 ip->e_flags |= EXTRACT; 315 /* fall through */ 316 case INOFND: 317 if ((ip->e_flags & KEEP) == 0) { 318 renameit(myname(ip), name); 319 moveentry(ip, name); 320 ip->e_flags |= KEEP; 321 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 322 flagvalues(ip)); 323 break; 324 } 325 if (ip->e_type == NODE) { 326 descend = FAIL; 327 fprintf(stderr, 328 "deleted hard link %s to directory %s\n", 329 name, myname(ip)); 330 break; 331 } 332 ep = addentry(name, ino, type|LINK); 333 ep->e_flags |= NEW; 334 dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, 335 flagvalues(ep)); 336 break; 337 338 /* 339 * A previously known file which is to be updated. If it is a link, 340 * then all names referring to the previous file must be removed 341 * so that the subset of them that remain can be recreated. 342 */ 343 case ONTAPE|INOFND|NAMEFND: 344 if (lookuptype == LINK) { 345 removeleaf(np); 346 freeentry(np); 347 ep = addentry(name, ino, type|LINK); 348 if (type == NODE) 349 newnode(ep); 350 ep->e_flags |= NEW|KEEP; 351 dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, 352 flagvalues(ep)); 353 break; 354 } 355 if (type == LEAF && lookuptype != LINK) 356 np->e_flags |= EXTRACT; 357 np->e_flags |= KEEP; 358 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 359 flagvalues(np)); 360 break; 361 362 /* 363 * An inode is being reused in a completely different way. 364 * Normally an extract can simply do an "unlink" followed 365 * by a "creat". Here we must do effectively the same 366 * thing. The complications arise because we cannot really 367 * delete a directory since it may still contain files 368 * that we need to rename, so we delete it from the symbol 369 * table, and put it on the list to be deleted eventually. 370 * Conversely if a directory is to be created, it must be 371 * done immediately, rather than waiting until the 372 * extraction phase. 373 */ 374 case ONTAPE|INOFND|MODECHG: 375 case ONTAPE|INOFND|NAMEFND|MODECHG: 376 if (ip->e_flags & KEEP) { 377 badentry(ip, "cannot KEEP and change modes"); 378 break; 379 } 380 if (ip->e_type == LEAF) { 381 /* changing from leaf to node */ 382 removeleaf(ip); 383 freeentry(ip); 384 ip = addentry(name, ino, type); 385 newnode(ip); 386 } else { 387 /* changing from node to leaf */ 388 if ((ip->e_flags & TMPNAME) == 0) 389 mktempname(ip); 390 deleteino(ip->e_ino); 391 ip->e_next = removelist; 392 removelist = ip; 393 ip = addentry(name, ino, type); 394 } 395 ip->e_flags |= NEW|KEEP; 396 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 397 flagvalues(ip)); 398 break; 399 400 /* 401 * A hard link to a diirectory that has been removed. 402 * Ignore it. 403 */ 404 case NAMEFND: 405 dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key), 406 name); 407 descend = FAIL; 408 break; 409 410 /* 411 * If we find a directory entry for a file that is not on 412 * the tape, then we must have found a file that was created 413 * while the dump was in progress. Since we have no contents 414 * for it, we discard the name knowing that it will be on the 415 * next incremental tape. 416 */ 417 case NULL: 418 fprintf(stderr, "%s: (inode %d) not found on tape\n", 419 name, ino); 420 break; 421 422 /* 423 * If any of these arise, something is grievously wrong with 424 * the current state of the symbol table. 425 */ 426 case INOFND|NAMEFND|MODECHG: 427 case NAMEFND|MODECHG: 428 case INOFND|MODECHG: 429 fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key), 430 name); 431 break; 432 433 /* 434 * These states "cannot" arise for any state of the symbol table. 435 */ 436 case ONTAPE|MODECHG: 437 case MODECHG: 438 default: 439 panic("[%s] %s: impossible state\n", keyval(key), name); 440 break; 441 } 442 return (descend); 443 } 444 445 /* 446 * Calculate the active flags in a key. 447 */ 448 static char * 449 keyval(key) 450 int key; 451 { 452 static char keybuf[32]; 453 454 (void) strcpy(keybuf, "|NIL"); 455 keybuf[0] = '\0'; 456 if (key & ONTAPE) 457 (void) strcat(keybuf, "|ONTAPE"); 458 if (key & INOFND) 459 (void) strcat(keybuf, "|INOFND"); 460 if (key & NAMEFND) 461 (void) strcat(keybuf, "|NAMEFND"); 462 if (key & MODECHG) 463 (void) strcat(keybuf, "|MODECHG"); 464 return (&keybuf[1]); 465 } 466 467 /* 468 * Find unreferenced link names. 469 */ 470 void 471 findunreflinks() 472 { 473 register struct entry *ep, *np; 474 register ino_t i; 475 476 vprintf(stdout, "Find unreferenced names.\n"); 477 for (i = ROOTINO; i < maxino; i++) { 478 ep = lookupino(i); 479 if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0) 480 continue; 481 for (np = ep->e_entries; np != NULL; np = np->e_sibling) { 482 if (np->e_flags == 0) { 483 dprintf(stdout, 484 "%s: remove unreferenced name\n", 485 myname(np)); 486 removeleaf(np); 487 freeentry(np); 488 } 489 } 490 } 491 /* 492 * Any leaves remaining in removed directories is unreferenced. 493 */ 494 for (ep = removelist; ep != NULL; ep = ep->e_next) { 495 for (np = ep->e_entries; np != NULL; np = np->e_sibling) { 496 if (np->e_type == LEAF) { 497 if (np->e_flags != 0) 498 badentry(np, "unreferenced with flags"); 499 dprintf(stdout, 500 "%s: remove unreferenced name\n", 501 myname(np)); 502 removeleaf(np); 503 freeentry(np); 504 } 505 } 506 } 507 } 508 509 /* 510 * Remove old nodes (directories). 511 * Note that this routine runs in O(N*D) where: 512 * N is the number of directory entries to be removed. 513 * D is the maximum depth of the tree. 514 * If N == D this can be quite slow. If the list were 515 * topologically sorted, the deletion could be done in 516 * time O(N). 517 */ 518 void 519 removeoldnodes() 520 { 521 register struct entry *ep, **prev; 522 long change; 523 524 vprintf(stdout, "Remove old nodes (directories).\n"); 525 do { 526 change = 0; 527 prev = &removelist; 528 for (ep = removelist; ep != NULL; ep = *prev) { 529 if (ep->e_entries != NULL) { 530 prev = &ep->e_next; 531 continue; 532 } 533 *prev = ep->e_next; 534 removenode(ep); 535 freeentry(ep); 536 change++; 537 } 538 } while (change); 539 for (ep = removelist; ep != NULL; ep = ep->e_next) 540 badentry(ep, "cannot remove, non-empty"); 541 } 542 543 /* 544 * This is the routine used to extract files for the 'r' command. 545 * Extract new leaves. 546 */ 547 void 548 createleaves(symtabfile) 549 char *symtabfile; 550 { 551 register struct entry *ep; 552 ino_t first; 553 long curvol; 554 555 if (command == 'R') { 556 vprintf(stdout, "Continue extraction of new leaves\n"); 557 } else { 558 vprintf(stdout, "Extract new leaves.\n"); 559 dumpsymtable(symtabfile, volno); 560 } 561 first = lowerbnd(ROOTINO); 562 curvol = volno; 563 while (curfile.ino < maxino) { 564 first = lowerbnd(first); 565 /* 566 * If the next available file is not the one which we 567 * expect then we have missed one or more files. Since 568 * we do not request files that were not on the tape, 569 * the lost files must have been due to a tape read error, 570 * or a file that was removed while the dump was in progress. 571 */ 572 while (first < curfile.ino) { 573 ep = lookupino(first); 574 if (ep == NULL) 575 panic("%d: bad first\n", first); 576 fprintf(stderr, "%s: not found on tape\n", myname(ep)); 577 ep->e_flags &= ~(NEW|EXTRACT); 578 first = lowerbnd(first); 579 } 580 /* 581 * If we find files on the tape that have no corresponding 582 * directory entries, then we must have found a file that 583 * was created while the dump was in progress. Since we have 584 * no name for it, we discard it knowing that it will be 585 * on the next incremental tape. 586 */ 587 if (first != curfile.ino) { 588 fprintf(stderr, "expected next file %d, got %d\n", 589 first, curfile.ino); 590 skipfile(); 591 goto next; 592 } 593 ep = lookupino(curfile.ino); 594 if (ep == NULL) 595 panic("unknown file on tape\n"); 596 if ((ep->e_flags & (NEW|EXTRACT)) == 0) 597 badentry(ep, "unexpected file on tape"); 598 /* 599 * If the file is to be extracted, then the old file must 600 * be removed since its type may change from one leaf type 601 * to another (eg "file" to "character special"). 602 */ 603 if ((ep->e_flags & EXTRACT) != 0) { 604 removeleaf(ep); 605 ep->e_flags &= ~REMOVED; 606 } 607 (void) extractfile(myname(ep)); 608 ep->e_flags &= ~(NEW|EXTRACT); 609 /* 610 * We checkpoint the restore after every tape reel, so 611 * as to simplify the amount of work re quired by the 612 * 'R' command. 613 */ 614 next: 615 if (curvol != volno) { 616 dumpsymtable(symtabfile, volno); 617 skipmaps(); 618 curvol = volno; 619 } 620 } 621 } 622 623 /* 624 * This is the routine used to extract files for the 'x' and 'i' commands. 625 * Efficiently extract a subset of the files on a tape. 626 */ 627 void 628 createfiles() 629 { 630 register ino_t first, next, last; 631 register struct entry *ep; 632 long curvol; 633 634 vprintf(stdout, "Extract requested files\n"); 635 curfile.action = SKIP; 636 getvol((long)1); 637 skipmaps(); 638 skipdirs(); 639 first = lowerbnd(ROOTINO); 640 last = upperbnd(maxino - 1); 641 for (;;) { 642 first = lowerbnd(first); 643 last = upperbnd(last); 644 /* 645 * Check to see if any files remain to be extracted 646 */ 647 if (first > last) 648 return; 649 /* 650 * Reject any volumes with inodes greater 651 * than the last one needed 652 */ 653 while (curfile.ino > last) { 654 curfile.action = SKIP; 655 getvol((long)0); 656 skipmaps(); 657 skipdirs(); 658 } 659 /* 660 * Decide on the next inode needed. 661 * Skip across the inodes until it is found 662 * or an out of order volume change is encountered 663 */ 664 next = lowerbnd(curfile.ino); 665 do { 666 curvol = volno; 667 while (next > curfile.ino && volno == curvol) 668 skipfile(); 669 skipmaps(); 670 skipdirs(); 671 } while (volno == curvol + 1); 672 /* 673 * If volume change out of order occurred the 674 * current state must be recalculated 675 */ 676 if (volno != curvol) 677 continue; 678 /* 679 * If the current inode is greater than the one we were 680 * looking for then we missed the one we were looking for. 681 * Since we only attempt to extract files listed in the 682 * dump map, the lost files must have been due to a tape 683 * read error, or a file that was removed while the dump 684 * was in progress. Thus we report all requested files 685 * between the one we were looking for, and the one we 686 * found as missing, and delete their request flags. 687 */ 688 while (next < curfile.ino) { 689 ep = lookupino(next); 690 if (ep == NULL) 691 panic("corrupted symbol table\n"); 692 fprintf(stderr, "%s: not found on tape\n", myname(ep)); 693 ep->e_flags &= ~NEW; 694 next = lowerbnd(next); 695 } 696 /* 697 * The current inode is the one that we are looking for, 698 * so extract it per its requested name. 699 */ 700 if (next == curfile.ino && next <= last) { 701 ep = lookupino(next); 702 if (ep == NULL) 703 panic("corrupted symbol table\n"); 704 (void) extractfile(myname(ep)); 705 ep->e_flags &= ~NEW; 706 if (volno != curvol) 707 skipmaps(); 708 } 709 } 710 } 711 712 /* 713 * Add links. 714 */ 715 void 716 createlinks() 717 { 718 register struct entry *np, *ep; 719 register ino_t i; 720 char name[BUFSIZ]; 721 722 vprintf(stdout, "Add links\n"); 723 for (i = ROOTINO; i < maxino; i++) { 724 ep = lookupino(i); 725 if (ep == NULL) 726 continue; 727 for (np = ep->e_links; np != NULL; np = np->e_links) { 728 if ((np->e_flags & NEW) == 0) 729 continue; 730 (void) strcpy(name, myname(ep)); 731 if (ep->e_type == NODE) { 732 (void) linkit(name, myname(np), SYMLINK); 733 } else { 734 (void) linkit(name, myname(np), HARDLINK); 735 } 736 np->e_flags &= ~NEW; 737 } 738 } 739 } 740 741 /* 742 * Check the symbol table. 743 * We do this to insure that all the requested work was done, and 744 * that no temporary names remain. 745 */ 746 void 747 checkrestore() 748 { 749 register struct entry *ep; 750 register ino_t i; 751 752 vprintf(stdout, "Check the symbol table.\n"); 753 for (i = ROOTINO; i < maxino; i++) { 754 for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { 755 ep->e_flags &= ~KEEP; 756 if (ep->e_type == NODE) 757 ep->e_flags &= ~(NEW|EXISTED); 758 if (ep->e_flags != NULL) 759 badentry(ep, "incomplete operations"); 760 } 761 } 762 } 763 764 /* 765 * Compare with the directory structure on the tape 766 * A paranoid check that things are as they should be. 767 */ 768 long 769 verifyfile(name, ino, type) 770 char *name; 771 ino_t ino; 772 int type; 773 { 774 struct entry *np, *ep; 775 long descend = GOOD; 776 777 ep = lookupname(name); 778 if (ep == NULL) { 779 fprintf(stderr, "Warning: missing name %s\n", name); 780 return (FAIL); 781 } 782 np = lookupino(ino); 783 if (np != ep) 784 descend = FAIL; 785 for ( ; np != NULL; np = np->e_links) 786 if (np == ep) 787 break; 788 if (np == NULL) 789 panic("missing inumber %d\n", ino); 790 if (ep->e_type == LEAF && type != LEAF) 791 badentry(ep, "type should be LEAF"); 792 return (descend); 793 } 794