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