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