commit d3df308747ee4d1fcc063a348dcf1146b390bda7 from: rsc date: Sat Dec 06 18:08:52 2003 UTC File system stuff. commit - e97ceade5e1bba5787e39429384336fa37797906 commit + d3df308747ee4d1fcc063a348dcf1146b390bda7 blob - /dev/null blob + 219b2774a5a98dbd58e8e9b4ee871215fec510fa (mode 644) --- /dev/null +++ include/fs.h @@ -0,0 +1,41 @@ +#ifndef _FS_H_ +#define _FS_H_ 1 +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Simple user-level 9P client. + */ + +typedef struct Fsys Fsys; +typedef struct Fid Fid; + +Fsys *fsinit(int); +Fsys *fsmount(int); + +int fsversion(Fsys*, int, char*, int); +Fid *fsauth(Fsys*, char*); +Fid *fsattach(Fsys*, Fid*, char*, char*); +Fid *fsopen(Fsys*, char*, int); +int fsopenfd(Fsys*, char*, int); +long fsread(Fid*, void*, long); +long fsreadn(Fid*, void*, long); +long fswrite(Fid*, void*, long); +void fsclose(Fid*); +void fsunmount(Fsys*); +int fsrpc(Fsys*, Fcall*, Fcall*, void**); +Fid *fswalk(Fid*, char*); +struct Dir; /* in case there's no lib9.h */ +long fsdirread(Fid*, struct Dir**); +long fsdirreadall(Fid*, struct Dir**); +struct Dir *fsdirstat(Fsys*, char*); +struct Dir *fsdirfstat(Fid*); +int fsdirwstat(Fsys*, char*, struct Dir*); +int fsdirfwstat(Fid*, struct Dir*); +Fid *fsroot(Fsys*); + +#ifdef __cplusplus +} +#endif +#endif blob - /dev/null blob + c43ce797a7cf70932f07e59d547e60dd37d6b299 (mode 644) --- /dev/null +++ include/mux.h @@ -0,0 +1,54 @@ +typedef struct Mux Mux; +typedef struct Muxrpc Muxrpc; +typedef struct Muxqueue Muxqueue; + +struct Muxrpc +{ + Muxrpc *next; + Muxrpc *prev; + Rendez r; + uint tag; + void *p; +}; + +struct Mux +{ + uint mintag; /* to be filled by client */ + uint maxtag; + int (*send)(Mux*, void*); + void *(*recv)(Mux*); + int (*gettag)(Mux*, void*); + int (*settag)(Mux*, void*, uint); + void *aux; /* for private use by client */ + +/* private */ + QLock lk; + QLock inlk; + QLock outlk; + Rendez tagrend; + Rendez rpcfork; + Muxqueue *readq; + Muxqueue *writeq; + uint nwait; + uint mwait; + uint freetag; + Muxrpc **wait; + uint muxer; + Muxrpc sleep; +}; + +void muxinit(Mux*); +void* muxrpc(Mux*, void*); +void muxthreads(Mux*); + +/* private */ +int _muxsend(Mux*, void*); +void* _muxrecv(Mux*); +void _muxsendproc(void*); +void _muxrecvproc(void*); +Muxqueue *_muxqalloc(void); +int _muxqsend(Muxqueue*, void*); +void *_muxqrecv(Muxqueue*); +void _muxqhangup(Muxqueue*); +void *_muxnbqrecv(Muxqueue*); + blob - /dev/null blob + 7c018c34b542cbfe666ab884688d000234dd6040 (mode 644) --- /dev/null +++ src/cmd/9p.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include + +char *addr; + +void +usage(void) +{ + fprint(2, "usage: 9p [-a address] cmd args...\n"); + fprint(2, "possible cmds:\n"); + fprint(2, " read name\n"); + fprint(2, " write name\n"); + fprint(2, " stat name\n"); +// fprint(2, " ls name\n"); + fprint(2, "without -a, name elem/path means /path on server unix!$ns/elem\n"); + exits("usage"); +} + +void xread(int, char**); +void xwrite(int, char**); +void xstat(int, char**); +void xls(int, char**); + +struct { + char *s; + void (*f)(int, char**); +} cmds[] = { + "read", xread, + "write", xwrite, + "stat", xstat, +// "ls", xls, +}; + +void +main(int argc, char **argv) +{ + char *cmd; + int i; + + ARGBEGIN{ + case 'a': + addr = EARGF(usage()); + break; + default: + usage(); + }ARGEND + + if(argc < 1) + usage(); + + cmd = argv[0]; + for(i=0; i 0) + write(1, buf, n); + if(n < 0) + sysfatal("read error: %r"); + exits(0); +} + +void +xwrite(int argc, char **argv) +{ + char buf[1024]; + int n; + Fid *fid; + + ARGBEGIN{ + default: + usage(); + }ARGEND + + if(argc != 1) + usage(); + + fid = xopen(argv[0], OWRITE|OTRUNC); + while((n = read(0, buf, sizeof buf)) > 0) + if(fswrite(fid, buf, n) != n) + sysfatal("write error: %r"); + if(n < 0) + sysfatal("read error: %r"); + exits(0); +} + +void +xstat(int argc, char **argv) +{ + Dir *d; + Fid *fid; + + ARGBEGIN{ + default: + usage(); + }ARGEND + + if(argc != 1) + usage(); + + fid = xwalk(argv[0]); + if((d = fsdirfstat(fid)) < 0) + sysfatal("dirfstat: %r"); + fmtinstall('D', dirfmt); + fmtinstall('M', dirmodefmt); + print("%D\n", d); + exits(0); +} blob - /dev/null blob + 40db17e52f8d9338317ec8f96b283f1ab0809947 (mode 644) --- /dev/null +++ src/cmd/9pserve.c @@ -0,0 +1,597 @@ +#include +#include +#include +#include + +enum +{ + STACK = 32768, + NHASH = 31, + MAXMSG = 64, /* per connection */ +}; + +typedef struct Hash Hash; +typedef struct Fid Fid; +typedef struct Msg Msg; +typedef struct Conn Conn; +typedef struct Queue Queue; + +struct Hash +{ + Hash *next; + uint n; + void *v; +}; + +struct Fid +{ + int fid; + int ref; + int cfid; + Fid *next; +}; + +struct Msg +{ + Conn *c; + int internal; + int ref; + int ctag; + int tag; + Fcall tx; + Fcall rx; + Fid *fid; + Fid *newfid; + Fid *afid; + Msg *oldm; + Msg *next; + uchar *tpkt; + uchar *rpkt; +}; + +struct Conn +{ + int fd; + int nmsg; + int nfid; + Channel *inc; + Channel *internal; + int inputstalled; + char dir[40]; + Hash *tag[NHASH]; + Hash *fid[NHASH]; + Queue *outq; + Queue *inq; +}; + +char *addr; +int afd; +char adir[40]; +int isunix; +Queue *outq; +Queue *inq; + +void *gethash(Hash**, uint); +int puthash(Hash**, uint, void*); +int delhash(Hash**, uint, void*); +Msg *mread9p(int); +int mwrite9p(int, Msg*); +uchar *read9ppkt(int); +int write9ppkt(int, uchar*); +Msg *msgnew(void); +void msgput(Msg*); +Msg *msgget(int); +Fid *fidnew(int); +void fidput(Fid*); +void *emalloc(int); +void *erealloc(void*, int); +int sendq(Queue*, void*); +void *recvq(Queue*); +void selectthread(void*); +void connthread(void*); +void listenthread(void*); +void rewritehdr(Fcall*, uchar*); +int tlisten(char*, char*); +int taccept(int, char*); + +void +usage(void) +{ + fprint(2, "usage: 9pserve [-u] address\n"); + fprint(2, "\treads/writes 9P messages on stdin/stdout\n"); + exits("usage"); +} + +void +threadmain(int argc, char **argv) +{ + ARGBEGIN{ + default: + usage(); + case 'u': + isunix = 1; + break; + }ARGEND + + if(argc != 1) + usage(); + + if((afd = announce(addr, adir)) < 0) + sysfatal("announce %s: %r", addr); + + threadcreateidle(selectthread, nil, STACK); +} + +void +listenthread(void *arg) +{ + Conn *c; + + USED(arg); + for(;;){ + c = malloc(sizeof(Conn)); + if(c == nil){ + fprint(2, "out of memory\n"); + sleep(60*1000); + continue; + } + c->fd = tlisten(adir, c->dir); + if(c->fd < 0){ + fprint(2, "listen: %r\n"); + close(afd); + free(c); + return; + } + threadcreate(connthread, c, STACK); + } +} + +void +err(Msg *m, char *ename) +{ + int n, nn; + + m->rx.type = Rerror; + m->rx.ename = ename; + m->rx.tag = m->ctag; + n = sizeS2M(&m->rx); + m->rpkt = emalloc(n); + nn = convS2M(&m->rx, m->rpkt, n); + if(nn != n) + sysfatal("sizeS2M + convS2M disagree"); + sendq(m->c->outq, m); +} + +void +connthread(void *arg) +{ + int i, fd; + Conn *c; + Hash *h; + Msg *m, *om; + Fid *f; + + c = arg; + fd = taccept(c->fd, c->dir); + if(fd < 0){ + fprint(2, "accept %s: %r\n", c->dir); + goto out; + } + close(c->fd); + c->fd = fd; + while((m = mread9p(c->fd)) != nil){ + m->c = c; + c->nmsg++; + if(puthash(c->tag, m->tx.tag, m) < 0){ + err(m, "duplicate tag"); + continue; + } + switch(m->tx.type){ + case Tflush: + if((m->oldm = gethash(c->tag, m->tx.oldtag)) == nil){ + m->rx.tag = Rflush; + sendq(c->outq, m); + continue; + } + break; + case Tattach: + m->fid = fidnew(m->tx.fid); + if(puthash(c->fid, m->tx.fid, m->fid) < 0){ + err(m, "duplicate fid"); + continue; + } + m->fid->ref++; + break; + case Twalk: + if((m->fid = gethash(c->fid, m->tx.fid)) == nil){ + err(m, "unknown fid"); + continue; + } + if(m->tx.newfid == m->tx.fid){ + m->fid->ref++; + m->newfid = m->fid; + }else{ + m->newfid = fidnew(m->tx.newfid); + if(puthash(c->fid, m->tx.newfid, m->newfid) < 0){ + err(m, "duplicate fid"); + continue; + } + m->newfid->ref++; + } + break; + case Tauth: + if((m->afid = gethash(c->fid, m->tx.afid)) == nil){ + err(m, "unknown fid"); + continue; + } + m->fid = fidnew(m->tx.fid); + if(puthash(c->fid, m->tx.fid, m->fid) < 0){ + err(m, "duplicate fid"); + continue; + } + m->fid->ref++; + break; + case Topen: + case Tclunk: + case Tread: + case Twrite: + case Tstat: + case Twstat: + if((m->fid = gethash(c->fid, m->tx.fid)) == nil){ + err(m, "unknown fid"); + continue; + } + m->fid->ref++; + break; + } + + /* have everything - translate and send */ + m->c = c; + m->ctag = m->tx.tag; + m->tx.tag = m->tag; + if(m->fid) + m->tx.fid = m->fid->fid; + if(m->newfid) + m->tx.newfid = m->newfid->fid; + if(m->afid) + m->tx.afid = m->afid->fid; + if(m->oldm) + m->tx.oldtag = m->oldm->tag; + rewritehdr(&m->tx, m->tpkt); + sendq(outq, m); + while(c->nmsg >= MAXMSG){ + c->inputstalled = 1; + recvp(c->inc); + } + } + + /* flush all outstanding messages */ + for(i=0; itag[i]; h; h=h->next){ + om = h->v; + m = msgnew(); + m->internal = 1; + m->c = c; + m->tx.type = Tflush; + m->tx.tag = m->tag; + m->tx.oldtag = om->tag; + m->oldm = om; + om->ref++; + sendq(outq, m); + recvp(c->internal); + } + } + + /* clunk all outstanding fids */ + for(i=0; ifid[i]; h; h=h->next){ + f = h->v; + m = msgnew(); + m->internal = 1; + m->c = c; + m->tx.type = Tclunk; + m->tx.tag = m->tag; + m->tx.fid = f->fid; + m->fid = f; + f->ref++; + sendq(outq, m); + recvp(c->internal); + } + } + +out: + assert(c->nmsg == 0); + assert(c->nfid == 0); + close(c->fd); + free(c); +} + +void +connoutthread(void *arg) +{ + int err; + Conn *c; + Msg *m, *om; + + c = arg; + while((m = recvq(c->outq)) != nil){ + err = m->tx.type+1 != m->rx.type; + switch(m->tx.type){ + case Tflush: + om = m->oldm; + if(delhash(om->c->tag, om->ctag, om) == 0) + msgput(om); + break; + case Tclunk: + if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0) + fidput(m->fid); + break; + case Tauth: + if(err) + if(delhash(m->c->fid, m->afid->cfid, m->fid) == 0) + fidput(m->fid); + case Tattach: + if(err) + if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0) + fidput(m->fid); + break; + case Twalk: + if(err && m->tx.fid != m->tx.newfid) + if(delhash(m->c->fid, m->newfid->cfid, m->newfid) == 0) + fidput(m->newfid); + break; + } + if(mwrite9p(c->fd, m) < 0) + fprint(2, "write error: %r\n"); + if(delhash(m->c->tag, m->ctag, m) == 0) + msgput(m); + msgput(m); + if(c->inputstalled && c->nmsg < MAXMSG) + nbsendp(c->inc, 0); + } +} + +void +outputthread(void *arg) +{ + Msg *m; + + USED(arg); + + while((m = recvq(outq)) != nil){ + if(mwrite9p(1, m) < 0) + sysfatal("output error: %r"); + msgput(m); + } +} + +void +inputthread(void *arg) +{ + uchar *pkt; + int n, nn, tag; + Msg *m; + + while((pkt = read9ppkt(0)) != nil){ + n = GBIT32(pkt); + if(n < 7){ + fprint(2, "short 9P packet\n"); + free(pkt); + continue; + } + tag = GBIT16(pkt+5); + if((m = msgget(tag)) == nil){ + fprint(2, "unexpected 9P response tag %d\n", tag); + free(pkt); + msgput(m); + continue; + } + if((nn = convM2S(pkt, n, &m->rx)) != n){ + fprint(2, "bad packet - convM2S %d but %d\n", nn, n); + free(pkt); + msgput(m); + continue; + } + m->rpkt = pkt; + m->rx.tag = m->ctag; + rewritehdr(&m->rx, m->rpkt); + sendq(m->c->outq, m); + } +} + +void* +gethash(Hash **ht, uint n) +{ + Hash *h; + + for(h=ht[n%NHASH]; h; h=h->next) + if(h->n == n) + return h->v; + return nil; +} + +int +delhash(Hash **ht, uint n, void *v) +{ + Hash *h, **l; + + for(l=&ht[n%NHASH]; h=*l; l=&h->next) + if(h->n == n){ + if(h->v != v) + fprint(2, "hash error\n"); + *l = h->next; + free(h); + return 0; + } + return -1; +} + +int +puthash(Hash **ht, uint n, void *v) +{ + Hash *h; + + if(gethash(ht, n)) + return -1; + h = emalloc(sizeof(Hash)); + h->next = ht[n%NHASH]; + h->n = n; + h->v = v; + ht[n%NHASH] = h; + return 0; +} + +Fid **fidtab; +int nfidtab; +Fid *freefid; + +Fid* +fidnew(int cfid) +{ + Fid *f; + + if(freefid == nil){ + fidtab = erealloc(fidtab, nfidtab*sizeof(fidtab[0])); + fidtab[nfidtab] = emalloc(sizeof(Fid)); + freefid = fidtab[nfidtab++]; + } + f = freefid; + freefid = f->next; + f->cfid = f->cfid; + f->ref = 1; + return f; +} + +void +fidput(Fid *f) +{ + assert(f->ref > 0); + if(--f->ref > 0) + return; + f->next = freefid; + f->cfid = -1; + freefid = f; +} + +Msg **msgtab; +int nmsgtab; +Msg *freemsg; + +Msg* +msgnew(void) +{ + Msg *m; + + if(freemsg == nil){ + msgtab = erealloc(msgtab, nmsgtab*sizeof(msgtab[0])); + msgtab[nmsgtab] = emalloc(sizeof(Msg)); + freemsg = msgtab[nmsgtab++]; + } + m = freemsg; + freemsg = m->next; + m->ref = 1; + return m; +} + +void +msgput(Msg *m) +{ + assert(m->ref > 0); + if(--m->ref > 0) + return; + m->next = freemsg; + freemsg = m; +} + +void* +emalloc(int n) +{ + void *v; + + v = mallocz(n, 1); + if(v == nil) + sysfatal("out of memory"); + return v; +} + +void* +erealloc(void *v, int n) +{ + v = realloc(v, n); + if(v == nil) + sysfatal("out of memory"); + return v; +} + +typedef struct Qel Qel; +struct Qel +{ + Qel *next; + void *p; +}; + +struct Queue +{ + int hungup; + QLock lk; + Rendez r; + Qel *head; + Qel *tail; +}; + +Queue* +qalloc(void) +{ + Queue *q; + + q = mallocz(sizeof(Queue), 1); + if(q == nil) + return nil; + q->r.l = &q->lk; + return q; +} + +int +sendq(Queue *q, void *p) +{ + Qel *e; + + e = emalloc(sizeof(Qel)); + qlock(&q->lk); + if(q->hungup){ + werrstr("hungup queue"); + qunlock(&q->lk); + return -1; + } + e->p = p; + e->next = nil; + if(q->head == nil) + q->head = e; + else + q->tail->next = e; + q->tail = e; + rwakeup(&q->r); + qunlock(&q->lk); + return 0; +} + +void* +recvq(Queue *q) +{ + void *p; + Qel *e; + + qlock(&q->lk); + while(q->head == nil && !q->hungup) + rsleep(&q->r); + if(q->hungup){ + qunlock(&q->lk); + return nil; + } + e = q->head; + q->head = e->next; + qunlock(&q->lk); + p = e->p; + free(e); + return p; +} blob - /dev/null blob + 5acee7e5c19f947dbab2084fd43532f6d613a9b3 (mode 644) --- /dev/null +++ src/lib9/convD2M.c @@ -0,0 +1,95 @@ +#include +#include +#include + +uint +sizeD2M(Dir *d) +{ + char *sv[4]; + int i, ns; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++) + if(sv[i]) + ns += strlen(sv[i]); + + return STATFIXLEN + ns; +} + +uint +convD2M(Dir *d, uchar *buf, uint nbuf) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns, nsv[4], ss; + + if(nbuf < BIT16SZ) + return 0; + + p = buf; + ebuf = buf + nbuf; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++){ + if(sv[i]) + nsv[i] = strlen(sv[i]); + else + nsv[i] = 0; + ns += nsv[i]; + } + + ss = STATFIXLEN + ns; + + /* set size befor erroring, so user can know how much is needed */ + /* note that length excludes count field itself */ + PBIT16(p, ss-BIT16SZ); + p += BIT16SZ; + + if(ss > nbuf) + return BIT16SZ; + + PBIT16(p, d->type); + p += BIT16SZ; + PBIT32(p, d->dev); + p += BIT32SZ; + PBIT8(p, d->qid.type); + p += BIT8SZ; + PBIT32(p, d->qid.vers); + p += BIT32SZ; + PBIT64(p, d->qid.path); + p += BIT64SZ; + PBIT32(p, d->mode); + p += BIT32SZ; + PBIT32(p, d->atime); + p += BIT32SZ; + PBIT32(p, d->mtime); + p += BIT32SZ; + PBIT64(p, d->length); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + ns = nsv[i]; + if(p + ns + BIT16SZ > ebuf) + return 0; + PBIT16(p, ns); + p += BIT16SZ; + if(ns) + memmove(p, sv[i], ns); + p += ns; + } + + if(ss != p - buf) + return 0; + + return p - buf; +} blob - /dev/null blob + 6f4b4bd935bef68910883fe15680609ff24489f0 (mode 644) --- /dev/null +++ src/lib9/convM2D.c @@ -0,0 +1,94 @@ +#include +#include +#include + +int +statcheck(uchar *buf, uint nbuf) +{ + uchar *ebuf; + int i; + + ebuf = buf + nbuf; + + if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) + return -1; + + buf += STATFIXLEN - 4 * BIT16SZ; + + for(i = 0; i < 4; i++){ + if(buf + BIT16SZ > ebuf) + return -1; + buf += BIT16SZ + GBIT16(buf); + } + + if(buf != ebuf) + return -1; + + return 0; +} + +static char nullstring[] = ""; + +uint +convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns; + + if(nbuf < STATFIXLEN) + return 0; + + p = buf; + ebuf = buf + nbuf; + + p += BIT16SZ; /* ignore size */ + d->type = GBIT16(p); + p += BIT16SZ; + d->dev = GBIT32(p); + p += BIT32SZ; + d->qid.type = GBIT8(p); + p += BIT8SZ; + d->qid.vers = GBIT32(p); + p += BIT32SZ; + d->qid.path = GBIT64(p); + p += BIT64SZ; + d->mode = GBIT32(p); + p += BIT32SZ; + d->atime = GBIT32(p); + p += BIT32SZ; + d->mtime = GBIT32(p); + p += BIT32SZ; + d->length = GBIT64(p); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + if(p + BIT16SZ > ebuf) + return 0; + ns = GBIT16(p); + p += BIT16SZ; + if(p + ns > ebuf) + return 0; + if(strs){ + sv[i] = strs; + memmove(strs, p, ns); + strs += ns; + *strs++ = '\0'; + } + p += ns; + } + + if(strs){ + d->name = sv[0]; + d->uid = sv[1]; + d->gid = sv[2]; + d->muid = sv[3]; + }else{ + d->name = nullstring; + d->uid = nullstring; + d->gid = nullstring; + d->muid = nullstring; + } + + return p - buf; +} blob - /dev/null blob + fcdcd42d60f6f0d533747aab47b01af7651cf926 (mode 644) --- /dev/null +++ src/lib9/convM2S.c @@ -0,0 +1,315 @@ +#include +#include +#include + +static +uchar* +gstring(uchar *p, uchar *ep, char **s) +{ + uint n; + + if(p+BIT16SZ > ep) + return nil; + n = GBIT16(p); + p += BIT16SZ - 1; + if(p+n+1 > ep) + return nil; + /* move it down, on top of count, to make room for '\0' */ + memmove(p, p + 1, n); + p[n] = '\0'; + *s = (char*)p; + p += n+1; + return p; +} + +static +uchar* +gqid(uchar *p, uchar *ep, Qid *q) +{ + if(p+QIDSZ > ep) + return nil; + q->type = GBIT8(p); + p += BIT8SZ; + q->vers = GBIT32(p); + p += BIT32SZ; + q->path = GBIT64(p); + p += BIT64SZ; + return p; +} + +/* + * no syntactic checks. + * three causes for error: + * 1. message size field is incorrect + * 2. input buffer too short for its own data (counts too long, etc.) + * 3. too many names or qids + * gqid() and gstring() return nil if they would reach beyond buffer. + * main switch statement checks range and also can fall through + * to test at end of routine. + */ +uint +convM2S(uchar *ap, uint nap, Fcall *f) +{ + uchar *p, *ep; + uint i, size; + + p = ap; + ep = p + nap; + + if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) + return 0; + size = GBIT32(p); + p += BIT32SZ; + + if(size < BIT32SZ+BIT8SZ+BIT16SZ) + return 0; + + f->type = GBIT8(p); + p += BIT8SZ; + f->tag = GBIT16(p); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Tflush: + if(p+BIT16SZ > ep) + return 0; + f->oldtag = GBIT16(p); + p += BIT16SZ; + break; + + case Tauth: + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Tattach: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Twalk: + if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->newfid = GBIT32(p); + p += BIT32SZ; + f->nwname = GBIT16(p); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; inwname; i++){ + p = gstring(p, ep, &f->wname[i]); + if(p == nil) + break; + } + break; + + case Topen: + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tcreate: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->name); + if(p == nil) + break; + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->perm = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tread: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Twrite: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Tclunk: + case Tremove: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Tstat: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Twstat: + if(p+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + +/* + */ + case Rversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Rerror: + p = gstring(p, ep, &f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = gqid(p, ep, &f->aqid); + if(p == nil) + break; + break; + + case Rattach: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + break; + + case Rwalk: + if(p+BIT16SZ > ep) + return 0; + f->nwqid = GBIT16(p); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; inwqid; i++){ + p = gqid(p, ep, &f->wqid[i]); + if(p == nil) + break; + } + break; + + case Ropen: + case Rcreate: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + if(p+BIT32SZ > ep) + return 0; + f->iounit = GBIT32(p); + p += BIT32SZ; + break; + + case Rread: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Rwrite: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Rclunk: + case Rremove: + break; + + case Rstat: + if(p+BIT16SZ > ep) + return 0; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + + case Rwstat: + break; + } + + if(p==nil || p>ep) + return 0; + if(ap+size == p) + return size; + return 0; +} blob - /dev/null blob + 9acdcfa567fbb744c66980c00bea5397ad895f98 (mode 644) --- /dev/null +++ src/lib9/convS2M.c @@ -0,0 +1,386 @@ +#include +#include +#include + +static +uchar* +pstring(uchar *p, char *s) +{ + uint n; + + if(s == nil){ + PBIT16(p, 0); + p += BIT16SZ; + return p; + } + + n = strlen(s); + PBIT16(p, n); + p += BIT16SZ; + memmove(p, s, n); + p += n; + return p; +} + +static +uchar* +pqid(uchar *p, Qid *q) +{ + PBIT8(p, q->type); + p += BIT8SZ; + PBIT32(p, q->vers); + p += BIT32SZ; + PBIT64(p, q->path); + p += BIT64SZ; + return p; +} + +static +uint +stringsz(char *s) +{ + if(s == nil) + return BIT16SZ; + + return BIT16SZ+strlen(s); +} + +uint +sizeS2M(Fcall *f) +{ + uint n; + int i; + + n = 0; + n += BIT32SZ; /* size */ + n += BIT8SZ; /* type */ + n += BIT16SZ; /* tag */ + + switch(f->type) + { + default: + return 0; + + case Tversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Tflush: + n += BIT16SZ; + break; + + case Tauth: + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Tattach: + n += BIT32SZ; + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Twalk: + n += BIT32SZ; + n += BIT32SZ; + n += BIT16SZ; + for(i=0; inwname; i++) + n += stringsz(f->wname[i]); + break; + + case Topen: + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tcreate: + n += BIT32SZ; + n += stringsz(f->name); + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tread: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + break; + + case Twrite: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + n += f->count; + break; + + case Tclunk: + case Tremove: + n += BIT32SZ; + break; + + case Tstat: + n += BIT32SZ; + break; + + case Twstat: + n += BIT32SZ; + n += BIT16SZ; + n += f->nstat; + break; +/* + */ + + case Rversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Rerror: + n += stringsz(f->ename); + break; + + case Rflush: + break; + + case Rauth: + n += QIDSZ; + break; + + case Rattach: + n += QIDSZ; + break; + + case Rwalk: + n += BIT16SZ; + n += f->nwqid*QIDSZ; + break; + + case Ropen: + case Rcreate: + n += QIDSZ; + n += BIT32SZ; + break; + + case Rread: + n += BIT32SZ; + n += f->count; + break; + + case Rwrite: + n += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + n += BIT16SZ; + n += f->nstat; + break; + + case Rwstat: + break; + } + return n; +} + +uint +convS2M(Fcall *f, uchar *ap, uint nap) +{ + uchar *p; + uint i, size; + + size = sizeS2M(f); + if(size == 0) + return 0; + if(size > nap) + return 0; + + p = (uchar*)ap; + + PBIT32(p, size); + p += BIT32SZ; + PBIT8(p, f->type); + p += BIT8SZ; + PBIT16(p, f->tag); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Tflush: + PBIT16(p, f->oldtag); + p += BIT16SZ; + break; + + case Tauth: + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Tattach: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Twalk: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->newfid); + p += BIT32SZ; + PBIT16(p, f->nwname); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; inwname; i++) + p = pstring(p, f->wname[i]); + break; + + case Topen: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tcreate: + PBIT32(p, f->fid); + p += BIT32SZ; + p = pstring(p, f->name); + PBIT32(p, f->perm); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tread: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Twrite: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Tclunk: + case Tremove: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Tstat: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Twstat: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; +/* + */ + + case Rversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Rerror: + p = pstring(p, f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = pqid(p, &f->aqid); + break; + + case Rattach: + p = pqid(p, &f->qid); + break; + + case Rwalk: + PBIT16(p, f->nwqid); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; inwqid; i++) + p = pqid(p, &f->wqid[i]); + break; + + case Ropen: + case Rcreate: + p = pqid(p, &f->qid); + PBIT32(p, f->iounit); + p += BIT32SZ; + break; + + case Rread: + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Rwrite: + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; + + case Rwstat: + break; + } + if(size != p-ap) + return 0; + return size; +} blob - /dev/null blob + 4eef88dece82b5c102c1a4deb66119bfaff3e2a3 (mode 644) --- /dev/null +++ src/lib9/fcallfmt.c @@ -0,0 +1,234 @@ +#include +#include +#include + +static uint dumpsome(char*, char*, char*, long); +static void fdirconv(char*, char*, Dir*); +static char *qidtype(char*, uchar); + +#define QIDFMT "(%.16llux %lud %s)" + +int +fcallfmt(Fmt *fmt) +{ + Fcall *f; + int fid, type, tag, i; + char buf[512], tmp[200]; + char *p, *e; + Dir *d; + Qid *q; + + e = buf+sizeof(buf); + f = va_arg(fmt->args, Fcall*); + type = f->type; + fid = f->fid; + tag = f->tag; + switch(type){ + case Tversion: /* 100 */ + seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Rversion: + seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Tauth: /* 102 */ + seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag, + f->afid, f->uname, f->aname); + break; + case Rauth: + seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag, + f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type)); + break; + case Tattach: /* 104 */ + seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag, + fid, f->afid, f->uname, f->aname); + break; + case Rattach: + seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type)); + break; + case Rerror: /* 107; 106 (Terror) illegal */ + seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename); + break; + case Tflush: /* 108 */ + seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag); + break; + case Rflush: + seprint(buf, e, "Rflush tag %ud", tag); + break; + case Twalk: /* 110 */ + p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname); + if(f->nwname <= MAXWELEM) + for(i=0; inwname; i++) + p = seprint(p, e, "%d:%s ", i, f->wname[i]); + break; + case Rwalk: + p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid); + if(f->nwqid <= MAXWELEM) + for(i=0; inwqid; i++){ + q = &f->wqid[i]; + p = seprint(p, e, "%d:" QIDFMT " ", i, + q->path, q->vers, qidtype(tmp, q->type)); + } + break; + case Topen: /* 112 */ + seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode); + break; + case Ropen: + seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tcreate: /* 114 */ + seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode); + break; + case Rcreate: + seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tread: /* 116 */ + seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud", + tag, fid, f->offset, f->count); + break; + case Rread: + p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Twrite: /* 118 */ + p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ", + tag, fid, f->offset, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Rwrite: + seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count); + break; + case Tclunk: /* 120 */ + seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid); + break; + case Rclunk: + seprint(buf, e, "Rclunk tag %ud", tag); + break; + case Tremove: /* 122 */ + seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid); + break; + case Rremove: + seprint(buf, e, "Rremove tag %ud", tag); + break; + case Tstat: /* 124 */ + seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid); + break; + case Rstat: + p = seprint(buf, e, "Rstat tag %ud ", tag); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Twstat: /* 126 */ + p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Rwstat: + seprint(buf, e, "Rwstat tag %ud", tag); + break; + default: + seprint(buf, e, "unknown type %d", type); + } + return fmtstrcpy(fmt, buf); +} + +static char* +qidtype(char *s, uchar t) +{ + char *p; + + p = s; + if(t & QTDIR) + *p++ = 'd'; + if(t & QTAPPEND) + *p++ = 'a'; + if(t & QTEXCL) + *p++ = 'l'; + if(t & QTAUTH) + *p++ = 'A'; + *p = '\0'; + return s; +} + +int +dirfmt(Fmt *fmt) +{ + char buf[160]; + + fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*)); + return fmtstrcpy(fmt, buf); +} + +static void +fdirconv(char *buf, char *e, Dir *d) +{ + char tmp[16]; + + seprint(buf, e, "'%s' '%s' '%s' '%s' " + "q " QIDFMT " m %#luo " + "at %ld mt %ld l %lld " + "t %d d %d", + d->name, d->uid, d->gid, d->muid, + d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode, + d->atime, d->mtime, d->length, + d->type, d->dev); +} + +/* + * dump out count (or DUMPL, if count is bigger) bytes from + * buf to ans, as a string if they are all printable, + * else as a series of hex bytes + */ +#define DUMPL 64 + +static uint +dumpsome(char *ans, char *e, char *buf, long count) +{ + int i, printable; + char *p; + + if(buf == nil){ + seprint(ans, e, ""); + return strlen(ans); + } + printable = 1; + if(count > DUMPL) + count = DUMPL; + for(i=0; i127) + printable = 0; + p = ans; + *p++ = '\''; + if(printable){ + if(count > e-p-2) + count = e-p-2; + memmove(p, buf, count); + p += count; + }else{ + if(2*count > e-p-2) + count = (e-p-2)/2; + for(i=0; i0 && i%4==0) + *p++ = ' '; + sprint(p, "%2.2ux", buf[i]); + p += 2; + } + } + *p++ = '\''; + *p = 0; + return p - ans; +} blob - /dev/null blob + 9e90ec5d6c668675519d2dd4f000580839be8066 (mode 644) --- /dev/null +++ src/lib9/read9pmsg.c @@ -0,0 +1,31 @@ +#include +#include +#include + +int +read9pmsg(int fd, void *abuf, uint n) +{ + int m, len; + uchar *buf; + + buf = abuf; + + /* read count */ + m = readn(fd, buf, BIT32SZ); + if(m != BIT32SZ){ + if(m < 0) + return -1; + return 0; + } + + len = GBIT32(buf); + if(len <= BIT32SZ || len > n){ + werrstr("bad length in 9P2000 message header"); + return -1; + } + len -= BIT32SZ; + m = readn(fd, buf+BIT32SZ, len); + if(m < len) + return 0; + return BIT32SZ+m; +} blob - /dev/null blob + de348d126b2bed47cefa2f493e03f8f1e23c5b19 (mode 644) --- /dev/null +++ src/libfs/COPYRIGHT @@ -0,0 +1,27 @@ + +This software was developed as part of a project at MIT: + /sys/src/libfs/* except dirread.c + /sys/include/fs.h + +Copyright (c) 2003 Russ Cox, + Massachusetts Institute of Technology + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + blob - /dev/null blob + 23388ae3e74836774f8d27b8309836abb03e0ce2 (mode 644) --- /dev/null +++ src/libfs/close.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include +#include "fsimpl.h" + +static void +fidclunk(Fid *fid) +{ + Fcall tx, rx; + + tx.type = Tclunk; + tx.fid = fid->fid; + fsrpc(fid->fs, &tx, &rx, 0); + _fsputfid(fid); +} + +void +fsclose(Fid *fid) +{ + /* maybe someday there will be a ref count */ + fidclunk(fid); +} blob - /dev/null blob + ef52a2a8ca4bee13d65e028f533b22591ff30c65 (mode 644) --- /dev/null +++ src/libfs/create.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include "fsimpl.h" + +Fid* +fscreate(Fsys *fs, char *name, int mode, ulong perm) +{ + Fid *fid; + Fcall tx, rx; + + if((fid = fswalk(fs->root, name)) == nil) + return nil; + tx.type = Tcreate; + tx.fid = fid->fid; + tx.mode = mode; + tx.perm = perm; + if(fsrpc(fs, &tx, &rx, 0) < 0){ + fsclose(fid); + return nil; + } + fid->mode = mode; + return fid; +} blob - /dev/null blob + 0ca4064542ef8c8f41aa98d736f11e005eb87d80 (mode 644) --- /dev/null +++ src/libfs/dirread.c @@ -0,0 +1,100 @@ +/* Mostly copied from Plan 9's libc. */ + +#include +#include +#include +#include + +static +long +dirpackage(uchar *buf, long ts, Dir **d) +{ + char *s; + long ss, i, n, nn, m; + + *d = nil; + if(ts <= 0) + return 0; + + /* + * first find number of all stats, check they look like stats, & size all associated strings + */ + ss = 0; + n = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16(&buf[i]); + if(statcheck(&buf[i], m) < 0) + break; + ss += m; + n++; + } + + if(i != ts) + return -1; + + *d = malloc(n * sizeof(Dir) + ss); + if(*d == nil) + return -1; + + /* + * then convert all buffers + */ + s = (char*)*d + n * sizeof(Dir); + nn = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16((uchar*)&buf[i]); + if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){ + free(*d); + *d = nil; + return -1; + } + nn++; + s += m; + } + + return nn; +} + +long +fsdirread(Fid *fid, Dir **d) +{ + uchar *buf; + long ts; + + buf = malloc(DIRMAX); + if(buf == nil) + return -1; + ts = fsread(fid, buf, DIRMAX); + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + return ts; +} + +long +fsdirreadall(Fid *fid, Dir **d) +{ + uchar *buf, *nbuf; + long n, ts; + + buf = nil; + ts = 0; + for(;;){ + nbuf = realloc(buf, ts+DIRMAX); + if(nbuf == nil){ + free(buf); + return -1; + } + buf = nbuf; + n = fsread(fid, buf+ts, DIRMAX); + if(n <= 0) + break; + ts += n; + } + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + if(ts == 0 && n < 0) + return -1; + return ts; +} blob - /dev/null blob + 985071c1c69ce4a6f45e996f624889f647ffea85 (mode 644) --- /dev/null +++ src/libfs/fs.c @@ -0,0 +1,276 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include +#include "fsimpl.h" + +static int _fssend(Mux*, void*); +static void *_fsrecv(Mux*); +static int _fsgettag(Mux*, void*); +static int _fssettag(Mux*, void*, uint); + +enum +{ + Fidchunk = 32 +}; + +Fsys* +fsinit(int fd) +{ + Fsys *fs; + + fs = mallocz(sizeof(Fsys), 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; + muxinit(&fs->mux); + return fs; +} + +Fid* +fsroot(Fsys *fs) +{ + /* N.B. no incref */ + return fs->root; +} + +Fsys* +fsmount(int fd) +{ + int n; + char *user; + Fsys *fs; + + fs = fsinit(fd); + if(fs == nil) + return nil; + strcpy(fs->version, "9P2000"); + if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){ + Error: + fsunmount(fs); + return nil; + } + fs->msize = n; + + user = getuser(); + if((fs->root = fsattach(fs, nil, getuser(), "")) == nil) + goto Error; + return fs; +} + +void +fsunmount(Fsys *fs) +{ + _fsdecref(fs); +} + +void +_fsdecref(Fsys *fs) +{ + Fid *f, *next; + + qlock(&fs->lk); + if(--fs->ref == 0){ + close(fs->fd); + for(f=fs->freefid; f; f=next){ + next = f->next; + if(f->fid%Fidchunk == 0) + free(f); + } + free(fs); + } + qunlock(&fs->lk); +} + +int +fsversion(Fsys *fs, int msize, char *version, int nversion) +{ + void *freep; + Fcall tx, rx; + + tx.type = Tversion; + tx.version = version; + tx.msize = msize; + + if(fsrpc(fs, &tx, &rx, &freep) < 0) + return -1; + strecpy(version, version+nversion, rx.version); + free(freep); + return rx.msize; +} + +Fid* +fsattach(Fsys *fs, Fid *afid, char *user, char *aname) +{ + Fcall tx, rx; + Fid *fid; + + if((fid = _fsgetfid(fs)) == nil) + return nil; + + 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; +} + +int +fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep) +{ + int n, nn; + void *tpkt, *rpkt; + + n = sizeS2M(tx); + tpkt = malloc(n); + if(tpkt == nil) + return -1; + 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"); + fprint(2, "%r\n"); + return -1; + } + 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; +} + +Fid* +_fsgetfid(Fsys *fs) +{ + int i; + Fid *f; + + qlock(&fs->lk); + if(fs->freefid == nil){ + f = malloc(sizeof(Fid)*Fidchunk); + if(f == nil){ + qunlock(&fs->lk); + return nil; + } + for(i=0; inextfid++; + f[i].next = &f[i+1]; + f[i].fs = fs; + fs->ref++; + } + f[i-1].next = nil; + fs->freefid = f; + } + f = fs->freefid; + fs->freefid = f->next; + qunlock(&fs->lk); + return f; +} + +void +_fsputfid(Fid *f) +{ + Fsys *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) +{ + Fsys *fs; + + fs = mux->aux; + return write(fs->fd, pkt, GBIT32((uchar*)pkt)); +} + +static void* +_fsrecv(Mux *mux) +{ + uchar *pkt; + uchar buf[4]; + int n; + Fsys *fs; + + fs = mux->aux; + n = readn(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(buf, n); + if(readn(fs->fd, pkt+4, n-4) != n-4){ + free(pkt); + return nil; + } +#if 0 + if(pkt[4] == Ropenfd){ + /* do unix socket crap */ + sysfatal("no socket crap implemented"); + } +#endif + return pkt; +} blob - /dev/null blob + fbcc37771b5ea281353c117d6b0ab37c36184f5b (mode 644) --- /dev/null +++ src/libfs/fsimpl.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +typedef struct Queue Queue; +Queue *_fsqalloc(void); +int _fsqsend(Queue*, void*); +void *_fsqrecv(Queue*); +void _fsqhangup(Queue*); +void *_fsnbqrecv(Queue*); + +#include +struct Fsys +{ + char version[20]; + int msize; + QLock lk; + int fd; + int ref; + Mux mux; + Fid *root; + Queue *txq; + Queue *rxq; + Fid *freefid; + int nextfid; +}; + +struct Fid +{ + int fid; + int mode; + Fid *next; + QLock lk; + Fsys *fs; + Qid qid; + vlong offset; +}; + +void _fsdecref(Fsys*); +void _fsputfid(Fid*); +Fid *_fsgetfid(Fsys*); + blob - /dev/null blob + acfb0ae5990ba8fdbdfb4eba69913ff94ec5c756 (mode 644) --- /dev/null +++ src/libfs/mkfile @@ -0,0 +1,22 @@ +PLAN9=../.. +<$PLAN9/src/mkhdr + +LIB=libfs.a + +OFILES=\ + close.$O\ + create.$O\ + dirread.$O\ + fs.$O\ + open.$O\ + read.$O\ + stat.$O\ + walk.$O\ + write.$O\ + wstat.$O\ + +HFILES=\ + $PLAN9/include/fs.h\ + $PLAN9/include/mux.h\ + +<$PLAN9/src/mksyslib blob - /dev/null blob + 458c5dac3dc0fbb80a934984540cea2d8b402e0b (mode 644) --- /dev/null +++ src/libfs/open.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include "fsimpl.h" + +Fid* +fsopen(Fsys *fs, char *name, int mode) +{ + Fid *fid; + Fcall tx, rx; + + if((fid = fswalk(fs->root, name)) == nil) + return nil; + tx.type = Topen; + tx.fid = fid->fid; + tx.mode = mode; + if(fsrpc(fs, &tx, &rx, 0) < 0){ + fsclose(fid); + return nil; + } + fid->mode = mode; + return fid; +} blob - /dev/null blob + ca6c628c4e909244c6f163b03aa208b6fe4c8d3a (mode 644) --- /dev/null +++ src/libfs/read.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include +#include "fsimpl.h" + +long +fspread(Fid *fid, void *buf, long n, vlong offset) +{ + Fcall tx, rx; + void *freep; + + tx.type = Tread; + if(offset == -1){ + qlock(&fid->lk); + tx.offset = fid->offset; + qunlock(&fid->lk); + }else + tx.offset = offset; + tx.count = n; + + fsrpc(fid->fs, &tx, &rx, &freep); + if(rx.type == Rerror){ + werrstr("%s", rx.ename); + free(freep); + return -1; + } + if(rx.count){ + memmove(buf, rx.data, rx.count); + if(offset == -1){ + qlock(&fid->lk); + tx.offset += n; + qunlock(&fid->lk); + } + } + free(freep); + + return rx.count; +} + +long +fsread(Fid *fid, void *buf, long n) +{ + return fspread(fid, buf, n, -1); +} blob - /dev/null blob + e55e0b126e72c18fa18d454d43c55aaa3ec3f1b7 (mode 644) --- /dev/null +++ src/libfs/stat.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include +#include "fsimpl.h" + +Dir* +fsdirstat(Fsys *fs, char *name) +{ + Dir *d; + Fid *fid; + + if((fid = fswalk(fs->root, name)) == nil) + return nil; + + d = fsdirfstat(fid); + fsclose(fid); + return d; +} + +Dir* +fsdirfstat(Fid *fid) +{ + Dir *d; + Fsys *fs; + Fcall tx, rx; + void *freep; + int n; + + fs = fid->fs; + tx.type = Tstat; + tx.fid = fid->fid; + + if(fsrpc(fs, &tx, &rx, &freep) < 0) + return nil; + + d = malloc(sizeof(Dir)+rx.nstat); + if(d == nil){ + free(freep); + return nil; + } + n = convM2D(rx.stat, rx.nstat, d, (char*)&d[1]); + free(freep); + if(n != rx.nstat){ + free(d); + werrstr("rx.nstat and convM2D disagree about dir length"); + return nil; + } + return d; +} + blob - /dev/null blob + ad4eddc7727dea7d76696c008fe64467e72685c3 (mode 644) --- /dev/null +++ src/libfs/walk.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include +#include "fsimpl.h" + +Fid* +fswalk(Fid *fid, char *oname) +{ + char *freep, *name; + int i, nwalk; + char *p; + Fid *wfid; + Fcall tx, rx; + + freep = nil; + name = oname; + if(name){ + freep = malloc(strlen(name)+1); + if(freep == nil) + return nil; + strcpy(freep, name); + name = freep; + } + + if((wfid = _fsgetfid(fid->fs)) == nil){ + free(freep); + return nil; + } + + nwalk = 0; + do{ + /* collect names */ + for(i=0; name && *name && i < MAXWELEM; ){ + p = name; + name = strchr(name, '/'); + if(name) + *name++ = 0; + if(*p == 0) + continue; + tx.wname[i++] = p; + } + + /* do a walk */ + tx.type = Twalk; + tx.fid = nwalk ? wfid->fid : fid->fid; + tx.newfid = wfid->fid; + tx.nwname = i; + if(fsrpc(fid->fs, &tx, &rx, 0) < 0){ + Error: + free(freep); + if(nwalk) + fsclose(wfid); + else + _fsputfid(wfid); + return nil; + } + if(rx.nwqid != tx.nwname){ + /* XXX lame error */ + werrstr("file '%s' not found", oname); + goto Error; + } + if(rx.nwqid == 0) + wfid->qid = fid->qid; + else + wfid->qid = rx.wqid[rx.nwqid-1]; + nwalk++; + }while(name && *name); + return wfid; +} blob - /dev/null blob + 96ecfa864653941be06444505860c82f6041545d (mode 644) --- /dev/null +++ src/libfs/write.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include +#include "fsimpl.h" + +long +fspwrite(Fid *fd, void *buf, long n, vlong offset) +{ + Fcall tx, rx; + void *freep; + + tx.type = Tread; + if(offset == -1){ + qlock(&fd->lk); + tx.offset = fd->offset; + fd->offset += n; + qunlock(&fd->lk); + }else + tx.offset = offset; + tx.count = n; + tx.data = buf; + + fsrpc(fd->fs, &tx, &rx, &freep); + if(rx.type == Rerror){ + if(offset == -1){ + qlock(&fd->lk); + fd->offset -= n; + qunlock(&fd->lk); + } + werrstr("%s", rx.ename); + free(freep); + return -1; + } + free(freep); + return rx.count; +} + +long +fswrite(Fid *fd, void *buf, long n) +{ + return fspwrite(fd, buf, n, -1); +} blob - /dev/null blob + 90ae0e0fce7250880e3d1e0307e37d71ed3a307f (mode 644) --- /dev/null +++ src/libfs/wstat.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include +#include "fsimpl.h" + +int +fsdirwstat(Fsys *fs, char *name, Dir *d) +{ + int n; + Fid *fid; + + if((fid = fswalk(fs->root, name)) == nil) + return -1; + + n = fsdirfwstat(fid, d); + fsclose(fid); + return n; +} + +int +fsdirfwstat(Fid *fid, Dir *d) +{ + char *a; + int n, nn; + Fcall tx, rx; + + n = sizeD2M(d); + a = malloc(n); + if(a == nil) + return -1; + nn = convD2M(d, a, n); + if(n != nn){ + werrstr("convD2M and sizeD2M disagree"); + free(a); + return -1; + } + + tx.type = Twstat; + tx.fid = fid->fid; + tx.stat = a; + tx.nstat = n; + n = fsrpc(fid->fs, &tx, &rx, 0); + free(a); + return n; +} blob - /dev/null blob + d9679c3ae2ec4630c535f35b4efb85129d1e2065 (mode 644) --- /dev/null +++ src/libmux/COPYRIGHT @@ -0,0 +1,27 @@ + +This software was developed as part of a project at MIT: + /sys/src/libmux/* + /sys/include/mux.h + +Copyright (c) 2003 Russ Cox, + Massachusetts Institute of Technology + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + blob - /dev/null blob + 3d932b1a1f4925bd0c79192b237ef990309bb667 (mode 644) --- /dev/null +++ src/libmux/io.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include + +/* + * If you fork off two procs running muxrecvproc and muxsendproc, + * then muxrecv/muxsend (and thus muxrpc) will never block except on + * rendevouses, which is nice when it's running in one thread of many. + */ +void +_muxrecvproc(void *v) +{ + void *p; + Mux *mux; + Muxqueue *q; + + mux = v; + q = _muxqalloc(); + + qlock(&mux->lk); + mux->readq = q; + qlock(&mux->inlk); + rwakeup(&mux->rpcfork); + qunlock(&mux->lk); + + while((p = mux->recv(mux)) != nil) + if(_muxqsend(q, p) < 0){ + free(p); + break; + } + qunlock(&mux->inlk); + qlock(&mux->lk); + _muxqhangup(q); + while((p = _muxnbqrecv(q)) != nil) + free(p); + free(q); + mux->readq = nil; + rwakeup(&mux->rpcfork); + qunlock(&mux->lk); +} + +void +_muxsendproc(void *v) +{ + Muxqueue *q; + void *p; + Mux *mux; + + mux = v; + q = _muxqalloc(); + + qlock(&mux->lk); + mux->writeq = q; + qlock(&mux->outlk); + rwakeup(&mux->rpcfork); + qunlock(&mux->lk); + + while((p = _muxqrecv(q)) != nil) + if(mux->send(mux, p) < 0) + break; + qunlock(&mux->outlk); + qlock(&mux->lk); + _muxqhangup(q); + while((p = _muxnbqrecv(q)) != nil) + free(p); + free(q); + mux->writeq = nil; + rwakeup(&mux->rpcfork); + qunlock(&mux->lk); + return; +} + +void* +_muxrecv(Mux *mux) +{ + void *p; + + qlock(&mux->lk); +/* + if(mux->state != VtStateConnected){ + werrstr("not connected"); + qunlock(&mux->lk); + return nil; + } +*/ + if(mux->readq){ + qunlock(&mux->lk); + return _muxqrecv(mux->readq); + } + + qlock(&mux->inlk); + qunlock(&mux->lk); + p = mux->recv(mux); + qunlock(&mux->inlk); +/* + if(!p) + vthangup(mux); +*/ + return p; +} + +int +_muxsend(Mux *mux, void *p) +{ + qlock(&mux->lk); +/* + if(mux->state != VtStateConnected){ + packetfree(p); + werrstr("not connected"); + qunlock(&mux->lk); + return -1; + } +*/ + if(mux->writeq){ + qunlock(&mux->lk); + if(_muxqsend(mux->writeq, p) < 0){ + free(p); + return -1; + } + return 0; + } + + qlock(&mux->outlk); + qunlock(&mux->lk); + if(mux->send(mux, p) < 0){ + qunlock(&mux->outlk); + /* vthangup(mux); */ + return -1; + } + qunlock(&mux->outlk); + return 0; +} + blob - /dev/null blob + 71d62a433c5a346bcc007203d4f6fc61a5e16cde (mode 644) --- /dev/null +++ src/libmux/mkfile @@ -0,0 +1,16 @@ +PLAN9=../.. +<$PLAN9/src/mkhdr + +LIB=libmux.a + +OFILES=\ + io.$O\ + mux.$O\ + queue.$O\ + thread.$O\ + +HFILES=\ + $PLAN9/include/mux.h\ + +<$PLAN9/src/mksyslib + blob - /dev/null blob + 0d33498e31dc9ac1db29f93a84f454c103204ca3 (mode 644) --- /dev/null +++ src/libmux/mux.c @@ -0,0 +1,152 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +/* + * Generic RPC packet multiplexor. Inspired by but not derived from + * Plan 9 kernel. Originally developed as part of Tra, later used in + * libnventi, and then finally split out into a generic library. + */ + +#include +#include +#include + +static int gettag(Mux*, Muxrpc*); +static void puttag(Mux*, Muxrpc*); +static void enqueue(Mux*, Muxrpc*); +static void dequeue(Mux*, Muxrpc*); + +void +muxinit(Mux *mux) +{ + mux->tagrend.l = &mux->lk; + mux->sleep.next = &mux->sleep; + mux->sleep.prev = &mux->sleep; +} + +void* +muxrpc(Mux *mux, void *tx) +{ + uint tag; + Muxrpc *r, *r2; + void *p; + + /* must malloc because stack could be private */ + r = mallocz(sizeof(Muxrpc), 1); + if(r == nil) + return nil; + r->r.l = &mux->lk; + + /* assign the tag */ + tag = gettag(mux, r); + if(mux->settag(mux, tx, tag) < 0){ + puttag(mux, r); + free(r); + return nil; + } + + /* send the packet */ + if(_muxsend(mux, tx) < 0){ + puttag(mux, r); + free(r); + return nil; + } + + /* add ourselves to sleep queue */ + qlock(&mux->lk); + enqueue(mux, r); + + /* wait for our packet */ + while(mux->muxer && !r->p) + rsleep(&r->r); + + /* if not done, there's no muxer: start muxing */ + if(!r->p){ + if(mux->muxer) + abort(); + mux->muxer = 1; + while(!r->p){ + qunlock(&mux->lk); + p = _muxrecv(mux); + if(p) + tag = mux->gettag(mux, p); + else + tag = ~0; + qlock(&mux->lk); + if(p == nil){ /* eof -- just give up and pass the buck */ + dequeue(mux, r); + break; + } + /* hand packet to correct sleeper */ + if(tag < 0 || tag >= mux->mwait){ + fprint(2, "%s: bad rpc tag %ux\n", argv0, tag); + /* must leak packet! don't know how to free it! */ + continue; + } + r2 = mux->wait[tag]; + r2->p = p; + rwakeup(&r2->r); + } + mux->muxer = 0; + + /* if there is anyone else sleeping, wake them to mux */ + if(mux->sleep.next != &mux->sleep) + rwakeup(&mux->sleep.next->r); + } + p = r->p; + puttag(mux, r); + free(r); + qunlock(&mux->lk); + return p; +} + +static void +enqueue(Mux *mux, Muxrpc *r) +{ + r->next = mux->sleep.next; + r->prev = &mux->sleep; + r->next->prev = r; + r->prev->next = r; +} + +static void +dequeue(Mux *mux, Muxrpc *r) +{ + r->next->prev = r->prev; + r->prev->next = r->next; + r->prev = nil; + r->next = nil; +} + +static int +gettag(Mux *mux, Muxrpc *r) +{ + int i; + +Again: + while(mux->nwait == mux->mwait) + rsleep(&mux->tagrend); + i=mux->freetag; + if(mux->wait[i] == 0) + goto Found; + for(i=0; imwait; i++) + if(mux->wait[i] == 0){ + Found: + mux->nwait++; + mux->wait[i] = r; + r->tag = i; + return i; + } + fprint(2, "libfs: nwait botch\n"); + goto Again; +} + +static void +puttag(Mux *mux, Muxrpc *r) +{ + assert(mux->wait[r->tag] == r); + mux->wait[r->tag] = nil; + mux->nwait--; + mux->freetag = r->tag; + rwakeup(&mux->tagrend); +} blob - /dev/null blob + 072f18609bb6ddf7273258b184174834b7c0dfff (mode 644) --- /dev/null +++ src/libmux/queue.c @@ -0,0 +1,109 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include + +typedef struct Qel Qel; +struct Qel +{ + Qel *next; + void *p; +}; + +struct Muxqueue +{ + int hungup; + QLock lk; + Rendez r; + Qel *head; + Qel *tail; +}; + +Muxqueue* +_muxqalloc(void) +{ + Muxqueue *q; + + q = mallocz(sizeof(Muxqueue), 1); + if(q == nil) + return nil; + q->r.l = &q->lk; + return q; +} + +int +_muxqsend(Muxqueue *q, void *p) +{ + Qel *e; + + e = malloc(sizeof(Qel)); + if(e == nil) + return -1; + qlock(&q->lk); + if(q->hungup){ + werrstr("hungup queue"); + qunlock(&q->lk); + return -1; + } + e->p = p; + e->next = nil; + if(q->head == nil) + q->head = e; + else + q->tail->next = e; + q->tail = e; + rwakeup(&q->r); + qunlock(&q->lk); + return 0; +} + +void* +_muxqrecv(Muxqueue *q) +{ + void *p; + Qel *e; + + qlock(&q->lk); + while(q->head == nil && !q->hungup) + rsleep(&q->r); + if(q->hungup){ + qunlock(&q->lk); + return nil; + } + e = q->head; + q->head = e->next; + qunlock(&q->lk); + p = e->p; + free(e); + return p; +} + +void* +_muxnbqrecv(Muxqueue *q) +{ + void *p; + Qel *e; + + qlock(&q->lk); + if(q->head == nil){ + qunlock(&q->lk); + return nil; + } + e = q->head; + q->head = e->next; + qunlock(&q->lk); + p = e->p; + free(e); + return p; +} + +void +_muxqhangup(Muxqueue *q) +{ + qlock(&q->lk); + q->hungup = 1; + rwakeupall(&q->r); + qunlock(&q->lk); +} blob - /dev/null blob + 1c643e06df7b6c94cd18d9b10dc112971f19b072 (mode 644) --- /dev/null +++ src/libmux/thread.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */ +/* See COPYRIGHT */ + +#include +#include +#include +#include + +enum +{ + STACK = 32768 +}; + +void +muxthreads(Mux *mux) +{ + proccreate(_muxrecvproc, mux, STACK); + qlock(&mux->lk); + while(!mux->writeq) + rsleep(&mux->rpcfork); + qunlock(&mux->lk); + proccreate(_muxsendproc, mux, STACK); + qlock(&mux->lk); + while(!mux->writeq) + rsleep(&mux->rpcfork); + qunlock(&mux->lk); +}