Annotation of researchv10dc/cmd/face/file.c, revision 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.