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