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