1 /* 2 * Copyright 1996, 1998, 2001, 2003 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 ip = ep; 247 break; 248 } 249 } 250 } 251 /* 252 * If both a name and an inode are found, but they do not 253 * correspond to the same file, then both the inode that has 254 * been found and the inode corresponding to the name that 255 * has been found need to be renamed. The current pathname 256 * is the new name for the inode that has been found. Since 257 * all files to be deleted have already been removed, the 258 * named file is either a now-unneeded link, or it must live 259 * under a new name in this dump level. If it is a link, it 260 * can be removed. If it is not a link, it is given a 261 * temporary name in anticipation that it will be renamed 262 * when it is later found by inode number. 263 */ 264 if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) { 265 if (lookuptype == LINK) { 266 removeleaf(np); 267 freeentry(np); 268 } else { 269 dprintf(stdout, 270 gettext("name/inode conflict, mktempname %s\n"), 271 myname(np)); 272 mktempname(np); 273 } 274 np = NIL; 275 key &= ~NAMEFND; 276 } 277 if ((key & ONTAPE) && 278 (((key & INOFND) && ip->e_type != type) || 279 ((key & NAMEFND) && np->e_type != type))) 280 key |= MODECHG; 281 282 /* 283 * Decide on the disposition of the file based on its flags. 284 * Note that we have already handled the case in which 285 * a name and inode are found that correspond to different files. 286 * Thus if both NAMEFND and INOFND are set then ip == np. 287 */ 288 switch (key) { 289 290 /* 291 * A previously existing file has been found. 292 * Mark it as KEEP so that other links to the inode can be 293 * detected, and so that it will not be reclaimed by the search 294 * for unreferenced names. 295 */ 296 case INOFND|NAMEFND: 297 /* LINTED: result fits into a short */ 298 ip->e_flags |= KEEP; 299 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 300 flagvalues(ip)); 301 break; 302 303 /* 304 * A file on the tape has a name which is the same as a name 305 * corresponding to a different file in the previous dump. 306 * Since all files to be deleted have already been removed, 307 * this file is either a now-unneeded link, or it must live 308 * under a new name in this dump level. If it is a link, it 309 * can simply be removed. If it is not a link, it is given a 310 * temporary name in anticipation that it will be renamed 311 * when it is later found by inode number (see INOFND case 312 * below). The entry is then treated as a new file. 313 */ 314 case ONTAPE|NAMEFND: 315 case ONTAPE|NAMEFND|MODECHG: 316 if (lookuptype == LINK) { 317 removeleaf(np); 318 freeentry(np); 319 } else { 320 mktempname(np); 321 } 322 /*FALLTHROUGH*/ 323 324 /* 325 * A previously non-existent file. 326 * Add it to the file system, and request its extraction. 327 * If it is a directory, create it immediately. 328 * (Since the name is unused there can be no conflict) 329 */ 330 case ONTAPE: 331 ep = addentry(name, ino, type); 332 if (type == NODE) 333 newnode(ep); 334 /* LINTED: result fits into a short */ 335 ep->e_flags |= NEW|KEEP; 336 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 337 flagvalues(ep)); 338 break; 339 340 /* 341 * A file with the same inode number, but a different 342 * name has been found. If the other name has not already 343 * been found (indicated by the KEEP flag, see above) then 344 * this must be a new name for the file, and it is renamed. 345 * If the other name has been found then this must be a 346 * link to the file. Hard links to directories are not 347 * permitted, and are either deleted or converted to 348 * symbolic links. Finally, if the file is on the tape, 349 * a request is made to extract it. 350 */ 351 case ONTAPE|INOFND: 352 if (type == LEAF && (ip->e_flags & KEEP) == 0) { 353 /* LINTED: result fits into a short */ 354 ip->e_flags |= EXTRACT; 355 } 356 /*FALLTHROUGH*/ 357 case INOFND: 358 if ((ip->e_flags & KEEP) == 0) { 359 renameit(myname(ip), name); 360 moveentry(ip, name); 361 /* LINTED: result fits into a short */ 362 ip->e_flags |= KEEP; 363 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 364 flagvalues(ip)); 365 break; 366 } 367 if (ip->e_type == NODE) { 368 descend = FAIL; 369 (void) fprintf(stderr, gettext( 370 "deleted hard link %s to directory %s\n"), 371 name, myname(ip)); 372 break; 373 } 374 ep = addentry(name, ino, type|LINK); 375 /* LINTED: result fits into a short */ 376 ep->e_flags |= NEW; 377 dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, 378 flagvalues(ep)); 379 break; 380 381 /* 382 * A previously known file which is to be updated. 383 */ 384 case ONTAPE|INOFND|NAMEFND: 385 if (type == LEAF && lookuptype != LINK) { 386 /* LINTED: result fits into a short */ 387 np->e_flags |= EXTRACT; 388 } 389 /* LINTED: result fits into a short */ 390 np->e_flags |= KEEP; 391 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 392 flagvalues(np)); 393 break; 394 395 /* 396 * An inode is being reused in a completely different way. 397 * Normally an extract can simply do an "unlink" followed 398 * by a "creat". Here we must do effectively the same 399 * thing. The complications arise because we cannot really 400 * delete a directory since it may still contain files 401 * that we need to rename, so we delete it from the symbol 402 * table, and put it on the list to be deleted eventually. 403 * Conversely if a directory is to be created, it must be 404 * done immediately, rather than waiting until the 405 * extraction phase. 406 */ 407 case ONTAPE|INOFND|MODECHG: 408 case ONTAPE|INOFND|NAMEFND|MODECHG: 409 if (ip->e_flags & KEEP) { 410 badentry(ip, gettext("cannot KEEP and change modes")); 411 break; 412 } 413 if (ip->e_type == LEAF) { 414 /* changing from leaf to node */ 415 removeleaf(ip); 416 freeentry(ip); 417 ip = addentry(name, ino, type); 418 newnode(ip); 419 } else { 420 /* changing from node to leaf */ 421 if ((ip->e_flags & TMPNAME) == 0) 422 mktempname(ip); 423 deleteino(ip->e_ino); 424 ip->e_next = removelist; 425 removelist = ip; 426 ip = addentry(name, ino, type); 427 } 428 /* LINTED: result fits into a short */ 429 ip->e_flags |= NEW|KEEP; 430 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 431 flagvalues(ip)); 432 break; 433 434 /* 435 * A hard link to a directory that has been removed. 436 * Ignore it. 437 */ 438 case NAMEFND: 439 dprintf(stdout, gettext("[%s] %s: Extraneous name\n"), 440 keyval(key), 441 name); 442 descend = FAIL; 443 break; 444 445 /* 446 * If we find a directory entry for a file that is not on 447 * the tape, then we must have found a file that was created 448 * while the dump was in progress. Since we have no contents 449 * for it, we discard the name knowing that it will be on the 450 * next incremental tape. 451 */ 452 case 0: 453 (void) fprintf(stderr, 454 gettext("%s: (inode %lu) not found on volume\n"), 455 name, ino); 456 break; 457 458 /* 459 * If any of these arise, something is grievously wrong with 460 * the current state of the symbol table. 461 */ 462 case INOFND|NAMEFND|MODECHG: 463 case NAMEFND|MODECHG: 464 case INOFND|MODECHG: 465 (void) fprintf(stderr, "[%s] %s: %s\n", 466 keyval(key), name, gettext("inconsistent state")); 467 done(1); 468 /*NOTREACHED*/ 469 470 /* 471 * These states "cannot" arise for any state of the symbol table. 472 */ 473 case ONTAPE|MODECHG: 474 case MODECHG: 475 default: 476 (void) fprintf(stderr, "[%s] %s: %s\n", 477 keyval(key), name, gettext("impossible state")); 478 done(1); 479 /*NOTREACHED*/ 480 } 481 return (descend); 482 } 483 484 /* 485 * Calculate the active flags in a key. 486 */ 487 static char * 488 keyval(key) 489 int key; 490 { 491 static char keybuf[32]; 492 493 /* Note longest case is everything except |NIL */ 494 495 (void) strcpy(keybuf, "|NIL"); 496 keybuf[0] = '\0'; 497 if (key & ONTAPE) 498 (void) strcat(keybuf, "|ONTAPE"); 499 if (key & INOFND) 500 (void) strcat(keybuf, "|INOFND"); 501 if (key & NAMEFND) 502 (void) strcat(keybuf, "|NAMEFND"); 503 if (key & MODECHG) 504 (void) strcat(keybuf, "|MODECHG"); 505 return (&keybuf[1]); 506 } 507 508 /* 509 * Find unreferenced link names. 510 */ 511 void 512 #ifdef __STDC__ 513 findunreflinks(void) 514 #else 515 findunreflinks() 516 #endif 517 { 518 struct entry *ep, *np; 519 ino_t i; 520 521 vprintf(stdout, gettext("Find unreferenced names.\n")); 522 for (i = ROOTINO; i < maxino; i++) { 523 ep = lookupino(i); 524 if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0) 525 continue; 526 for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 527 if (np->e_flags == 0) { 528 dprintf(stdout, gettext( 529 "%s: remove unreferenced name\n"), 530 myname(np)); 531 removeleaf(np); 532 freeentry(np); 533 } 534 } 535 } 536 /* 537 * Any leaves remaining in removed directories are unreferenced. 538 */ 539 for (ep = removelist; ep != NIL; ep = ep->e_next) { 540 for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 541 if (np->e_type == LEAF) { 542 if (np->e_flags != 0) 543 badentry(np, gettext( 544 "unreferenced with flags")); 545 dprintf(stdout, gettext( 546 "%s: remove unreferenced name\n"), 547 myname(np)); 548 removeleaf(np); 549 freeentry(np); 550 } 551 } 552 } 553 } 554 555 /* 556 * Remove old nodes (directories). 557 * Note that this routine runs in O(N*D) where: 558 * N is the number of directory entries to be removed. 559 * D is the maximum depth of the tree. 560 * If N == D this can be quite slow. If the list were 561 * topologically sorted, the deletion could be done in 562 * time O(N). 563 */ 564 void 565 #ifdef __STDC__ 566 removeoldnodes(void) 567 #else 568 removeoldnodes() 569 #endif 570 { 571 struct entry *ep, **prev; 572 long change; 573 574 vprintf(stdout, gettext("Remove old nodes (directories).\n")); 575 do { 576 change = 0; 577 prev = &removelist; 578 for (ep = removelist; ep != NIL; ep = *prev) { 579 if (ep->e_entries != NIL) { 580 prev = &ep->e_next; 581 continue; 582 } 583 *prev = ep->e_next; 584 removenode(ep); 585 freeentry(ep); 586 change++; 587 } 588 } while (change); 589 for (ep = removelist; ep != NIL; ep = ep->e_next) 590 badentry(ep, gettext("cannot remove, non-empty")); 591 } 592 593 /* 594 * This is the routine used to extract files for the 'r' command. 595 * Extract new leaves. 596 */ 597 void 598 createleaves(symtabfile) 599 char *symtabfile; 600 { 601 struct entry *ep; 602 char name[MAXCOMPLEXLEN]; 603 ino_t first; 604 int curvol; 605 606 if (command == 'R') { 607 vprintf(stdout, gettext("Continue extraction of new leaves\n")); 608 } else { 609 vprintf(stdout, gettext("Extract new leaves.\n")); 610 dumpsymtable(symtabfile, volno); 611 } 612 first = lowerbnd(ROOTINO); 613 curvol = volno; 614 while (curfile.ino < maxino) { 615 first = lowerbnd(first); 616 /* 617 * If the next available file is not the one which we 618 * expect then we have missed one or more files. Since 619 * we do not request files that were not on the tape, 620 * the lost files must have been due to a tape read error, 621 * or a file that was removed while the dump was in progress. 622 * 623 * The loop will terminate with first == maxino, if not 624 * sooner. Due to the e_flags manipulation, lowerbnd() 625 * will never return its argument. 626 */ 627 while (first < curfile.ino) { 628 ep = lookupino(first); 629 if (ep == NIL) { 630 (void) fprintf(stderr, 631 gettext("%d: bad first\n"), first); 632 done(1); 633 } 634 (void) fprintf(stderr, 635 gettext("%s: not found on volume\n"), 636 myname(ep)); 637 /* LINTED: result fits into a short */ 638 ep->e_flags &= ~(NEW|EXTRACT); 639 first = lowerbnd(first); 640 } 641 /* 642 * If we find files on the tape that have no corresponding 643 * directory entries, then we must have found a file that 644 * was created while the dump was in progress. Since we have 645 * no name for it, we discard it knowing that it will be 646 * on the next incremental tape. 647 */ 648 if (first != curfile.ino) { 649 (void) fprintf(stderr, 650 gettext("expected next file %d, got %d\n"), 651 first, curfile.ino); 652 skipfile(); 653 goto next; 654 } 655 ep = lookupino(curfile.ino); 656 if (ep == NIL) { 657 (void) fprintf(stderr, 658 gettext("unknown file on volume\n")); 659 done(1); 660 } 661 if ((ep->e_flags & (NEW|EXTRACT)) == 0) 662 badentry(ep, gettext("unexpected file on volume")); 663 /* 664 * If the file is to be extracted, then the old file must 665 * be removed since its type may change from one leaf type 666 * to another (eg "file" to "character special"). But we 667 * also need to preserve any existing extended attributes; 668 * so first rename the file, then move its attributes, then 669 * remove it. 670 */ 671 if ((ep->e_flags & EXTRACT) != 0) { 672 char *sname = savename(ep->e_name); 673 complexcpy(name, myname(ep), MAXCOMPLEXLEN); 674 mktempname(ep); 675 (void) extractfile(name); 676 movexattrs(myname(ep), name); 677 removeleaf(ep); 678 freename(ep->e_name); 679 ep->e_name = sname; 680 ep->e_namlen = strlen(ep->e_name); 681 /* LINTED: result fits into a short */ 682 ep->e_flags &= ~REMOVED; 683 } else { 684 (void) extractfile(myname(ep)); 685 } 686 /* LINTED: result fits into a short */ 687 ep->e_flags &= ~(NEW|EXTRACT); 688 /* 689 * We checkpoint the restore after every tape reel, so 690 * as to simplify the amount of work required by the 691 * 'R' command. 692 */ 693 next: 694 if (curvol != volno) { 695 dumpsymtable(symtabfile, volno); 696 skipmaps(); 697 curvol = volno; 698 } 699 } 700 } 701 702 /* 703 * This is the routine used to extract files for the 'x' and 'i' commands. 704 * Efficiently extract a subset of the files on a tape. 705 */ 706 void 707 #ifdef __STDC__ 708 createfiles(void) 709 #else 710 createfiles() 711 #endif 712 { 713 ino_t first, next, last; 714 struct entry *ep; 715 int curvol, nextvol; 716 717 vprintf(stdout, gettext("Extract requested files\n")); 718 first = lowerbnd(ROOTINO); 719 last = upperbnd(maxino - 1); 720 nextvol = volnumber(first); 721 if (nextvol == 0) { 722 curfile.action = SKIP; 723 getvol(1); 724 skipmaps(); 725 skipdirs(); 726 } 727 for (;;) { 728 first = lowerbnd(first); 729 last = upperbnd(last); 730 /* 731 * Check to see if any files remain to be extracted 732 */ 733 if (first > last) 734 return; 735 /* 736 * If a map of inode numbers to tape volumes is 737 * available, then select the next volume to be read. 738 */ 739 if (nextvol > 0) { 740 nextvol = volnumber(first); 741 if (nextvol != volno) { 742 curfile.action = UNKNOWN; 743 getvol(nextvol); 744 skipmaps(); 745 } 746 } 747 /* 748 * Reject any volumes with inodes greater than 749 * the last one needed. This will only be true 750 * if the above code has not selected a volume. 751 */ 752 while (curfile.ino > last) { 753 curfile.action = SKIP; 754 getvol(0); 755 skipmaps(); 756 skipdirs(); 757 } 758 /* 759 * Decide on the next inode needed. 760 * Skip across the inodes until it is found 761 * or an out of order volume change is encountered 762 */ 763 next = lowerbnd(curfile.ino); 764 do { 765 curvol = volno; 766 while (next > curfile.ino && volno == curvol) 767 skipfile(); 768 skipmaps(); 769 skipdirs(); 770 } while (volno == curvol + 1); 771 /* 772 * If volume change out of order occurred the 773 * current state must be recalculated 774 */ 775 if (volno != curvol) 776 continue; 777 /* 778 * If the current inode is greater than the one we were 779 * looking for then we missed the one we were looking for. 780 * Since we only attempt to extract files listed in the 781 * dump map, the lost files must have been due to a tape 782 * read error, or a file that was removed while the dump 783 * was in progress. Thus we report all requested files 784 * between the one we were looking for, and the one we 785 * found as missing, and delete their request flags. 786 */ 787 while (next < curfile.ino) { 788 ep = lookupino(next); 789 if (ep == NIL) { 790 (void) fprintf(stderr, 791 gettext("corrupted symbol table\n")); 792 done(1); 793 } 794 (void) fprintf(stderr, 795 gettext("%s: not found on volume\n"), 796 myname(ep)); 797 /* LINTED: result fits into a short */ 798 ep->e_flags &= ~NEW; 799 next = lowerbnd(next); 800 } 801 /* 802 * The current inode is the one that we are looking for, 803 * so extract it per its requested name. 804 */ 805 if (next == curfile.ino && next <= last) { 806 ep = lookupino(next); 807 if (ep == NIL) { 808 (void) fprintf(stderr, 809 gettext("corrupted symbol table\n")); 810 done(1); 811 } 812 (void) extractfile(myname(ep)); 813 /* LINTED: result fits into a short */ 814 ep->e_flags &= ~NEW; 815 if (volno != curvol) 816 skipmaps(); 817 } 818 } 819 } 820 821 /* 822 * Add links. 823 */ 824 void 825 #ifdef __STDC__ 826 createlinks(void) 827 #else 828 createlinks() 829 #endif 830 { 831 struct entry *np, *ep; 832 ino_t i; 833 int dfd; 834 char *to, *from; 835 int saverr; 836 837 vprintf(stdout, gettext("Add links\n")); 838 for (i = ROOTINO; i < maxino; i++) { 839 ep = lookupino(i); 840 if (ep == NIL) 841 continue; 842 to = savename(myname(ep)); 843 for (np = ep->e_links; np != NIL; np = np->e_links) { 844 if ((np->e_flags & NEW) == 0) 845 continue; 846 resolve(myname(np), &dfd, &from); 847 if (dfd != AT_FDCWD) { 848 if (fchdir(dfd) < 0) { 849 saverr = errno; 850 (void) fprintf(stderr, 851 gettext("%s->%s: link failed: %s\n"), 852 from, to, strerror(saverr)); 853 (void) close(dfd); 854 continue; 855 } 856 } 857 if (ep->e_type == NODE) { 858 (void) lf_linkit(to, from, SYMLINK); 859 } else { 860 (void) lf_linkit(to, from, HARDLINK); 861 } 862 /* LINTED: result fits into a short */ 863 np->e_flags &= ~NEW; 864 if (dfd != AT_FDCWD) { 865 fchdir(savepwd); 866 (void) close(dfd); 867 } 868 } 869 freename(to); 870 } 871 } 872 873 /* 874 * Check the symbol table. 875 * We do this to insure that all the requested work was done, and 876 * that no temporary names remain. 877 */ 878 void 879 #ifdef __STDC__ 880 checkrestore(void) 881 #else 882 checkrestore() 883 #endif 884 { 885 struct entry *ep; 886 ino_t i; 887 888 vprintf(stdout, gettext("Check the symbol table.\n")); 889 for (i = ROOTINO; i < maxino; i++) { 890 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 891 /* LINTED: result fits into a short */ 892 ep->e_flags &= ~KEEP; 893 if (ep->e_type == NODE) { 894 /* LINTED: result fits into a short */ 895 ep->e_flags &= ~(NEW|EXISTED); 896 } 897 if ((ep->e_flags & ~(XATTR|XATTRROOT)) != 0) 898 badentry(ep, gettext("incomplete operations")); 899 } 900 } 901 } 902 903 /* 904 * Compare with the directory structure on the tape 905 * A paranoid check that things are as they should be. 906 */ 907 long 908 verifyfile(name, ino, type) 909 char *name; 910 ino_t ino; 911 int type; 912 { 913 struct entry *np, *ep; 914 long descend = GOOD; 915 916 ep = lookupname(name); 917 if (ep == NIL) { 918 (void) fprintf(stderr, 919 gettext("Warning: missing name %s\n"), name); 920 return (FAIL); 921 } 922 np = lookupino(ino); 923 if (np != ep) 924 descend = FAIL; 925 for (; np != NIL; np = np->e_links) 926 if (np == ep) 927 break; 928 if (np == NIL) { 929 (void) fprintf(stderr, gettext("missing inumber %d\n"), ino); 930 done(1); 931 } 932 if (ep->e_type == LEAF && type != LEAF) 933 badentry(ep, gettext("type should be LEAF")); 934 return (descend); 935 } 936 937 /* 938 * This routine does not actually remove any attribute files, it 939 * just removes entries from the symbol table. The attribute files 940 * themselves are assumed to be removed automatically when the 941 * parent file is removed. 942 */ 943 static void 944 removexattrs(ep) 945 struct entry *ep; 946 { 947 struct entry *np = ep; 948 949 if (ep == NIL) 950 return; 951 for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 952 if (np->e_type == NODE) { 953 removexattrs(np); 954 } else { 955 np->e_flags |= REMOVED; 956 freeentry(np); 957 } 958 } 959 ep->e_flags |= REMOVED; 960 freeentry(ep); 961 } 962 963 /* 964 * Move all the extended attributes associated with orig to 965 * the file named by the second argument (targ). 966 */ 967 static void 968 movexattrs(orig, targ) 969 char *orig; 970 char *targ; 971 { 972 char *to, *from; 973 int fromfd, fromdir, tofd, todir, tfd; 974 DIR *dirp = NULL; 975 struct dirent *dp = NULL; 976 977 fromfd = tofd = fromdir = todir = tfd = -1; 978 979 resolve(orig, &tfd, &from); 980 if (tfd == AT_FDCWD && pathconf(orig, _PC_XATTR_EXISTS) != 1) { 981 /* no attributes to move */ 982 return; 983 } 984 if ((fromfd = openat64(tfd, from, O_RDONLY|O_NONBLOCK)) == -1) { 985 fprintf(stderr, gettext("%s: cannot move attributes: "), from); 986 perror(""); 987 if (tfd != AT_FDCWD) (void) close(tfd); 988 goto out; 989 } 990 991 if (fpathconf(fromfd, _PC_XATTR_EXISTS) != 1) { 992 /* no attributes to move */ 993 if (tfd != AT_FDCWD) (void) close(tfd); 994 goto out; 995 } 996 if ((fromdir = openat64(fromfd, ".", 997 O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) { 998 fprintf(stderr, gettext("%s: cannot access attributes: "), 999 from); 1000 perror(""); 1001 if (tfd != AT_FDCWD) (void) close(tfd); 1002 goto out; 1003 } 1004 if (tfd != AT_FDCWD) (void) close(tfd); 1005 1006 resolve(targ, &tfd, &to); 1007 if ((tofd = openat64(tfd, to, O_RDONLY|O_NONBLOCK)) == -1 || 1008 (todir = openat64(tofd, ".", O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) { 1009 fprintf(stderr, gettext("%s: cannot create attributes: "), to); 1010 perror(""); 1011 goto out; 1012 } 1013 if (tfd != AT_FDCWD) (void) close(tfd); 1014 (void) close(tofd); 1015 1016 if ((tfd = dup(fromdir)) == -1 || 1017 (dirp = fdopendir(tfd)) == NULL) { 1018 fprintf(stderr, 1019 gettext("%s: cannot allocate DIR structure to attribute directory: "), 1020 from); 1021 perror(""); 1022 if (tfd != -1) (void) close(tfd); 1023 goto out; 1024 } 1025 1026 while ((dp = readdir(dirp)) != NULL) { 1027 if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') || 1028 (dp->d_name[0] == '.' && dp->d_name[1] == '.' && 1029 dp->d_name[2] == '\0')) 1030 continue; 1031 if ((renameat(fromdir, dp->d_name, todir, dp->d_name)) == -1) { 1032 fprintf(stderr, 1033 gettext("%s: cannot move attribute %s: "), 1034 from, dp->d_name); 1035 goto out; 1036 } 1037 } 1038 out: 1039 if (fromfd != -1) 1040 (void) close(fromfd); 1041 if (tofd != -1) 1042 (void) close(tofd); 1043 if (dirp != NULL) 1044 (void) closedir(dirp); 1045 if (fromdir != -1) 1046 (void) close(fromdir); 1047 if (todir != -1) 1048 (void) close(todir); 1049 } 1050