Showing the changes to c9.c (1 of 4 files). Show all
Unified · Split
| @@ -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 | } | ||