aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/9660srv/xfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/9660srv/xfile.c')
-rw-r--r--src/cmd/9660srv/xfile.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/cmd/9660srv/xfile.c b/src/cmd/9660srv/xfile.c
new file mode 100644
index 00000000..c46adf21
--- /dev/null
+++ b/src/cmd/9660srv/xfile.c
@@ -0,0 +1,170 @@
+#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;
+}
+