File system stuff.
This commit is contained in:
parent
e97ceade5e
commit
d3df308747
29 changed files with 3316 additions and 0 deletions
41
include/fs.h
Normal file
41
include/fs.h
Normal 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
54
include/mux.h
Normal 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
191
src/cmd/9p.c
Normal 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
597
src/cmd/9pserve.c
Normal 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
95
src/lib9/convD2M.c
Normal 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
94
src/lib9/convM2D.c
Normal 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
315
src/lib9/convM2S.c
Normal 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
386
src/lib9/convS2M.c
Normal 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
234
src/lib9/fcallfmt.c
Normal 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
31
src/lib9/read9pmsg.c
Normal 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
27
src/libfs/COPYRIGHT
Normal 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
26
src/libfs/close.c
Normal 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
25
src/libfs/create.c
Normal 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
100
src/libfs/dirread.c
Normal 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
276
src/libfs/fs.c
Normal 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
41
src/libfs/fsimpl.h
Normal 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
22
src/libfs/mkfile
Normal 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
24
src/libfs/open.c
Normal 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
48
src/libfs/read.c
Normal 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
54
src/libfs/stat.c
Normal 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
73
src/libfs/walk.c
Normal 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
46
src/libfs/write.c
Normal 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
49
src/libfs/wstat.c
Normal 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
27
src/libmux/COPYRIGHT
Normal 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
136
src/libmux/io.c
Normal 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
16
src/libmux/mkfile
Normal 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
152
src/libmux/mux.c
Normal 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
109
src/libmux/queue.c
Normal 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
27
src/libmux/thread.c
Normal 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);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue