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