Annotation of 43BSD/etc/restore/symtab.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.