History

Squashed 'c9/' content from commit 24bfa2e

Sigrid Haflínudóttir committed 6 years ago

Commit c19685cNo parent (first commit)4 files · +1518 −0Browse files

Showing the changes to c9.c (1 of 4 files). Show all

Unified · Split

c9.c+1159−0
@@ -0,0 +1,1159 @@
1+/*
2+ * This is 9p client and server implementation which aims to be
3+ * correct, small and secure. It's the lowest level implementation.
4+ * It doesn't have much comments, mostly because it doesn't make
5+ * any sense to copy-paste protocol documentation, which
6+ * you can read at http://man.cat-v.org/plan_9/5/, see 'intro'.
7+ */
8+#include <string.h>
9+#include <stdint.h>
10+#include "c9.h"
11+
12+enum
13+{
14+ Svver = 1<<0,
15+};
16+
17+#define safestrlen(s) (s == NULL ? 0 : (uint32_t)strlen(s))
18+#define maxread(c) (c->msize-4-4-1-2)
19+#define maxwrite(c) maxread(c)
20+
21+static void
22+w08(uint8_t **p, uint8_t x)
23+{
24+ (*p)[0] = x;
25+ *p += 1;
26+}
27+
28+static void
29+w16(uint8_t **p, uint16_t x)
30+{
31+ (*p)[0] = x;
32+ (*p)[1] = x>>8;
33+ *p += 2;
34+}
35+
36+static void
37+w32(uint8_t **p, uint32_t x)
38+{
39+ (*p)[0] = x;
40+ (*p)[1] = x>>8;
41+ (*p)[2] = x>>16;
42+ (*p)[3] = x>>24;
43+ *p += 4;
44+}
45+
46+static void
47+w64(uint8_t **p, uint64_t x)
48+{
49+ (*p)[0] = x;
50+ (*p)[1] = x>>8;
51+ (*p)[2] = x>>16;
52+ (*p)[3] = x>>24;
53+ (*p)[4] = x>>32;
54+ (*p)[5] = x>>40;
55+ (*p)[6] = x>>48;
56+ (*p)[7] = x>>56;
57+ *p += 8;
58+}
59+
60+static void
61+wcs(uint8_t **p, const char *s, int len)
62+{
63+ w16(p, len);
64+ if(s != NULL){
65+ memmove(*p, s, len);
66+ *p += len;
67+ }
68+}
69+
70+static uint8_t
71+r08(uint8_t **p)
72+{
73+ *p += 1;
74+ return (*p)[-1];
75+}
76+
77+static uint16_t
78+r16(uint8_t **p)
79+{
80+ *p += 2;
81+ return (uint16_t)(*p)[-2]<<0 | (uint16_t)(*p)[-1]<<8;
82+}
83+
84+static uint32_t
85+r32(uint8_t **p)
86+{
87+ return r16(p) | (uint32_t)r16(p)<<16;
88+}
89+
90+static uint64_t
91+r64(uint8_t **p)
92+{
93+ return r32(p) | (uint64_t)r32(p)<<32;
94+}
95+
96+static C9error
97+newtag(C9ctx *c, C9ttype type, C9tag *tag)
98+{
99+ uint32_t i;
100+
101+ if(type == Tversion){
102+ *tag = 0xffff;
103+ return 0;
104+ }
105+
106+ if(c->lowfreetag < C9maxtags){
107+ uint32_t d = c->lowfreetag / C9tagsbits, m = c->lowfreetag % C9tagsbits;
108+ if((c->tags[d] & 1<<m) != 0){
109+ c->tags[d] &= ~(1<<m);
110+ *tag = c->lowfreetag++;
111+ return 0;
112+ }
113+ }
114+
115+ for(i = 0; i < (int)sizeof(c->tags)/sizeof(c->tags[0]); i++){
116+ uint32_t x, j;
117+ if((x = c->tags[i]) == 0)
118+ continue;
119+ for(j = 0; j < C9tagsbits; j++){
120+ if((x & (1<<j)) != 0){
121+ c->tags[i] &= ~(1<<j);
122+ *tag = i*C9tagsbits + j;
123+ c->lowfreetag = *tag + 1;
124+ return 0;
125+ }
126+ }
127+ }
128+
129+ c->error("newtag: no free tags");
130+ return C9Etag;
131+}
132+
133+static int
134+freetag(C9ctx *c, C9tag tag)
135+{
136+ if(tag != 0xffff){
137+ uint32_t d = tag / C9tagsbits, m = tag % C9tagsbits;
138+ if(tag >= C9maxtags){
139+ c->error("freetag: invalid tag");
140+ return -1;
141+ }
142+ if((c->tags[d] & 1<<m) != 0){
143+ c->error("freetag: double free");
144+ return -1;
145+ }
146+ if(c->lowfreetag > tag)
147+ c->lowfreetag = tag;
148+ c->tags[d] |= 1<<m;
149+ }
150+ return 0;
151+}
152+
153+static uint8_t *
154+T(C9ctx *c, uint32_t size, C9ttype type, C9tag *tag, C9error *err)
155+{
156+ uint8_t *p = NULL;
157+
158+ if(size > c->msize-4-1-2){
159+ c->error("T: invalid size");
160+ *err = C9Esize;
161+ }else if((*err = newtag(c, type, tag)) == 0){
162+ size += 4+1+2;
163+ if((p = c->begin(c, size)) == NULL){
164+ c->error("T: no buffer");
165+ freetag(c, *tag);
166+ *err = C9Ebuf;
167+ }else{
168+ *err = 0;
169+ w32(&p, size);
170+ w08(&p, type);
171+ w16(&p, *tag);
172+ }
173+ }
174+ return p;
175+}
176+
177+static uint8_t *
178+R(C9ctx *c, uint32_t size, C9rtype type, C9tag tag, C9error *err)
179+{
180+ uint8_t *p = NULL;
181+
182+ if(size > c->msize-4-1-2){
183+ c->error("R: invalid size");
184+ *err = C9Esize;
185+ }else{
186+ size += 4+1+2;
187+ if((p = c->begin(c, size)) == NULL){
188+ c->error("R: no buffer");
189+ *err = C9Ebuf;
190+ }else{
191+ *err = 0;
192+ w32(&p, size);
193+ w08(&p, type);
194+ w16(&p, tag);
195+ }
196+ }
197+ return p;
198+}
199+
200+C9error
201+c9parsedir(C9ctx *c, C9stat *stat, uint8_t **t, uint32_t *size)
202+{
203+ uint8_t *b;
204+ uint32_t cnt, sz;
205+
206+ if(*size < 49 || (sz = r16(t)) < 47 || *size < 2+sz)
207+ goto error;
208+ *size -= 2+sz;
209+ *t += 6; /* skip type(2) and dev(4) */
210+ stat->qid.type = r08(t);
211+ stat->qid.version = r32(t);
212+ stat->qid.path = r64(t);
213+ stat->mode = r32(t);
214+ stat->atime = r32(t);
215+ stat->mtime = r32(t);
216+ stat->size = r64(t);
217+ sz -= 39;
218+ if((cnt = r16(t)) > sz-2)
219+ goto error;
220+ stat->name = (char*)*t; b = *t = *t+cnt; sz -= 2+cnt;
221+ if(sz < 2 || (cnt = r16(t)) > sz-2)
222+ goto error;
223+ stat->uid = (char*)*t; *b = 0; b = *t = *t+cnt; sz -= 2+cnt;
224+ if(sz < 2 || (cnt = r16(t)) > sz-2)
225+ goto error;
226+ stat->gid = (char*)*t; *b = 0; b = *t = *t+cnt; sz -= 2+cnt;
227+ if(sz < 2 || (cnt = r16(t)) > sz-2)
228+ goto error;
229+ stat->muid = memmove(*t-1, *t, cnt); *b = stat->muid[cnt] = 0; *t = *t+cnt; sz -= 2+cnt;
230+ *t += sz;
231+ return 0;
232+error:
233+ c->error("c9parsedir: invalid size");
234+ return C9Epkt;
235+}
236+
237+C9error
238+c9version(C9ctx *c, C9tag *tag, uint32_t msize)
239+{
240+ uint8_t *b;
241+ C9error err;
242+
243+ if(msize < C9minmsize){
244+ c->error("c9version: msize too small");
245+ return C9Einit;
246+ }
247+ memset(c->tags, 0xff, sizeof(c->tags));
248+ memset(c->flush, 0xff, sizeof(c->flush));
249+ c->lowfreetag = 0;
250+ c->msize = msize;
251+
252+ if((b = T(c, 4+2+6, Tversion, tag, &err)) != NULL){
253+ w32(&b, msize);
254+ wcs(&b, "9P2000", 6);
255+ err = c->end(c);
256+ }
257+ return err;
258+}
259+
260+C9error
261+c9auth(C9ctx *c, C9tag *tag, C9fid afid, const char *uname, const char *aname)
262+{
263+ uint8_t *b;
264+ uint32_t ulen = safestrlen(uname), alen = safestrlen(aname);
265+ C9error err;
266+
267+ if(ulen > C9maxstr || alen > C9maxstr){
268+ c->error("c9auth: string too long");
269+ return C9Estr;
270+ }
271+ if((b = T(c, 4+2+ulen+2+alen, Tauth, tag, &err)) != NULL){
272+ w32(&b, afid);
273+ wcs(&b, uname, ulen);
274+ wcs(&b, aname, alen);
275+ err = c->end(c);
276+ }
277+ return err;
278+}
279+
280+C9error
281+c9flush(C9ctx *c, C9tag *tag, C9tag oldtag)
282+{
283+ uint8_t *b;
284+ C9error err;
285+ int i;
286+
287+ for(i = 0; i < C9maxflush && c->flush[i] != (uint32_t)~0; i++);
288+ if(i == C9maxflush){
289+ c->error("c9flush: no free flush slots");
290+ return C9Eflush;
291+ }
292+ if((b = T(c, 2, Tflush, tag, &err)) != NULL){
293+ w16(&b, oldtag);
294+ err = c->end(c);
295+ if(err == 0)
296+ c->flush[i] = (uint32_t)oldtag<<16 | *tag;
297+ }
298+ return err;
299+}
300+
301+C9error
302+c9attach(C9ctx *c, C9tag *tag, C9fid fid, C9fid afid, const char *uname, const char *aname)
303+{
304+ uint32_t ulen = safestrlen(uname), alen = safestrlen(aname);
305+ uint8_t *b;
306+ C9error err;
307+
308+ if(ulen > C9maxstr || alen > C9maxstr){
309+ c->error("c9attach: string too long");
310+ return C9Estr;
311+ }
312+ if((b = T(c, 4+4+2+ulen+2+alen, Tattach, tag, &err)) != NULL){
313+ w32(&b, fid);
314+ w32(&b, afid);
315+ wcs(&b, uname, ulen);
316+ wcs(&b, aname, alen);
317+ err = c->end(c);
318+ }
319+ return err;
320+}
321+
322+C9error
323+c9walk(C9ctx *c, C9tag *tag, C9fid fid, C9fid newfid, const char *path[])
324+{
325+ uint32_t i, j, sz;
326+ uint32_t len[C9maxpathel];
327+ uint8_t *b;
328+ C9error err;
329+
330+ for(sz = i = 0; i < (int)sizeof(len)/sizeof(len[0]) && path[i] != NULL; i++){
331+ len[i] = safestrlen(path[i]);
332+ if(len[i] == 0 || len[i] > C9maxstr){
333+ c->error("c9walk: path element too long");
334+ return C9Epath;
335+ }
336+ sz += 2 + len[i];
337+ }
338+ if(path[i] != NULL || i == 0){
339+ c->error("c9walk: invalid elements !(0 < %d <= %d)", i, C9maxpathel);
340+ return C9Epath;
341+ }
342+
343+ if((b = T(c, 4+4+2+sz, Twalk, tag, &err)) != NULL){
344+ w32(&b, fid);
345+ w32(&b, newfid);
346+ w16(&b, i);
347+ for(j = 0; j < i; j++)
348+ wcs(&b, path[j], len[j]);
349+ err = c->end(c);
350+ }
351+ return err;
352+}
353+
354+C9error
355+c9open(C9ctx *c, C9tag *tag, C9fid fid, C9mode mode)
356+{
357+ uint8_t *b;
358+ C9error err;
359+
360+ if((b = T(c, 4+1, Topen, tag, &err)) != NULL){
361+ w32(&b, fid);
362+ w08(&b, mode);
363+ err = c->end(c);
364+ }
365+ return err;
366+}
367+
368+C9error
369+c9create(C9ctx *c, C9tag *tag, C9fid fid, const char *name, uint32_t perm, C9mode mode)
370+{
371+ uint32_t nlen = strlen(name);
372+ uint8_t *b;
373+ C9error err;
374+
375+ if(nlen == 0 || nlen > C9maxstr){
376+ c->error("c9create: invalid name");
377+ return C9Epath;
378+ }
379+ if((b = T(c, 4+2+nlen+4+1, Tcreate, tag, &err)) != NULL){
380+ w32(&b, fid);
381+ wcs(&b, name, nlen);
382+ w32(&b, perm);
383+ w08(&b, mode);
384+ err = c->end(c);
385+ }
386+ return err;
387+}
388+
389+C9error
390+c9read(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, uint32_t count)
391+{
392+ uint8_t *b;
393+ C9error err;
394+
395+ if((b = T(c, 4+8+4, Tread, tag, &err)) != NULL){
396+ w32(&b, fid);
397+ w64(&b, offset);
398+ w32(&b, count);
399+ err = c->end(c);
400+ }
401+ return err;
402+}
403+
404+C9error
405+c9write(C9ctx *c, C9tag *tag, C9fid fid, uint64_t offset, const void *in, uint32_t count)
406+{
407+ uint8_t *b;
408+ C9error err;
409+
410+ if((b = T(c, 4+8+4+count, Twrite, tag, &err)) != NULL){
411+ w32(&b, fid);
412+ w64(&b, offset);
413+ w32(&b, count);
414+ memmove(b, in, count);
415+ err = c->end(c);
416+ }
417+ return err;
418+}
419+
420+C9error
421+c9wrstr(C9ctx *c, C9tag *tag, C9fid fid, const char *s)
422+{
423+ return c9write(c, tag, fid, 0, s, strlen(s));
424+}
425+
426+C9error
427+c9clunk(C9ctx *c, C9tag *tag, C9fid fid)
428+{
429+ uint8_t *b;
430+ C9error err;
431+
432+ if((b = T(c, 4, Tclunk, tag, &err)) != NULL){
433+ w32(&b, fid);
434+ err = c->end(c);
435+ }
436+ return err;
437+}
438+
439+C9error
440+c9remove(C9ctx *c, C9tag *tag, C9fid fid)
441+{
442+ uint8_t *b;
443+ C9error err;
444+
445+ if((b = T(c, 4, Tremove, tag, &err)) != NULL){
446+ w32(&b, fid);
447+ err = c->end(c);
448+ }
449+ return err;
450+}
451+
452+C9error
453+c9stat(C9ctx *c, C9tag *tag, C9fid fid)
454+{
455+ uint8_t *b;
456+ C9error err;
457+
458+ if((b = T(c, 4, Tstat, tag, &err)) != NULL){
459+ w32(&b, fid);
460+ err = c->end(c);
461+ }
462+ return err;
463+}
464+
465+C9error
466+c9wstat(C9ctx *c, C9tag *tag, C9fid fid, const C9stat *s)
467+{
468+ uint32_t nlen = safestrlen(s->name), ulen = safestrlen(s->uid), glen = safestrlen(s->gid);
469+ uint32_t unusedsz = 2+4+13, statsz = unusedsz+4+4+4+8+2+nlen+2+ulen+2+glen+2;
470+ uint8_t *b;
471+ C9error err;
472+
473+ if(nlen == 0 || nlen > C9maxstr){
474+ c->error("c9wstat: invalid name");
475+ return C9Epath;
476+ }
477+ if(ulen > C9maxstr || glen > C9maxstr){
478+ c->error("c9wstat: string too long");
479+ return C9Estr;
480+ }
481+ if((b = T(c, 4+2+2+statsz, Twstat, tag, &err)) != NULL){
482+ w32(&b, fid);
483+ w16(&b, statsz+2);
484+ w16(&b, statsz);
485+ memset(b, 0xff, unusedsz); /* leave type(2), dev(4) and qid(13) unchanged */
486+ b += unusedsz;
487+ w32(&b, s->mode);
488+ w32(&b, s->atime);
489+ w32(&b, s->mtime);
490+ w64(&b, s->size);
491+ wcs(&b, s->name, nlen);
492+ wcs(&b, s->uid, ulen);
493+ wcs(&b, s->gid, glen);
494+ wcs(&b, NULL, 0); /* muid unchanged */
495+ err = c->end(c);
496+ }
497+ return err;
498+}
499+
500+C9error
501+c9proc(C9ctx *c)
502+{
503+ uint32_t i, sz, cnt, msize;
504+ uint8_t *b;
505+ int err;
506+ C9r r;
507+
508+ err = -1;
509+ if((b = c->read(c, 4, &err)) == NULL){
510+ if(err != 0)
511+ c->error("c9proc: short read");
512+ return err == 0 ? 0 : C9Epkt;
513+ }
514+
515+ sz = r32(&b);
516+ if(sz < 7 || sz > c->msize){
517+ c->error("c9proc: invalid packet size !(7 <= %u <= %u)", sz, c->msize);
518+ return C9Epkt;
519+ }
520+ sz -= 4;
521+ err = -1;
522+ if((b = c->read(c, sz, &err)) == NULL){
523+ if(err != 0)
524+ c->error("c9proc: short read");
525+ return err == 0 ? 0 : C9Epkt;
526+ }
527+
528+ r.type = r08(&b);
529+ r.tag = r16(&b);
530+ if(r.type != Rversion){
531+ if(r.tag >= C9maxtags){
532+ c->error("c9proc: invalid tag 0x%x", r.tag);
533+ return C9Epkt;
534+ }
535+ if(freetag(c, r.tag) != 0)
536+ return C9Etag;
537+ }
538+ sz -= 3;
539+ r.numqid = 0;
540+
541+ switch(r.type){
542+ case Rread:
543+ if(sz < 4 || (cnt = r32(&b)) > sz-4)
544+ goto error;
545+ r.read.data = b;
546+ r.read.size = cnt;
547+ c->r(c, &r);
548+ break;
549+
550+ case Rwrite:
551+ if(sz < 4 || (cnt = r32(&b)) > c->msize)
552+ goto error;
553+ r.write.size = cnt;
554+ c->r(c, &r);
555+ break;
556+
557+ case Rwalk:
558+ if(sz < 2+13 || (cnt = r16(&b))*13 > sz-2)
559+ goto error;
560+ if(cnt > C9maxpathel){
561+ c->error("c9proc: Rwalk !(%d <= %d)", cnt, C9maxpathel);
562+ return C9Epath;
563+ }
564+ for(i = 0; i < cnt; i++){
565+ r.qid[i].type = r08(&b);
566+ r.qid[i].version = r32(&b);
567+ r.qid[i].path = r64(&b);
568+ }
569+ r.numqid = cnt;
570+ c->r(c, &r);
571+ break;
572+
573+ case Rstat:
574+ b += 2; sz -= 2;
575+ if((err = c9parsedir(c, &r.stat, &b, &sz)) != 0){
576+ c->error("c9proc");
577+ return err;
578+ }
579+ r.numqid = 1;
580+ c->r(c, &r);
581+ break;
582+
583+ case Rflush:
584+ for(i = 0; i < C9maxflush; i++){
585+ if((c->flush[i] & 0xffff) == r.tag){
586+ freetag(c, c->flush[i]>>16);
587+ c->flush[i] = 0xffffffff;
588+ break;
589+ }
590+ }
591+ /* fallthrough */
592+ case Rclunk:
593+ case Rremove:
594+ case Rwstat:
595+ c->r(c, &r);
596+ break;
597+
598+ case Ropen:
599+ case Rcreate:
600+ if(sz < 17)
601+ goto error;
602+ r.qid[0].type = r08(&b);
603+ r.qid[0].version = r32(&b);
604+ r.qid[0].path = r64(&b);
605+ r.iounit = r32(&b);
606+ r.numqid = 1;
607+ c->r(c, &r);
608+ break;
609+
610+ case Rerror:
611+ if(sz < 2 || (cnt = r16(&b)) > sz-2)
612+ goto error;
613+ r.error = memmove(b-1, b, cnt);
614+ r.error[cnt] = 0;
615+ c->r(c, &r);
616+ break;
617+
618+ case Rauth:
619+ case Rattach:
620+ if(sz < 13)
621+ goto error;
622+ r.qid[0].type = r08(&b);
623+ r.qid[0].version = r32(&b);
624+ r.qid[0].path = r64(&b);
625+ r.numqid = 1;
626+ c->r(c, &r);
627+ break;
628+
629+ case Rversion:
630+ if(sz < 4+2 || (msize = r32(&b)) < C9minmsize || (cnt = r16(&b)) > sz-4-2)
631+ goto error;
632+ if(cnt < 6 || memcmp(b, "9P2000", 6) != 0){
633+ c->error("invalid version");
634+ return C9Ever;
635+ }
636+ if(msize < c->msize)
637+ c->msize = msize;
638+ c->r(c, &r);
639+ break;
640+
641+ default:
642+ goto error;
643+ }
644+ return 0;
645+error:
646+ c->error("c9proc: invalid packet (type=%d)", r.type);
647+ return C9Epkt;
648+}
649+
650+C9error
651+s9version(C9ctx *c)
652+{
653+ uint8_t *b;
654+ C9error err;
655+
656+ if((b = R(c, 4+2+6, Rversion, 0xffff, &err)) != NULL){
657+ w32(&b, c->msize);
658+ wcs(&b, "9P2000", 6);
659+ err = c->end(c);
660+ };
661+ return err;
662+}
663+
664+C9error
665+s9auth(C9ctx *c, C9tag tag, const C9qid *aqid)
666+{
667+ uint8_t *b;
668+ C9error err;
669+
670+ if((b = R(c, 13, Rauth, tag, &err)) != NULL){
671+ w08(&b, aqid->type);
672+ w32(&b, aqid->version);
673+ w64(&b, aqid->path);
674+ err = c->end(c);
675+ }
676+ return err;
677+}
678+
679+C9error
680+s9error(C9ctx *c, C9tag tag, const char *ename)
681+{
682+ uint32_t len = safestrlen(ename);
683+ uint8_t *b;
684+ C9error err;
685+
686+ if(len > C9maxstr){
687+ c->error("s9error: invalid ename");
688+ return C9Estr;
689+ }
690+ if((b = R(c, 2+len, Rerror, tag, &err)) != NULL){
691+ wcs(&b, ename, len);
692+ err = c->end(c);
693+ }
694+ return err;
695+}
696+
697+C9error
698+s9attach(C9ctx *c, C9tag tag, const C9qid *qid)
699+{
700+ uint8_t *b;
701+ C9error err;
702+
703+ if((b = R(c, 13, Rattach, tag, &err)) != NULL){
704+ w08(&b, qid->type);
705+ w32(&b, qid->version);
706+ w64(&b, qid->path);
707+ err = c->end(c);
708+ }
709+ return err;
710+}
711+
712+C9error
713+s9flush(C9ctx *c, C9tag tag)
714+{
715+ uint8_t *b;
716+ C9error err;
717+
718+ if((b = R(c, 0, Rflush, tag, &err)) != NULL)
719+ err = c->end(c);
720+ return err;
721+}
722+
723+C9error
724+s9walk(C9ctx *c, C9tag tag, C9qid *qids[])
725+{
726+ uint32_t i, n;
727+ uint8_t *b;
728+ C9error err;
729+
730+ for(n = 0; n < C9maxpathel && qids[n] != NULL; n++);
731+ if(n > C9maxpathel){
732+ c->error("s9walk: invalid elements !(0 <= %d <= %d)", n, C9maxpathel);
733+ return C9Epath;
734+ }
735+
736+ if((b = R(c, 2+n*13, Rwalk, tag, &err)) != NULL){
737+ w16(&b, n);
738+ for(i = 0; i < n; i++){
739+ w08(&b, qids[i]->type);
740+ w32(&b, qids[i]->version);
741+ w64(&b, qids[i]->path);
742+ }
743+ err = c->end(c);
744+ }
745+ return err;
746+}
747+
748+C9error
749+s9open(C9ctx *c, C9tag tag, const C9qid *qid, uint32_t iounit)
750+{
751+ uint8_t *b;
752+ C9error err;
753+
754+ if((b = R(c, 13+4, Ropen, tag, &err)) != NULL){
755+ w08(&b, qid->type);
756+ w32(&b, qid->version);
757+ w64(&b, qid->path);
758+ w32(&b, iounit);
759+ err = c->end(c);
760+ }
761+ return err;
762+}
763+
764+C9error
765+s9create(C9ctx *c, C9tag tag, const C9qid *qid, uint32_t iounit)
766+{
767+ uint8_t *b;
768+ C9error err;
769+
770+ if((b = R(c, 13+4, Rcreate, tag, &err)) != NULL){
771+ w08(&b, qid->type);
772+ w32(&b, qid->version);
773+ w64(&b, qid->path);
774+ w32(&b, iounit);
775+ err = c->end(c);
776+ }
777+ return err;
778+}
779+
780+C9error
781+s9read(C9ctx *c, C9tag tag, const void *data, uint32_t size)
782+{
783+ uint8_t *b;
784+ C9error err;
785+
786+ if((b = R(c, 4+size, Rread, tag, &err)) != NULL){
787+ w32(&b, size);
788+ memmove(b, data, size);
789+ err = c->end(c);
790+ }
791+ return err;
792+}
793+
794+C9error
795+s9write(C9ctx *c, C9tag tag, uint32_t size)
796+{
797+ uint8_t *b;
798+ C9error err;
799+
800+ if((b = R(c, 4, Rwrite, tag, &err)) != NULL){
801+ w32(&b, size);
802+ err = c->end(c);
803+ }
804+ return err;
805+}
806+
807+C9error
808+s9readdir(C9ctx *c, C9tag tag, C9stat *st[], int *num, uint64_t *offset, uint32_t size)
809+{
810+ uint8_t *b;
811+ const C9stat *s;
812+ uint32_t nlen, ulen, glen, mulen, m, n;
813+ C9error err;
814+ int i;
815+
816+ if(size > c->msize-4-1-2)
817+ size = c->msize-4-1-2;
818+
819+ m = 0;
820+ for(i = 0; i < *num; i++){
821+ s = st[i];
822+ nlen = safestrlen(s->name);
823+ ulen = safestrlen(s->uid);
824+ glen = safestrlen(s->gid);
825+ mulen = safestrlen(s->muid);
826+
827+ if(nlen == 0 || nlen > C9maxstr){
828+ c->error("s9readdir: invalid name");
829+ return C9Epath;
830+ }
831+ if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){
832+ c->error("s9readdir: string too long");
833+ return C9Estr;
834+ }
835+
836+ n = 2 + 2+4+13+4+4+4+8+2+nlen+2+ulen+2+glen+2+mulen;
837+ if(4+m+n > size)
838+ break;
839+ m += n;
840+ }
841+
842+ if((b = R(c, 4+m, Rread, tag, &err)) != NULL){
843+ *num = i;
844+ w32(&b, m);
845+ for(i = 0; i < *num; i++){
846+ s = st[i];
847+ nlen = safestrlen(s->name);
848+ ulen = safestrlen(s->uid);
849+ glen = safestrlen(s->gid);
850+ mulen = safestrlen(s->muid);
851+ w16(&b, 2+4+13+4+4+4+8+2+nlen+2+ulen+2+glen+2+mulen);
852+ w16(&b, 0xffff); /* type */
853+ w32(&b, 0xffffffff); /* dev */
854+ w08(&b, s->qid.type);
855+ w32(&b, s->qid.version);
856+ w64(&b, s->qid.path);
857+ w32(&b, s->mode);
858+ w32(&b, s->atime);
859+ w32(&b, s->mtime);
860+ w64(&b, s->size);
861+ wcs(&b, s->name, nlen);
862+ wcs(&b, s->uid, ulen);
863+ wcs(&b, s->gid, glen);
864+ wcs(&b, s->muid, mulen);
865+ }
866+ err = c->end(c);
867+ if(err == 0)
868+ *offset += m;
869+ }
870+ return err;
871+}
872+
873+C9error
874+s9clunk(C9ctx *c, C9tag tag)
875+{
876+ uint8_t *b;
877+ C9error err;
878+
879+ if((b = R(c, 0, Rclunk, tag, &err)) != NULL)
880+ err = c->end(c);
881+ return err;
882+}
883+
884+C9error
885+s9remove(C9ctx *c, C9tag tag)
886+{
887+ uint8_t *b;
888+ C9error err;
889+
890+ if((b = R(c, 0, Rremove, tag, &err)) != NULL)
891+ err = c->end(c);
892+ return err;
893+}
894+
895+C9error
896+s9stat(C9ctx *c, C9tag tag, const C9stat *s)
897+{
898+ uint32_t nlen = safestrlen(s->name), ulen = safestrlen(s->uid);
899+ uint32_t glen = safestrlen(s->gid), mulen = safestrlen(s->name);
900+ uint32_t statsz = 2+4+13+4+4+4+8+2+nlen+2+ulen+2+glen+2+mulen;
901+ uint8_t *b;
902+ C9error err;
903+
904+ if(nlen == 0 || nlen > C9maxstr){
905+ c->error("s9stat: invalid name");
906+ return C9Epath;
907+ }
908+ if(ulen > C9maxstr || glen > C9maxstr || mulen > C9maxstr){
909+ c->error("s9stat: string too long");
910+ return C9Estr;
911+ }
912+
913+ if((b = R(c, 2+2+statsz, Rstat, tag, &err)) != NULL){
914+ w16(&b, statsz+2);
915+ w16(&b, statsz);
916+ w16(&b, 0xffff); /* type */
917+ w32(&b, 0xffffffff); /* dev */
918+ w08(&b, s->qid.type);
919+ w32(&b, s->qid.version);
920+ w64(&b, s->qid.path);
921+ w32(&b, s->mode);
922+ w32(&b, s->atime);
923+ w32(&b, s->mtime);
924+ w64(&b, s->size);
925+ wcs(&b, s->name, nlen);
926+ wcs(&b, s->uid, ulen);
927+ wcs(&b, s->gid, glen);
928+ wcs(&b, s->muid, mulen);
929+ err = c->end(c);
930+ }
931+ return err;
932+}
933+
934+C9error
935+s9wstat(C9ctx *c, C9tag tag)
936+{
937+ uint8_t *b;
938+ C9error err;
939+
940+ if((b = R(c, 0, Rwstat, tag, &err)) != NULL)
941+ err = c->end(c);
942+ return err;
943+}
944+
945+C9error
946+s9proc(C9ctx *c)
947+{
948+ uint32_t i, sz, cnt, n, msize;
949+ int readerr;
950+ uint8_t *b;
951+ C9error err;
952+ C9t t;
953+
954+ readerr = -1;
955+ if((b = c->read(c, 4, &readerr)) == NULL){
956+ if(readerr != 0)
957+ c->error("s9proc: short read");
958+ return readerr == 0 ? 0 : C9Epkt;
959+ }
960+
961+ sz = r32(&b);
962+ if(sz < 7 || sz > c->msize){
963+ c->error("s9proc: invalid packet size !(7 <= %u <= %u)", sz, c->msize);
964+ return C9Epkt;
965+ }
966+ sz -= 4;
967+ readerr = -1;
968+ if((b = c->read(c, sz, &readerr)) == NULL){
969+ if(readerr != 0)
970+ c->error("s9proc: short read");
971+ return readerr == 0 ? 0 : C9Epkt;
972+ }
973+
974+ t.type = r08(&b);
975+ t.tag = r16(&b);
976+ sz -= 3;
977+
978+ if((c->svflags & Svver) == 0 && t.type != Tversion){
979+ c->error("s9proc: expected Tversion, got %d", t.type);
980+ return C9Epkt;
981+ }
982+
983+ switch(t.type){
984+ case Tread:
985+ if(sz < 4+8+4)
986+ goto error;
987+ t.fid = r32(&b);
988+ t.read.offset = r64(&b);
989+ t.read.size = r32(&b);
990+ if(t.read.size > maxread(c))
991+ t.read.size = maxread(c);
992+ c->t(c, &t);
993+ break;
994+
995+ case Twrite:
996+ if(sz < 4+8+4)
997+ goto error;
998+ t.fid = r32(&b);
999+ t.write.offset = r64(&b);
1000+ if((t.write.size = r32(&b)) < sz-4-8-4)
1001+ goto error;
1002+ if(t.write.size > maxwrite(c))
1003+ t.write.size = maxwrite(c);
1004+ t.write.data = b;
1005+ c->t(c, &t);
1006+ break;
1007+
1008+ case Tclunk:
1009+ case Tstat:
1010+ case Tremove:
1011+ if(sz < 4)
1012+ goto error;
1013+ t.fid = r32(&b);
1014+ c->t(c, &t);
1015+ break;
1016+
1017+ case Twalk:
1018+ if(sz < 4+4+2)
1019+ goto error;
1020+ t.fid = r32(&b);
1021+ t.walk.newfid = r32(&b);
1022+ if((n = r16(&b)) > 16){
1023+ c->error("s9proc: Twalk !(%d <= 16)", n);
1024+ return C9Epath;
1025+ }
1026+ sz -= 4+4+2;
1027+ if(n > 0){
1028+ for(i = 0; i < n; i++){
1029+ if(sz < 2 || (cnt = r16(&b)) > sz-2)
1030+ goto error;
1031+ if(cnt < 1){
1032+ c->error("s9proc: Twalk invalid element [%d]", i);
1033+ return C9Epath;
1034+ }
1035+ b[-2] = 0;
1036+ t.walk.wname[i] = (char*)b;
1037+ b += cnt;
1038+ sz -= 2 + cnt;
1039+ }
1040+ memmove(t.walk.wname[i-1]-1, t.walk.wname[i-1], (char*)b - t.walk.wname[i-1]);
1041+ t.walk.wname[i-1]--;
1042+ b[-1] = 0;
1043+ }else
1044+ i = 0;
1045+ t.walk.wname[i] = NULL;
1046+ c->t(c, &t);
1047+ break;
1048+
1049+ case Topen:
1050+ if(sz < 4+1)
1051+ goto error;
1052+ t.fid = r32(&b);
1053+ t.open.mode = r08(&b);
1054+ c->t(c, &t);
1055+ break;
1056+
1057+ case Twstat:
1058+ if(sz < 4+2)
1059+ goto error;
1060+ t.fid = r32(&b);
1061+ if((cnt = r16(&b)) > sz-4)
1062+ goto error;
1063+ if((err = c9parsedir(c, &t.wstat, &b, &cnt)) != 0){
1064+ c->error("s9proc");
1065+ return err;
1066+ }
1067+ c->t(c, &t);
1068+ break;
1069+
1070+ case Tcreate:
1071+ if(sz < 4+2+4+1)
1072+ goto error;
1073+ t.fid = r32(&b);
1074+ if((cnt = r16(&b)) < 1 || cnt > sz-4-2-4-1)
1075+ goto error;
1076+ t.create.name = (char*)b;
1077+ b += cnt;
1078+ t.create.perm = r32(&b);
1079+ t.create.mode = r08(&b);
1080+ t.create.name[cnt] = 0;
1081+ c->t(c, &t);
1082+ break;
1083+
1084+ case Tflush:
1085+ if(sz < 2)
1086+ goto error;
1087+ t.flush.oldtag = r16(&b);
1088+ c->t(c, &t);
1089+ break;
1090+
1091+ case Tversion:
1092+ if(sz < 4+2 || (msize = r32(&b)) < C9minmsize || (cnt = r16(&b)) > sz-4-2)
1093+ goto error;
1094+ if(cnt < 6 || memcmp(b, "9P2000", 6) != 0){
1095+ if((b = R(c, 4+2+7, Rversion, 0xffff, &err)) != NULL){
1096+ w32(&b, 0);
1097+ wcs(&b, "unknown", 7);
1098+ err = c->end(c);
1099+ c->error("s9proc: invalid version");
1100+ }
1101+ return C9Ever;
1102+ }
1103+ if(msize < c->msize)
1104+ c->msize = msize;
1105+ c->svflags |= Svver;
1106+ c->t(c, &t);
1107+ break;
1108+
1109+ case Tattach:
1110+ if(sz < 4+4+2+2)
1111+ goto error;
1112+ t.fid = r32(&b);
1113+ t.attach.afid = r32(&b);
1114+ cnt = r16(&b);
1115+ sz -= 4+4+2;
1116+ if(cnt+2 > sz)
1117+ goto error;
1118+ t.attach.uname = (char*)b;
1119+ b += cnt;
1120+ cnt = r16(&b);
1121+ b[-2] = 0;
1122+ sz -= cnt+2;
1123+ if(cnt > sz)
1124+ goto error;
1125+ memmove(b-1, b, cnt);
1126+ t.attach.aname = (char*)b-1;
1127+ t.attach.aname[cnt] = 0;
1128+ c->t(c, &t);
1129+ break;
1130+
1131+ case Tauth:
1132+ if(sz < 4+2+2)
1133+ goto error;
1134+ t.auth.afid = r32(&b);
1135+ cnt = r16(&b);
1136+ sz -= 4+2;
1137+ if(cnt+2 > sz)
1138+ goto error;
1139+ t.auth.uname = (char*)b;
1140+ b += cnt;
1141+ cnt = r16(&b);
1142+ b[-2] = 0;
1143+ sz -= cnt+2;
1144+ if(cnt > sz)
1145+ goto error;
1146+ memmove(b-1, b, cnt);
1147+ t.auth.aname = (char*)b-1;
1148+ t.auth.aname[cnt] = 0;
1149+ c->t(c, &t);
1150+ break;
1151+
1152+ default:
1153+ goto error;
1154+ }
1155+ return 0;
1156+error:
1157+ c->error("s9proc: invalid packet (type=%d)", t.type);
1158+ return C9Epkt;
1159+}

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