blob: c46adf21e82877b3c95176b611856bba830429d0 [file] [log] [blame]
#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;
}