| @@ -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 | } |