aboutsummaryrefslogtreecommitdiff
path: root/src/lib9pclient/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib9pclient/fs.c')
-rw-r--r--src/lib9pclient/fs.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/lib9pclient/fs.c b/src/lib9pclient/fs.c
new file mode 100644
index 00000000..d72aa4c7
--- /dev/null
+++ b/src/lib9pclient/fs.c
@@ -0,0 +1,333 @@
+/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
+/* See COPYRIGHT */
+
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <9pclient.h>
+#include <thread.h>
+#include "fsimpl.h"
+
+static int _fssend(Mux*, void*);
+static void *_fsrecv(Mux*);
+static int _fsgettag(Mux*, void*);
+static int _fssettag(Mux*, void*, uint);
+
+enum
+{
+ CFidchunk = 32
+};
+
+CFsys*
+fsinit(int fd)
+{
+ CFsys *fs;
+
+ fmtinstall('F', fcallfmt);
+ fmtinstall('D', dirfmt);
+ fmtinstall('M', dirmodefmt);
+
+ fs = mallocz(sizeof(CFsys), 1);
+ if(fs == nil)
+ return nil;
+ fs->fd = fd;
+ fs->ref = 1;
+ fs->mux.aux = fs;
+ fs->mux.mintag = 0;
+ fs->mux.maxtag = 256;
+ fs->mux.send = _fssend;
+ fs->mux.recv = _fsrecv;
+ fs->mux.gettag = _fsgettag;
+ fs->mux.settag = _fssettag;
+ fs->iorecv = ioproc();
+ fs->iosend = ioproc();
+ muxinit(&fs->mux);
+ return fs;
+}
+
+CFid*
+fsroot(CFsys *fs)
+{
+ /* N.B. no incref */
+ return fs->root;
+}
+
+CFsys*
+fsmount(int fd, char *aname)
+{
+ int n;
+ char *user;
+ CFsys *fs;
+ CFid *fid;
+
+ fs = fsinit(fd);
+ if(fs == nil)
+ return nil;
+ strcpy(fs->version, "9P2000");
+ if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
+ Error:
+ fs->fd = -1;
+ fsunmount(fs);
+ return nil;
+ }
+ fs->msize = n;
+
+ user = getuser();
+ if((fid = fsattach(fs, nil, getuser(), aname)) == nil)
+ goto Error;
+ fssetroot(fs, fid);
+ return fs;
+}
+
+void
+fsunmount(CFsys *fs)
+{
+ fsclose(fs->root);
+ fs->root = nil;
+ _fsdecref(fs);
+}
+
+void
+_fsdecref(CFsys *fs)
+{
+ CFid *f, **l, *next;
+
+ qlock(&fs->lk);
+ --fs->ref;
+ //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);
+ if(fs->ref == 0){
+ close(fs->fd);
+ /* trim the list down to just the first in each chunk */
+ for(l=&fs->freefid; *l; ){
+ if((*l)->fid%CFidchunk == 0)
+ l = &(*l)->next;
+ else
+ *l = (*l)->next;
+ }
+ /* now free the list */
+ for(f=fs->freefid; f; f=next){
+ next = f->next;
+ free(f);
+ }
+ closeioproc(fs->iorecv);
+ closeioproc(fs->iosend);
+ free(fs);
+ return;
+ }
+ qunlock(&fs->lk);
+}
+
+int
+fsversion(CFsys *fs, int msize, char *version, int nversion)
+{
+ void *freep;
+ int r, oldmintag, oldmaxtag;
+ Fcall tx, rx;
+
+ tx.tag = 0;
+ tx.type = Tversion;
+ tx.version = version;
+ tx.msize = msize;
+
+ /*
+ * bit of a clumsy hack -- force libmux to use NOTAG as tag.
+ * version can only be sent when there are no other messages
+ * outstanding on the wire, so this is more reasonable than it looks.
+ */
+ oldmintag = fs->mux.mintag;
+ oldmaxtag = fs->mux.maxtag;
+ fs->mux.mintag = NOTAG;
+ fs->mux.maxtag = NOTAG+1;
+ r = _fsrpc(fs, &tx, &rx, &freep);
+ fs->mux.mintag = oldmintag;
+ fs->mux.maxtag = oldmaxtag;
+ if(r < 0)
+ return -1;
+
+ strecpy(version, version+nversion, rx.version);
+ free(freep);
+ return rx.msize;
+}
+
+CFid*
+fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
+{
+ Fcall tx, rx;
+ CFid *fid;
+
+ if(aname == nil)
+ aname = "";
+
+ if((fid = _fsgetfid(fs)) == nil)
+ return nil;
+
+ tx.tag = 0;
+ tx.type = Tattach;
+ tx.afid = afid ? afid->fid : NOFID;
+ tx.fid = fid->fid;
+ tx.uname = user;
+ tx.aname = aname;
+
+ if(_fsrpc(fs, &tx, &rx, 0) < 0){
+ _fsputfid(fid);
+ return nil;
+ }
+ fid->qid = rx.qid;
+ return fid;
+}
+
+void
+fssetroot(CFsys *fs, CFid *fid)
+{
+ if(fs->root)
+ _fsputfid(fs->root);
+ fs->root = fid;
+}
+
+int
+_fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
+{
+ int n, nn;
+ void *tpkt, *rpkt;
+
+ n = sizeS2M(tx);
+ tpkt = malloc(n);
+ if(freep)
+ *freep = nil;
+ if(tpkt == nil)
+ return -1;
+ //fprint(2, "<- %F\n", tx);
+ nn = convS2M(tx, tpkt, n);
+ if(nn != n){
+ free(tpkt);
+ werrstr("libfs: sizeS2M convS2M mismatch");
+ fprint(2, "%r\n");
+ return -1;
+ }
+ rpkt = muxrpc(&fs->mux, tpkt);
+ free(tpkt);
+ if(rpkt == nil)
+ return -1;
+ n = GBIT32((uchar*)rpkt);
+ nn = convM2S(rpkt, n, rx);
+ if(nn != n){
+ free(rpkt);
+ werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);
+ fprint(2, "%r\n");
+ return -1;
+ }
+ //fprint(2, "-> %F\n", rx);
+ if(rx->type == Rerror){
+ werrstr("%s", rx->ename);
+ free(rpkt);
+ return -1;
+ }
+ if(rx->type != tx->type+1){
+ werrstr("packet type mismatch -- tx %d rx %d",
+ tx->type, rx->type);
+ free(rpkt);
+ return -1;
+ }
+ if(freep)
+ *freep = rpkt;
+ else
+ free(rpkt);
+ return 0;
+}
+
+CFid*
+_fsgetfid(CFsys *fs)
+{
+ int i;
+ CFid *f;
+
+ qlock(&fs->lk);
+ if(fs->freefid == nil){
+ f = mallocz(sizeof(CFid)*CFidchunk, 1);
+ if(f == nil){
+ qunlock(&fs->lk);
+ return nil;
+ }
+ for(i=0; i<CFidchunk; i++){
+ f[i].fid = fs->nextfid++;
+ f[i].next = &f[i+1];
+ f[i].fs = fs;
+ }
+ f[i-1].next = nil;
+ fs->freefid = f;
+ }
+ f = fs->freefid;
+ fs->freefid = f->next;
+ fs->ref++;
+ qunlock(&fs->lk);
+ return f;
+}
+
+void
+_fsputfid(CFid *f)
+{
+ CFsys *fs;
+
+ fs = f->fs;
+ qlock(&fs->lk);
+ f->next = fs->freefid;
+ fs->freefid = f;
+ qunlock(&fs->lk);
+ _fsdecref(fs);
+}
+
+static int
+_fsgettag(Mux *mux, void *pkt)
+{
+ return GBIT16((uchar*)pkt+5);
+}
+
+static int
+_fssettag(Mux *mux, void *pkt, uint tag)
+{
+ PBIT16((uchar*)pkt+5, tag);
+ return 0;
+}
+
+static int
+_fssend(Mux *mux, void *pkt)
+{
+ CFsys *fs;
+
+ fs = mux->aux;
+ return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));
+}
+
+static void*
+_fsrecv(Mux *mux)
+{
+ uchar *pkt;
+ uchar buf[4];
+ int n, nfd;
+ CFsys *fs;
+
+ fs = mux->aux;
+ n = ioreadn(fs->iorecv, fs->fd, buf, 4);
+ if(n != 4)
+ return nil;
+ n = GBIT32(buf);
+ pkt = malloc(n+4);
+ if(pkt == nil){
+ fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");
+ return nil;
+ }
+ PBIT32(pkt, n);
+ if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
+ free(pkt);
+ return nil;
+ }
+ if(pkt[4] == Ropenfd){
+ if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
+ fprint(2, "recv fd error: %r\n");
+ free(pkt);
+ return nil;
+ }
+ PBIT32(pkt+n-4, nfd);
+ }
+ return pkt;
+}