1170 lines · 21.8 KB · C
RawDownload
/* * 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 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 (uint16_t)(*p)[-2]<<0 | (uint16_t)(*p)[-1]<<8;} static uint32_tr32(uint8_t **p){	return r16(p) | (uint32_t)r16(p)<<16;} static uint64_tr64(uint8_t **p){	return r32(p) | (uint64_t)r32(p)<<32;} #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("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("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;} C9errorc9version(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;} 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("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;} 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("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("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;} 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("c9walk: invalid path element: %u chars", len[i]);			return C9Epath;		}		sz += 2 + len[i];	}	if(path[i] != NULL){		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;} 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("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;} 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("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;} 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("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 || (cnt = r16(&b))*13 > sz-2)

Lines 1–500 of 1170.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t