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