ref: 029d0dddbb30252237d37c426da70d74b8bb4d45
parent: 54ff6c3406e158066ebe40b243e698ccbd4f2f51
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Thu May 7 13:02:20 EDT 2020
remove old c9
--- a/c9/LICENSE
+++ /dev/null
@@ -1,1 +1,0 @@
-Public domain.
--- a/c9/README.md
+++ /dev/null
@@ -1,8 +1,0 @@
-# c9
-
-Low level 9p client and server.
-
-## Examples
-
-Until I have time to write a minimal example you could take a look at
-https://github.com/ftrvxmtrx/9pro/blob/master/9pex.c
--- a/c9/c9.c
+++ /dev/null
@@ -1,1170 +1,0 @@
-/*
- * This is 9p client and server implementation which aims to be
- * correct, small and secure. It's the lowest level implementation.
- * It doesn't have much comments, mostly because it doesn't make
- * any sense to copy-paste protocol documentation, which
- * you can read at http://man.cat-v.org/plan_9/5/, see 'intro'.
- */
-#include <stdint.h>
-#include <string.h>
-#include "c9.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 (uint16_t)(*p)[-2]<<0 | (uint16_t)(*p)[-1]<<8;
-}
-
-static uint32_t
-r32(uint8_t **p)
-{
- return r16(p) | (uint32_t)r16(p)<<16;
-}
-
-static uint64_t
-r64(uint8_t **p)
-{
- return r32(p) | (uint64_t)r32(p)<<32;
-}
-
-#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("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("freetag: invalid tag %u", (uint32_t)tag);
- return -1;
- }
- if((c->tags[d] & 1<<m) != 0){
- c->error("freetag: double free for tag %u", (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("T: invalid size %u", size);
- *err = C9Esize;
- }else if((*err = newtag(c, type, tag)) == 0){
- size += 4+1+2;
- if((p = c->begin(c, size)) == NULL){
- c->error("T: no buffer for %u 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("c9version: msize too small: %u", 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("c9auth: string too long: %u 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("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("c9attach: string too long: %u 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("c9walk: invalid path element: %u chars", len[i]);
- return C9Epath;
- }
- sz += 2 + len[i];
- }
- if(path[i] != NULL || i == 0){
- c->error("c9walk: invalid elements !(0 < %u <= %u)", 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("c9create: invalid name: %u 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("c9wstat: invalid name: %u chars", nlen);
- return C9Epath;
- }
- if(ulen > C9maxstr || glen > C9maxstr){
- c->error("c9wstat: string too long: %u 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("c9proc: short read");
- return err == 0 ? 0 : C9Epkt;
- }
-
- sz = r32(&b);
- if(sz < 7 || sz > c->msize){
- c->error("c9proc: invalid packet size !(7 <= %u <= %u)", sz, c->msize);
- return C9Epkt;
- }
- sz -= 4;
- err = -1;
- if((b = c->read(c, sz, &err)) == NULL){
- if(err != 0)
- c->error("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("c9proc: invalid tag %u", (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+13 || (cnt = r16(&b))*13 > sz-2)
- goto error;
- if(cnt > C9maxpathel){
- c->error("c9proc: Rwalk !(%u <= %u)", cnt, C9maxpathel);
- return C9Epath;
- }
- for(i = 0; i < cnt; i++){
- r.qid[i].type = r08(&b);
- r.qid[i].version = r32(&b);
- r.qid[i].path = r64(&b);
- }
- r.numqid = cnt;
- c->r(c, &r);
- break;
-
- case Rstat:
- b += 2; sz -= 2;
- if((err = c9parsedir(c, &r.stat, &b, &sz)) != 0)
- return err;
- r.numqid = 1;
- c->r(c, &r);
- break;
-
- case Rflush:
- for(i = 0; i < C9maxflush; i++){
- if((c->flush[i] & 0xffff) == r.tag){
- freetag(c, c->flush[i]>>16);
- c->flush[i] = 0xffffffff;
- break;
- }
- }
- /* fallthrough */
- case Rclunk:
- case Rremove:
- case Rwstat:
- c->r(c, &r);
- break;
-
- case Ropen:
- case Rcreate:
- if(sz < 17)
- goto error;
- r.qid[0].type = r08(&b);
- r.qid[0].version = r32(&b);
- r.qid[0].path = r64(&b);
- r.iounit = r32(&b);
- r.numqid = 1;
- c->r(c, &r);
- break;
-
- case Rerror:
- if(sz < 2 || (cnt = r16(&b)) > sz-2)
- goto error;
- r.error = memmove(b-1, b, cnt);
- r.error[cnt] = 0;
- c->r(c, &r);
- break;
-
- case Rauth:
- case Rattach:
- if(sz < 13)
- goto error;
- r.qid[0].type = r08(&b);
- r.qid[0].version = r32(&b);
- r.qid[0].path = r64(&b);
- r.numqid = 1;
- c->r(c, &r);
- break;
-
- case Rversion:
- if(sz < 4+2 || (msize = r32(&b)) < C9minmsize || (cnt = r16(&b)) > sz-4-2)
- goto error;
- if(cnt < 6 || memcmp(b, "9P2000", 6) != 0){
- c->error("invalid version");
- return C9Ever;
- }
- if(msize < c->msize)
- c->msize = msize;
- c->r(c, &r);
- break;
-
- default:
- goto error;
- }
- return 0;
-error:
- c->error("c9proc: invalid packet type %u", r.type);
- return C9Epkt;
-}
-
-#endif /* C9_NO_CLIENT */
-
-C9error
-c9parsedir(C9ctx *c, C9stat *stat, uint8_t **t, uint32_t *size)
-{
- uint8_t *b;
- uint32_t cnt, sz;
-
- sz = 0;
- if(*size < 49 || (sz = r16(t)) < 47 || *size < 2+sz)
- goto error;
- *size -= 2+sz;
- *t += 6; /* skip type(2) and dev(4) */
- stat->qid.type = r08(t);
- stat->qid.version = r32(t);
- stat->qid.path = r64(t);
- stat->mode = r32(t);
- stat->atime = r32(t);
- stat->mtime = r32(t);
- stat->size = r64(t);
- sz -= 39;
- if((cnt = r16(t)) > sz-2)
- goto error;
- stat->name = (char*)*t; b = *t = *t+cnt; sz -= 2+cnt;
- if(sz < 2 || (cnt = r16(t)) > sz-2)
- goto error;
- stat->uid = (char*)*t; *b = 0; b = *t = *t+cnt; sz -= 2+cnt;
- if(sz < 2 || (cnt = r16(t)) > sz-2)
- goto error;
- stat->gid = (char*)*t; *b = 0; b = *t = *t+cnt; sz -= 2+cnt;
- if(sz < 2 || (cnt = r16(t)) > sz-2)
- goto error;
- stat->muid = memmove(*t-1, *t, cnt); *b = stat->muid[cnt] = 0; *t = *t+cnt; sz -= 2+cnt;
- *t += sz;
- return 0;
-error:
- c->error("c9parsedir: invalid size: size=%u sz=%u", *size, sz);
- return C9Epkt;
-}
-
-#ifndef C9_NO_SERVER
-
-static uint8_t *
-R(C9ctx *c, uint32_t size, C9rtype type, C9tag tag, C9error *err)
-{
- uint8_t *p = NULL;
-
- if(size > c->msize-4-1-2){
- c->error("R: invalid size %u", size);
- *err = C9Esize;
- }else{
- size += 4+1+2;
- if((p = c->begin(c, size)) == NULL){
- c->error("R: no buffer for %u bytes", size);
- *err = C9Ebuf;
- }else{
- *err = 0;
- w32(&p, size);
- w08(&p, type);
- w16(&p, tag);
- }
- }
- return p;
-}
-
-C9error
-s9version(C9ctx *c)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 4+2+6, Rversion, 0xffff, &err)) != NULL){
- w32(&b, c->msize);
- wcs(&b, "9P2000", 6);
- err = c->end(c);
- };
- return err;
-}
-
-C9error
-s9auth(C9ctx *c, C9tag tag, const C9qid *aqid)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 13, Rauth, tag, &err)) != NULL){
- w08(&b, aqid->type);
- w32(&b, aqid->version);
- w64(&b, aqid->path);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9error(C9ctx *c, C9tag tag, const char *ename)
-{
- uint32_t len = safestrlen(ename);
- uint8_t *b;
- C9error err;
-
- if(len > C9maxstr){
- c->error("s9error: invalid ename: %u chars", len);
- return C9Estr;
- }
- if((b = R(c, 2+len, Rerror, tag, &err)) != NULL){
- wcs(&b, ename, len);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9attach(C9ctx *c, C9tag tag, const C9qid *qid)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 13, Rattach, tag, &err)) != NULL){
- w08(&b, qid->type);
- w32(&b, qid->version);
- w64(&b, qid->path);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9flush(C9ctx *c, C9tag tag)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 0, Rflush, tag, &err)) != NULL)
- err = c->end(c);
- return err;
-}
-
-C9error
-s9walk(C9ctx *c, C9tag tag, C9qid *qids[])
-{
- uint32_t i, n;
- uint8_t *b;
- C9error err;
-
- for(n = 0; n < C9maxpathel && qids[n] != NULL; n++);
- if(n > C9maxpathel){
- c->error("s9walk: invalid elements !(0 <= %u <= %u)", n, C9maxpathel);
- return C9Epath;
- }
-
- if((b = R(c, 2+n*13, Rwalk, tag, &err)) != NULL){
- w16(&b, n);
- for(i = 0; i < n; i++){
- w08(&b, qids[i]->type);
- w32(&b, qids[i]->version);
- w64(&b, qids[i]->path);
- }
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9open(C9ctx *c, C9tag tag, const C9qid *qid, uint32_t iounit)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 13+4, Ropen, tag, &err)) != NULL){
- w08(&b, qid->type);
- w32(&b, qid->version);
- w64(&b, qid->path);
- w32(&b, iounit);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9create(C9ctx *c, C9tag tag, const C9qid *qid, uint32_t iounit)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 13+4, Rcreate, tag, &err)) != NULL){
- w08(&b, qid->type);
- w32(&b, qid->version);
- w64(&b, qid->path);
- w32(&b, iounit);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9read(C9ctx *c, C9tag tag, const void *data, uint32_t size)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 4+size, Rread, tag, &err)) != NULL){
- w32(&b, size);
- memmove(b, data, size);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9write(C9ctx *c, C9tag tag, uint32_t size)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 4, Rwrite, tag, &err)) != NULL){
- w32(&b, size);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9readdir(C9ctx *c, C9tag tag, C9stat *st[], int *num, uint64_t *offset, uint32_t size)
-{
- uint8_t *b;
- const C9stat *s;
- uint32_t nlen, ulen, glen, mulen, m, n;
- C9error err;
- int i;
-
- if(size > c->msize-4-1-2)
- size = c->msize-4-1-2;
-
- m = 0;
- for(i = 0; i < *num; i++){
- s = st[i];
- nlen = safestrlen(s->name);
- ulen = safestrlen(s->uid);
- glen = safestrlen(s->gid);
- mulen = safestrlen(s->muid);
-
- if(nlen == 0 || nlen > C9maxstr){
- c->error("s9readdir: invalid name: %u chars", nlen);
- return C9Epath;
- }
- if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){
- ulen = ulen > glen ? ulen : glen;
- ulen = ulen > mulen ? ulen : mulen;
- c->error("s9readdir: string too long: %u chars", ulen);
- return C9Estr;
- }
-
- n = 2 + 2+4+13+4+4+4+8+2+nlen+2+ulen+2+glen+2+mulen;
- if(4+m+n > size)
- break;
- m += n;
- }
-
- if((b = R(c, 4+m, Rread, tag, &err)) != NULL){
- *num = i;
- w32(&b, m);
- for(i = 0; i < *num; i++){
- s = st[i];
- nlen = safestrlen(s->name);
- ulen = safestrlen(s->uid);
- glen = safestrlen(s->gid);
- mulen = safestrlen(s->muid);
- w16(&b, 2+4+13+4+4+4+8+2+nlen+2+ulen+2+glen+2+mulen);
- w16(&b, 0xffff); /* type */
- w32(&b, 0xffffffff); /* dev */
- w08(&b, s->qid.type);
- w32(&b, s->qid.version);
- w64(&b, s->qid.path);
- 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, s->muid, mulen);
- }
- err = c->end(c);
- if(err == 0)
- *offset += m;
- }
- return err;
-}
-
-C9error
-s9clunk(C9ctx *c, C9tag tag)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 0, Rclunk, tag, &err)) != NULL)
- err = c->end(c);
- return err;
-}
-
-C9error
-s9remove(C9ctx *c, C9tag tag)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 0, Rremove, tag, &err)) != NULL)
- err = c->end(c);
- return err;
-}
-
-C9error
-s9stat(C9ctx *c, C9tag tag, const C9stat *s)
-{
- uint32_t nlen = safestrlen(s->name), ulen = safestrlen(s->uid);
- uint32_t glen = safestrlen(s->gid), mulen = safestrlen(s->name);
- uint32_t statsz = 2+4+13+4+4+4+8+2+nlen+2+ulen+2+glen+2+mulen;
- uint8_t *b;
- C9error err;
-
- if(nlen == 0 || nlen > C9maxstr){
- c->error("s9stat: invalid name: %u chars", nlen);
- return C9Epath;
- }
- if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){
- ulen = ulen > glen ? ulen : glen;
- ulen = ulen > mulen ? ulen : mulen;
- c->error("s9stat: string too long: %u chars", ulen);
- return C9Estr;
- }
-
- if((b = R(c, 2+2+statsz, Rstat, tag, &err)) != NULL){
- w16(&b, statsz+2);
- w16(&b, statsz);
- w16(&b, 0xffff); /* type */
- w32(&b, 0xffffffff); /* dev */
- w08(&b, s->qid.type);
- w32(&b, s->qid.version);
- w64(&b, s->qid.path);
- 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, s->muid, mulen);
- err = c->end(c);
- }
- return err;
-}
-
-C9error
-s9wstat(C9ctx *c, C9tag tag)
-{
- uint8_t *b;
- C9error err;
-
- if((b = R(c, 0, Rwstat, tag, &err)) != NULL)
- err = c->end(c);
- return err;
-}
-
-C9error
-s9proc(C9ctx *c)
-{
- uint32_t i, sz, cnt, n, msize;
- int readerr;
- uint8_t *b;
- C9error err;
- C9t t;
-
- readerr = -1;
- if((b = c->read(c, 4, &readerr)) == NULL){
- if(readerr != 0)
- c->error("s9proc: short read");
- return readerr == 0 ? 0 : C9Epkt;
- }
-
- sz = r32(&b);
- if(sz < 7 || sz > c->msize){
- c->error("s9proc: invalid packet size !(7 <= %u <= %u)", sz, c->msize);
- return C9Epkt;
- }
- sz -= 4;
- readerr = -1;
- if((b = c->read(c, sz, &readerr)) == NULL){
- if(readerr != 0)
- c->error("s9proc: short read");
- return readerr == 0 ? 0 : C9Epkt;
- }
-
- t.type = r08(&b);
- t.tag = r16(&b);
- sz -= 3;
-
- if((c->svflags & Svver) == 0 && t.type != Tversion){
- c->error("s9proc: expected Tversion, got %u", t.type);
- return C9Epkt;
- }
-
- switch(t.type){
- case Tread:
- if(sz < 4+8+4)
- goto error;
- t.fid = r32(&b);
- t.read.offset = r64(&b);
- t.read.size = r32(&b);
- if(t.read.size > maxread(c))
- t.read.size = maxread(c);
- c->t(c, &t);
- break;
-
- case Twrite:
- if(sz < 4+8+4)
- goto error;
- t.fid = r32(&b);
- t.write.offset = r64(&b);
- if((t.write.size = r32(&b)) < sz-4-8-4)
- goto error;
- if(t.write.size > maxwrite(c))
- t.write.size = maxwrite(c);
- t.write.data = b;
- c->t(c, &t);
- break;
-
- case Tclunk:
- case Tstat:
- case Tremove:
- if(sz < 4)
- goto error;
- t.fid = r32(&b);
- c->t(c, &t);
- break;
-
- case Twalk:
- if(sz < 4+4+2)
- goto error;
- t.fid = r32(&b);
- t.walk.newfid = r32(&b);
- if((n = r16(&b)) > 16){
- c->error("s9proc: Twalk !(%u <= 16)", n);
- return C9Epath;
- }
- sz -= 4+4+2;
- if(n > 0){
- for(i = 0; i < n; i++){
- if(sz < 2 || (cnt = r16(&b)) > sz-2)
- goto error;
- if(cnt < 1){
- c->error("s9proc: Twalk invalid element [%u]", i);
- return C9Epath;
- }
- b[-2] = 0;
- t.walk.wname[i] = (char*)b;
- b += cnt;
- sz -= 2 + cnt;
- }
- memmove(t.walk.wname[i-1]-1, t.walk.wname[i-1], (char*)b - t.walk.wname[i-1]);
- t.walk.wname[i-1]--;
- b[-1] = 0;
- }else
- i = 0;
- t.walk.wname[i] = NULL;
- c->t(c, &t);
- break;
-
- case Topen:
- if(sz < 4+1)
- goto error;
- t.fid = r32(&b);
- t.open.mode = r08(&b);
- c->t(c, &t);
- break;
-
- case Twstat:
- if(sz < 4+2)
- goto error;
- t.fid = r32(&b);
- if((cnt = r16(&b)) > sz-4)
- goto error;
- if((err = c9parsedir(c, &t.wstat, &b, &cnt)) != 0){
- c->error("s9proc");
- return err;
- }
- c->t(c, &t);
- break;
-
- case Tcreate:
- if(sz < 4+2+4+1)
- goto error;
- t.fid = r32(&b);
- if((cnt = r16(&b)) < 1 || cnt > sz-4-2-4-1)
- goto error;
- t.create.name = (char*)b;
- b += cnt;
- t.create.perm = r32(&b);
- t.create.mode = r08(&b);
- t.create.name[cnt] = 0;
- c->t(c, &t);
- break;
-
- case Tflush:
- if(sz < 2)
- goto error;
- t.flush.oldtag = r16(&b);
- c->t(c, &t);
- break;
-
- case Tversion:
- if(sz < 4+2 || (msize = r32(&b)) < C9minmsize || (cnt = r16(&b)) > sz-4-2)
- goto error;
- if(cnt < 6 || memcmp(b, "9P2000", 6) != 0){
- if((b = R(c, 4+2+7, Rversion, 0xffff, &err)) != NULL){
- w32(&b, 0);
- wcs(&b, "unknown", 7);
- err = c->end(c);
- c->error("s9proc: invalid version");
- }
- return C9Ever;
- }
- if(msize < c->msize)
- c->msize = msize;
- c->svflags |= Svver;
- c->t(c, &t);
- break;
-
- case Tattach:
- if(sz < 4+4+2+2)
- goto error;
- t.fid = r32(&b);
- t.attach.afid = r32(&b);
- cnt = r16(&b);
- sz -= 4+4+2;
- if(cnt+2 > sz)
- goto error;
- t.attach.uname = (char*)b;
- b += cnt;
- cnt = r16(&b);
- b[-2] = 0;
- sz -= cnt+2;
- if(cnt > sz)
- goto error;
- memmove(b-1, b, cnt);
- t.attach.aname = (char*)b-1;
- t.attach.aname[cnt] = 0;
- c->t(c, &t);
- break;
-
- case Tauth:
- if(sz < 4+2+2)
- goto error;
- t.auth.afid = r32(&b);
- cnt = r16(&b);
- sz -= 4+2;
- if(cnt+2 > sz)
- goto error;
- t.auth.uname = (char*)b;
- b += cnt;
- cnt = r16(&b);
- b[-2] = 0;
- sz -= cnt+2;
- if(cnt > sz)
- goto error;
- memmove(b-1, b, cnt);
- t.auth.aname = (char*)b-1;
- t.auth.aname[cnt] = 0;
- c->t(c, &t);
- break;
-
- default:
- goto error;
- }
- return 0;
-error:
- c->error("s9proc: invalid packet (type=%u)", t.type);
- return C9Epkt;
-}
-
-#endif /* C9_NO_SERVER */
--- a/c9/c9.h
+++ /dev/null
@@ -1,355 +1,0 @@
-struct C9aux;
-
-typedef struct C9r C9r;
-typedef struct C9t C9t;
-typedef struct C9stat C9stat;
-typedef struct C9ctx C9ctx;
-typedef struct C9qid C9qid;
-typedef uint32_t C9fid;
-typedef uint16_t C9tag;
-
-/* Stat field is not changed if it's set to this value when calling c9wstat. */
-#define C9nochange (~0)
-
-/* Special fid used with auth/attach to basically avoid authentication. */
-#define C9nofid ((C9fid)~0)
-
-/* C9modes for opening a file. */
-typedef enum
-{
- C9read = 0,
- C9write = 1,
- C9rdwr = 2,
- C9exec = 3,
- C9trunc = 0x10,
- C9rclose = 0x40,
-}C9mode;
-
-typedef enum
-{
- /* User/owner. */
- C9permur = 1<<8, /* Readable. */
- C9permuw = 1<<7, /* Writable. */
- C9permux = 1<<6, /* Executable. */
-
- /* Group. */
- C9permgr = 1<<5,
- C9permgw = 1<<4,
- C9permgx = 1<<3,
-
- /* Other. */
- C9permor = 1<<2,
- C9permow = 1<<1,
- C9permox = 1<<0,
-}C9perm;
-
-/* Directory. */
-#define C9permdir 0x80000000
-
-/* Bitmask of stat.mode. */
-#define C9stdir 0x80000000
-#define C9stappend 0x40000000
-#define C9stexcl 0x20000000
-#define C9sttmp 0x04000000
-
-/* Limits. */
-enum
-{
- C9maxtags = 64, /* Maximal number of outstanding requests. [1-65535] */
- C9maxflush = 8, /* Maximal number of outstanding flushes. [1-65535] */
- C9maxstr = 0xffff, /* Maximal string length. [1-65535] */
- C9minmsize = 4096, /* Minimal sane msize. [4096-...] */
- C9maxpathel = 16, /* Maximal number of elements in a path. Do not change. */
-};
-
-/* Errors. */
-typedef enum
-{
- C9Einit = -1, /* Initialization failed. */
- C9Ever = -2, /* Protocol version doesn't match. */
- C9Epkt = -3, /* Incoming packet error. */
- C9Etag = -4, /* No free tags or bad tag. */
- C9Ebuf = -5, /* No buffer space enough for a message. */
- C9Epath = -6, /* Path is too long or just invalid. */
- C9Eflush = -7, /* Limit of outstanding flushes reached. */
- C9Esize = -8, /* Can't fit data in one message. */
- C9Estr = -9 /* Bad string. */
-}C9error;
-
-/* Request types. */
-typedef enum
-{
- Tversion = 100,
- Tauth = 102,
- Tattach = 104,
- Tflush = 108,
- Twalk = 110,
- Topen = 112,
- Tcreate = 114,
- Tread = 116,
- Twrite = 118,
- Tclunk = 120,
- Tremove = 122,
- Tstat = 124,
- Twstat = 126
-}C9ttype;
-
-/* Response types. */
-typedef enum
-{
- Rversion = 101,
- Rauth = 103,
- Rattach = 105,
- Rerror = 107,
- Rflush = 109,
- Rwalk = 111,
- Ropen = 113,
- Rcreate = 115,
- Rread = 117,
- Rwrite = 119,
- Rclunk = 121,
- Rremove = 123,
- Rstat = 125,
- Rwstat = 127
-}C9rtype;
-
-/* Unique file id type. */
-typedef enum
-{
- C9qtdir = 1<<7,
- C9qtappend = 1<<6,
- C9qtexcl = 1<<5,
- C9qtauth = 1<<3,
- C9qttmp = 1<<2,
- C9qtfile = 0
-}C9qt;
-
-/* Unique file id. */
-struct C9qid
-{
- uint64_t path;
- uint32_t version;
- C9qt type;
-};
-
-/*
- * File stats. Version and muid are ignored on wstat. Dmdir bit
- * change in mode won't work on wstat. Set any integer field to
- * C9nochange to keep it unchanged on wstat. Set any string to NULL to
- * keep it unchanged. Strings can be empty (""), but never NULL after
- * stat call.
- */
-struct C9stat
-{
- uint64_t size; /* Size of the file (in bytes). */
- char *name; /* Name of the file. */
- char *uid; /* Owner of the file. */
- char *gid; /* Group of the file. */
- char *muid; /* The user who modified the file last. */
- C9qid qid; /* Same as qid[0]. */
- uint32_t mode; /* Permissions. See C9st* and C9perm. */
- uint32_t atime; /* Last access time. */
- uint32_t mtime; /* Last modification time. */
-};
-
-/* Response data. */
-struct C9r
-{
- union
- {
- char *error;
-
- struct
- {
- uint8_t *data;
- uint32_t size;
- }read;
-
- struct
- {
- uint32_t size;
- }write;
-
- /* File stats (only valid if type is Rstat). */
- C9stat stat;
-
- /*
- * Qid(s). qid[0] is valid for auth/attach/create/stat/open.
- * More ids may be a result of a walk, see numqid.
- */
- C9qid qid[C9maxpathel];
- };
- C9rtype type; /* Response type. */
-
- /*
- * If not zero, is the maximum number of bytes that are guaranteed
- * to be read or written atomically, without breaking into multiple
- * messages.
- */
- uint32_t iounit;
-
- int numqid; /* Number of valid unique ids in qid array. */
- C9tag tag; /* Tag number. */
-};
-
-/* Request data. */
-struct C9t
-{
- C9ttype type;
- C9tag tag;
- union
- {
- struct
- {
- char *uname;
- char *aname;
- C9fid afid;
- }attach;
-
- struct
- {
- char *uname;
- char *aname;
- C9fid afid;
- }auth;
-
- struct
- {
- char *name;
- uint32_t perm;
- C9mode mode;
- }create;
-
- struct
- {
- C9tag oldtag;
- }flush;
-
- struct
- {
- C9mode mode;
- }open;
-
- struct
- {
- uint64_t offset;
- uint32_t size;
- }read;
-
- struct
- {
- char *wname[C9maxpathel+1]; /* wname[16] is always NULL */
- C9fid newfid;
- }walk;
-
- struct
- {
- uint64_t offset;
- uint8_t *data;
- uint32_t size;
- }write;
-
- C9stat wstat;
- };
- C9fid fid;
-};
-
-enum
-{
- C9tagsbits = sizeof(uint32_t) * 8,
-};
-
-struct C9ctx
-{
- /*
- * Should return a pointer to the data (exactly 'size' bytes) read.
- * Set 'err' to non-zero and return NULL in case of error.
- * 'err' set to zero (no error) should be used to return from c9process
- * early (timeout on read to do non-blocking operations, for example).
- */
- uint8_t *(*read)(C9ctx *ctx, uint32_t size, int *err) __attribute__((nonnull(1, 3)));
-
- /* Should return a buffer to store 'size' bytes. Nil means no memory. */
- uint8_t *(*begin)(C9ctx *ctx, uint32_t size) __attribute__((nonnull(1)));
-
- /*
- * Marks the end of a message. Callback may decide if any accumulated
- * messages should be sent to the server/client.
- */
- int (*end)(C9ctx *ctx) __attribute__((nonnull(1)));
-
- /* Callback called every time a new R-message is received. */
- void (*r)(C9ctx *ctx, C9r *r) __attribute__((nonnull(1, 2)));
-
- /* Callback called every time a new T-message is received. */
- void (*t)(C9ctx *ctx, C9t *t) __attribute__((nonnull(1, 2)));
-
- /* Callback for error messages. */
- void (*error)(const char *fmt, ...) __attribute__((nonnull(1), format(printf, 1, 2)));
-
- /* Auxiliary data, can be used by any of above callbacks. */
- struct C9aux *aux;
-
- /* private stuff */
- uint32_t msize;
-#ifndef C9_NO_CLIENT
- uint32_t flush[C9maxflush];
- uint32_t tags[C9maxtags/C9tagsbits];
-#endif
- union
- {
- C9tag lowfreetag;
- uint16_t svflags;
- };
-};
-
-/* Parse one directory entry. */
-extern C9error c9parsedir(C9ctx *c, C9stat *stat, uint8_t **data, uint32_t *size) __attribute__((nonnull(1, 2, 3)));
-
-#ifndef C9_NO_CLIENT
-
-extern C9error c9version(C9ctx *c, C9tag *tag, uint32_t msize) __attribute__((nonnull(1, 2)));
-extern C9error c9auth(C9ctx *c, C9tag *tag, C9fid afid, const char *uname, const char *aname) __attribute__((nonnull(1, 2)));
-extern C9error c9flush(C9ctx *c, C9tag *tag, C9tag oldtag) __attribute__((nonnull(1, 2)));
-extern C9error c9attach(C9ctx *c, C9tag *tag, C9fid fid, C9fid afid, const char *uname, const char *aname) __attribute__((nonnull(1, 2)));
-extern C9error c9walk(C9ctx *c, C9tag *tag, C9fid fid, C9fid newfid, const char *path[]) __attribute__((nonnull(1, 2, 5)));
-extern C9error c9open(C9ctx *c, C9tag *tag, C9fid fid, C9mode mode) __attribute__((nonnull(1, 2)));
-extern C9error c9create(C9ctx *c, C9tag *tag, C9fid fid, const char *name, uint32_t perm, C9mode mode) __attribute__((nonnull(1, 2, 4)));
-extern C9error c9read(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, uint32_t count) __attribute__((nonnull(1, 2)));
-extern C9error c9write(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, const void *in, uint32_t count) __attribute__((nonnull(1, 2, 5)));
-extern C9error c9wrstr(C9ctx *c, C9tag *tag, C9fid fid, const char *s) __attribute__((nonnull(1, 2, 4)));
-extern C9error c9clunk(C9ctx *c, C9tag *tag, C9fid fid) __attribute__((nonnull(1, 2)));
-extern C9error c9remove(C9ctx *c, C9tag *tag, C9fid fid) __attribute__((nonnull(1, 2)));
-extern C9error c9stat(C9ctx *c, C9tag *tag, C9fid fid) __attribute__((nonnull(1, 2)));
-extern C9error c9wstat(C9ctx *c, C9tag *tag, C9fid fid, const C9stat *s) __attribute__((nonnull(1, 2, 4)));
-
-/*
- * Wait until a response comes and process it. If the function returns
- * any error, context must be treated as 'broken' and no subsequent calls
- * should be made without reinitialization (c9version).
- */
-extern C9error c9proc(C9ctx *c) __attribute__((nonnull(1)));
-
-#endif /* C9_NO_CLIENT */
-
-#ifndef C9_NO_SERVER
-
-extern C9error s9version(C9ctx *c) __attribute__((nonnull(1)));
-extern C9error s9auth(C9ctx *c, C9tag tag, const C9qid *aqid) __attribute__((nonnull(1, 3)));
-extern C9error s9error(C9ctx *c, C9tag tag, const char *err) __attribute__((nonnull(1)));
-extern C9error s9attach(C9ctx *c, C9tag tag, const C9qid *qid) __attribute__((nonnull(1, 3)));
-extern C9error s9flush(C9ctx *c, C9tag tag) __attribute__((nonnull(1)));
-extern C9error s9walk(C9ctx *c, C9tag tag, C9qid *qids[]) __attribute__((nonnull(1, 3)));
-extern C9error s9open(C9ctx *c, C9tag tag, const C9qid *qid, uint32_t iounit) __attribute__((nonnull(1, 3)));
-extern C9error s9create(C9ctx *c, C9tag tag, const C9qid *qid, uint32_t iounit) __attribute__((nonnull(1, 3)));
-extern C9error s9read(C9ctx *c, C9tag tag, const void *data, uint32_t size) __attribute__((nonnull(1, 3)));
-extern C9error s9readdir(C9ctx *c, C9tag tag, C9stat *st[], int *num, uint64_t *offset, uint32_t size) __attribute__((nonnull(1, 3, 4)));
-extern C9error s9write(C9ctx *c, C9tag tag, uint32_t size) __attribute__((nonnull(1)));
-extern C9error s9clunk(C9ctx *c, C9tag tag) __attribute__((nonnull(1)));
-extern C9error s9remove(C9ctx *c, C9tag tag) __attribute__((nonnull(1)));
-extern C9error s9stat(C9ctx *c, C9tag tag, const C9stat *s) __attribute__((nonnull(1, 3)));
-extern C9error s9wstat(C9ctx *c, C9tag tag) __attribute__((nonnull(1)));
-
-extern C9error s9proc(C9ctx *c) __attribute__((nonnull(1)));
-
-#endif /* C9_NO_SERVER */