#include <stdint.h>#include <string.h>#include "c9/proto.h" enum{ Svver = 1<<0,}; #define safestrlen(s) (s == NULL ? 0 : (uint32_t)strlen(s))#define maxread(c) (c->msize-4-4-1-2)#define maxwrite(c) maxread(c) static voidw08(uint8_t **p, uint8_t x){ (*p)[0] = x; *p += 1;} static voidw16(uint8_t **p, uint16_t x){ (*p)[0] = x; (*p)[1] = x>>8; *p += 2;} static voidw32(uint8_t **p, uint32_t x){ (*p)[0] = x; (*p)[1] = x>>8; (*p)[2] = x>>16; (*p)[3] = x>>24; *p += 4;} static voidw64(uint8_t **p, uint64_t x){ (*p)[0] = x; (*p)[1] = x>>8; (*p)[2] = x>>16; (*p)[3] = x>>24; (*p)[4] = x>>32; (*p)[5] = x>>40; (*p)[6] = x>>48; (*p)[7] = x>>56; *p += 8;} static voidwcs(uint8_t **p, const char *s, int len){ w16(p, len); if(s != NULL){ memmove(*p, s, len); *p += len; }} static uint8_tr08(uint8_t **p){ *p += 1; return (*p)[-1];} static uint16_tr16(uint8_t **p){ *p += 2; return (*p)[-2]<<0 | (*p)[-1]<<8;} static uint32_tr32(uint8_t **p){ *p += 4; return (*p)[-4]<<0 | (*p)[-3]<<8 | (*p)[-2]<<16 | (uint32_t)((*p)[-1])<<24;} static uint64_tr64(uint8_t **p){ uint64_t v; v = r32(p); v |= (uint64_t)r32(p)<<32; return v;} #ifndef C9_NO_CLIENT static C9errornewtag(C9ctx *c, C9ttype type, C9tag *tag){ uint32_t i; if(type == Tversion){ *tag = 0xffff; return 0; } if(c->lowfreetag < C9maxtags){ uint32_t d = c->lowfreetag / C9tagsbits, m = c->lowfreetag % C9tagsbits; if((c->tags[d] & 1<<m) != 0){ c->tags[d] &= ~(1<<m); *tag = c->lowfreetag++; return 0; } } for(i = 0; i < (int)sizeof(c->tags)/sizeof(c->tags[0]); i++){ uint32_t x, j; if((x = c->tags[i]) == 0) continue; for(j = 0; j < C9tagsbits; j++){ if((x & (1<<j)) != 0){ c->tags[i] &= ~(1<<j); *tag = i*C9tagsbits + j; c->lowfreetag = *tag + 1; return 0; } } } c->error(c, "newtag: no free tags"); return C9Etag;} static intfreetag(C9ctx *c, C9tag tag){ if(tag != 0xffff){ uint32_t d = tag / C9tagsbits, m = tag % C9tagsbits; if(tag >= C9maxtags){ c->error(c, "freetag: invalid tag %ud", (uint32_t)tag); return -1; } if((c->tags[d] & 1<<m) != 0){ c->error(c, "freetag: double free for tag %ud", (uint32_t)tag); return -1; } if(c->lowfreetag > tag) c->lowfreetag = tag; c->tags[d] |= 1<<m; } return 0;} static uint8_t *T(C9ctx *c, uint32_t size, C9ttype type, C9tag *tag, C9error *err){ uint8_t *p = NULL; if(size > c->msize-4-1-2){ c->error(c, "T: invalid size %ud", size); *err = C9Esize; }else if((*err = newtag(c, type, tag)) == 0){ size += 4+1+2; if((p = c->begin(c, size)) == NULL){ c->error(c, "T: no buffer for %ud bytes", size); freetag(c, *tag); *err = C9Ebuf; }else{ *err = 0; w32(&p, size); w08(&p, type); w16(&p, *tag); } } return p;} C9errorc9version(C9ctx *c, C9tag *tag, uint32_t msize){ uint8_t *b; C9error err; if(msize < C9minmsize){ c->error(c, "c9version: msize too small: %ud", msize); return C9Einit; } memset(c->tags, 0xff, sizeof(c->tags)); memset(c->flush, 0xff, sizeof(c->flush)); c->lowfreetag = 0; c->msize = msize; if((b = T(c, 4+2+6, Tversion, tag, &err)) != NULL){ w32(&b, msize); wcs(&b, "9P2000", 6); err = c->end(c); } return err;} C9errorc9auth(C9ctx *c, C9tag *tag, C9fid afid, const char *uname, const char *aname){ uint8_t *b; uint32_t ulen = safestrlen(uname), alen = safestrlen(aname); C9error err; if(ulen > C9maxstr || alen > C9maxstr){ c->error(c, "c9auth: string too long: %ud chars", ulen > alen ? ulen : alen); return C9Estr; } if((b = T(c, 4+2+ulen+2+alen, Tauth, tag, &err)) != NULL){ w32(&b, afid); wcs(&b, uname, ulen); wcs(&b, aname, alen); err = c->end(c); } return err;} C9errorc9flush(C9ctx *c, C9tag *tag, C9tag oldtag){ uint8_t *b; C9error err; int i; for(i = 0; i < C9maxflush && c->flush[i] != (uint32_t)~0; i++); if(i == C9maxflush){ c->error(c, "c9flush: no free flush slots"); return C9Eflush; } if((b = T(c, 2, Tflush, tag, &err)) != NULL){ w16(&b, oldtag); err = c->end(c); if(err == 0) c->flush[i] = (uint32_t)oldtag<<16 | *tag; } return err;} C9errorc9attach(C9ctx *c, C9tag *tag, C9fid fid, C9fid afid, const char *uname, const char *aname){ uint32_t ulen = safestrlen(uname), alen = safestrlen(aname); uint8_t *b; C9error err; if(ulen > C9maxstr || alen > C9maxstr){ c->error(c, "c9attach: string too long: %ud chars", ulen > alen ? ulen : alen); return C9Estr; } if((b = T(c, 4+4+2+ulen+2+alen, Tattach, tag, &err)) != NULL){ w32(&b, fid); w32(&b, afid); wcs(&b, uname, ulen); wcs(&b, aname, alen); err = c->end(c); } return err;} C9errorc9walk(C9ctx *c, C9tag *tag, C9fid fid, C9fid newfid, const char *path[]){ uint32_t i, j, sz; uint32_t len[C9maxpathel]; uint8_t *b; C9error err; for(sz = i = 0; i < (int)sizeof(len)/sizeof(len[0]) && path[i] != NULL; i++){ len[i] = safestrlen(path[i]); if(len[i] == 0 || len[i] > C9maxstr){ c->error(c, "c9walk: invalid path element: %ud chars", len[i]); return C9Epath; } sz += 2 + len[i]; } if(path[i] != NULL){ c->error(c, "c9walk: invalid elements !(0 <= %ud <= %ud)", i, C9maxpathel); return C9Epath; } if((b = T(c, 4+4+2+sz, Twalk, tag, &err)) != NULL){ w32(&b, fid); w32(&b, newfid); w16(&b, i); for(j = 0; j < i; j++) wcs(&b, path[j], len[j]); err = c->end(c); } return err;} C9errorc9open(C9ctx *c, C9tag *tag, C9fid fid, C9mode mode){ uint8_t *b; C9error err; if((b = T(c, 4+1, Topen, tag, &err)) != NULL){ w32(&b, fid); w08(&b, mode); err = c->end(c); } return err;} C9errorc9create(C9ctx *c, C9tag *tag, C9fid fid, const char *name, uint32_t perm, C9mode mode){ uint32_t nlen = strlen(name); uint8_t *b; C9error err; if(nlen == 0 || nlen > C9maxstr){ c->error(c, "c9create: invalid name: %ud chars", nlen); return C9Epath; } if((b = T(c, 4+2+nlen+4+1, Tcreate, tag, &err)) != NULL){ w32(&b, fid); wcs(&b, name, nlen); w32(&b, perm); w08(&b, mode); err = c->end(c); } return err;} C9errorc9read(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, uint32_t count){ uint8_t *b; C9error err; if((b = T(c, 4+8+4, Tread, tag, &err)) != NULL){ w32(&b, fid); w64(&b, offset); w32(&b, count); err = c->end(c); } return err;} C9errorc9write(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, const void *in, uint32_t count){ uint8_t *b; C9error err; if((b = T(c, 4+8+4+count, Twrite, tag, &err)) != NULL){ w32(&b, fid); w64(&b, offset); w32(&b, count); memmove(b, in, count); err = c->end(c); } return err;} C9errorc9wrstr(C9ctx *c, C9tag *tag, C9fid fid, const char *s){ return c9write(c, tag, fid, 0, s, strlen(s));} C9errorc9clunk(C9ctx *c, C9tag *tag, C9fid fid){ uint8_t *b; C9error err; if((b = T(c, 4, Tclunk, tag, &err)) != NULL){ w32(&b, fid); err = c->end(c); } return err;} C9errorc9remove(C9ctx *c, C9tag *tag, C9fid fid){ uint8_t *b; C9error err; if((b = T(c, 4, Tremove, tag, &err)) != NULL){ w32(&b, fid); err = c->end(c); } return err;} C9errorc9stat(C9ctx *c, C9tag *tag, C9fid fid){ uint8_t *b; C9error err; if((b = T(c, 4, Tstat, tag, &err)) != NULL){ w32(&b, fid); err = c->end(c); } return err;} C9errorc9wstat(C9ctx *c, C9tag *tag, C9fid fid, const C9stat *s){ uint32_t nlen = safestrlen(s->name), ulen = safestrlen(s->uid), glen = safestrlen(s->gid); uint32_t unusedsz = 2+4+13, statsz = unusedsz+4+4+4+8+2+nlen+2+ulen+2+glen+2; uint8_t *b; C9error err; if(nlen == 0 || nlen > C9maxstr){ c->error(c, "c9wstat: invalid name: %ud chars", nlen); return C9Epath; } if(ulen > C9maxstr || glen > C9maxstr){ c->error(c, "c9wstat: string too long: %ud chars", ulen > glen ? ulen : glen); return C9Estr; } if((b = T(c, 4+2+2+statsz, Twstat, tag, &err)) != NULL){ w32(&b, fid); w16(&b, statsz+2); w16(&b, statsz); memset(b, 0xff, unusedsz); /* leave type(2), dev(4) and qid(13) unchanged */ b += unusedsz; w32(&b, s->mode); w32(&b, s->atime); w32(&b, s->mtime); w64(&b, s->size); wcs(&b, s->name, nlen); wcs(&b, s->uid, ulen); wcs(&b, s->gid, glen); wcs(&b, NULL, 0); /* muid unchanged */ err = c->end(c); } return err;} C9errorc9proc(C9ctx *c){ uint32_t i, sz, cnt, msize; uint8_t *b; int err; C9r r; err = -1; if((b = c->read(c, 4, &err)) == NULL){ if(err != 0) c->error(c, "c9proc: short read"); return err == 0 ? 0 : C9Epkt; } sz = r32(&b); if(sz < 7 || sz > c->msize){ c->error(c, "c9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); return C9Epkt; } sz -= 4; err = -1; if((b = c->read(c, sz, &err)) == NULL){ if(err != 0) c->error(c, "c9proc: short read"); return err == 0 ? 0 : C9Epkt; } r.type = r08(&b); r.tag = r16(&b); if(r.type != Rversion){ if(r.tag >= C9maxtags){ c->error(c, "c9proc: invalid tag %ud", (uint32_t)r.tag); return C9Epkt; } if(freetag(c, r.tag) != 0) return C9Etag; } sz -= 3; r.numqid = 0; switch(r.type){ case Rread: if(sz < 4 || (cnt = r32(&b)) > sz-4) goto error; r.read.data = b; r.read.size = cnt; c->r(c, &r); break; case Rwrite: if(sz < 4 || (cnt = r32(&b)) > c->msize) goto error; r.write.size = cnt; c->r(c, &r); break; case Rwalk: if(sz < 2 || (cnt = r16(&b))*13 > sz-2) goto error; if(cnt > C9maxpathel){Lines 1–500 of 1165. Load more
#include <stdint.h> #include <string.h> #include "c9/proto.h" enum { Svver = 1<<0, }; #define safestrlen(s) (s == NULL ? 0 : (uint32_t)strlen(s)) #define maxread(c) (c->msize-4-4-1-2) #define maxwrite(c) maxread(c) static void w08(uint8_t **p, uint8_t x) { (*p)[0] = x; *p += 1; } static void w16(uint8_t **p, uint16_t x) { (*p)[0] = x; (*p)[1] = x>>8; *p += 2; } static void w32(uint8_t **p, uint32_t x) { (*p)[0] = x; (*p)[1] = x>>8; (*p)[2] = x>>16; (*p)[3] = x>>24; *p += 4; } static void w64(uint8_t **p, uint64_t x) { (*p)[0] = x; (*p)[1] = x>>8; (*p)[2] = x>>16; (*p)[3] = x>>24; (*p)[4] = x>>32; (*p)[5] = x>>40; (*p)[6] = x>>48; (*p)[7] = x>>56; *p += 8; } static void wcs(uint8_t **p, const char *s, int len) { w16(p, len); if(s != NULL){ memmove(*p, s, len); *p += len; } } static uint8_t r08(uint8_t **p) { *p += 1; return (*p)[-1]; } static uint16_t r16(uint8_t **p) { *p += 2; return (*p)[-2]<<0 | (*p)[-1]<<8; } static uint32_t r32(uint8_t **p) { *p += 4; return (*p)[-4]<<0 | (*p)[-3]<<8 | (*p)[-2]<<16 | (uint32_t)((*p)[-1])<<24; } static uint64_t r64(uint8_t **p) { uint64_t v; v = r32(p); v |= (uint64_t)r32(p)<<32; return v; } #ifndef C9_NO_CLIENT static C9error newtag(C9ctx *c, C9ttype type, C9tag *tag) { uint32_t i; if(type == Tversion){ *tag = 0xffff; return 0; } if(c->lowfreetag < C9maxtags){ uint32_t d = c->lowfreetag / C9tagsbits, m = c->lowfreetag % C9tagsbits; if((c->tags[d] & 1<<m) != 0){ c->tags[d] &= ~(1<<m); *tag = c->lowfreetag++; return 0; } } for(i = 0; i < (int)sizeof(c->tags)/sizeof(c->tags[0]); i++){ uint32_t x, j; if((x = c->tags[i]) == 0) continue; for(j = 0; j < C9tagsbits; j++){ if((x & (1<<j)) != 0){ c->tags[i] &= ~(1<<j); *tag = i*C9tagsbits + j; c->lowfreetag = *tag + 1; return 0; } } } c->error(c, "newtag: no free tags"); return C9Etag; } static int freetag(C9ctx *c, C9tag tag) { if(tag != 0xffff){ uint32_t d = tag / C9tagsbits, m = tag % C9tagsbits; if(tag >= C9maxtags){ c->error(c, "freetag: invalid tag %ud", (uint32_t)tag); return -1; } if((c->tags[d] & 1<<m) != 0){ c->error(c, "freetag: double free for tag %ud", (uint32_t)tag); return -1; } if(c->lowfreetag > tag) c->lowfreetag = tag; c->tags[d] |= 1<<m; } return 0; } static uint8_t * T(C9ctx *c, uint32_t size, C9ttype type, C9tag *tag, C9error *err) { uint8_t *p = NULL; if(size > c->msize-4-1-2){ c->error(c, "T: invalid size %ud", size); *err = C9Esize; }else if((*err = newtag(c, type, tag)) == 0){ size += 4+1+2; if((p = c->begin(c, size)) == NULL){ c->error(c, "T: no buffer for %ud bytes", size); freetag(c, *tag); *err = C9Ebuf; }else{ *err = 0; w32(&p, size); w08(&p, type); w16(&p, *tag); } } return p; } C9error c9version(C9ctx *c, C9tag *tag, uint32_t msize) { uint8_t *b; C9error err; if(msize < C9minmsize){ c->error(c, "c9version: msize too small: %ud", msize); return C9Einit; } memset(c->tags, 0xff, sizeof(c->tags)); memset(c->flush, 0xff, sizeof(c->flush)); c->lowfreetag = 0; c->msize = msize; if((b = T(c, 4+2+6, Tversion, tag, &err)) != NULL){ w32(&b, msize); wcs(&b, "9P2000", 6); err = c->end(c); } return err; } C9error c9auth(C9ctx *c, C9tag *tag, C9fid afid, const char *uname, const char *aname) { uint8_t *b; uint32_t ulen = safestrlen(uname), alen = safestrlen(aname); C9error err; if(ulen > C9maxstr || alen > C9maxstr){ c->error(c, "c9auth: string too long: %ud chars", ulen > alen ? ulen : alen); return C9Estr; } if((b = T(c, 4+2+ulen+2+alen, Tauth, tag, &err)) != NULL){ w32(&b, afid); wcs(&b, uname, ulen); wcs(&b, aname, alen); err = c->end(c); } return err; } C9error c9flush(C9ctx *c, C9tag *tag, C9tag oldtag) { uint8_t *b; C9error err; int i; for(i = 0; i < C9maxflush && c->flush[i] != (uint32_t)~0; i++); if(i == C9maxflush){ c->error(c, "c9flush: no free flush slots"); return C9Eflush; } if((b = T(c, 2, Tflush, tag, &err)) != NULL){ w16(&b, oldtag); err = c->end(c); if(err == 0) c->flush[i] = (uint32_t)oldtag<<16 | *tag; } return err; } C9error c9attach(C9ctx *c, C9tag *tag, C9fid fid, C9fid afid, const char *uname, const char *aname) { uint32_t ulen = safestrlen(uname), alen = safestrlen(aname); uint8_t *b; C9error err; if(ulen > C9maxstr || alen > C9maxstr){ c->error(c, "c9attach: string too long: %ud chars", ulen > alen ? ulen : alen); return C9Estr; } if((b = T(c, 4+4+2+ulen+2+alen, Tattach, tag, &err)) != NULL){ w32(&b, fid); w32(&b, afid); wcs(&b, uname, ulen); wcs(&b, aname, alen); err = c->end(c); } return err; } C9error c9walk(C9ctx *c, C9tag *tag, C9fid fid, C9fid newfid, const char *path[]) { uint32_t i, j, sz; uint32_t len[C9maxpathel]; uint8_t *b; C9error err; for(sz = i = 0; i < (int)sizeof(len)/sizeof(len[0]) && path[i] != NULL; i++){ len[i] = safestrlen(path[i]); if(len[i] == 0 || len[i] > C9maxstr){ c->error(c, "c9walk: invalid path element: %ud chars", len[i]); return C9Epath; } sz += 2 + len[i]; } if(path[i] != NULL){ c->error(c, "c9walk: invalid elements !(0 <= %ud <= %ud)", i, C9maxpathel); return C9Epath; } if((b = T(c, 4+4+2+sz, Twalk, tag, &err)) != NULL){ w32(&b, fid); w32(&b, newfid); w16(&b, i); for(j = 0; j < i; j++) wcs(&b, path[j], len[j]); err = c->end(c); } return err; } C9error c9open(C9ctx *c, C9tag *tag, C9fid fid, C9mode mode) { uint8_t *b; C9error err; if((b = T(c, 4+1, Topen, tag, &err)) != NULL){ w32(&b, fid); w08(&b, mode); err = c->end(c); } return err; } C9error c9create(C9ctx *c, C9tag *tag, C9fid fid, const char *name, uint32_t perm, C9mode mode) { uint32_t nlen = strlen(name); uint8_t *b; C9error err; if(nlen == 0 || nlen > C9maxstr){ c->error(c, "c9create: invalid name: %ud chars", nlen); return C9Epath; } if((b = T(c, 4+2+nlen+4+1, Tcreate, tag, &err)) != NULL){ w32(&b, fid); wcs(&b, name, nlen); w32(&b, perm); w08(&b, mode); err = c->end(c); } return err; } C9error c9read(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, uint32_t count) { uint8_t *b; C9error err; if((b = T(c, 4+8+4, Tread, tag, &err)) != NULL){ w32(&b, fid); w64(&b, offset); w32(&b, count); err = c->end(c); } return err; } C9error c9write(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, const void *in, uint32_t count) { uint8_t *b; C9error err; if((b = T(c, 4+8+4+count, Twrite, tag, &err)) != NULL){ w32(&b, fid); w64(&b, offset); w32(&b, count); memmove(b, in, count); err = c->end(c); } return err; } C9error c9wrstr(C9ctx *c, C9tag *tag, C9fid fid, const char *s) { return c9write(c, tag, fid, 0, s, strlen(s)); } C9error c9clunk(C9ctx *c, C9tag *tag, C9fid fid) { uint8_t *b; C9error err; if((b = T(c, 4, Tclunk, tag, &err)) != NULL){ w32(&b, fid); err = c->end(c); } return err; } C9error c9remove(C9ctx *c, C9tag *tag, C9fid fid) { uint8_t *b; C9error err; if((b = T(c, 4, Tremove, tag, &err)) != NULL){ w32(&b, fid); err = c->end(c); } return err; } C9error c9stat(C9ctx *c, C9tag *tag, C9fid fid) { uint8_t *b; C9error err; if((b = T(c, 4, Tstat, tag, &err)) != NULL){ w32(&b, fid); err = c->end(c); } return err; } C9error c9wstat(C9ctx *c, C9tag *tag, C9fid fid, const C9stat *s) { uint32_t nlen = safestrlen(s->name), ulen = safestrlen(s->uid), glen = safestrlen(s->gid); uint32_t unusedsz = 2+4+13, statsz = unusedsz+4+4+4+8+2+nlen+2+ulen+2+glen+2; uint8_t *b; C9error err; if(nlen == 0 || nlen > C9maxstr){ c->error(c, "c9wstat: invalid name: %ud chars", nlen); return C9Epath; } if(ulen > C9maxstr || glen > C9maxstr){ c->error(c, "c9wstat: string too long: %ud chars", ulen > glen ? ulen : glen); return C9Estr; } if((b = T(c, 4+2+2+statsz, Twstat, tag, &err)) != NULL){ w32(&b, fid); w16(&b, statsz+2); w16(&b, statsz); memset(b, 0xff, unusedsz); /* leave type(2), dev(4) and qid(13) unchanged */ b += unusedsz; w32(&b, s->mode); w32(&b, s->atime); w32(&b, s->mtime); w64(&b, s->size); wcs(&b, s->name, nlen); wcs(&b, s->uid, ulen); wcs(&b, s->gid, glen); wcs(&b, NULL, 0); /* muid unchanged */ err = c->end(c); } return err; } C9error c9proc(C9ctx *c) { uint32_t i, sz, cnt, msize; uint8_t *b; int err; C9r r; err = -1; if((b = c->read(c, 4, &err)) == NULL){ if(err != 0) c->error(c, "c9proc: short read"); return err == 0 ? 0 : C9Epkt; } sz = r32(&b); if(sz < 7 || sz > c->msize){ c->error(c, "c9proc: invalid packet size !(7 <= %ud <= %ud)", sz, c->msize); return C9Epkt; } sz -= 4; err = -1; if((b = c->read(c, sz, &err)) == NULL){ if(err != 0) c->error(c, "c9proc: short read"); return err == 0 ? 0 : C9Epkt; } r.type = r08(&b); r.tag = r16(&b); if(r.type != Rversion){ if(r.tag >= C9maxtags){ c->error(c, "c9proc: invalid tag %ud", (uint32_t)r.tag); return C9Epkt; } if(freetag(c, r.tag) != 0) return C9Etag; } sz -= 3; r.numqid = 0; switch(r.type){ case Rread: if(sz < 4 || (cnt = r32(&b)) > sz-4) goto error; r.read.data = b; r.read.size = cnt; c->r(c, &r); break; case Rwrite: if(sz < 4 || (cnt = r32(&b)) > c->msize) goto error; r.write.size = cnt; c->r(c, &r); break; case Rwalk: if(sz < 2 || (cnt = r16(&b))*13 > sz-2) goto error; if(cnt > C9maxpathel){