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