1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1983 Regents of the University of California. 11 * All rights reserved. The Berkeley software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include "restore.h" 18 /* undef MAXNAMLEN to prevent compiler warnings about redef in dirent.h */ 19 #undef MAXNAMLEN 20 #include <dirent.h> 21 22 #ifdef __STDC__ 23 static char *keyval(int); 24 static void removexattrs(struct entry *); 25 static void movexattrs(char *, char *); 26 #else 27 static char *keyval(); 28 static void removexattrs(); 29 static void movexattrs(); 30 #endif 31 32 /* 33 * This implements the 't' option. 34 * List entries on the tape. 35 */ 36 long 37 listfile(name, ino, type) 38 char *name; 39 ino_t ino; 40 int type; 41 { 42 long descend = hflag ? GOOD : FAIL; 43 44 if (BIT(ino, dumpmap) == 0) { 45 return (descend); 46 } 47 vprintf(stdout, "%s", type == LEAF ? gettext("leaf") : gettext("dir ")); 48 (void) fprintf(stdout, "%10lu\t%s\n", ino, name); 49 return (descend); 50 } 51 52 /* 53 * This implements the 'x' option. 54 * Request that new entries be extracted. 55 */ 56 long 57 addfile(name, ino, type) 58 char *name; 59 ino_t ino; 60 int type; 61 { 62 struct entry *ep; 63 long descend = hflag ? GOOD : FAIL; 64 char buf[100]; 65 66 /* Don't know if ino_t is long or long long, so be safe w/ *printf() */ 67 68 if (BIT(ino, dumpmap) == 0) { 69 if (mflag) { 70 dprintf(stdout, gettext( 71 "%s: not on the volume\n"), name); 72 } else { 73 dprintf(stdout, gettext( 74 "inode %llu: not on the volume\n"), 75 (u_longlong_t)ino); 76 } 77 return (descend); 78 } 79 if (!mflag) { 80 (void) snprintf(buf, sizeof (buf), "./%llu", (u_longlong_t)ino); 81 buf[sizeof (buf) - 1] = '\0'; 82 name = buf; 83 if (type == NODE) { 84 (void) genliteraldir(name, ino); 85 return (descend); 86 } 87 } 88 ep = lookupino(ino); 89 if (ep != NIL) { 90 if (strcmp(name, myname(ep)) == 0) { 91 /* LINTED: result fits into a short */ 92 ep->e_flags |= NEW; 93 return (descend); 94 } 95 type |= LINK; 96 } 97 ep = addentry(name, ino, type); 98 if (type == NODE) 99 newnode(ep); 100 /* LINTED: result fits into a short */ 101 ep->e_flags |= NEW; 102 return (descend); 103 } 104 105 /* 106 * This is used by the 'i' option to undo previous requests made by addfile. 107 * Delete entries from the request queue. 108 */ 109 /* ARGSUSED */ 110 long 111 deletefile(name, ino, type) 112 char *name; 113 ino_t ino; 114 int type; 115 { 116 long descend = hflag ? GOOD : FAIL; 117 struct entry *ep; 118 119 if (BIT(ino, dumpmap) == 0) { 120 return (descend); 121 } 122 ep = lookupino(ino); 123 if (ep != NIL) { 124 /* LINTED: result fits into a short */ 125 ep->e_flags &= ~NEW; 126 } 127 return (descend); 128 } 129 130 /* 131 * The following four routines implement the incremental 132 * restore algorithm. The first removes old entries, the second 133 * does renames and calculates the extraction list, the third 134 * cleans up link names missed by the first two, and the final 135 * one deletes old directories. 136 * 137 * Directories cannot be immediately deleted, as they may have 138 * other files in them which need to be moved out first. As 139 * directories to be deleted are found, they are put on the 140 * following deletion list. After all deletions and renames 141 * are done, this list is actually deleted. 142 */ 143 static struct entry *removelist; 144 145 /* 146 * Remove unneeded leaves from the old tree. 147 * Remove directories from the lookup chains. 148 */ 149 void 150 #ifdef __STDC__ 151 removeoldleaves(void) 152 #else 153 removeoldleaves() 154 #endif 155 { 156 struct entry *ep; 157 ino_t i; 158 159 vprintf(stdout, gettext("Mark entries to be removed.\n")); 160 for (i = ROOTINO + 1; i < maxino; i++) { 161 if (BIT(i, clrimap)) 162 continue; 163 ep = lookupino(i); 164 if (ep == NIL) 165 continue; 166 while (ep != NIL) { 167 dprintf(stdout, gettext("%s: REMOVE\n"), myname(ep)); 168 removexattrs(ep->e_xattrs); 169 if (ep->e_type == LEAF) { 170 removeleaf(ep); 171 freeentry(ep); 172 } else { 173 mktempname(ep); 174 deleteino(ep->e_ino); 175 /* 176 * once the inode is deleted from the symbol 177 * table, the e_next field is reusable 178 */ 179 ep->e_next = removelist; 180 removelist = ep; 181 } 182 ep = ep->e_links; 183 } 184 } 185 } 186 187 /* 188 * For each directory entry on the incremental tape, determine which 189 * category it falls into as follows: 190 * KEEP - entries that are to be left alone. 191 * NEW - new entries to be added. 192 * EXTRACT - files that must be updated with new contents. 193 * LINK - new links to be added. 194 * Renames are done at the same time. 195 */ 196 long 197 nodeupdates(name, ino, type) 198 char *name; 199 ino_t ino; 200 int type; 201 { 202 struct entry *ep, *np, *ip; 203 long descend = GOOD; 204 int lookuptype = 0; 205 int key = 0; 206 /* key values */ 207 #define ONTAPE 0x1 /* inode is on the tape */ 208 #define INOFND 0x2 /* inode already exists */ 209 #define NAMEFND 0x4 /* name already exists */ 210 #define MODECHG 0x8 /* mode of inode changed */ 211 212 /* 213 * This routine is called once for each element in the 214 * directory hierarchy, with a full path name. 215 * The "type" value is incorrectly specified as LEAF for 216 * directories that are not on the dump tape. 217 * 218 * Check to see if the file is on the tape. 219 */ 220 if (BIT(ino, dumpmap)) 221 key |= ONTAPE; 222 /* 223 * Check to see if the name exists, and if the name is a link. 224 */ 225 np = lookupname(name); 226 if (np != NIL) { 227 key |= NAMEFND; 228 ip = lookupino(np->e_ino); 229 if (ip == NULL) { 230 (void) fprintf(stderr, 231 gettext("corrupted symbol table\n")); 232 done(1); 233 } 234 if (ip != np) 235 lookuptype = LINK; 236 } 237 /* 238 * Check to see if the inode exists, and if one of its links 239 * corresponds to the name (if one was found). 240 */ 241 ip = lookupino(ino); 242 if (ip != NIL) { 243 key |= INOFND; 244 for (ep = ip->e_links; ep != NIL; ep = ep->e_links) { 245 if (ep == np) { 246 /* 247 * Need to set the NEW flag on the hard link 248 * so it gets created because we extract the 249 * "parent". If the NAMEFND key is set, remove 250 * the leaf. 251 */ 252 if (ip->e_flags & EXTRACT) { 253 if (key & NAMEFND) { 254 removeleaf(np); 255 freeentry(np); 256 np = NIL; 257 key &= ~NAMEFND; 258 } 259 ep->e_flags |= NEW; 260 } else { 261 ip = ep; 262 } 263 break; 264 } 265 } 266 } 267 /* 268 * If both a name and an inode are found, but they do not 269 * correspond to the same file, then both the inode that has 270 * been found and the inode corresponding to the name that 271 * has been found need to be renamed. The current pathname 272 * is the new name for the inode that has been found. Since 273 * all files to be deleted have already been removed, the 274 * named file is either a now-unneeded link, or it must live 275 * under a new name in this dump level. If it is a link, it 276 * can be removed. If it is not a link, it is given a 277 * temporary name in anticipation that it will be renamed 278 * when it is later found by inode number. 279 */ 280 if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) { 281 if (lookuptype == LINK) { 282 removeleaf(np); 283 freeentry(np); 284 } else { 285 dprintf(stdout, 286 gettext("name/inode conflict, mktempname %s\n"), 287 myname(np)); 288 mktempname(np); 289 } 290 np = NIL; 291 key &= ~NAMEFND; 292 } 293 if ((key & ONTAPE) && 294 (((key & INOFND) && ip->e_type != type) || 295 ((key & NAMEFND) && np->e_type != type))) 296 key |= MODECHG; 297 298 /* 299 * Decide on the disposition of the file based on its flags. 300 * Note that we have already handled the case in which 301 * a name and inode are found that correspond to different files. 302 * Thus if both NAMEFND and INOFND are set then ip == np. 303 */ 304 switch (key) { 305 306 /* 307 * A previously existing file has been found. 308 * Mark it as KEEP so that other links to the inode can be 309 * detected, and so that it will not be reclaimed by the search 310 * for unreferenced names. 311 */ 312 case INOFND|NAMEFND: 313 /* LINTED: result fits into a short */ 314 ip->e_flags |= KEEP; 315 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 316 flagvalues(ip)); 317 break; 318 319 /* 320 * A file on the tape has a name which is the same as a name 321 * corresponding to a different file in the previous dump. 322 * Since all files to be deleted have already been removed, 323 * this file is either a now-unneeded link, or it must live 324 * under a new name in this dump level. If it is a link, it 325 * can simply be removed. If it is not a link, it is given a 326 * temporary name in anticipation that it will be renamed 327 * when it is later found by inode number (see INOFND case 328 * below). The entry is then treated as a new file. 329 */ 330 case ONTAPE|NAMEFND: 331 case ONTAPE|NAMEFND|MODECHG: 332 if (lookuptype == LINK || key == (ONTAPE|NAMEFND)) { 333 removeleaf(np); 334 freeentry(np); 335 } else { 336 /* 337 * Create a temporary node only if MODECHG. 338 */ 339 mktempname(np); 340 } 341 /*FALLTHROUGH*/ 342 343 /* 344 * A previously non-existent file. 345 * Add it to the file system, and request its extraction. 346 * If it is a directory, create it immediately. 347 * (Since the name is unused there can be no conflict) 348 */ 349 case ONTAPE: 350 ep = addentry(name, ino, type); 351 if (type == NODE) 352 newnode(ep); 353 /* LINTED: result fits into a short */ 354 ep->e_flags |= NEW|KEEP; 355 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 356 flagvalues(ep)); 357 break; 358 359 /* 360 * A file with the same inode number, but a different 361 * name has been found. If the other name has not already 362 * been found (indicated by the KEEP flag, see above) then 363 * this must be a new name for the file, and it is renamed. 364 * If the other name has been found then this must be a 365 * link to the file. Hard links to directories are not 366 * permitted, and are either deleted or converted to 367 * symbolic links. Finally, if the file is on the tape, 368 * a request is made to extract it. 369 */ 370 case ONTAPE|INOFND: 371 if (type == LEAF && (ip->e_flags & KEEP) == 0) { 372 /* LINTED: result fits into a short */ 373 ip->e_flags |= EXTRACT; 374 } 375 /*FALLTHROUGH*/ 376 case INOFND: 377 if ((ip->e_flags & KEEP) == 0) { 378 renameit(myname(ip), name); 379 moveentry(ip, name); 380 /* LINTED: result fits into a short */ 381 ip->e_flags |= KEEP; 382 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 383 flagvalues(ip)); 384 break; 385 } 386 if (ip->e_type == NODE) { 387 descend = FAIL; 388 (void) fprintf(stderr, gettext( 389 "deleted hard link %s to directory %s\n"), 390 name, myname(ip)); 391 break; 392 } 393 ep = addentry(name, ino, type|LINK); 394 /* LINTED: result fits into a short */ 395 ep->e_flags |= NEW; 396 dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, 397 flagvalues(ep)); 398 break; 399 400 /* 401 * A previously known file which is to be updated. 402 */ 403 case ONTAPE|INOFND|NAMEFND: 404 /* 405 * Extract leaf nodes. 406 */ 407 if (type == LEAF) { 408 /* LINTED: result fits into a short */ 409 np->e_flags |= EXTRACT; 410 } 411 /* LINTED: result fits into a short */ 412 np->e_flags |= KEEP; 413 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 414 flagvalues(np)); 415 break; 416 417 /* 418 * An inode is being reused in a completely different way. 419 * Normally an extract can simply do an "unlink" followed 420 * by a "creat". Here we must do effectively the same 421 * thing. The complications arise because we cannot really 422 * delete a directory since it may still contain files 423 * that we need to rename, so we delete it from the symbol 424 * table, and put it on the list to be deleted eventually. 425 * Conversely if a directory is to be created, it must be 426 * done immediately, rather than waiting until the 427 * extraction phase. 428 */ 429 case ONTAPE|INOFND|MODECHG: 430 case ONTAPE|INOFND|NAMEFND|MODECHG: 431 if (ip->e_flags & KEEP) { 432 badentry(ip, gettext("cannot KEEP and change modes")); 433 break; 434 } 435 if (ip->e_type == LEAF) { 436 /* changing from leaf to node */ 437 removeleaf(ip); 438 freeentry(ip); 439 ip = addentry(name, ino, type); 440 newnode(ip); 441 } else { 442 /* changing from node to leaf */ 443 if ((ip->e_flags & TMPNAME) == 0) 444 mktempname(ip); 445 deleteino(ip->e_ino); 446 ip->e_next = removelist; 447 removelist = ip; 448 ip = addentry(name, ino, type); 449 } 450 /* LINTED: result fits into a short */ 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 directory that has been removed. 458 * Ignore it. 459 */ 460 case NAMEFND: 461 dprintf(stdout, gettext("[%s] %s: Extraneous name\n"), 462 keyval(key), 463 name); 464 descend = FAIL; 465 break; 466 467 /* 468 * If we find a directory entry for a file that is not on 469 * the tape, then we must have found a file that was created 470 * while the dump was in progress. Since we have no contents 471 * for it, we discard the name knowing that it will be on the 472 * next incremental tape. 473 */ 474 case 0: 475 (void) fprintf(stderr, 476 gettext("%s: (inode %lu) not found on volume\n"), 477 name, ino); 478 break; 479 480 /* 481 * If any of these arise, something is grievously wrong with 482 * the current state of the symbol table. 483 */ 484 case INOFND|NAMEFND|MODECHG: 485 case NAMEFND|MODECHG: 486 case INOFND|MODECHG: 487 (void) fprintf(stderr, "[%s] %s: %s\n", 488 keyval(key), name, gettext("inconsistent state")); 489 done(1); 490 /*NOTREACHED*/ 491 492 /* 493 * These states "cannot" arise for any state of the symbol table. 494 */ 495 case ONTAPE|MODECHG: 496 case MODECHG: 497 default: 498 (void) fprintf(stderr, "[%s] %s: %s\n", 499 keyval(key), name, gettext("impossible state")); 500 done(1); 501 /*NOTREACHED*/ 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 /* Note longest case is everything except |NIL */ 516 517 (void) strcpy(keybuf, "|NIL"); 518 keybuf[0] = '\0'; 519 if (key & ONTAPE) 520 (void) strcat(keybuf, "|ONTAPE"); 521 if (key & INOFND) 522 (void) strcat(keybuf, "|INOFND"); 523 if (key & NAMEFND) 524 (void) strcat(keybuf, "|NAMEFND"); 525 if (key & MODECHG) 526 (void) strcat(keybuf, "|MODECHG"); 527 return (&keybuf[1]); 528 } 529 530 /* 531 * Find unreferenced link names. 532 */ 533 void 534 #ifdef __STDC__ 535 findunreflinks(void) 536 #else 537 findunreflinks() 538 #endif 539 { 540 struct entry *ep, *np; 541 ino_t i; 542 543 vprintf(stdout, gettext("Find unreferenced names.\n")); 544 for (i = ROOTINO; i < maxino; i++) { 545 ep = lookupino(i); 546 if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0) 547 continue; 548 for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 549 if (np->e_flags == 0) { 550 dprintf(stdout, gettext( 551 "%s: remove unreferenced name\n"), 552 myname(np)); 553 removeleaf(np); 554 freeentry(np); 555 } 556 } 557 } 558 /* 559 * Any leaves remaining in removed directories are unreferenced. 560 */ 561 for (ep = removelist; ep != NIL; ep = ep->e_next) { 562 for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 563 if (np->e_type == LEAF) { 564 if (np->e_flags != 0) 565 badentry(np, gettext( 566 "unreferenced with flags")); 567 dprintf(stdout, gettext( 568 "%s: remove unreferenced name\n"), 569 myname(np)); 570 removeleaf(np); 571 freeentry(np); 572 } 573 } 574 } 575 } 576 577 /* 578 * Remove old nodes (directories). 579 * Note that this routine runs in O(N*D) where: 580 * N is the number of directory entries to be removed. 581 * D is the maximum depth of the tree. 582 * If N == D this can be quite slow. If the list were 583 * topologically sorted, the deletion could be done in 584 * time O(N). 585 */ 586 void 587 #ifdef __STDC__ 588 removeoldnodes(void) 589 #else 590 removeoldnodes() 591 #endif 592 { 593 struct entry *ep, **prev; 594 long change; 595 596 vprintf(stdout, gettext("Remove old nodes (directories).\n")); 597 do { 598 change = 0; 599 prev = &removelist; 600 for (ep = removelist; ep != NIL; ep = *prev) { 601 if (ep->e_entries != NIL) { 602 prev = &ep->e_next; 603 continue; 604 } 605 *prev = ep->e_next; 606 removenode(ep); 607 freeentry(ep); 608 change++; 609 } 610 } while (change); 611 for (ep = removelist; ep != NIL; ep = ep->e_next) 612 badentry(ep, gettext("cannot remove, non-empty")); 613 } 614 615 /* 616 * This is the routine used to extract files for the 'r' command. 617 * Extract new leaves. 618 */ 619 void 620 createleaves(symtabfile) 621 char *symtabfile; 622 { 623 struct entry *ep; 624 char name[MAXCOMPLEXLEN]; 625 ino_t first; 626 int curvol; 627 628 if (command == 'R') { 629 vprintf(stdout, gettext("Continue extraction of new leaves\n")); 630 } else { 631 vprintf(stdout, gettext("Extract new leaves.\n")); 632 dumpsymtable(symtabfile, volno); 633 } 634 first = lowerbnd(ROOTINO); 635 curvol = volno; 636 while (curfile.ino < maxino) { 637 first = lowerbnd(first); 638 /* 639 * If the next available file is not the one which we 640 * expect then we have missed one or more files. Since 641 * we do not request files that were not on the tape, 642 * the lost files must have been due to a tape read error, 643 * or a file that was removed while the dump was in progress. 644 * 645 * The loop will terminate with first == maxino, if not 646 * sooner. Due to the e_flags manipulation, lowerbnd() 647 * will never return its argument. 648 */ 649 while (first < curfile.ino) { 650 ep = lookupino(first); 651 if (ep == NIL) { 652 (void) fprintf(stderr, 653 gettext("%d: bad first\n"), first); 654 done(1); 655 } 656 (void) fprintf(stderr, 657 gettext("%s: not found on volume\n"), 658 myname(ep)); 659 /* LINTED: result fits into a short */ 660 ep->e_flags &= ~(NEW|EXTRACT); 661 first = lowerbnd(first); 662 } 663 /* 664 * If we find files on the tape that have no corresponding 665 * directory entries, then we must have found a file that 666 * was created while the dump was in progress. Since we have 667 * no name for it, we discard it knowing that it will be 668 * on the next incremental tape. 669 */ 670 if (first != curfile.ino) { 671 (void) fprintf(stderr, 672 gettext("expected next file %d, got %d\n"), 673 first, curfile.ino); 674 skipfile(); 675 goto next; 676 } 677 ep = lookupino(curfile.ino); 678 if (ep == NIL) { 679 (void) fprintf(stderr, 680 gettext("unknown file on volume\n")); 681 done(1); 682 } 683 if ((ep->e_flags & (NEW|EXTRACT)) == 0) 684 badentry(ep, gettext("unexpected file on volume")); 685 /* 686 * If the file is to be extracted, then the old file must 687 * be removed since its type may change from one leaf type 688 * to another (eg "file" to "character special"). But we 689 * also need to preserve any existing extended attributes; 690 * so first rename the file, then move its attributes, then 691 * remove it. 692 */ 693 if ((ep->e_flags & EXTRACT) != 0) { 694 char *sname = savename(ep->e_name); 695 complexcpy(name, myname(ep), MAXCOMPLEXLEN); 696 mktempname(ep); 697 (void) extractfile(name); 698 movexattrs(myname(ep), name); 699 removeleaf(ep); 700 freename(ep->e_name); 701 ep->e_name = sname; 702 ep->e_namlen = strlen(ep->e_name); 703 /* LINTED: result fits into a short */ 704 ep->e_flags &= ~REMOVED; 705 } else { 706 (void) extractfile(myname(ep)); 707 } 708 /* LINTED: result fits into a short */ 709 ep->e_flags &= ~(NEW|EXTRACT); 710 /* 711 * We checkpoint the restore after every tape reel, so 712 * as to simplify the amount of work required by the 713 * 'R' command. 714 */ 715 next: 716 if (curvol != volno) { 717 dumpsymtable(symtabfile, volno); 718 skipmaps(); 719 curvol = volno; 720 } 721 } 722 } 723 724 /* 725 * This is the routine used to extract files for the 'x' and 'i' commands. 726 * Efficiently extract a subset of the files on a tape. 727 */ 728 void 729 #ifdef __STDC__ 730 createfiles(void) 731 #else 732 createfiles() 733 #endif 734 { 735 ino_t first, next, last; 736 struct entry *ep; 737 int curvol, nextvol; 738 739 vprintf(stdout, gettext("Extract requested files\n")); 740 first = lowerbnd(ROOTINO); 741 last = upperbnd(maxino - 1); 742 nextvol = volnumber(first); 743 if (nextvol == 0) { 744 curfile.action = SKIP; 745 getvol(1); 746 skipmaps(); 747 skipdirs(); 748 } 749 for (;;) { 750 first = lowerbnd(first); 751 last = upperbnd(last); 752 /* 753 * Check to see if any files remain to be extracted 754 */ 755 if (first > last) 756 return; 757 /* 758 * If a map of inode numbers to tape volumes is 759 * available, then select the next volume to be read. 760 */ 761 if (nextvol > 0) { 762 nextvol = volnumber(first); 763 if (nextvol != volno) { 764 curfile.action = UNKNOWN; 765 getvol(nextvol); 766 skipmaps(); 767 } 768 } 769 /* 770 * Reject any volumes with inodes greater than 771 * the last one needed. This will only be true 772 * if the above code has not selected a volume. 773 */ 774 while (curfile.ino > last) { 775 curfile.action = SKIP; 776 getvol(0); 777 skipmaps(); 778 skipdirs(); 779 } 780 /* 781 * Decide on the next inode needed. 782 * Skip across the inodes until it is found 783 * or an out of order volume change is encountered 784 */ 785 next = lowerbnd(curfile.ino); 786 do { 787 curvol = volno; 788 while (next > curfile.ino && volno == curvol) 789 skipfile(); 790 skipmaps(); 791 skipdirs(); 792 } while (volno == curvol + 1); 793 /* 794 * If volume change out of order occurred the 795 * current state must be recalculated 796 */ 797 if (volno != curvol) 798 continue; 799 /* 800 * If the current inode is greater than the one we were 801 * looking for then we missed the one we were looking for. 802 * Since we only attempt to extract files listed in the 803 * dump map, the lost files must have been due to a tape 804 * read error, or a file that was removed while the dump 805 * was in progress. Thus we report all requested files 806 * between the one we were looking for, and the one we 807 * found as missing, and delete their request flags. 808 */ 809 while (next < curfile.ino) { 810 ep = lookupino(next); 811 if (ep == NIL) { 812 (void) fprintf(stderr, 813 gettext("corrupted symbol table\n")); 814 done(1); 815 } 816 (void) fprintf(stderr, 817 gettext("%s: not found on volume\n"), 818 myname(ep)); 819 /* LINTED: result fits into a short */ 820 ep->e_flags &= ~NEW; 821 next = lowerbnd(next); 822 } 823 /* 824 * The current inode is the one that we are looking for, 825 * so extract it per its requested name. 826 */ 827 if (next == curfile.ino && next <= last) { 828 ep = lookupino(next); 829 if (ep == NIL) { 830 (void) fprintf(stderr, 831 gettext("corrupted symbol table\n")); 832 done(1); 833 } 834 (void) extractfile(myname(ep)); 835 /* LINTED: result fits into a short */ 836 ep->e_flags &= ~NEW; 837 if (volno != curvol) 838 skipmaps(); 839 } 840 } 841 } 842 843 /* 844 * Add links. 845 */ 846 void 847 #ifdef __STDC__ 848 createlinks(void) 849 #else 850 createlinks() 851 #endif 852 { 853 struct entry *np, *ep; 854 ino_t i; 855 int dfd; 856 char *to, *from; 857 int saverr; 858 859 vprintf(stdout, gettext("Add links\n")); 860 for (i = ROOTINO; i < maxino; i++) { 861 ep = lookupino(i); 862 if (ep == NIL) 863 continue; 864 to = savename(myname(ep)); 865 for (np = ep->e_links; np != NIL; np = np->e_links) { 866 if ((np->e_flags & NEW) == 0) 867 continue; 868 resolve(myname(np), &dfd, &from); 869 if (dfd != AT_FDCWD) { 870 if (fchdir(dfd) < 0) { 871 saverr = errno; 872 (void) fprintf(stderr, 873 gettext("%s->%s: link failed: %s\n"), 874 from, to, strerror(saverr)); 875 (void) close(dfd); 876 continue; 877 } 878 } 879 if (ep->e_type == NODE) { 880 (void) lf_linkit(to, from, SYMLINK); 881 } else { 882 (void) lf_linkit(to, from, HARDLINK); 883 } 884 /* LINTED: result fits into a short */ 885 np->e_flags &= ~NEW; 886 if (dfd != AT_FDCWD) { 887 fchdir(savepwd); 888 (void) close(dfd); 889 } 890 } 891 freename(to); 892 } 893 } 894 895 /* 896 * Check the symbol table. 897 * We do this to insure that all the requested work was done, and 898 * that no temporary names remain. 899 */ 900 void 901 #ifdef __STDC__ 902 checkrestore(void) 903 #else 904 checkrestore() 905 #endif 906 { 907 struct entry *ep; 908 ino_t i; 909 910 vprintf(stdout, gettext("Check the symbol table.\n")); 911 for (i = ROOTINO; i < maxino; i++) { 912 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 913 /* LINTED: result fits into a short */ 914 ep->e_flags &= ~KEEP; 915 if (ep->e_type == NODE) { 916 /* LINTED: result fits into a short */ 917 ep->e_flags &= ~(NEW|EXISTED); 918 } 919 if ((ep->e_flags & ~(XATTR|XATTRROOT)) != 0) 920 badentry(ep, gettext("incomplete operations")); 921 } 922 } 923 } 924 925 /* 926 * Compare with the directory structure on the tape 927 * A paranoid check that things are as they should be. 928 */ 929 long 930 verifyfile(name, ino, type) 931 char *name; 932 ino_t ino; 933 int type; 934 { 935 struct entry *np, *ep; 936 long descend = GOOD; 937 938 ep = lookupname(name); 939 if (ep == NIL) { 940 (void) fprintf(stderr, 941 gettext("Warning: missing name %s\n"), name); 942 return (FAIL); 943 } 944 np = lookupino(ino); 945 if (np != ep) 946 descend = FAIL; 947 for (; np != NIL; np = np->e_links) 948 if (np == ep) 949 break; 950 if (np == NIL) { 951 (void) fprintf(stderr, gettext("missing inumber %d\n"), ino); 952 done(1); 953 } 954 if (ep->e_type == LEAF && type != LEAF) 955 badentry(ep, gettext("type should be LEAF")); 956 return (descend); 957 } 958 959 /* 960 * This routine does not actually remove any attribute files, it 961 * just removes entries from the symbol table. The attribute files 962 * themselves are assumed to be removed automatically when the 963 * parent file is removed. 964 */ 965 static void 966 removexattrs(ep) 967 struct entry *ep; 968 { 969 struct entry *np = ep; 970 971 if (ep == NIL) 972 return; 973 for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 974 if (np->e_type == NODE) { 975 removexattrs(np); 976 } else { 977 np->e_flags |= REMOVED; 978 freeentry(np); 979 } 980 } 981 ep->e_flags |= REMOVED; 982 freeentry(ep); 983 } 984 985 /* 986 * Move all the extended attributes associated with orig to 987 * the file named by the second argument (targ). 988 */ 989 static void 990 movexattrs(orig, targ) 991 char *orig; 992 char *targ; 993 { 994 char *to, *from; 995 int fromfd, fromdir, tofd, todir, tfd; 996 DIR *dirp = NULL; 997 struct dirent *dp = NULL; 998 999 fromfd = tofd = fromdir = todir = tfd = -1; 1000 1001 resolve(orig, &tfd, &from); 1002 if (tfd == AT_FDCWD && pathconf(orig, _PC_XATTR_EXISTS) != 1) { 1003 /* no attributes to move */ 1004 return; 1005 } 1006 if ((fromfd = openat64(tfd, from, O_RDONLY|O_NONBLOCK)) == -1) { 1007 fprintf(stderr, gettext("%s: cannot move attributes: "), from); 1008 perror(""); 1009 if (tfd != AT_FDCWD) (void) close(tfd); 1010 goto out; 1011 } 1012 1013 if (fpathconf(fromfd, _PC_XATTR_EXISTS) != 1) { 1014 /* no attributes to move */ 1015 if (tfd != AT_FDCWD) (void) close(tfd); 1016 goto out; 1017 } 1018 if ((fromdir = openat64(fromfd, ".", 1019 O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) { 1020 fprintf(stderr, gettext("%s: cannot access attributes: "), 1021 from); 1022 perror(""); 1023 if (tfd != AT_FDCWD) (void) close(tfd); 1024 goto out; 1025 } 1026 if (tfd != AT_FDCWD) (void) close(tfd); 1027 1028 resolve(targ, &tfd, &to); 1029 if ((tofd = openat64(tfd, to, O_RDONLY|O_NONBLOCK)) == -1 || 1030 (todir = openat64(tofd, ".", O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) { 1031 fprintf(stderr, gettext("%s: cannot create attributes: "), to); 1032 perror(""); 1033 goto out; 1034 } 1035 if (tfd != AT_FDCWD) (void) close(tfd); 1036 (void) close(tofd); 1037 1038 if ((tfd = dup(fromdir)) == -1 || 1039 (dirp = fdopendir(tfd)) == NULL) { 1040 fprintf(stderr, 1041 gettext("%s: cannot allocate DIR structure to attribute directory: "), 1042 from); 1043 perror(""); 1044 if (tfd != -1) (void) close(tfd); 1045 goto out; 1046 } 1047 1048 while ((dp = readdir(dirp)) != NULL) { 1049 if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') || 1050 (dp->d_name[0] == '.' && dp->d_name[1] == '.' && 1051 dp->d_name[2] == '\0')) 1052 continue; 1053 if ((renameat(fromdir, dp->d_name, todir, dp->d_name)) == -1) { 1054 fprintf(stderr, 1055 gettext("%s: cannot move attribute %s: "), 1056 from, dp->d_name); 1057 goto out; 1058 } 1059 } 1060 out: 1061 if (fromfd != -1) 1062 (void) close(fromfd); 1063 if (tofd != -1) 1064 (void) close(tofd); 1065 if (dirp != NULL) 1066 (void) closedir(dirp); 1067 if (fromdir != -1) 1068 (void) close(fromdir); 1069 if (todir != -1) 1070 (void) close(todir); 1071 } 1072