Annotation of researchv10no/cmd/face/file.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * routines for creating and looking up internal files
                      3:  *
                      4:  * the internal file structure is a tree of Files.
                      5:  * terminal nodes are regular files;
                      6:  * their contents is in a real file outside.
                      7:  * other nodes are directories;
                      8:  * they exist only in our memory.
                      9:  *
                     10:  * directories are sorted lists;
                     11:  * files are looked up by binary search.
                     12:  */
                     13: 
                     14: #include "faces.h"
                     15: #include "faceproto.h" /* for FROOT */
                     16: #include <stdio.h>
                     17: #include <sys/types.h>
                     18: #include <sys/stat.h>
                     19: #include "dirent.h"    /* non-portable portable routines */
                     20: 
                     21: static File *root;
                     22: static int nextino;
                     23: 
                     24: #define        DIRINIT         10
                     25: #define        DIRCHUNK        100
                     26: 
                     27: /*
                     28:  * built-in directories
                     29:  * every outside data file must be in one of these
                     30:  */
                     31: 
                     32: struct builtin {
                     33:        char *ourname;
                     34:        char *extname;
                     35:        File *file;
                     36:        time_t mtime;
                     37: } builtins[] = {
                     38:        {"48x48x1",     "/usr/jerq/icon/face48"},
                     39:        {"48x48x2",     "/usr/jerq/icon/48x48x2"},
                     40:        {"512x512x8",   "/t0/face/512x512x8"},
                     41:        0
                     42: };
                     43: 
                     44: static time_t ptime, mtime;
                     45: 
                     46: extern char *strchr();
                     47: extern File *falloc();
                     48: 
                     49: /*
                     50:  * remake the face tree
                     51:  */
                     52: 
                     53: maketree(pfile, mfile)
                     54: char *pfile, *mfile;
                     55: {
                     56:        File *df, *f;
                     57:        FILE *fp;
                     58:        char *dir, *pers, *ref;
                     59:        register struct builtin *bp;
                     60: 
                     61:        (void)newdata(pfile, mfile);    /* store times */
                     62:        if (root == NULL) {
                     63:                nextino = FROOT;
                     64:                root = newfile();
                     65:        } else {
                     66:                nextino = FROOT + 1;
                     67:                freetree(root);
                     68:        }
                     69:        initdir(root, root);
                     70:        for (bp = builtins; bp->ourname; bp++) {
                     71:                f = newfile();
                     72:                initdir(f, root);
                     73:                filldir(f, bp->extname);
                     74:                enterfile(root, bp->ourname, f);
                     75:                bp->file = f;
                     76:        }
                     77:        if ((fp = fopen(pfile, "r")) == NULL)
                     78:                log("%s: cannot open; no people\n", pfile);
                     79:        else {
                     80:                while (pcrack(fp, pfile, &dir, &pers, &ref)) {
                     81:                        if ((df = lookent(root, dir)) == NULL) {
                     82:                                df = newfile();
                     83:                                initdir(df, root);
                     84:                                enterfile(root, dir, df);
                     85:                        }
                     86:                        f = newfile();  /* make dir/pers */
                     87:                        if (enterfile(df, pers, f)) {
                     88:                                log("%s: %s/%s=%s: dup for %s/%s\n",
                     89:                                        pfile, dir, pers, ref, dir, pers);
                     90:                                ffree(f);
                     91:                                continue;
                     92:                        }
                     93:                        initdir(f, df);
                     94:                        for (bp = builtins; bp->ourname; bp++)
                     95:                                if ((df = lookent(bp->file, ref)) != NULL)
                     96:                                        enterfile(f, bp->ourname, df);
                     97:                }
                     98:                fclose(fp);
                     99:        }
                    100:        if ((fp = fopen(mfile, "r")) == NULL)
                    101:                log("%s: cannot open; no machines\n", mfile);
                    102:        else {
                    103:                while (pcrack(fp, mfile, &dir, (char **)NULL, &ref)) {
                    104:                        if ((df = lookent(root, ref)) == NULL) {
                    105:                                log("%s: %s=%s: %s not found\n",
                    106:                                        mfile, dir, ref, ref);
                    107:                                continue;
                    108:                        }
                    109:                        if ((f = enterfile(root, dir, df)) != NULL) {
                    110:                                if (f == df) {
                    111:                                        log("%s: %s=%s: already true\n",
                    112:                                                mfile, dir, ref);
                    113:                                        continue;
                    114:                                }
                    115:                                uniondir(df, f, mfile, dir, ref);
                    116:                        }
                    117:                }
                    118:                fclose(fp);
                    119:        }
                    120: }
                    121: 
                    122: /*
                    123:  * parse a line in people file or machine file
                    124:  * fairly hackish
                    125:  * people file: dir/person=realfile
                    126:  * machine file: machdir=dir
                    127:  * return 1 if a valid entry found,
                    128:  * 0 if end of file
                    129:  */
                    130: 
                    131: pcrack(fp, fname, dirp, persp, refp)
                    132: FILE *fp;
                    133: char *fname;
                    134: char **dirp, **persp, **refp;
                    135: {
                    136:        static char buf[100];
                    137:        register char *p;
                    138: 
                    139: again:
                    140:        buf[sizeof(buf)-1] = 0;
                    141:        if (fgets(buf, sizeof(buf), fp) == NULL)
                    142:                return (0);             /* EOF */
                    143:        if (buf[sizeof(buf)-1]) {
                    144:                buf[sizeof(buf)-1] = 0;
                    145:                log("%s: line too long: %s ...\n", fname, buf);
                    146:                return (0);             /* too hard to recover for now */
                    147:        }
                    148:        if (buf[0] == '#' || buf[0] == '\n')
                    149:                goto again;     /* skip comments, empties */
                    150:        p = buf;
                    151:        *dirp = p;
                    152:        if (persp) {
                    153:                if ((p = strchr(p, '/')) == NULL) {
                    154:                        log("%s: missing /: %s", fname, buf);
                    155:                        goto again;
                    156:                }
                    157:                *p++ = 0;
                    158:                *persp = p;
                    159:        }
                    160:        if ((p = strchr(p, '=')) == NULL) {
                    161:                if (persp)
                    162:                        (*persp)[-1] = '/';     /* hack */
                    163:                log("%s: missing =: %s", fname, buf);
                    164:                goto again;
                    165:        }
                    166:        *p++ = 0;
                    167:        *refp = p;
                    168:        if ((p = strchr(p, '\n')) != NULL)      /* fgets should promise this */
                    169:                *p = 0;
                    170:        return (1);
                    171: }
                    172: 
                    173: /*
                    174:  * see if the outside data has changed,
                    175:  * and we should rebuild the tree
                    176:  */
                    177: 
                    178: newdata(pfile, mfile)
                    179: char *pfile, *mfile;
                    180: {
                    181:        struct stat st;
                    182:        int new;
                    183:        register struct builtin *bp;
                    184: 
                    185:        new = 0;
                    186:        for (bp = builtins; bp->ourname; bp++) {
                    187:                if (stat(bp->extname, &st) < 0)
                    188:                        continue;
                    189:                if (bp->mtime == 0)
                    190:                        bp->mtime = st.st_mtime;
                    191:                if (bp->mtime < st.st_mtime) {
                    192:                        bp->mtime = st.st_mtime;
                    193:                        new = 1;
                    194:                }
                    195:        }
                    196:        if (stat(pfile, &st) >= 0) {
                    197:                if (ptime == 0)
                    198:                        ptime = st.st_mtime;
                    199:                if (ptime < st.st_mtime) {
                    200:                        ptime = st.st_mtime;
                    201:                        new = 1;
                    202:                }
                    203:        }
                    204:        if (stat(mfile, &st) >= 0) {
                    205:                if (mtime == 0)
                    206:                        mtime = st.st_mtime;
                    207:                if (mtime < st.st_mtime) {
                    208:                        mtime = st.st_mtime;
                    209:                        new = 1;
                    210:                }
                    211:        }
                    212:        return (new);
                    213: }
                    214: 
                    215: /*
                    216:  * free a sub-tree
                    217:  */
                    218: freetree(f)
                    219: register File *f;
                    220: {
                    221:        register int i;
                    222:        register File *nf;
                    223: 
                    224:        if (!isdir(f))
                    225:                return;
                    226:        for (i = 0; i < f->nfiles; i++) {
                    227:                nf = f->dir[i].file;
                    228:                if (nf == f                             /* probably "." */
                    229:                ||  strcmp(f->dir[i].name, "..") == 0) {
                    230:                        nf->nlinks--;
                    231:                        continue;
                    232:                }
                    233:                if (isdir(nf))
                    234:                        freetree(nf);
                    235:                if (--nf->nlinks > 0)
                    236:                        continue;
                    237:                if (nf->data)
                    238:                        free(nf->data);
                    239:                if (nf->dir)
                    240:                        free((char *)nf->dir);
                    241:                ffree(nf);
                    242:        }
                    243:        if (f->data)
                    244:                free(f->data);
                    245:        f->data = NULL;
                    246:        f->nfiles = 0;          /* (but still allocated) */
                    247: }
                    248: 
                    249: /*
                    250:  * make a new file
                    251:  */
                    252: 
                    253: File *
                    254: newfile()
                    255: {
                    256:        register File *f;
                    257: 
                    258:        f = falloc();
                    259:        f->nlinks = 0;          /* no entries yet */
                    260:        f->ino = nextino++;
                    261:        f->data = NULL;
                    262:        f->dir = NULL;
                    263:        return (f);
                    264: }
                    265: 
                    266: /*
                    267:  * init a directory:
                    268:  * set up . and ..
                    269:  */
                    270: 
                    271: initdir(f, parent)
                    272: register File *f;
                    273: File *parent;
                    274: {
                    275:        extern long time();
                    276: 
                    277:        if (f->dir == NULL) {
                    278:                f->dir = (Dirent *)emalloc(DIRINIT*sizeof(Dirent));
                    279:                f->nalloc = DIRINIT;
                    280:        } else if (f->nalloc < 2)
                    281:                panic("init badly formed dir\n");
                    282:        if (f->data) {
                    283:                free(f->data);
                    284:                f->data = NULL;
                    285:        }
                    286:        f->nfiles = 2;
                    287:        strcpy(f->dir[0].name, ".");
                    288:        f->dir[0].file = f;
                    289:        f->nlinks++;
                    290:        strcpy(f->dir[1].name, "..");
                    291:        f->dir[1].file = parent;
                    292:        parent->nlinks++;
                    293:        f->tc = time((long *)0);
                    294:        f->ta = f->tc;
                    295:        f->tm = f->tc;
                    296: }
                    297: 
                    298: /*
                    299:  * look up an entry in a directory
                    300:  */
                    301: 
                    302: File *
                    303: lookent(f, name)
                    304: File *f;
                    305: register char *name;
                    306: {
                    307:        register Dirent *d;
                    308:        register int i, cmp, u, l;
                    309: 
                    310:        if (!isdir(f))
                    311:                return (NULL);
                    312:        d = f->dir;
                    313:        u = f->nfiles;  /* first entry known to be too big */
                    314:        l = 0;          /* first entry known to be big enough */
                    315:        while (u > l) {
                    316:                i = (u + l)/2;
                    317:                if ((cmp = name[0] - d[i].name[0]) == 0
                    318:                &&  (cmp = strcmp(name, d[i].name)) == 0)
                    319:                        return (d[i].file);
                    320:                else if (cmp < 0)
                    321:                        u = i;
                    322:                else
                    323:                        l = i + 1;
                    324:        }
                    325:        return (NULL);
                    326: }
                    327: 
                    328: /*
                    329:  * enter newf in f with the given name
                    330:  * if it is a new entry, return NULL
                    331:  * if f already had name, return the old one, leave it in place
                    332:  */
                    333: 
                    334: File *
                    335: enterfile(f, name, newf)
                    336: File *f;
                    337: register char *name;
                    338: File *newf;
                    339: {
                    340:        register Dirent *d;
                    341:        register int i, cmp, u, l;
                    342: 
                    343:        if (!isdir(f))
                    344:                panic("enter non-dir\n");
                    345:        if (f->nalloc <= f->nfiles) {   /* need more room */
                    346:                f->nalloc += DIRCHUNK;
                    347:                f->dir = (Dirent *)erealloc((char *)f->dir, f->nalloc*sizeof(Dirent));
                    348:        }
                    349:        d = f->dir;
                    350:        u = f->nfiles;  /* first entry known to be too big */
                    351:        l = 0;          /* first entry known to be big enough */
                    352:        while (u > l) {
                    353:                i = (u + l)/2;
                    354:                if ((cmp = name[0] - d[i].name[0]) == 0
                    355:                &&  (cmp = strcmp(name, d[i].name)) == 0)
                    356:                        return (d[i].file);     /* unexpected */
                    357:                else if (cmp < 0)
                    358:                        u = i;
                    359:                else
                    360:                        l = i + 1;
                    361:        }
                    362:        /*
                    363:         * not found; d[u] is too big
                    364:         * insert before d[u]
                    365:         */
                    366:        for (i = f->nfiles; i > u; i--)
                    367:                d[i] = d[i-1];
                    368:        strncpy(d[i].name, name, DIRNSIZE);
                    369:        d[i].file = newf;
                    370:        f->nfiles++;
                    371:        newf->nlinks++;
                    372:        if (f->data) {          /* invalid now */
                    373:                free(f->data);
                    374:                f->data = NULL;
                    375:        }
                    376:        return (NULL);
                    377: }
                    378: 
                    379: /*
                    380:  * look up a full pathname
                    381:  */
                    382: 
                    383: File *
                    384: lookfile(path)
                    385: register char *path;
                    386: {
                    387:        File *f;
                    388:        register char *sl;
                    389: 
                    390:        f = root;
                    391:        for (;;) {
                    392:                while (*path == '/')
                    393:                        path++;
                    394:                if (*path == 0)
                    395:                        return (f);
                    396:                if ((sl = strchr(path, '/')) != NULL)
                    397:                        *sl = 0;                /* cheap hack */
                    398:                f = lookent(f, path);
                    399:                if (sl)
                    400:                        *sl = '/';              /* cheap hack returns */
                    401:                if (f == NULL)
                    402:                        return (NULL);
                    403:                if (sl == NULL)
                    404:                        return (f);     /* no more slashes, so we're done */
                    405:                path = sl + 1;
                    406:        }
                    407: }
                    408: 
                    409: /*
                    410:  * link each entry from f to uf,
                    411:  * fussing about duplicates
                    412:  * --the string arguments are just for the log message
                    413:  */
                    414: 
                    415: uniondir(f, uf, mfile, dir, ref)
                    416: File *f, *uf;
                    417: char *mfile, *dir, *ref;
                    418: {
                    419:        register int i;
                    420:        register Dirent *dp;
                    421:        register File *ef;
                    422: 
                    423:        dp = f->dir;
                    424:        for (i = 0; i < f->nfiles; dp++, i++) {
                    425:                if (dp->name[0] == '.'
                    426:                &&  (strcmp(dp->name, ".") == 0 || strcmp(dp->name, "..") == 0))
                    427:                        continue;
                    428:                if ((ef = enterfile(uf, dp->name, dp->file)) != NULL
                    429:                &&  ef != dp->file)             /* same file already there */
                    430:                        log("%s: %s=%s: file %s duplicate\n",
                    431:                                mfile, dir, ref, dp->name);
                    432:        }
                    433: }
                    434: 
                    435: /*
                    436:  * copy directory entries from the outside
                    437:  * to one of ours
                    438:  * save many calls to enterfile, and many searches
                    439:  * for files that don't exist, by building the directory
                    440:  * here and sorting it
                    441:  */
                    442: 
                    443: static int
                    444: dircmp(a, b)
                    445: char *a, *b;
                    446: {
                    447:        return (strncmp(((Dirent *)a)->name, ((Dirent *)b)->name, DIRNSIZE));
                    448: }
                    449: 
                    450: filldir(f, realdir)
                    451: register File *f;
                    452: char *realdir;
                    453: {
                    454:        DIR *fp;
                    455:        register struct dirent *dp;
                    456:        register Dirent *idp;
                    457:        File *nf;
                    458:        int rdlen;
                    459: 
                    460:        if ((fp = opendir(realdir)) == NULL) {
                    461:                log("%s: can't opendir\n", realdir);
                    462:                return;
                    463:        }
                    464:        rdlen = strlen(realdir);
                    465:        idp = &f->dir[f->nfiles];
                    466:        while ((dp = readdir(fp)) != NULL) {
                    467:                if (dp->d_name[0] == '.'
                    468:                &&  (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0))
                    469:                        continue;
                    470:                nf = newfile();
                    471:                if (f->nalloc <= f->nfiles) {
                    472:                        f->nalloc += DIRCHUNK;
                    473:                        f->dir = (Dirent *)erealloc((char *)f->dir, f->nalloc*sizeof(Dirent));
                    474:                        idp = &f->dir[f->nfiles];       /* realloc may move it */
                    475:                }
                    476:                strncpy(idp->name, dp->d_name, DIRNSIZE);
                    477:                idp->file = nf;
                    478:                idp++;
                    479:                f->nfiles++;
                    480:                nf->nlinks++;
                    481:                nf->data = emalloc(rdlen+1+strlen(dp->d_name)+1);
                    482:                strcpy(nf->data, realdir);
                    483:                nf->data[rdlen] = '/';
                    484:                strcpy(nf->data+rdlen+1, dp->d_name);
                    485:        }
                    486:        closedir(fp);
                    487:        qsort((char *)f->dir, f->nfiles, sizeof(Dirent), dircmp);
                    488: }
                    489: 
                    490: /*
                    491:  * set up directory data to be sent to client
                    492:  */
                    493: dirdata(f)
                    494: register File *f;
                    495: {
                    496:        register int i;
                    497:        register unsigned char *p;
                    498: 
                    499:        if (!isdir(f))
                    500:                panic("dirdata not dir\n");
                    501:        f->size = f->nfiles * FDLEN;
                    502:        f->data = emalloc((int)f->size);
                    503:        p = (unsigned char *)f->data;
                    504:        for (i = 0; i < f->nfiles; i++) {
                    505:                tofshort(p, FD_INO, f->dir[i].file->ino);
                    506:                strncpy(p + FD_NAME, f->dir[i].name, FDLEN - FD_NAME);
                    507:                p += FDLEN;
                    508:        }
                    509: }
                    510: 
                    511: /*
                    512:  * manage storage for Files;
                    513:  * cheap hack for speed, to cut malloc calls
                    514:  * keep a free list of Files, linked on f->data
                    515:  */
                    516: 
                    517: static File *fflist;
                    518: #define        FILECHUNK       100
                    519: 
                    520: File *
                    521: falloc()
                    522: {
                    523:        register File *f;
                    524:        register int i;
                    525: 
                    526:        if ((f = fflist) != NULL) {
                    527:                fflist = (File *)f->data;
                    528:                return (f);
                    529:        }
                    530:        f = (File *)emalloc(FILECHUNK*sizeof(File));
                    531:        for (i = 0; i < FILECHUNK-1; f++, i++) {
                    532:                f->data = (char *)fflist;
                    533:                fflist = f;
                    534:        }
                    535:        return (f);
                    536: }
                    537: 
                    538: ffree(f)
                    539: File *f;
                    540: {
                    541:        f->data = (char *)fflist;
                    542:        fflist = f;
                    543: }

unix.superglobalmegacorp.com

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