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