diff options
author | rsc <devnull@localhost> | 2005-01-04 21:22:40 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-01-04 21:22:40 +0000 |
commit | 46f79934b79ef526ed42bbe5a565e6b5d884d24a (patch) | |
tree | d1e663f7d3b2b328f03aeb34fdb3f4006aa97ec0 /src/lib9pclient/fs.c | |
parent | 5ba841dffa1f6cda712ebcff27c55c9d0a672c67 (diff) | |
download | plan9port-46f79934b79ef526ed42bbe5a565e6b5d884d24a.tar.gz plan9port-46f79934b79ef526ed42bbe5a565e6b5d884d24a.tar.bz2 plan9port-46f79934b79ef526ed42bbe5a565e6b5d884d24a.zip |
lib9pclient is the new libfs
Diffstat (limited to 'src/lib9pclient/fs.c')
-rw-r--r-- | src/lib9pclient/fs.c | 333 |
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; +} |