Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include "dat.h"
#include "fns.h"

static Xfile*   clean(Xfile*);

#define FIDMOD  127     /* prime */

static Xdata*   xhead;
static Xfile*   xfiles[FIDMOD];
static Xfile*   freelist;

Xdata*
getxdata(char *name)
{
        int fd;
        Dir *dir;
        Xdata *xf, *fxf;
        int flag;

        if(name[0] == 0)
                name = deffile;
        if(name == 0)
                error(Enofile);
        flag = (access(name, 6) == 0) ? ORDWR : OREAD;
        fd = open(name, flag);
        if(fd < 0)
                error(Enonexist);
        dir = nil;
        if(waserror()){
                close(fd);
                free(dir);
                nexterror();
        }
        if((dir = dirfstat(fd)) == nil)
                error("I/O error");
        if((dir->qid.type & ~QTTMP) != QTFILE)
                error("attach name not a plain file");
        for(fxf=0,xf=xhead; xf; xf=xf->next){
                if(xf->name == 0){
                        if(fxf == 0)
                                fxf = xf;
                        continue;
                }
                if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
                        continue;
                if(xf->type != dir->type || xf->fdev != dir->dev)
                        continue;
                xf->ref++;
                chat("incref=%d, \"%s\", dev=%d...", xf->ref, xf->name, xf->dev);
                close(fd);
                poperror();
                free(dir);
                return xf;
        }
        if(fxf==0){
                fxf = ealloc(sizeof(Xfs));
                fxf->next = xhead;
                xhead = fxf;
        }
        chat("alloc \"%s\", dev=%d...", name, fd);
        fxf->ref = 1;
        fxf->name = strcpy(ealloc(strlen(name)+1), name);
        fxf->qid = dir->qid;
        fxf->type = dir->type;
        fxf->fdev = dir->dev;
        fxf->dev = fd;
        free(dir);
        poperror();
        return fxf;
}

static void
putxdata(Xdata *d)
{
        if(d->ref <= 0)
                panic(0, "putxdata");
        d->ref--;
        chat("decref=%d, \"%s\", dev=%d...", d->ref, d->name, d->dev);
        if(d->ref == 0){
                chat("purgebuf...");
                purgebuf(d);
                close(d->dev);
                free(d->name);
                d->name = 0;
        }
}

void
refxfs(Xfs *xf, int delta)
{
        xf->ref += delta;
        if(xf->ref == 0){
                if(xf->d)
                        putxdata(xf->d);
                if(xf->ptr)
                        free(xf->ptr);
                free(xf);
        }
}

Xfile*
xfile(int fid, int flag)
{
        int k = fid%FIDMOD;
        Xfile **hp=&xfiles[k], *f, *pf;

        for(f=*hp,pf=0; f; pf=f,f=f->next)
                if(f->fid == fid)
                        break;
        if(f && pf){
                pf->next = f->next;
                f->next = *hp;
                *hp = f;
        }
        switch(flag){
        default:
                panic(0, "xfile");
        case Asis:
                if(f == 0)
                        error("unassigned fid");
                return f;
        case Clean:
                break;
        case Clunk:
                if(f){
                        *hp = f->next;
                        clean(f);
                        f->next = freelist;
                        freelist = f;
                }
                return 0;
        }
        if(f)
                return clean(f);
        if(f = freelist)        /* assign = */
                freelist = f->next;
        else
                f = ealloc(sizeof(Xfile));
        f->next = *hp;
        *hp = f;
        f->xf = 0;
        f->fid = fid;
        f->flags = 0;
        f->qid = (Qid){0,0,0};
        f->len = 0;
        f->ptr = 0;
        return f;
}

static Xfile *
clean(Xfile *f)
{
        if(f->xf){
                refxfs(f->xf, -1);
                f->xf = 0;
        }
        if(f->len){
                free(f->ptr);
                f->len = 0;
        }
        f->ptr = 0;
        f->flags = 0;
        f->qid = (Qid){0,0,0};
        return f;
}