File system stuff.

This commit is contained in:
rsc 2003-12-06 18:08:52 +00:00
parent e97ceade5e
commit d3df308747
29 changed files with 3316 additions and 0 deletions

41
include/fs.h Normal file
View file

@ -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

54
include/mux.h Normal file
View file

@ -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*);

191
src/cmd/9p.c Normal file
View file

@ -0,0 +1,191 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
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<nelem(cmds); i++){
if(strcmp(cmds[i].s, cmd) == 0){
cmds[i].f(argc, argv);
exits(0);
}
}
usage();
}
Fsys*
xparse(char *name, char **path)
{
int fd;
char *ns;
char *p;
Fsys *fs;
if(addr == nil){
p = strchr(name, '/');
if(p == nil)
p = name+strlen(name);
else
*p++ = 0;
*path = p;
if(*name == 0)
usage();
ns = getenv("ns");
if(ns == nil)
sysfatal("ns not set");
addr = smprint("unix!%s/%s", ns, name);
if(addr == nil)
sysfatal("out of memory");
}else
*path = name;
fprint(2, "dial %s...", addr);
if((fd = dial(addr, nil, nil, nil)) < 0)
sysfatal("dial: %r");
if((fs = fsmount(fd)) == nil)
sysfatal("fsmount: %r");
return fs;
}
Fid*
xwalk(char *name)
{
Fid *fid;
Fsys *fs;
fs = xparse(name, &name);
fid = fswalk(fsroot(fs), name);
if(fid == nil)
sysfatal("fswalk %s: %r", name);
return fid;
}
Fid*
xopen(char *name, int mode)
{
Fid *fid;
Fsys *fs;
fs = xparse(name, &name);
fid = fsopen(fs, name, mode);
if(fid == nil)
sysfatal("fsopen %s: %r", name);
return fid;
}
void
xread(int argc, char **argv)
{
char buf[1024];
int n;
Fid *fid;
ARGBEGIN{
default:
usage();
}ARGEND
if(argc != 1)
usage();
fid = xopen(argv[0], OREAD);
while((n = fsread(fid, buf, sizeof buf)) > 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);
}

597
src/cmd/9pserve.c Normal file
View file

@ -0,0 +1,597 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
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; i<NHASH; i++){
for(h=c->tag[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; i<NHASH; i++){
for(h=c->fid[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;
}

95
src/lib9/convD2M.c Normal file
View file

@ -0,0 +1,95 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
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;
}

94
src/lib9/convM2D.c Normal file
View file

@ -0,0 +1,94 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
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;
}

315
src/lib9/convM2S.c Normal file
View file

@ -0,0 +1,315 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
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; i<f->nwname; 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; i<f->nwqid; 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;
}

386
src/lib9/convS2M.c Normal file
View file

@ -0,0 +1,386 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
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; i<f->nwname; 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; i<f->nwname; 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; i<f->nwqid; 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;
}

234
src/lib9/fcallfmt.c Normal file
View file

@ -0,0 +1,234 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
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; i<f->nwname; 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; i<f->nwqid; 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, "<no data>");
return strlen(ans);
}
printable = 1;
if(count > DUMPL)
count = DUMPL;
for(i=0; i<count && printable; i++)
if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127)
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; i<count; i++){
if(i>0 && i%4==0)
*p++ = ' ';
sprint(p, "%2.2ux", buf[i]);
p += 2;
}
}
*p++ = '\'';
*p = 0;
return p - ans;
}

31
src/lib9/read9pmsg.c Normal file
View file

@ -0,0 +1,31 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
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;
}

27
src/libfs/COPYRIGHT Normal file
View file

@ -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.

26
src/libfs/close.c Normal file
View file

@ -0,0 +1,26 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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);
}

25
src/libfs/create.c Normal file
View file

@ -0,0 +1,25 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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;
}

100
src/libfs/dirread.c Normal file
View file

@ -0,0 +1,100 @@
/* Mostly copied from Plan 9's libc. */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
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;
}

276
src/libfs/fs.c Normal file
View file

@ -0,0 +1,276 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.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
{
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; i<Fidchunk; i++){
f[i].fid = fs->nextfid++;
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;
}

41
src/libfs/fsimpl.h Normal file
View file

@ -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 <mux.h>
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*);

22
src/libfs/mkfile Normal file
View file

@ -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

24
src/libfs/open.c Normal file
View file

@ -0,0 +1,24 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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;
}

48
src/libfs/read.c Normal file
View file

@ -0,0 +1,48 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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);
}

54
src/libfs/stat.c Normal file
View file

@ -0,0 +1,54 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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;
}

73
src/libfs/walk.c Normal file
View file

@ -0,0 +1,73 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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;
}

46
src/libfs/write.c Normal file
View file

@ -0,0 +1,46 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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);
}

49
src/libfs/wstat.c Normal file
View file

@ -0,0 +1,49 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#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;
}

27
src/libmux/COPYRIGHT Normal file
View file

@ -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.

136
src/libmux/io.c Normal file
View file

@ -0,0 +1,136 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <mux.h>
/*
* 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;
}

16
src/libmux/mkfile Normal file
View file

@ -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

152
src/libmux/mux.c Normal file
View file

@ -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 <u.h>
#include <libc.h>
#include <mux.h>
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; i<mux->mwait; 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);
}

109
src/libmux/queue.c Normal file
View file

@ -0,0 +1,109 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <mux.h>
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);
}

27
src/libmux/thread.c Normal file
View file

@ -0,0 +1,27 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <mux.h>
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);
}