#include #include #include #include #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; }