summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ext2srv/xfile.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ext2srv/xfile.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ext2srv/xfile.c')
-rwxr-xr-xsys/src/cmd/ext2srv/xfile.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/sys/src/cmd/ext2srv/xfile.c b/sys/src/cmd/ext2srv/xfile.c
new file mode 100755
index 000000000..2950398a1
--- /dev/null
+++ b/sys/src/cmd/ext2srv/xfile.c
@@ -0,0 +1,161 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "dat.h"
+#include "fns.h"
+
+
+static Xfs *xhead;
+static Xfile *freelist;
+static Lock xlock, freelock;
+
+int client;
+
+Xfs *
+getxfs(char *name)
+{
+ int fd;
+ Dir *dir;
+ Xfs *xf, *fxf;
+
+ if(name==0 || name[0]==0)
+ name = deffile;
+ if(name == 0){
+ errno = Enofilsys;
+ return 0;
+ }
+ fd = open(name, rdonly ? OREAD : ORDWR);
+ if(fd < 0){
+ errno = Enonexist;
+ return 0;
+ }
+ if((dir = dirfstat(fd)) == 0){
+ errno = Eio;
+ close(fd);
+ return 0;
+ }
+ lock(&xlock);
+ for(fxf=0, xf=xhead; xf; xf=xf->next){
+ if(xf->ref == 0){
+ if(fxf == 0)
+ fxf = xf;
+ continue;
+ }
+ if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
+ continue;
+ if(strcmp(xf->name, name) != 0 || xf->dev < 0)
+ continue;
+ chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
+ ++xf->ref;
+ unlock(&xlock);
+ close(fd);
+ free(dir);
+ return xf;
+ }
+ if(fxf==0){
+ fxf = malloc(sizeof(Xfs));
+ if(fxf==0){
+ unlock(&xlock);
+ close(fd);
+ free(dir);
+ errno = Enomem;
+ return 0;
+ }
+ fxf->next = xhead;
+ xhead = fxf;
+ }
+ chat("alloc \"%s\", dev=%d...", name, fd);
+ fxf->name = strdup(name);
+ fxf->ref = 1;
+ fxf->qid = dir->qid;
+ fxf->dev = fd;
+ fxf->fmt = 0;
+ fxf->ptr = 0;
+ free(dir);
+ if( ext2fs(fxf)<0 ){
+ xhead = fxf->next;
+ free(fxf);
+ unlock(&xlock);
+ return 0;
+ }
+ unlock(&xlock);
+ return fxf;
+}
+
+void
+refxfs(Xfs *xf, int delta)
+{
+ lock(&xlock);
+ xf->ref += delta;
+ if(xf->ref == 0){
+ /*mchat("free \"%s\", dev=%d...", xf->name, xf->dev);
+ dumpbuf();*/
+ CleanSuper(xf);
+ syncbuf();
+ free(xf->name);
+ purgebuf(xf);
+ if(xf->dev >= 0){
+ close(xf->dev);
+ xf->dev = -1;
+ }
+ }
+ unlock(&xlock);
+}
+
+Xfile *
+xfile(Fid *fid, int flag)
+{
+ Xfile *f;
+
+ f = (Xfile*)fid->aux;
+ switch(flag){
+ default:
+ panic("xfile");
+ case Asis:
+ return (f && f->xf && f->xf->dev < 0) ? 0 : f;
+ case Clean:
+ if (f) chat("Clean and fid->aux already exists\n");
+ break;
+ case Clunk:
+ if(f){
+ clean(f);
+ lock(&freelock);
+ f->next = freelist;
+ freelist = f;
+ unlock(&freelock);
+ fid->aux = 0;
+ }
+ return 0;
+ }
+ if(f)
+ return clean(f);
+ lock(&freelock);
+ if(f = freelist){ /* assign = */
+ freelist = f->next;
+ unlock(&freelock);
+ } else {
+ unlock(&freelock);
+ f = malloc(sizeof(Xfile));
+ }
+ fid->aux = f;
+ f->fid = fid->fid;
+ f->client = client;
+ f->xf = 0;
+ f->ptr = 0;
+ f->root = 0;
+ return f;
+}
+Xfile *
+clean(Xfile *f)
+{
+ if(f->xf && f->root){
+ refxfs(f->xf, -1);
+ f->xf = 0;
+ }
+ f->xf = 0;
+ f->root = 0;
+ f->dirindex = 0;
+ return f;
+}