1 /* $OpenBSD: restore.c,v 1.2 1996/06/23 14:32:17 deraadt Exp $ */ 2 /* $NetBSD: restore.c,v 1.6 1995/03/18 14:59:51 cgd 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.2 1996/06/23 14:32:17 deraadt 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 register 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) sprintf(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 register struct entry *ep, *nextep; 170 register 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 register 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 removeleaf(ip); 439 freeentry(ip); 440 ip = addentry(name, ino, type); 441 newnode(ip); 442 } else { 443 /* changing from node to leaf */ 444 if ((ip->e_flags & TMPNAME) == 0) 445 mktempname(ip); 446 deleteino(ip->e_ino); 447 ip->e_next = removelist; 448 removelist = ip; 449 ip = addentry(name, ino, type); 450 } 451 ip->e_flags |= NEW|KEEP; 452 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 453 flagvalues(ip)); 454 break; 455 456 /* 457 * A hard link to a diirectory that has been removed. 458 * Ignore it. 459 */ 460 case NAMEFND: 461 dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key), 462 name); 463 descend = FAIL; 464 break; 465 466 /* 467 * If we find a directory entry for a file that is not on 468 * the tape, then we must have found a file that was created 469 * while the dump was in progress. Since we have no contents 470 * for it, we discard the name knowing that it will be on the 471 * next incremental tape. 472 */ 473 case NULL: 474 fprintf(stderr, "%s: (inode %d) not found on tape\n", 475 name, ino); 476 break; 477 478 /* 479 * If any of these arise, something is grievously wrong with 480 * the current state of the symbol table. 481 */ 482 case INOFND|NAMEFND|MODECHG: 483 case NAMEFND|MODECHG: 484 case INOFND|MODECHG: 485 fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key), 486 name); 487 break; 488 489 /* 490 * These states "cannot" arise for any state of the symbol table. 491 */ 492 case ONTAPE|MODECHG: 493 case MODECHG: 494 default: 495 panic("[%s] %s: impossible state\n", keyval(key), name); 496 break; 497 } 498 return (descend); 499 } 500 501 /* 502 * Calculate the active flags in a key. 503 */ 504 static char * 505 keyval(key) 506 int key; 507 { 508 static char keybuf[32]; 509 510 (void) strcpy(keybuf, "|NIL"); 511 keybuf[0] = '\0'; 512 if (key & ONTAPE) 513 (void) strcat(keybuf, "|ONTAPE"); 514 if (key & INOFND) 515 (void) strcat(keybuf, "|INOFND"); 516 if (key & NAMEFND) 517 (void) strcat(keybuf, "|NAMEFND"); 518 if (key & MODECHG) 519 (void) strcat(keybuf, "|MODECHG"); 520 return (&keybuf[1]); 521 } 522 523 /* 524 * Find unreferenced link names. 525 */ 526 void 527 findunreflinks() 528 { 529 register struct entry *ep, *np; 530 register ino_t i; 531 532 vprintf(stdout, "Find unreferenced names.\n"); 533 for (i = ROOTINO; i < maxino; i++) { 534 ep = lookupino(i); 535 if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0) 536 continue; 537 for (np = ep->e_entries; np != NULL; np = np->e_sibling) { 538 if (np->e_flags == 0) { 539 dprintf(stdout, 540 "%s: remove unreferenced name\n", 541 myname(np)); 542 removeleaf(np); 543 freeentry(np); 544 } 545 } 546 } 547 /* 548 * Any leaves remaining in removed directories is unreferenced. 549 */ 550 for (ep = removelist; ep != NULL; ep = ep->e_next) { 551 for (np = ep->e_entries; np != NULL; np = np->e_sibling) { 552 if (np->e_type == LEAF) { 553 if (np->e_flags != 0) 554 badentry(np, "unreferenced with flags"); 555 dprintf(stdout, 556 "%s: remove unreferenced name\n", 557 myname(np)); 558 removeleaf(np); 559 freeentry(np); 560 } 561 } 562 } 563 } 564 565 /* 566 * Remove old nodes (directories). 567 * Note that this routine runs in O(N*D) where: 568 * N is the number of directory entries to be removed. 569 * D is the maximum depth of the tree. 570 * If N == D this can be quite slow. If the list were 571 * topologically sorted, the deletion could be done in 572 * time O(N). 573 */ 574 void 575 removeoldnodes() 576 { 577 register struct entry *ep, **prev; 578 long change; 579 580 vprintf(stdout, "Remove old nodes (directories).\n"); 581 do { 582 change = 0; 583 prev = &removelist; 584 for (ep = removelist; ep != NULL; ep = *prev) { 585 if (ep->e_entries != NULL) { 586 prev = &ep->e_next; 587 continue; 588 } 589 *prev = ep->e_next; 590 removenode(ep); 591 freeentry(ep); 592 change++; 593 } 594 } while (change); 595 for (ep = removelist; ep != NULL; ep = ep->e_next) 596 badentry(ep, "cannot remove, non-empty"); 597 } 598 599 /* 600 * This is the routine used to extract files for the 'r' command. 601 * Extract new leaves. 602 */ 603 void 604 createleaves(symtabfile) 605 char *symtabfile; 606 { 607 register struct entry *ep; 608 ino_t first; 609 long curvol; 610 611 if (command == 'R') { 612 vprintf(stdout, "Continue extraction of new leaves\n"); 613 } else { 614 vprintf(stdout, "Extract new leaves.\n"); 615 dumpsymtable(symtabfile, volno); 616 } 617 first = lowerbnd(ROOTINO); 618 curvol = volno; 619 while (curfile.ino < maxino) { 620 first = lowerbnd(first); 621 /* 622 * If the next available file is not the one which we 623 * expect then we have missed one or more files. Since 624 * we do not request files that were not on the tape, 625 * the lost files must have been due to a tape read error, 626 * or a file that was removed while the dump was in progress. 627 */ 628 while (first < curfile.ino) { 629 ep = lookupino(first); 630 if (ep == NULL) 631 panic("%d: bad first\n", first); 632 fprintf(stderr, "%s: not found on tape\n", myname(ep)); 633 ep->e_flags &= ~(NEW|EXTRACT); 634 first = lowerbnd(first); 635 } 636 /* 637 * If we find files on the tape that have no corresponding 638 * directory entries, then we must have found a file that 639 * was created while the dump was in progress. Since we have 640 * no name for it, we discard it knowing that it will be 641 * on the next incremental tape. 642 */ 643 if (first != curfile.ino) { 644 fprintf(stderr, "expected next file %d, got %d\n", 645 first, curfile.ino); 646 skipfile(); 647 goto next; 648 } 649 ep = lookupino(curfile.ino); 650 if (ep == NULL) 651 panic("unknown file on tape\n"); 652 if ((ep->e_flags & (NEW|EXTRACT)) == 0) 653 badentry(ep, "unexpected file on tape"); 654 /* 655 * If the file is to be extracted, then the old file must 656 * be removed since its type may change from one leaf type 657 * to another (eg "file" to "character special"). 658 */ 659 if ((ep->e_flags & EXTRACT) != 0) { 660 removeleaf(ep); 661 ep->e_flags &= ~REMOVED; 662 } 663 (void) extractfile(myname(ep)); 664 ep->e_flags &= ~(NEW|EXTRACT); 665 /* 666 * We checkpoint the restore after every tape reel, so 667 * as to simplify the amount of work re quired by the 668 * 'R' command. 669 */ 670 next: 671 if (curvol != volno) { 672 dumpsymtable(symtabfile, volno); 673 skipmaps(); 674 curvol = volno; 675 } 676 } 677 } 678 679 /* 680 * This is the routine used to extract files for the 'x' and 'i' commands. 681 * Efficiently extract a subset of the files on a tape. 682 */ 683 void 684 createfiles() 685 { 686 register ino_t first, next, last; 687 register struct entry *ep; 688 long curvol; 689 690 vprintf(stdout, "Extract requested files\n"); 691 curfile.action = SKIP; 692 getvol((long)1); 693 skipmaps(); 694 skipdirs(); 695 first = lowerbnd(ROOTINO); 696 last = upperbnd(maxino - 1); 697 for (;;) { 698 first = lowerbnd(first); 699 last = upperbnd(last); 700 /* 701 * Check to see if any files remain to be extracted 702 */ 703 if (first > last) 704 return; 705 /* 706 * Reject any volumes with inodes greater 707 * than the last one needed 708 */ 709 while (curfile.ino > last) { 710 curfile.action = SKIP; 711 getvol((long)0); 712 skipmaps(); 713 skipdirs(); 714 } 715 /* 716 * Decide on the next inode needed. 717 * Skip across the inodes until it is found 718 * or an out of order volume change is encountered 719 */ 720 next = lowerbnd(curfile.ino); 721 do { 722 curvol = volno; 723 while (next > curfile.ino && volno == curvol) 724 skipfile(); 725 skipmaps(); 726 skipdirs(); 727 } while (volno == curvol + 1); 728 /* 729 * If volume change out of order occurred the 730 * current state must be recalculated 731 */ 732 if (volno != curvol) 733 continue; 734 /* 735 * If the current inode is greater than the one we were 736 * looking for then we missed the one we were looking for. 737 * Since we only attempt to extract files listed in the 738 * dump map, the lost files must have been due to a tape 739 * read error, or a file that was removed while the dump 740 * was in progress. Thus we report all requested files 741 * between the one we were looking for, and the one we 742 * found as missing, and delete their request flags. 743 */ 744 while (next < curfile.ino) { 745 ep = lookupino(next); 746 if (ep == NULL) 747 panic("corrupted symbol table\n"); 748 fprintf(stderr, "%s: not found on tape\n", myname(ep)); 749 ep->e_flags &= ~NEW; 750 next = lowerbnd(next); 751 } 752 /* 753 * The current inode is the one that we are looking for, 754 * so extract it per its requested name. 755 */ 756 if (next == curfile.ino && next <= last) { 757 ep = lookupino(next); 758 if (ep == NULL) 759 panic("corrupted symbol table\n"); 760 (void) extractfile(myname(ep)); 761 ep->e_flags &= ~NEW; 762 if (volno != curvol) 763 skipmaps(); 764 } 765 } 766 } 767 768 /* 769 * Add links. 770 */ 771 void 772 createlinks() 773 { 774 register struct entry *np, *ep; 775 register ino_t i; 776 char name[BUFSIZ]; 777 778 if (ep = lookupino(WINO)) { 779 vprintf(stdout, "Add whiteouts\n"); 780 for ( ; ep != NULL; ep = ep->e_links) { 781 if ((ep->e_flags & NEW) == 0) 782 continue; 783 (void) addwhiteout(myname(ep)); 784 ep->e_flags &= ~NEW; 785 } 786 } 787 vprintf(stdout, "Add links\n"); 788 for (i = ROOTINO; i < maxino; i++) { 789 ep = lookupino(i); 790 if (ep == NULL) 791 continue; 792 for (np = ep->e_links; np != NULL; np = np->e_links) { 793 if ((np->e_flags & NEW) == 0) 794 continue; 795 (void) strcpy(name, myname(ep)); 796 if (ep->e_type == NODE) { 797 (void) linkit(name, myname(np), SYMLINK); 798 } else { 799 (void) linkit(name, myname(np), HARDLINK); 800 } 801 np->e_flags &= ~NEW; 802 } 803 } 804 } 805 806 /* 807 * Check the symbol table. 808 * We do this to insure that all the requested work was done, and 809 * that no temporary names remain. 810 */ 811 void 812 checkrestore() 813 { 814 register struct entry *ep; 815 register ino_t i; 816 817 vprintf(stdout, "Check the symbol table.\n"); 818 for (i = WINO; i < maxino; i++) { 819 for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { 820 ep->e_flags &= ~KEEP; 821 if (ep->e_type == NODE) 822 ep->e_flags &= ~(NEW|EXISTED); 823 if (ep->e_flags != NULL) 824 badentry(ep, "incomplete operations"); 825 } 826 } 827 } 828 829 /* 830 * Compare with the directory structure on the tape 831 * A paranoid check that things are as they should be. 832 */ 833 long 834 verifyfile(name, ino, type) 835 char *name; 836 ino_t ino; 837 int type; 838 { 839 struct entry *np, *ep; 840 long descend = GOOD; 841 842 ep = lookupname(name); 843 if (ep == NULL) { 844 fprintf(stderr, "Warning: missing name %s\n", name); 845 return (FAIL); 846 } 847 np = lookupino(ino); 848 if (np != ep) 849 descend = FAIL; 850 for ( ; np != NULL; np = np->e_links) 851 if (np == ep) 852 break; 853 if (np == NULL) 854 panic("missing inumber %d\n", ino); 855 if (ep->e_type == LEAF && type != LEAF) 856 badentry(ep, "type should be LEAF"); 857 return (descend); 858 } 859