#include <lib9.h>#include <styx.h>#include "styxserver.h"#include "styxaux.h" #define MAXSTAT 512#define EMSGLEN 256 /* %r */ #define TABSZ 32 /* power of 2 */ static unsigned long boottime;static char* eve = "inferno";static int Debug = 0; char Enomem[] = "out of memory";char Eperm[] = "permission denied";char Enodev[] = "no free devices";char Ehungup[] = "write to hungup channel";char Eexist[] = "file exists";char Enonexist[] = "file does not exist";char Ebadcmd[] = "bad command";char Ebadarg[] = "bad arg in system call";char Enofid[] = "no such fid";char Enotdir[] = "not a directory";char Eopen[] = "already open";char Ebadfid[] = "bad fid"; /* client state */enum{ CDISC = 01, CNREAD = 02, CRECV = 04,}; typedef struct Walkqid Walkqid; struct Fid{ Client *client; Fid *next; short fid; ushort open; ushort mode; /* read/write */ ulong offset; /* in file */ int dri; /* dirread index */ Qid qid;}; struct Walkqid{ Fid *clone; int nqid; Qid qid[1];}; #define ASSERT(A,B) styxassert((int)A,B) static int hash(Path);static void deletefids(Client *); static voidstyxfatal(char *fmt, ...){ char buf[1024], *out; va_list arg; out = seprint(buf, buf+sizeof(buf), "Fatal error: "); va_start(arg, fmt); out = vseprint(out, buf+sizeof(buf), fmt, arg); va_end(arg); write(2, buf, out-buf); styxexit(1);} static voidstyxassert(int true, char *reason){ if(!true) styxfatal("assertion failed: %s\n", reason);} void *styxmalloc(int bytes){ char *m = malloc(bytes); if(m == nil) styxfatal(Enomem); memset(m, 0, bytes); return m;} voidstyxfree(void *p){ free(p);} voidstyxdebug(){ Debug = 1;} static Client *newclient(Styxserver *server, int fd){ Client *c = (Client *)styxmalloc(sizeof(Client)); if(Debug) fprint(2, "New client at %lux\n", (ulong)c); c->server = server; c->fd = fd; c->nread = 0; c->nc = 0; c->state = 0; c->fids = nil; c->uname = strdup(eve); c->aname = strdup(eve); c->next = server->clients; server->clients = c; if(server->ops->newclient) server->ops->newclient(c); return c;} static voidfreeclient(Client *c){ Client **p; Styxserver *server; if(Debug) fprint(2, "Freeing client at %lux\n", (ulong)c); server = c->server; if(server->ops->freeclient) server->ops->freeclient(c); for(p = &server->clients; *p; p = &(*p)->next) if(*p == c){ styxclosesocket(c->fd); *p = c->next; deletefids(c); free(c->uname); free(c->aname); styxfree(c); return; }} static intnbread(Client *c, int nr){ int nb; if(c->state&CDISC) return -1; nb = styxrecv(c->server, c->fd, c->msg + c->nread, nr, 0); if(nb <= 0){ c->nread = 0; c->state |= CDISC; return -1; } c->nread += nb; return 0;} static intrd(Client *c, Fcall *r){ if(c->nc > 0){ /* last convM2S consumed nc bytes */ c->nread -= c->nc; if(c->nread < 0){ r->ename = "negative size in rd"; return -1; } memmove(c->msg, c->msg+c->nc, c->nread); c->nc = 0; } if(c->state&CRECV){ if(nbread(c, MSGMAX - c->nread) != 0){ r->ename = "unexpected EOF"; return -1; } c->state &= ~CRECV; } c->nc = convM2S((uchar*)(c->msg), c->nread, r); if(c->nc < 0){ r->ename = "bad message format"; return -1; } if(c->nc == 0 && c->nread > 0){ c->nread = 0; c->state &= ~CNREAD; return 0; } if(c->nread > c->nc) c->state |= CNREAD; else c->state &= ~CNREAD; if(c->nc == 0) return 0; /* fprint(2, "rd: %F\n", r); */ return 1;} static intwr(Client *c, Fcall *r){ int n; char buf[MSGMAX]; n = convS2M(r, (uchar*)buf, sizeof(buf)); if(n < 0){ r->ename = "bad message type in wr"; return -1; } /* fprint(2, "wr: %F\n", r); */ return styxsend(c->server, c->fd, buf, n, 0);} static voidsremove(Styxserver *server, Styxfile *f){ Styxfile *s, *next, **p; if(f == nil) return; if(Debug) fprint(2, "Remove file %s Qid=%llx\n", f->d.name, f->d.qid.path); if(f->d.qid.type&QTDIR) for(s = f->child; s != nil; s = next){ next = s->sibling; sremove(server, s); } for(p = &server->ftab[hash(f->d.qid.path)]; *p; p = &(*p)->next) if(*p == f){ *p = f->next; break; } for(p = &f->parent->child; *p; p = &(*p)->sibling) if(*p == f){ *p = f->sibling; break; } styxfree(f->d.name); styxfree(f->d.uid); styxfree(f->d.gid); styxfree(f);} intstyxrmfile(Styxserver *server, Path qid){ Styxfile *f; f = styxfindfile(server, qid); if(f != nil){ if(f->parent == nil) return -1; sremove(server, f); return 0; } return -1;} static voidincref(Styxfile *f){ if(f != nil) f->ref++;} static voiddecref(Styxfile *f){ if(f != nil) --f->ref;} static voidincreff(Fid *f){ incref(styxfindfile(f->client->server, f->qid.path));} static voiddecreff(Fid *f){ decref(styxfindfile(f->client->server, f->qid.path));} static voidincopen(Fid *f){ Styxfile *file; if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) file->open++;} static voiddecopen(Fid *f){ Styxfile *file; if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) file->open--;} intstyxperm(Styxfile *f, char *uid, int mode){ int m, p; p = 0; switch(mode&3){ case OREAD: p = AREAD; break; case OWRITE: p = AWRITE; break; case ORDWR: p = AREAD+AWRITE; break; case OEXEC: p = AEXEC; break; } if(mode&OTRUNC) p |= AWRITE; m = f->d.mode&7; if((p&m) == p) return 1; if(strcmp(f->d.uid, uid) == 0){ m |= (f->d.mode>>6)&7; if((p&m) == p) return 1; } if(strcmp(f->d.gid, uid) == 0){ m |= (f->d.mode>>3)&7; if((p&m) == p) return 1; } return 0;} static inthash(Path path){ return path&(TABSZ-1);} Styxfile *styxfindfile(Styxserver *server, Path path){ Styxfile *f; for(f = server->ftab[hash(path)]; f != nil; f = f->next){ if(f->d.qid.path == path) return f; } return nil;} static Fid *findfid(Client *c, short fid){ Fid *f; for(f = c->fids; f && f->fid != fid; f = f->next) ; return f;} static voiddeletefid(Client *c, Fid *d){ /* TODO: end any outstanding reads on this fid */ Fid **f; for(f = &c->fids; *f; f = &(*f)->next) if(*f == d){ decreff(d); decopen(d); *f = d->next; styxfree(d); return; }} static voiddeletefids(Client *c){ Fid *f, *g; for(f = c->fids; f; f = g){ decreff(f); decopen(f); g = f->next; styxfree(f); }} Fid *newfid(Client *c, short fid, Qid qid){ Fid *f; f = styxmalloc(sizeof(Fid)); ASSERT(f, "newfid"); f->client = c; f->fid = fid; f->open = 0; f->dri = 0; f->qid = qid; f->next = c->fids; c->fids = f; increff(f); return f;} static voidflushtag(int oldtag){ USED(oldtag);} inteqqid(Qid a, Qid b){ return a.path == b.path && a.vers == b.vers;} static Fid *fidclone(Fid *old, short fid){ Fid *new; new = newfid(old->client, fid, old->qid); return new;} static Walkqid*devwalk(Client *c, Styxfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err){ Styxserver *server; long j; Walkqid *wq; char *n; Styxfile *p, *f; Styxops *ops; Qid qid; *err = nil; server = c->server; ops = server->ops; wq = styxmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); wq->nqid = 0; p = file; qid = p != nil ? p->d.qid : fp->qid; for(j = 0; j < nname; j++){ if(!(qid.type&QTDIR)){ if(j == 0) styxfatal("devwalk error"); *err = Enotdir; goto Done; } if(p != nil && !styxperm(p, c->uname, OEXEC)){ *err = Eperm; goto Done; } n = name[j]; if(strcmp(n, ".") == 0){ Accept: wq->qid[wq->nqid++] = nfp->qid; continue; } if(p != nil && strcmp(n, "..") == 0 && p->parent){ decref(p); nfp->qid.path = p->parent->d.qid.path; nfp->qid.type = p->parent->d.qid.type; nfp->qid.vers = 0; incref(p->parent); p = p->parent; qid = p->d.qid; goto Accept; } if(ops->walk != nil){ char *e; e = ops->walk(&qid, n); if(e == nil){ decreff(nfp); nfp->qid = qid; increff(nfp); p = styxfindfile(server, qid.path); if(server->needfile && p == nil) goto Done; qid = p != nil ? p->d.qid : nfp->qid; goto Accept; } } if(p != nil) for(f = p->child; f != nil; f = f->sibling){ if(strcmp(n, f->d.name) == 0){ decref(p); nfp->qid.path = f->d.qid.path;Lines 1–500 of 1067. Load more
#include <lib9.h> #include <styx.h> #include "styxserver.h" #include "styxaux.h" #define MAXSTAT 512 #define EMSGLEN 256 /* %r */ #define TABSZ 32 /* power of 2 */ static unsigned long boottime; static char* eve = "inferno"; static int Debug = 0; char Enomem[] = "out of memory"; char Eperm[] = "permission denied"; char Enodev[] = "no free devices"; char Ehungup[] = "write to hungup channel"; char Eexist[] = "file exists"; char Enonexist[] = "file does not exist"; char Ebadcmd[] = "bad command"; char Ebadarg[] = "bad arg in system call"; char Enofid[] = "no such fid"; char Enotdir[] = "not a directory"; char Eopen[] = "already open"; char Ebadfid[] = "bad fid"; /* client state */ enum{ CDISC = 01, CNREAD = 02, CRECV = 04, }; typedef struct Walkqid Walkqid; struct Fid { Client *client; Fid *next; short fid; ushort open; ushort mode; /* read/write */ ulong offset; /* in file */ int dri; /* dirread index */ Qid qid; }; struct Walkqid { Fid *clone; int nqid; Qid qid[1]; }; #define ASSERT(A,B) styxassert((int)A,B) static int hash(Path); static void deletefids(Client *); static void styxfatal(char *fmt, ...) { char buf[1024], *out; va_list arg; out = seprint(buf, buf+sizeof(buf), "Fatal error: "); va_start(arg, fmt); out = vseprint(out, buf+sizeof(buf), fmt, arg); va_end(arg); write(2, buf, out-buf); styxexit(1); } static void styxassert(int true, char *reason) { if(!true) styxfatal("assertion failed: %s\n", reason); } void * styxmalloc(int bytes) { char *m = malloc(bytes); if(m == nil) styxfatal(Enomem); memset(m, 0, bytes); return m; } void styxfree(void *p) { free(p); } void styxdebug() { Debug = 1; } static Client * newclient(Styxserver *server, int fd) { Client *c = (Client *)styxmalloc(sizeof(Client)); if(Debug) fprint(2, "New client at %lux\n", (ulong)c); c->server = server; c->fd = fd; c->nread = 0; c->nc = 0; c->state = 0; c->fids = nil; c->uname = strdup(eve); c->aname = strdup(eve); c->next = server->clients; server->clients = c; if(server->ops->newclient) server->ops->newclient(c); return c; } static void freeclient(Client *c) { Client **p; Styxserver *server; if(Debug) fprint(2, "Freeing client at %lux\n", (ulong)c); server = c->server; if(server->ops->freeclient) server->ops->freeclient(c); for(p = &server->clients; *p; p = &(*p)->next) if(*p == c){ styxclosesocket(c->fd); *p = c->next; deletefids(c); free(c->uname); free(c->aname); styxfree(c); return; } } static int nbread(Client *c, int nr) { int nb; if(c->state&CDISC) return -1; nb = styxrecv(c->server, c->fd, c->msg + c->nread, nr, 0); if(nb <= 0){ c->nread = 0; c->state |= CDISC; return -1; } c->nread += nb; return 0; } static int rd(Client *c, Fcall *r) { if(c->nc > 0){ /* last convM2S consumed nc bytes */ c->nread -= c->nc; if(c->nread < 0){ r->ename = "negative size in rd"; return -1; } memmove(c->msg, c->msg+c->nc, c->nread); c->nc = 0; } if(c->state&CRECV){ if(nbread(c, MSGMAX - c->nread) != 0){ r->ename = "unexpected EOF"; return -1; } c->state &= ~CRECV; } c->nc = convM2S((uchar*)(c->msg), c->nread, r); if(c->nc < 0){ r->ename = "bad message format"; return -1; } if(c->nc == 0 && c->nread > 0){ c->nread = 0; c->state &= ~CNREAD; return 0; } if(c->nread > c->nc) c->state |= CNREAD; else c->state &= ~CNREAD; if(c->nc == 0) return 0; /* fprint(2, "rd: %F\n", r); */ return 1; } static int wr(Client *c, Fcall *r) { int n; char buf[MSGMAX]; n = convS2M(r, (uchar*)buf, sizeof(buf)); if(n < 0){ r->ename = "bad message type in wr"; return -1; } /* fprint(2, "wr: %F\n", r); */ return styxsend(c->server, c->fd, buf, n, 0); } static void sremove(Styxserver *server, Styxfile *f) { Styxfile *s, *next, **p; if(f == nil) return; if(Debug) fprint(2, "Remove file %s Qid=%llx\n", f->d.name, f->d.qid.path); if(f->d.qid.type&QTDIR) for(s = f->child; s != nil; s = next){ next = s->sibling; sremove(server, s); } for(p = &server->ftab[hash(f->d.qid.path)]; *p; p = &(*p)->next) if(*p == f){ *p = f->next; break; } for(p = &f->parent->child; *p; p = &(*p)->sibling) if(*p == f){ *p = f->sibling; break; } styxfree(f->d.name); styxfree(f->d.uid); styxfree(f->d.gid); styxfree(f); } int styxrmfile(Styxserver *server, Path qid) { Styxfile *f; f = styxfindfile(server, qid); if(f != nil){ if(f->parent == nil) return -1; sremove(server, f); return 0; } return -1; } static void incref(Styxfile *f) { if(f != nil) f->ref++; } static void decref(Styxfile *f) { if(f != nil) --f->ref; } static void increff(Fid *f) { incref(styxfindfile(f->client->server, f->qid.path)); } static void decreff(Fid *f) { decref(styxfindfile(f->client->server, f->qid.path)); } static void incopen(Fid *f) { Styxfile *file; if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) file->open++; } static void decopen(Fid *f) { Styxfile *file; if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) file->open--; } int styxperm(Styxfile *f, char *uid, int mode) { int m, p; p = 0; switch(mode&3){ case OREAD: p = AREAD; break; case OWRITE: p = AWRITE; break; case ORDWR: p = AREAD+AWRITE; break; case OEXEC: p = AEXEC; break; } if(mode&OTRUNC) p |= AWRITE; m = f->d.mode&7; if((p&m) == p) return 1; if(strcmp(f->d.uid, uid) == 0){ m |= (f->d.mode>>6)&7; if((p&m) == p) return 1; } if(strcmp(f->d.gid, uid) == 0){ m |= (f->d.mode>>3)&7; if((p&m) == p) return 1; } return 0; } static int hash(Path path) { return path&(TABSZ-1); } Styxfile * styxfindfile(Styxserver *server, Path path) { Styxfile *f; for(f = server->ftab[hash(path)]; f != nil; f = f->next){ if(f->d.qid.path == path) return f; } return nil; } static Fid * findfid(Client *c, short fid) { Fid *f; for(f = c->fids; f && f->fid != fid; f = f->next) ; return f; } static void deletefid(Client *c, Fid *d) { /* TODO: end any outstanding reads on this fid */ Fid **f; for(f = &c->fids; *f; f = &(*f)->next) if(*f == d){ decreff(d); decopen(d); *f = d->next; styxfree(d); return; } } static void deletefids(Client *c) { Fid *f, *g; for(f = c->fids; f; f = g){ decreff(f); decopen(f); g = f->next; styxfree(f); } } Fid * newfid(Client *c, short fid, Qid qid){ Fid *f; f = styxmalloc(sizeof(Fid)); ASSERT(f, "newfid"); f->client = c; f->fid = fid; f->open = 0; f->dri = 0; f->qid = qid; f->next = c->fids; c->fids = f; increff(f); return f; } static void flushtag(int oldtag) { USED(oldtag); } int eqqid(Qid a, Qid b) { return a.path == b.path && a.vers == b.vers; } static Fid * fidclone(Fid *old, short fid) { Fid *new; new = newfid(old->client, fid, old->qid); return new; } static Walkqid* devwalk(Client *c, Styxfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err) { Styxserver *server; long j; Walkqid *wq; char *n; Styxfile *p, *f; Styxops *ops; Qid qid; *err = nil; server = c->server; ops = server->ops; wq = styxmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); wq->nqid = 0; p = file; qid = p != nil ? p->d.qid : fp->qid; for(j = 0; j < nname; j++){ if(!(qid.type&QTDIR)){ if(j == 0) styxfatal("devwalk error"); *err = Enotdir; goto Done; } if(p != nil && !styxperm(p, c->uname, OEXEC)){ *err = Eperm; goto Done; } n = name[j]; if(strcmp(n, ".") == 0){ Accept: wq->qid[wq->nqid++] = nfp->qid; continue; } if(p != nil && strcmp(n, "..") == 0 && p->parent){ decref(p); nfp->qid.path = p->parent->d.qid.path; nfp->qid.type = p->parent->d.qid.type; nfp->qid.vers = 0; incref(p->parent); p = p->parent; qid = p->d.qid; goto Accept; } if(ops->walk != nil){ char *e; e = ops->walk(&qid, n); if(e == nil){ decreff(nfp); nfp->qid = qid; increff(nfp); p = styxfindfile(server, qid.path); if(server->needfile && p == nil) goto Done; qid = p != nil ? p->d.qid : nfp->qid; goto Accept; } } if(p != nil) for(f = p->child; f != nil; f = f->sibling){ if(strcmp(n, f->d.name) == 0){ decref(p); nfp->qid.path = f->d.qid.path;