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: }

Defined functions

addfile defined in line 37; used 1 times
createleaves defined in line 520; used 2 times
deletefile defined in line 79; used 1 times
findunreflinks defined in line 445; used 1 times
keyval defined in line 423; used 10 times
listfile defined in line 17; used 1 times
nodeupdates defined in line 152; used 1 times
removeoldleaves defined in line 116; used 1 times
removeoldnodes defined in line 492; used 1 times
verifyfile defined in line 737; used 1 times

Defined variables

removelist defined in line 110; used 8 times
sccsid defined in line 8; never used

Defined macros

INOFND defined in line 164; used 11 times
MODECHG defined in line 166; used 2 times
NAMEFND defined in line 165; used 10 times
ONTAPE defined in line 163; used 10 times
Last modified: 1986-03-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2247
Valid CSS Valid XHTML 1.0 Strict