|
|
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[] = "@(#)symtab.c 5.1 (Berkeley) 5/28/85"; ! 9: #endif not lint ! 10: ! 11: /* ! 12: * These routines maintain the symbol table which tracks the state ! 13: * of the file system being restored. They provide lookup by either ! 14: * name or inode number. They also provide for creation, deletion, ! 15: * and renaming of entries. Because of the dynamic nature of pathnames, ! 16: * names should not be saved, but always constructed just before they ! 17: * are needed, by calling "myname". ! 18: */ ! 19: ! 20: #include "restore.h" ! 21: #include <sys/stat.h> ! 22: ! 23: /* ! 24: * The following variables define the inode symbol table. ! 25: * The primary hash table is dynamically allocated based on ! 26: * the number of inodes in the file system (maxino), scaled by ! 27: * HASHFACTOR. The variable "entry" points to the hash table; ! 28: * the variable "entrytblsize" indicates its size (in entries). ! 29: */ ! 30: #define HASHFACTOR 5 ! 31: static struct entry **entry; ! 32: static long entrytblsize; ! 33: ! 34: /* ! 35: * Look up an entry by inode number ! 36: */ ! 37: struct entry * ! 38: lookupino(inum) ! 39: ino_t inum; ! 40: { ! 41: register struct entry *ep; ! 42: ! 43: if (inum < ROOTINO || inum >= maxino) ! 44: return (NIL); ! 45: for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next) ! 46: if (ep->e_ino == inum) ! 47: return (ep); ! 48: return (NIL); ! 49: } ! 50: ! 51: /* ! 52: * Add an entry into the entry table ! 53: */ ! 54: addino(inum, np) ! 55: ino_t inum; ! 56: struct entry *np; ! 57: { ! 58: struct entry **epp; ! 59: ! 60: if (inum < ROOTINO || inum >= maxino) ! 61: panic("addino: out of range %d\n", inum); ! 62: epp = &entry[inum % entrytblsize]; ! 63: np->e_ino = inum; ! 64: np->e_next = *epp; ! 65: *epp = np; ! 66: if (dflag) ! 67: for (np = np->e_next; np != NIL; np = np->e_next) ! 68: if (np->e_ino == inum) ! 69: badentry(np, "duplicate inum"); ! 70: } ! 71: ! 72: /* ! 73: * Delete an entry from the entry table ! 74: */ ! 75: deleteino(inum) ! 76: ino_t inum; ! 77: { ! 78: register struct entry *next; ! 79: struct entry **prev; ! 80: ! 81: if (inum < ROOTINO || inum >= maxino) ! 82: panic("deleteino: out of range %d\n", inum); ! 83: prev = &entry[inum % entrytblsize]; ! 84: for (next = *prev; next != NIL; next = next->e_next) { ! 85: if (next->e_ino == inum) { ! 86: next->e_ino = 0; ! 87: *prev = next->e_next; ! 88: return; ! 89: } ! 90: prev = &next->e_next; ! 91: } ! 92: panic("deleteino: %d not found\n", inum); ! 93: } ! 94: ! 95: /* ! 96: * Look up an entry by name ! 97: */ ! 98: struct entry * ! 99: lookupname(name) ! 100: char *name; ! 101: { ! 102: register struct entry *ep; ! 103: register char *np, *cp; ! 104: char buf[MAXPATHLEN]; ! 105: ! 106: cp = name; ! 107: for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) { ! 108: for (np = buf; *cp != '/' && *cp != '\0'; ) ! 109: *np++ = *cp++; ! 110: *np = '\0'; ! 111: for ( ; ep != NIL; ep = ep->e_sibling) ! 112: if (strcmp(ep->e_name, buf) == 0) ! 113: break; ! 114: if (ep == NIL) ! 115: break; ! 116: if (*cp++ == '\0') ! 117: return (ep); ! 118: } ! 119: return (NIL); ! 120: } ! 121: ! 122: /* ! 123: * Look up the parent of a pathname ! 124: */ ! 125: struct entry * ! 126: lookupparent(name) ! 127: char *name; ! 128: { ! 129: struct entry *ep; ! 130: char *tailindex; ! 131: ! 132: tailindex = rindex(name, '/'); ! 133: if (tailindex == 0) ! 134: return (NIL); ! 135: *tailindex = '\0'; ! 136: ep = lookupname(name); ! 137: *tailindex = '/'; ! 138: if (ep == NIL) ! 139: return (NIL); ! 140: if (ep->e_type != NODE) ! 141: panic("%s is not a directory\n", name); ! 142: return (ep); ! 143: } ! 144: ! 145: /* ! 146: * Determine the current pathname of a node or leaf ! 147: */ ! 148: char * ! 149: myname(ep) ! 150: register struct entry *ep; ! 151: { ! 152: register char *cp; ! 153: static char namebuf[MAXPATHLEN]; ! 154: ! 155: for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) { ! 156: cp -= ep->e_namlen; ! 157: bcopy(ep->e_name, cp, (long)ep->e_namlen); ! 158: if (ep == lookupino(ROOTINO)) ! 159: return (cp); ! 160: *(--cp) = '/'; ! 161: ep = ep->e_parent; ! 162: } ! 163: panic("%s: pathname too long\n", cp); ! 164: return(cp); ! 165: } ! 166: ! 167: /* ! 168: * Unused symbol table entries are linked together on a freelist ! 169: * headed by the following pointer. ! 170: */ ! 171: static struct entry *freelist = NIL; ! 172: ! 173: /* ! 174: * add an entry to the symbol table ! 175: */ ! 176: struct entry * ! 177: addentry(name, inum, type) ! 178: char *name; ! 179: ino_t inum; ! 180: int type; ! 181: { ! 182: register struct entry *np, *ep; ! 183: ! 184: if (freelist != NIL) { ! 185: np = freelist; ! 186: freelist = np->e_next; ! 187: bzero((char *)np, (long)sizeof(struct entry)); ! 188: } else { ! 189: np = (struct entry *)calloc(1, sizeof(struct entry)); ! 190: if (np == NIL) ! 191: panic("no memory to extend symbol table\n"); ! 192: } ! 193: np->e_type = type & ~LINK; ! 194: ep = lookupparent(name); ! 195: if (ep == NIL) { ! 196: if (inum != ROOTINO || lookupino(ROOTINO) != NIL) ! 197: panic("bad name to addentry %s\n", name); ! 198: np->e_name = savename(name); ! 199: np->e_namlen = strlen(name); ! 200: np->e_parent = np; ! 201: addino(ROOTINO, np); ! 202: return (np); ! 203: } ! 204: np->e_name = savename(rindex(name, '/') + 1); ! 205: np->e_namlen = strlen(np->e_name); ! 206: np->e_parent = ep; ! 207: np->e_sibling = ep->e_entries; ! 208: ep->e_entries = np; ! 209: if (type & LINK) { ! 210: ep = lookupino(inum); ! 211: if (ep == NIL) ! 212: panic("link to non-existant name\n"); ! 213: np->e_ino = inum; ! 214: np->e_links = ep->e_links; ! 215: ep->e_links = np; ! 216: } else if (inum != 0) { ! 217: if (lookupino(inum) != NIL) ! 218: panic("duplicate entry\n"); ! 219: addino(inum, np); ! 220: } ! 221: return (np); ! 222: } ! 223: ! 224: /* ! 225: * delete an entry from the symbol table ! 226: */ ! 227: freeentry(ep) ! 228: register struct entry *ep; ! 229: { ! 230: register struct entry *np; ! 231: ino_t inum; ! 232: ! 233: if (ep->e_flags != REMOVED) ! 234: badentry(ep, "not marked REMOVED"); ! 235: if (ep->e_type == NODE) { ! 236: if (ep->e_links != NIL) ! 237: badentry(ep, "freeing referenced directory"); ! 238: if (ep->e_entries != NIL) ! 239: badentry(ep, "freeing non-empty directory"); ! 240: } ! 241: if (ep->e_ino != 0) { ! 242: np = lookupino(ep->e_ino); ! 243: if (np == NIL) ! 244: badentry(ep, "lookupino failed"); ! 245: if (np == ep) { ! 246: inum = ep->e_ino; ! 247: deleteino(inum); ! 248: if (ep->e_links != NIL) ! 249: addino(inum, ep->e_links); ! 250: } else { ! 251: for (; np != NIL; np = np->e_links) { ! 252: if (np->e_links == ep) { ! 253: np->e_links = ep->e_links; ! 254: break; ! 255: } ! 256: } ! 257: if (np == NIL) ! 258: badentry(ep, "link not found"); ! 259: } ! 260: } ! 261: removeentry(ep); ! 262: freename(ep->e_name); ! 263: ep->e_next = freelist; ! 264: freelist = ep; ! 265: } ! 266: ! 267: /* ! 268: * Relocate an entry in the tree structure ! 269: */ ! 270: moveentry(ep, newname) ! 271: register struct entry *ep; ! 272: char *newname; ! 273: { ! 274: struct entry *np; ! 275: char *cp; ! 276: ! 277: np = lookupparent(newname); ! 278: if (np == NIL) ! 279: badentry(ep, "cannot move ROOT"); ! 280: if (np != ep->e_parent) { ! 281: removeentry(ep); ! 282: ep->e_parent = np; ! 283: ep->e_sibling = np->e_entries; ! 284: np->e_entries = ep; ! 285: } ! 286: cp = rindex(newname, '/') + 1; ! 287: freename(ep->e_name); ! 288: ep->e_name = savename(cp); ! 289: ep->e_namlen = strlen(cp); ! 290: if (strcmp(gentempname(ep), ep->e_name) == 0) ! 291: ep->e_flags |= TMPNAME; ! 292: else ! 293: ep->e_flags &= ~TMPNAME; ! 294: } ! 295: ! 296: /* ! 297: * Remove an entry in the tree structure ! 298: */ ! 299: removeentry(ep) ! 300: register struct entry *ep; ! 301: { ! 302: register struct entry *np; ! 303: ! 304: np = ep->e_parent; ! 305: if (np->e_entries == ep) { ! 306: np->e_entries = ep->e_sibling; ! 307: } else { ! 308: for (np = np->e_entries; np != NIL; np = np->e_sibling) { ! 309: if (np->e_sibling == ep) { ! 310: np->e_sibling = ep->e_sibling; ! 311: break; ! 312: } ! 313: } ! 314: if (np == NIL) ! 315: badentry(ep, "cannot find entry in parent list"); ! 316: } ! 317: } ! 318: ! 319: /* ! 320: * Table of unused string entries, sorted by length. ! 321: * ! 322: * Entries are allocated in STRTBLINCR sized pieces so that names ! 323: * of similar lengths can use the same entry. The value of STRTBLINCR ! 324: * is chosen so that every entry has at least enough space to hold ! 325: * a "struct strtbl" header. Thus every entry can be linked onto an ! 326: * apprpriate free list. ! 327: * ! 328: * NB. The macro "allocsize" below assumes that "struct strhdr" ! 329: * has a size that is a power of two. ! 330: */ ! 331: struct strhdr { ! 332: struct strhdr *next; ! 333: }; ! 334: ! 335: #define STRTBLINCR (sizeof(struct strhdr)) ! 336: #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) ! 337: ! 338: static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR]; ! 339: ! 340: /* ! 341: * Allocate space for a name. It first looks to see if it already ! 342: * has an appropriate sized entry, and if not allocates a new one. ! 343: */ ! 344: char * ! 345: savename(name) ! 346: char *name; ! 347: { ! 348: struct strhdr *np; ! 349: long len; ! 350: char *cp; ! 351: ! 352: if (name == NULL) ! 353: panic("bad name\n"); ! 354: len = strlen(name); ! 355: np = strtblhdr[len / STRTBLINCR].next; ! 356: if (np != NULL) { ! 357: strtblhdr[len / STRTBLINCR].next = np->next; ! 358: cp = (char *)np; ! 359: } else { ! 360: cp = malloc((unsigned)allocsize(len)); ! 361: if (cp == NULL) ! 362: panic("no space for string table\n"); ! 363: } ! 364: (void) strcpy(cp, name); ! 365: return (cp); ! 366: } ! 367: ! 368: /* ! 369: * Free space for a name. The resulting entry is linked onto the ! 370: * appropriate free list. ! 371: */ ! 372: freename(name) ! 373: char *name; ! 374: { ! 375: struct strhdr *tp, *np; ! 376: ! 377: tp = &strtblhdr[strlen(name) / STRTBLINCR]; ! 378: np = (struct strhdr *)name; ! 379: np->next = tp->next; ! 380: tp->next = np; ! 381: } ! 382: ! 383: /* ! 384: * Useful quantities placed at the end of a dumped symbol table. ! 385: */ ! 386: struct symtableheader { ! 387: long volno; ! 388: long stringsize; ! 389: long entrytblsize; ! 390: time_t dumptime; ! 391: time_t dumpdate; ! 392: ino_t maxino; ! 393: long ntrec; ! 394: }; ! 395: ! 396: /* ! 397: * dump a snapshot of the symbol table ! 398: */ ! 399: dumpsymtable(filename, checkpt) ! 400: char *filename; ! 401: long checkpt; ! 402: { ! 403: register struct entry *ep, *tep; ! 404: register ino_t i; ! 405: struct entry temp, *tentry; ! 406: long mynum = 1, stroff = 0; ! 407: FILE *fd; ! 408: struct symtableheader hdr; ! 409: ! 410: vprintf(stdout, "Check pointing the restore\n"); ! 411: if ((fd = fopen(filename, "w")) == NULL) { ! 412: perror("fopen"); ! 413: panic("cannot create save file %s for symbol table\n", ! 414: filename); ! 415: } ! 416: clearerr(fd); ! 417: /* ! 418: * Assign indicies to each entry ! 419: * Write out the string entries ! 420: */ ! 421: for (i = ROOTINO; i < maxino; i++) { ! 422: for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { ! 423: ep->e_index = mynum++; ! 424: (void) fwrite(ep->e_name, sizeof(char), ! 425: (int)allocsize(ep->e_namlen), fd); ! 426: } ! 427: } ! 428: /* ! 429: * Convert pointers to indexes, and output ! 430: */ ! 431: tep = &temp; ! 432: stroff = 0; ! 433: for (i = ROOTINO; i < maxino; i++) { ! 434: for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { ! 435: bcopy((char *)ep, (char *)tep, ! 436: (long)sizeof(struct entry)); ! 437: tep->e_name = (char *)stroff; ! 438: stroff += allocsize(ep->e_namlen); ! 439: tep->e_parent = (struct entry *)ep->e_parent->e_index; ! 440: if (ep->e_links != NIL) ! 441: tep->e_links = ! 442: (struct entry *)ep->e_links->e_index; ! 443: if (ep->e_sibling != NIL) ! 444: tep->e_sibling = ! 445: (struct entry *)ep->e_sibling->e_index; ! 446: if (ep->e_entries != NIL) ! 447: tep->e_entries = ! 448: (struct entry *)ep->e_entries->e_index; ! 449: if (ep->e_next != NIL) ! 450: tep->e_next = ! 451: (struct entry *)ep->e_next->e_index; ! 452: (void) fwrite((char *)tep, sizeof(struct entry), 1, fd); ! 453: } ! 454: } ! 455: /* ! 456: * Convert entry pointers to indexes, and output ! 457: */ ! 458: for (i = 0; i < entrytblsize; i++) { ! 459: if (entry[i] == NIL) ! 460: tentry = NIL; ! 461: else ! 462: tentry = (struct entry *)entry[i]->e_index; ! 463: (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd); ! 464: } ! 465: hdr.volno = checkpt; ! 466: hdr.maxino = maxino; ! 467: hdr.entrytblsize = entrytblsize; ! 468: hdr.stringsize = stroff; ! 469: hdr.dumptime = dumptime; ! 470: hdr.dumpdate = dumpdate; ! 471: hdr.ntrec = ntrec; ! 472: (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); ! 473: if (ferror(fd)) { ! 474: perror("fwrite"); ! 475: panic("output error to file %s writing symbol table\n", ! 476: filename); ! 477: } ! 478: (void) fclose(fd); ! 479: } ! 480: ! 481: /* ! 482: * Initialize a symbol table from a file ! 483: */ ! 484: initsymtable(filename) ! 485: char *filename; ! 486: { ! 487: char *base; ! 488: long tblsize; ! 489: register struct entry *ep; ! 490: struct entry *baseep, *lep; ! 491: struct symtableheader hdr; ! 492: struct stat stbuf; ! 493: register long i; ! 494: int fd; ! 495: ! 496: vprintf(stdout, "Initialize symbol table.\n"); ! 497: if (filename == NULL) { ! 498: entrytblsize = maxino / HASHFACTOR; ! 499: entry = (struct entry **) ! 500: calloc((unsigned)entrytblsize, sizeof(struct entry *)); ! 501: if (entry == (struct entry **)NIL) ! 502: panic("no memory for entry table\n"); ! 503: ep = addentry(".", ROOTINO, NODE); ! 504: ep->e_flags |= NEW; ! 505: return; ! 506: } ! 507: if ((fd = open(filename, 0)) < 0) { ! 508: perror("open"); ! 509: panic("cannot open symbol table file %s\n", filename); ! 510: } ! 511: if (fstat(fd, &stbuf) < 0) { ! 512: perror("stat"); ! 513: panic("cannot stat symbol table file %s\n", filename); ! 514: } ! 515: tblsize = stbuf.st_size - sizeof(struct symtableheader); ! 516: base = calloc(sizeof(char), (unsigned)tblsize); ! 517: if (base == NULL) ! 518: panic("cannot allocate space for symbol table\n"); ! 519: if (read(fd, base, (int)tblsize) < 0 || ! 520: read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { ! 521: perror("read"); ! 522: panic("cannot read symbol table file %s\n", filename); ! 523: } ! 524: switch (command) { ! 525: case 'r': ! 526: /* ! 527: * For normal continuation, insure that we are using ! 528: * the next incremental tape ! 529: */ ! 530: if (hdr.dumpdate != dumptime) { ! 531: if (hdr.dumpdate < dumptime) ! 532: fprintf(stderr, "Incremental tape too low\n"); ! 533: else ! 534: fprintf(stderr, "Incremental tape too high\n"); ! 535: done(1); ! 536: } ! 537: break; ! 538: case 'R': ! 539: /* ! 540: * For restart, insure that we are using the same tape ! 541: */ ! 542: curfile.action = SKIP; ! 543: dumptime = hdr.dumptime; ! 544: dumpdate = hdr.dumpdate; ! 545: if (!bflag) ! 546: newtapebuf(hdr.ntrec); ! 547: getvol(hdr.volno); ! 548: break; ! 549: default: ! 550: panic("initsymtable called from command %c\n", command); ! 551: break; ! 552: } ! 553: maxino = hdr.maxino; ! 554: entrytblsize = hdr.entrytblsize; ! 555: entry = (struct entry **) ! 556: (base + tblsize - (entrytblsize * sizeof(struct entry *))); ! 557: baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); ! 558: lep = (struct entry *)entry; ! 559: for (i = 0; i < entrytblsize; i++) { ! 560: if (entry[i] == NIL) ! 561: continue; ! 562: entry[i] = &baseep[(long)entry[i]]; ! 563: } ! 564: for (ep = &baseep[1]; ep < lep; ep++) { ! 565: ep->e_name = base + (long)ep->e_name; ! 566: ep->e_parent = &baseep[(long)ep->e_parent]; ! 567: if (ep->e_sibling != NIL) ! 568: ep->e_sibling = &baseep[(long)ep->e_sibling]; ! 569: if (ep->e_links != NIL) ! 570: ep->e_links = &baseep[(long)ep->e_links]; ! 571: if (ep->e_entries != NIL) ! 572: ep->e_entries = &baseep[(long)ep->e_entries]; ! 573: if (ep->e_next != NIL) ! 574: ep->e_next = &baseep[(long)ep->e_next]; ! 575: } ! 576: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.