Subversion Repositories planix.SVN

Rev

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

#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "dat.h"
#include "fns.h"


static Xfs      *xhead;
static Xfile *freelist;
static Lock     xlock, freelock;

int     client;

Xfs *
getxfs(char *name)
{
        int fd;
        Dir *dir;
        Xfs *xf, *fxf;

        if(name==0 || name[0]==0)
                name = deffile;
        if(name == 0){
                errno = Enofilsys;
                return 0;
        }
        fd = open(name, rdonly ? OREAD : ORDWR);
        if(fd < 0){
                errno = Enonexist;
                return 0;
        }
        if((dir = dirfstat(fd)) == 0){
                errno = Eio;
                close(fd);
                return 0;
        }
        lock(&xlock);
        for(fxf=0, xf=xhead; xf; xf=xf->next){
                if(xf->ref == 0){
                        if(fxf == 0)
                                fxf = xf;
                        continue;
                }
                if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
                        continue;
                if(strcmp(xf->name, name) != 0 || xf->dev < 0)
                        continue;
                chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
                ++xf->ref;
                unlock(&xlock);
                close(fd);
                free(dir);
                return xf;
        }
        if(fxf==0){
                fxf = malloc(sizeof(Xfs));
                if(fxf==0){
                        unlock(&xlock);
                        close(fd);
                        free(dir);
                        errno = Enomem;
                        return 0;
                }
                fxf->next = xhead;
                xhead = fxf;
        }
        chat("alloc \"%s\", dev=%d...", name, fd);
        fxf->name = strdup(name);
        fxf->ref = 1;
        fxf->qid = dir->qid;
        fxf->dev = fd;
        fxf->fmt = 0;
        fxf->ptr = 0;
        free(dir);
        if( ext2fs(fxf)<0 ){ 
                xhead = fxf->next;
                free(fxf);
                unlock(&xlock);
                return 0;
        }
        unlock(&xlock);
        return fxf;
}

void
refxfs(Xfs *xf, int delta)
{
        lock(&xlock);
        xf->ref += delta;
        if(xf->ref == 0){
                /*mchat("free \"%s\", dev=%d...", xf->name, xf->dev);
                dumpbuf();*/
                CleanSuper(xf);
                syncbuf();
                free(xf->name);
                purgebuf(xf);
                if(xf->dev >= 0){
                        close(xf->dev);
                        xf->dev = -1;
                }
        }
        unlock(&xlock);
}

Xfile *
xfile(Fid *fid, int flag)
{
        Xfile *f;

        f = (Xfile*)fid->aux;
        switch(flag){
        default:
                panic("xfile");
        case Asis:
                return (f && f->xf && f->xf->dev < 0) ? 0 : f;
        case Clean:
                if (f) chat("Clean and fid->aux already exists\n");
                break;
        case Clunk:
                if(f){
                        clean(f);
                        lock(&freelock);
                        f->next = freelist;
                        freelist = f;
                        unlock(&freelock);
                        fid->aux = 0;
                }
                return 0;
        }
        if(f)
                return clean(f);
        lock(&freelock);
        if(f = freelist){       /* assign = */
                freelist = f->next;
                unlock(&freelock);
        } else {
                unlock(&freelock);
                f = malloc(sizeof(Xfile));
        }
        fid->aux = f;
        f->fid = fid->fid;
        f->client = client;
        f->xf = 0;
        f->ptr = 0;
        f->root = 0;
        return f;
}
Xfile *
clean(Xfile *f)
{
        if(f->xf && f->root){
                refxfs(f->xf, -1);
                f->xf = 0;
        }
        f->xf = 0;
        f->root = 0;
        f->dirindex = 0;
        return f;
}