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