#include <lib9.h>#include "ninep.h"#include "ninepserver.h"#include "ninepaux.h" #define MAXSTAT 512#define EMSGLEN 256 /* %r */ #define HASHSZ 32 /* power of 2 */ static unsigned long boottime;static char* eve = "eve";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"; enum{ CDISC = 01, CNREAD = 02, CRECV = 04,}; typedef struct Parent Parent;typedef struct Walkqid Walkqid; struct Fid{ Client *client; Fid *next; Parent *parent; short fid; ushort open; ushort mode; /* read/write */ ulong offset; /* in file */ int dri; /* dirread index */ Qid qid;}; struct Parent{ Ninepfile *file; Parent *parent;}; struct Walkqid{ Fid *clone; int nqid; Qid qid[1];}; #define ASSERT(A,B) ninepassert((int)A,B) extern time_t time(time_t *t); static int hash(int);static void deletefids(Client*);static Pending* findpending(Client*, ushort); staticvoidninepfatal(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); ninepexit(1);} staticvoidninepassert(int true, char *reason){ if(!true) ninepfatal("assertion failed: %s\n", reason);} void *ninepmalloc(int bytes){ char *m = malloc(bytes); if(m == nil) ninepfatal(Enomem); memset(m, 0, bytes); return m;} voidninepfree(void *p){ free(p);} voidninepdebug(){ Debug = 1;} staticClient *newclient(Ninepserver *server, int fd){ Client *c = (Client *)ninepmalloc(sizeof(Client)); if(Debug) fprint(2, "New client at fd %d\n", fd); c->server = server; c->fd = fd; c->nread = 0; c->nc = 0; c->state = 0; c->fids = nil; c->pending = (Pending**)ninepmalloc(HASHSZ*sizeof(Pending*)); c->uname = strdup(eve); c->aname = strdup(""); c->next = server->clients; server->clients = c; if(server->ops->newclient) server->ops->newclient(c); return c;} staticvoidfreeclient(Client *c){ Client **p; Ninepserver *server; if(Debug) fprint(2, "Freeing client at fd %d\n", c->fd); server = c->server; if(server->ops->freeclient) server->ops->freeclient(c); for(p = &server->clients; *p; p = &(*p)->next) if(*p == c){ ninepclosesocket(c->fd); *p = c->next; deletefids(c); free(c->uname); free(c->aname); ninepfree(c); return; }} staticintnbread(Client *c, int nr){ int nb; if(c->state&CDISC) return -1; nb = nineprecv(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;} staticintrd(Client *c, Fcall *f){ memset(c->data, 0, sizeof(c->data)); if(c->nc > 0){ /* last convM2S consumed nc bytes */ c->nread -= c->nc; if((int)c->nread < 0){ f->ename = "negative size in rd"; return -1; } memmove(c->msg, c->msg+c->nc, c->nread); c->nc = 0; c->nc = convM2S((uchar*)(c->msg), c->nread, f); if(c->nc > 0){ if(c->nread == c->nc) c->state &= ~CRECV; goto Newmsg; } } if(c->state&CRECV){ if(nbread(c, MSGMAX - c->nread) != 0){ f->ename = "unexpected EOF"; return -1; } c->state &= ~CRECV; } c->nc = convM2S((uchar*)(c->msg), c->nread, f);Newmsg: if(c->nc < 0){ f->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;} staticintwr(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 ninepsend(c->server, c->fd, buf, n, 0);} staticvoidsremove(Ninepserver *server, Ninepfile *f){ Ninepfile *s, *next, **p; if(f == nil) return; 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; } ninepfree(f->d.name); ninepfree(f->d.uid); ninepfree(f->d.gid); ninepfree(f);} intnineprmfile(Ninepserver *server, Path qid){ Ninepfile *f; f = ninepfindfile(server, qid); if(f != nil){ if(f->parent == nil) return -1; sremove(server, f); return 0; } return -1;} staticvoidincref(Ninepfile *f){ if(f != nil) f->ref++;} staticvoiddecref(Ninepfile *f){ if(f != nil) --f->ref;} staticvoidincreff(Fid *f){ incref(ninepfindfile(f->client->server, f->qid.path));} staticvoiddecreff(Fid *f){ decref(ninepfindfile(f->client->server, f->qid.path));} staticvoidincopen(Fid *f){ Ninepfile *file; if(f->open && (file = ninepfindfile(f->client->server, f->qid.path)) != nil) file->open++;} staticvoiddecopen(Fid *f){ Ninepfile *file; if(f->open && (file = ninepfindfile(f->client->server, f->qid.path)) != nil) file->open--;} intninepperm(Ninepfile *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;} staticinthash(int n){ return n&(HASHSZ-1);} Ninepfile *ninepfindfile(Ninepserver *server, Path path){ Ninepfile *f; for(f = server->ftab[hash(path)]; f != nil; f = f->next){ if(f->d.qid.path == path) return f; } return nil;} staticFid *findfid(Client *c, short fid){ Fid *f; for(f = c->fids; f && f->fid != fid; f = f->next) ; return f;} staticvoiddeletefid(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; ninepfree(d); return; }} staticvoiddeletefids(Client *c){ Fid *f, *g; for(f = c->fids; f; f = g){ decreff(f); decopen(f); g = f->next; ninepfree(f); }} Fid *newfid(Client *c, short fid, Qid qid){ Fid *f; f = ninepmalloc(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;} inteqqid(Qid a, Qid b){ return a.path == b.path && a.vers == b.vers;} staticFid *fidclone(Fid *old, short fid){ Fid *new; new = newfid(old->client, fid, old->qid); return new;} staticNinepfile *nextfile(Ninepfile *f, int first){ static int n, cap; static Ninepfile **nf; if(first) n = 0; if(f == nil && n > 0) f = nf[--n]; if(f == nil || f->bind == nil) return f; if(n == cap){ cap = (cap == 0) ? 12 : cap * 3/2; nf = realloc(nf, cap); } nf[n++] = f->sibling; return nextfile(f->bind->child, 0);} staticWalkqid*devwalk(Client *c, Ninepfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err){ Ninepserver *server; long j; Walkqid *wq; char *n; Ninepfile *p, *f; Ninepops *ops; Parent *parent; Qid qid; *err = nil; server = c->server; ops = server->ops; wq = ninepmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));Lines 1–500 of 1234. Load more
#include <lib9.h> #include "ninep.h" #include "ninepserver.h" #include "ninepaux.h" #define MAXSTAT 512 #define EMSGLEN 256 /* %r */ #define HASHSZ 32 /* power of 2 */ static unsigned long boottime; static char* eve = "eve"; 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"; enum{ CDISC = 01, CNREAD = 02, CRECV = 04, }; typedef struct Parent Parent; typedef struct Walkqid Walkqid; struct Fid { Client *client; Fid *next; Parent *parent; short fid; ushort open; ushort mode; /* read/write */ ulong offset; /* in file */ int dri; /* dirread index */ Qid qid; }; struct Parent { Ninepfile *file; Parent *parent; }; struct Walkqid { Fid *clone; int nqid; Qid qid[1]; }; #define ASSERT(A,B) ninepassert((int)A,B) extern time_t time(time_t *t); static int hash(int); static void deletefids(Client*); static Pending* findpending(Client*, ushort); static void ninepfatal(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); ninepexit(1); } static void ninepassert(int true, char *reason) { if(!true) ninepfatal("assertion failed: %s\n", reason); } void * ninepmalloc(int bytes) { char *m = malloc(bytes); if(m == nil) ninepfatal(Enomem); memset(m, 0, bytes); return m; } void ninepfree(void *p) { free(p); } void ninepdebug() { Debug = 1; } static Client * newclient(Ninepserver *server, int fd) { Client *c = (Client *)ninepmalloc(sizeof(Client)); if(Debug) fprint(2, "New client at fd %d\n", fd); c->server = server; c->fd = fd; c->nread = 0; c->nc = 0; c->state = 0; c->fids = nil; c->pending = (Pending**)ninepmalloc(HASHSZ*sizeof(Pending*)); c->uname = strdup(eve); c->aname = strdup(""); c->next = server->clients; server->clients = c; if(server->ops->newclient) server->ops->newclient(c); return c; } static void freeclient(Client *c) { Client **p; Ninepserver *server; if(Debug) fprint(2, "Freeing client at fd %d\n", c->fd); server = c->server; if(server->ops->freeclient) server->ops->freeclient(c); for(p = &server->clients; *p; p = &(*p)->next) if(*p == c){ ninepclosesocket(c->fd); *p = c->next; deletefids(c); free(c->uname); free(c->aname); ninepfree(c); return; } } static int nbread(Client *c, int nr) { int nb; if(c->state&CDISC) return -1; nb = nineprecv(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 *f) { memset(c->data, 0, sizeof(c->data)); if(c->nc > 0){ /* last convM2S consumed nc bytes */ c->nread -= c->nc; if((int)c->nread < 0){ f->ename = "negative size in rd"; return -1; } memmove(c->msg, c->msg+c->nc, c->nread); c->nc = 0; c->nc = convM2S((uchar*)(c->msg), c->nread, f); if(c->nc > 0){ if(c->nread == c->nc) c->state &= ~CRECV; goto Newmsg; } } if(c->state&CRECV){ if(nbread(c, MSGMAX - c->nread) != 0){ f->ename = "unexpected EOF"; return -1; } c->state &= ~CRECV; } c->nc = convM2S((uchar*)(c->msg), c->nread, f); Newmsg: if(c->nc < 0){ f->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 ninepsend(c->server, c->fd, buf, n, 0); } static void sremove(Ninepserver *server, Ninepfile *f) { Ninepfile *s, *next, **p; if(f == nil) return; 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; } ninepfree(f->d.name); ninepfree(f->d.uid); ninepfree(f->d.gid); ninepfree(f); } int nineprmfile(Ninepserver *server, Path qid) { Ninepfile *f; f = ninepfindfile(server, qid); if(f != nil){ if(f->parent == nil) return -1; sremove(server, f); return 0; } return -1; } static void incref(Ninepfile *f) { if(f != nil) f->ref++; } static void decref(Ninepfile *f) { if(f != nil) --f->ref; } static void increff(Fid *f) { incref(ninepfindfile(f->client->server, f->qid.path)); } static void decreff(Fid *f) { decref(ninepfindfile(f->client->server, f->qid.path)); } static void incopen(Fid *f) { Ninepfile *file; if(f->open && (file = ninepfindfile(f->client->server, f->qid.path)) != nil) file->open++; } static void decopen(Fid *f) { Ninepfile *file; if(f->open && (file = ninepfindfile(f->client->server, f->qid.path)) != nil) file->open--; } int ninepperm(Ninepfile *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(int n) { return n&(HASHSZ-1); } Ninepfile * ninepfindfile(Ninepserver *server, Path path) { Ninepfile *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; ninepfree(d); return; } } static void deletefids(Client *c) { Fid *f, *g; for(f = c->fids; f; f = g){ decreff(f); decopen(f); g = f->next; ninepfree(f); } } Fid * newfid(Client *c, short fid, Qid qid){ Fid *f; f = ninepmalloc(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; } 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 Ninepfile * nextfile(Ninepfile *f, int first) { static int n, cap; static Ninepfile **nf; if(first) n = 0; if(f == nil && n > 0) f = nf[--n]; if(f == nil || f->bind == nil) return f; if(n == cap){ cap = (cap == 0) ? 12 : cap * 3/2; nf = realloc(nf, cap); } nf[n++] = f->sibling; return nextfile(f->bind->child, 0); } static Walkqid* devwalk(Client *c, Ninepfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err) { Ninepserver *server; long j; Walkqid *wq; char *n; Ninepfile *p, *f; Ninepops *ops; Parent *parent; Qid qid; *err = nil; server = c->server; ops = server->ops; wq = ninepmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));