1 #include <lib9.h> 2 #include <styx.h> 3 #include "styxserver.h" 4 #include "styxaux.h" 5 6 #define MAXSTAT 512 7 #define EMSGLEN 256 /* %r */ 8 9 #define TABSZ 32 /* power of 2 */ 10 11 static unsigned long boottime; 12 static char* eve = "inferno"; 13 static int Debug = 0; 14 15 char Enomem[] = "out of memory"; 16 char Eperm[] = "permission denied"; 17 char Enodev[] = "no free devices"; 18 char Ehungup[] = "write to hungup channel"; 19 char Eexist[] = "file exists"; 20 char Enonexist[] = "file does not exist"; 21 char Ebadcmd[] = "bad command"; 22 char Ebadarg[] = "bad arg in system call"; 23 char Enofid[] = "no such fid"; 24 char Enotdir[] = "not a directory"; 25 char Eopen[] = "already open"; 26 char Ebadfid[] = "bad fid"; 27 28 /* client state */ 29 enum{ 30 CDISC = 01, 31 CNREAD = 02, 32 CRECV = 04, 33 }; 34 35 typedef struct Walkqid Walkqid; 36 37 struct Fid 38 { 39 Client *client; 40 Fid *next; 41 short fid; 42 ushort open; 43 ushort mode; /* read/write */ 44 ulong offset; /* in file */ 45 int dri; /* dirread index */ 46 Qid qid; 47 }; 48 49 struct Walkqid 50 { 51 Fid *clone; 52 int nqid; 53 Qid qid[1]; 54 }; 55 56 #define ASSERT(A,B) styxassert((int)A,B) 57 58 static int hash(Path); 59 static void deletefids(Client *); 60 61 static void 62 styxfatal(char *fmt, ...) 63 { 64 char buf[1024], *out; 65 va_list arg; 66 out = seprint(buf, buf+sizeof(buf), "Fatal error: "); 67 va_start(arg, fmt); 68 out = vseprint(out, buf+sizeof(buf), fmt, arg); 69 va_end(arg); 70 write(2, buf, out-buf); 71 styxexit(1); 72 } 73 74 static void 75 styxassert(int true, char *reason) 76 { 77 if(!true) 78 styxfatal("assertion failed: %s\n", reason); 79 } 80 81 void * 82 styxmalloc(int bytes) 83 { 84 char *m = malloc(bytes); 85 if(m == nil) 86 styxfatal(Enomem); 87 memset(m, 0, bytes); 88 return m; 89 } 90 91 void 92 styxfree(void *p) 93 { 94 free(p); 95 } 96 97 void 98 styxdebug() 99 { 100 Debug = 1; 101 } 102 103 static Client * 104 newclient(Styxserver *server, int fd) 105 { 106 Client *c = (Client *)styxmalloc(sizeof(Client)); 107 108 if(Debug) 109 fprint(2, "New client at %lux\n", (ulong)c); 110 c->server = server; 111 c->fd = fd; 112 c->nread = 0; 113 c->nc = 0; 114 c->state = 0; 115 c->fids = nil; 116 c->uname = strdup(eve); 117 c->aname = strdup(""); 118 c->next = server->clients; 119 server->clients = c; 120 if(server->ops->newclient) 121 server->ops->newclient(c); 122 return c; 123 } 124 125 static void 126 freeclient(Client *c) 127 { 128 Client **p; 129 Styxserver *server; 130 131 if(Debug) 132 fprint(2, "Freeing client at %lux\n", (ulong)c); 133 server = c->server; 134 if(server->ops->freeclient) 135 server->ops->freeclient(c); 136 for(p = &server->clients; *p; p = &(*p)->next) 137 if(*p == c){ 138 styxclosesocket(c->fd); 139 *p = c->next; 140 deletefids(c); 141 free(c->uname); 142 free(c->aname); 143 styxfree(c); 144 return; 145 } 146 } 147 148 static int 149 nbread(Client *c, int nr) 150 { 151 int nb; 152 153 if(c->state&CDISC) 154 return -1; 155 nb = styxrecv(c->server, c->fd, c->msg + c->nread, nr, 0); 156 if(nb <= 0){ 157 c->nread = 0; 158 c->state |= CDISC; 159 return -1; 160 } 161 c->nread += nb; 162 return 0; 163 } 164 165 static int 166 rd(Client *c, Fcall *r) 167 { 168 if(c->nc > 0){ /* last convM2S consumed nc bytes */ 169 c->nread -= c->nc; 170 if((int)c->nread < 0){ 171 r->ename = "negative size in rd"; 172 return -1; 173 } 174 memmove(c->msg, c->msg+c->nc, c->nread); 175 c->nc = 0; 176 } 177 if(c->state&CRECV){ 178 if(nbread(c, MSGMAX - c->nread) != 0){ 179 r->ename = "unexpected EOF"; 180 return -1; 181 } 182 c->state &= ~CRECV; 183 } 184 c->nc = convM2S((uchar*)(c->msg), c->nread, r); 185 if(c->nc < 0){ 186 r->ename = "bad message format"; 187 return -1; 188 } 189 if(c->nc == 0 && c->nread > 0){ 190 c->nread = 0; 191 c->state &= ~CNREAD; 192 return 0; 193 } 194 if(c->nread > c->nc) 195 c->state |= CNREAD; 196 else 197 c->state &= ~CNREAD; 198 if(c->nc == 0) 199 return 0; 200 /* fprint(2, "rd: %F\n", r); */ 201 return 1; 202 } 203 204 static int 205 wr(Client *c, Fcall *r) 206 { 207 int n; 208 char buf[MSGMAX]; 209 210 n = convS2M(r, (uchar*)buf, sizeof(buf)); 211 if(n < 0){ 212 r->ename = "bad message type in wr"; 213 return -1; 214 } 215 /* fprint(2, "wr: %F\n", r); */ 216 return styxsend(c->server, c->fd, buf, n, 0); 217 } 218 219 static void 220 sremove(Styxserver *server, Styxfile *f) 221 { 222 Styxfile *s, *next, **p; 223 224 if(f == nil) 225 return; 226 if(Debug) 227 fprint(2, "Remove file %s Qid=%llx\n", f->d.name, f->d.qid.path); 228 if(f->d.qid.type&QTDIR) 229 for(s = f->child; s != nil; s = next){ 230 next = s->sibling; 231 sremove(server, s); 232 } 233 for(p = &server->ftab[hash(f->d.qid.path)]; *p; p = &(*p)->next) 234 if(*p == f){ 235 *p = f->next; 236 break; 237 } 238 for(p = &f->parent->child; *p; p = &(*p)->sibling) 239 if(*p == f){ 240 *p = f->sibling; 241 break; 242 } 243 styxfree(f->d.name); 244 styxfree(f->d.uid); 245 styxfree(f->d.gid); 246 styxfree(f); 247 } 248 249 int 250 styxrmfile(Styxserver *server, Path qid) 251 { 252 Styxfile *f; 253 254 f = styxfindfile(server, qid); 255 if(f != nil){ 256 if(f->parent == nil) 257 return -1; 258 sremove(server, f); 259 return 0; 260 } 261 return -1; 262 } 263 264 static void 265 incref(Styxfile *f) 266 { 267 if(f != nil) 268 f->ref++; 269 } 270 271 static void 272 decref(Styxfile *f) 273 { 274 if(f != nil) 275 --f->ref; 276 } 277 278 static void 279 increff(Fid *f) 280 { 281 incref(styxfindfile(f->client->server, f->qid.path)); 282 } 283 284 static void 285 decreff(Fid *f) 286 { 287 decref(styxfindfile(f->client->server, f->qid.path)); 288 } 289 290 static void 291 incopen(Fid *f) 292 { 293 Styxfile *file; 294 295 if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) 296 file->open++; 297 } 298 299 static void 300 decopen(Fid *f) 301 { 302 Styxfile *file; 303 304 if(f->open && (file = styxfindfile(f->client->server, f->qid.path)) != nil) 305 file->open--; 306 } 307 308 int 309 styxperm(Styxfile *f, char *uid, int mode) 310 { 311 int m, p; 312 313 p = 0; 314 switch(mode&3){ 315 case OREAD: p = AREAD; break; 316 case OWRITE: p = AWRITE; break; 317 case ORDWR: p = AREAD+AWRITE; break; 318 case OEXEC: p = AEXEC; break; 319 } 320 if(mode&OTRUNC) 321 p |= AWRITE; 322 m = f->d.mode&7; 323 if((p&m) == p) 324 return 1; 325 if(strcmp(f->d.uid, uid) == 0){ 326 m |= (f->d.mode>>6)&7; 327 if((p&m) == p) 328 return 1; 329 } 330 if(strcmp(f->d.gid, uid) == 0){ 331 m |= (f->d.mode>>3)&7; 332 if((p&m) == p) 333 return 1; 334 } 335 return 0; 336 } 337 338 static int 339 hash(Path path) 340 { 341 return path&(TABSZ-1); 342 } 343 344 Styxfile * 345 styxfindfile(Styxserver *server, Path path) 346 { 347 Styxfile *f; 348 349 for(f = server->ftab[hash(path)]; f != nil; f = f->next){ 350 if(f->d.qid.path == path) 351 return f; 352 } 353 return nil; 354 } 355 356 static Fid * 357 findfid(Client *c, short fid) 358 { 359 Fid *f; 360 for(f = c->fids; f && f->fid != fid; f = f->next) 361 ; 362 return f; 363 } 364 365 static void 366 deletefid(Client *c, Fid *d) 367 { 368 /* TODO: end any outstanding reads on this fid */ 369 Fid **f; 370 371 for(f = &c->fids; *f; f = &(*f)->next) 372 if(*f == d){ 373 decreff(d); 374 decopen(d); 375 *f = d->next; 376 styxfree(d); 377 return; 378 } 379 } 380 381 static void 382 deletefids(Client *c) 383 { 384 Fid *f, *g; 385 386 for(f = c->fids; f; f = g){ 387 decreff(f); 388 decopen(f); 389 g = f->next; 390 styxfree(f); 391 } 392 } 393 394 Fid * 395 newfid(Client *c, short fid, Qid qid){ 396 Fid *f; 397 398 f = styxmalloc(sizeof(Fid)); 399 ASSERT(f, "newfid"); 400 f->client = c; 401 f->fid = fid; 402 f->open = 0; 403 f->dri = 0; 404 f->qid = qid; 405 f->next = c->fids; 406 c->fids = f; 407 increff(f); 408 return f; 409 } 410 411 static void 412 flushtag(int oldtag) 413 { 414 USED(oldtag); 415 } 416 417 int 418 eqqid(Qid a, Qid b) 419 { 420 return a.path == b.path && a.vers == b.vers; 421 } 422 423 static Fid * 424 fidclone(Fid *old, short fid) 425 { 426 Fid *new; 427 428 new = newfid(old->client, fid, old->qid); 429 return new; 430 } 431 432 static Walkqid* 433 devwalk(Client *c, Styxfile *file, Fid *fp, Fid *nfp, char **name, int nname, char **err) 434 { 435 Styxserver *server; 436 long j; 437 Walkqid *wq; 438 char *n; 439 Styxfile *p, *f; 440 Styxops *ops; 441 Qid qid; 442 443 *err = nil; 444 server = c->server; 445 ops = server->ops; 446 447 wq = styxmalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); 448 wq->nqid = 0; 449 450 p = file; 451 qid = p != nil ? p->d.qid : fp->qid; 452 for(j = 0; j < nname; j++){ 453 if(!(qid.type&QTDIR)){ 454 if(j == 0) 455 styxfatal("devwalk error"); 456 *err = Enotdir; 457 goto Done; 458 } 459 if(p != nil && !styxperm(p, c->uname, OEXEC)){ 460 *err = Eperm; 461 goto Done; 462 } 463 n = name[j]; 464 if(strcmp(n, ".") == 0){ 465 Accept: 466 wq->qid[wq->nqid++] = nfp->qid; 467 continue; 468 } 469 if(p != nil && strcmp(n, "..") == 0 && p->parent){ 470 decref(p); 471 nfp->qid.path = p->parent->d.qid.path; 472 nfp->qid.type = p->parent->d.qid.type; 473 nfp->qid.vers = 0; 474 incref(p->parent); 475 p = p->parent; 476 qid = p->d.qid; 477 goto Accept; 478 } 479 480 if(ops->walk != nil){ 481 char *e; 482 483 e = ops->walk(&qid, n); 484 if(e == nil){ 485 decreff(nfp); 486 nfp->qid = qid; 487 increff(nfp); 488 p = styxfindfile(server, qid.path); 489 if(server->needfile && p == nil) 490 goto Done; 491 qid = p != nil ? p->d.qid : nfp->qid; 492 goto Accept; 493 } 494 } 495 496 if(p != nil) 497 for(f = p->child; f != nil; f = f->sibling){ 498 if(strcmp(n, f->d.name) == 0){ 499 decref(p); 500 nfp->qid.path = f->d.qid.path; 501 nfp->qid.type = f->d.qid.type; 502 nfp->qid.vers = 0; 503 incref(f); 504 p = f; 505 qid = p->d.qid; 506 goto Accept; 507 } 508 } 509 if(j == 0 && *err == nil) 510 *err = Enonexist; 511 goto Done; 512 } 513 Done: 514 if(*err != nil){ 515 styxfree(wq); 516 return nil; 517 } 518 return wq; 519 } 520 521 static long 522 devdirread(Fid *fp, Styxfile *file, char *d, long n) 523 { 524 long dsz, m; 525 Styxfile *f; 526 int i; 527 528 struct{ 529 Dir d; 530 char slop[100]; /* TO DO */ 531 }dir; 532 533 f = file->child; 534 for(i = 0; i < fp->dri; i++) 535 if(f == 0) 536 return 0; 537 else 538 f = f->sibling; 539 for(m = 0; m < n; fp->dri++){ 540 if(f == nil) 541 break; 542 dir.d = f->d; 543 dsz = convD2M(&dir.d, (uchar*)d, n-m); 544 m += dsz; 545 d += dsz; 546 f = f->sibling; 547 } 548 549 return m; 550 } 551 552 static char* 553 nilconv(char *s) 554 { 555 if(s != nil && s[0] == '\0') 556 return nil; 557 return s; 558 } 559 560 static Styxfile * 561 newfile(Styxserver *server, Styxfile *parent, int isdir, Path qid, char *name, int mode, char *owner) 562 { 563 Styxfile *file; 564 Dir d; 565 int h; 566 567 if(qid == -1) 568 qid = server->qidgen++; 569 file = styxfindfile(server, qid); 570 if(file != nil) 571 return nil; 572 if(parent != nil){ 573 for(file = parent->child; file != nil; file = file->sibling) 574 if(strcmp(name, file->d.name) == 0) 575 return nil; 576 } 577 file = (Styxfile *)styxmalloc(sizeof(Styxfile)); 578 file->parent = parent; 579 file->child = nil; 580 h = hash(qid); 581 file->next = server->ftab[h]; 582 server->ftab[h] = file; 583 if(parent){ 584 file->sibling = parent->child; 585 parent->child = file; 586 }else 587 file->sibling = nil; 588 589 d.type = 'X'; 590 d.dev = 'x'; 591 d.qid.path = qid; 592 d.qid.type = 0; 593 d.qid.vers = 0; 594 d.mode = mode; 595 d.atime = time(0); 596 d.mtime = boottime; 597 d.length = 0; 598 d.name = strdup(name); 599 d.uid = strdup(owner); 600 d.gid = strdup(eve); 601 d.muid = ""; 602 603 if(isdir){ 604 d.qid.type |= QTDIR; 605 d.mode |= DMDIR; 606 } 607 else{ 608 d.qid.type &= ~QTDIR; 609 d.mode &= ~DMDIR; 610 } 611 612 file->d = d; 613 file->ref = 0; 614 file->open = 0; 615 if(Debug) 616 fprint(2, "New file %s Qid=%llx\n", name, qid); 617 return file; 618 } 619 620 static void 621 run(Client *c) 622 { 623 Fcall f; 624 Fid *fp, *nfp; 625 int i, open, mode; 626 char ebuf[EMSGLEN]; 627 Walkqid *wq; 628 Styxfile *file; 629 Dir dir; 630 Qid qid; 631 Styxops *ops; 632 char strs[128]; 633 634 ebuf[0] = 0; 635 if(rd(c, &f) <= 0) 636 return; 637 if(f.type == Tflush){ 638 flushtag(f.oldtag); 639 f.type = Rflush; 640 wr(c, &f); 641 return; 642 } 643 ops = c->server->ops; 644 file = nil; 645 fp = findfid(c, f.fid); 646 if(f.type != Tversion && f.type != Tauth && f.type != Tattach){ 647 if(fp == nil){ 648 f.type = Rerror; 649 f.ename = Enofid; 650 wr(c, &f); 651 return; 652 } 653 else{ 654 file = styxfindfile(c->server, fp->qid.path); 655 if(c->server->needfile && file == nil){ 656 f.type = Rerror; 657 f.ename = Enonexist; 658 wr(c, &f); 659 return; 660 } 661 } 662 } 663 /* if(fp == nil) fprint(2, "fid not found for %d\n", f.fid); */ 664 switch(f.type){ 665 case Twalk: 666 if(Debug){ 667 fprint(2, "Twalk %d %d", f.fid, f.newfid); 668 for(i = 0; i < f.nwname; i++) 669 fprint(2, " %s", f.wname[i]); 670 fprint(2, "\n"); 671 } 672 nfp = findfid(c, f.newfid); 673 f.type = Rerror; 674 if(nfp){ 675 deletefid(c, nfp); 676 nfp = nil; 677 } 678 if(nfp){ 679 f.ename = "fid in use"; 680 if(Debug) fprint(2, "walk: %s\n", f.ename); 681 wr(c, &f); 682 break; 683 }else if(fp->open){ 684 f.ename = "can't clone"; 685 wr(c, &f); 686 break; 687 } 688 if(f.newfid != f.fid) 689 nfp = fidclone(fp, f.newfid); 690 else 691 nfp = fp; 692 if((wq = devwalk(c, file, fp, nfp, f.wname, f.nwname, &f.ename)) == nil){ 693 if(nfp != fp) 694 deletefid(c, nfp); 695 f.type = Rerror; 696 }else{ 697 if(nfp != fp){ 698 if(wq->nqid != f.nwname) 699 deletefid(c, nfp); 700 } 701 f.type = Rwalk; 702 f.nwqid = wq->nqid; 703 for(i = 0; i < wq->nqid; i++) 704 f.wqid[i] = wq->qid[i]; 705 styxfree(wq); 706 } 707 wr(c, &f); 708 break; 709 case Topen: 710 if(Debug) 711 fprint(2, "Topen %d\n", f.fid); 712 f.ename = nil; 713 if(fp->open) 714 f.ename = Eopen; 715 else if((fp->qid.type&QTDIR) && (f.mode&(OWRITE|OTRUNC|ORCLOSE))) 716 f.ename = Eperm; 717 else if(file != nil && !styxperm(file, c->uname, f.mode)) 718 f.ename = Eperm; 719 else if((f.mode&ORCLOSE) && file != nil && file->parent != nil && !styxperm(file->parent, c->uname, OWRITE)) 720 f.ename = Eperm; 721 if(f.ename != nil){ 722 f.type = Rerror; 723 wr(c, &f); 724 break; 725 } 726 f.ename = Enonexist; 727 decreff(fp); 728 if(ops->open == nil || (f.ename = ops->open(&fp->qid, f.mode)) == nil){ 729 f.type = Ropen; 730 f.qid = fp->qid; 731 fp->mode = f.mode; 732 fp->open = 1; 733 fp->offset = 0; 734 incopen(fp); 735 } 736 else 737 f.type = Rerror; 738 increff(fp); 739 wr(c, &f); 740 break; 741 case Tcreate: 742 if(Debug) 743 fprint(2, "Tcreate %d %s\n", f.fid, f.name); 744 f.ename = nil; 745 if(fp->open) 746 f.ename = Eopen; 747 else if(!(fp->qid.type&QTDIR)) 748 f.ename = Enotdir; 749 else if((f.perm&DMDIR) && (f.mode&(OWRITE|OTRUNC|ORCLOSE))) 750 f.ename = Eperm; 751 else if(file != nil && !styxperm(file, c->uname, OWRITE)) 752 f.ename = Eperm; 753 if(f.ename != nil){ 754 f.type = Rerror; 755 wr(c, &f); 756 break; 757 } 758 f.ename = Eperm; 759 decreff(fp); 760 if(file != nil){ 761 if(f.perm&DMDIR) 762 f.perm = (f.perm&~0777) | (file->d.mode&f.perm&0777) | DMDIR; 763 else 764 f.perm = (f.perm&(~0777|0111)) | (file->d.mode&f.perm&0666); 765 } 766 if(ops->create && (f.ename = ops->create(&fp->qid, f.name, f.perm, f.mode)) == nil){ 767 f.type = Rcreate; 768 f.qid = fp->qid; 769 fp->mode = f.mode; 770 fp->open = 1; 771 fp->offset = 0; 772 incopen(fp); 773 } 774 else 775 f.type = Rerror; 776 increff(fp); 777 wr(c, &f); 778 break; 779 case Tread: 780 if(Debug) 781 fprint(2, "Tread %d\n", f.fid); 782 if(!fp->open){ 783 f.type = Rerror; 784 f.ename = Ebadfid; 785 wr(c, &f); 786 break; 787 } 788 if(fp->qid.type&QTDIR || (file != nil && file->d.qid.type&QTDIR)){ 789 f.type = Rread; 790 if(file == nil){ 791 f.ename = Eperm; 792 if(ops->read && (f.ename = ops->read(fp->qid, c->data, (ulong*)(&f.count), fp->dri)) == nil){ 793 f.data = c->data; 794 } 795 else 796 f.type = Rerror; 797 } 798 else{ 799 f.count = devdirread(fp, file, c->data, f.count); 800 f.data = c->data; 801 } 802 }else{ 803 f.ename = Eperm; 804 f.type = Rerror; 805 if(ops->read && (f.ename = ops->read(fp->qid, c->data, (ulong*)(&f.count), f.offset)) == nil){ 806 f.type = Rread; 807 f.data = c->data; 808 } 809 } 810 wr(c, &f); 811 break; 812 case Twrite: 813 if(Debug) 814 fprint(2, "Twrite %d\n", f.fid); 815 if(!fp->open){ 816 f.type = Rerror; 817 f.ename = Ebadfid; 818 wr(c, &f); 819 break; 820 } 821 f.ename = Eperm; 822 f.type = Rerror; 823 if(ops->write && (f.ename = ops->write(fp->qid, f.data, (ulong*)(&f.count), f.offset)) == nil){ 824 f.type = Rwrite; 825 } 826 wr(c, &f); 827 break; 828 case Tclunk: 829 if(Debug) 830 fprint(2, "Tclunk %d\n", f.fid); 831 open = fp->open; 832 mode = fp->mode; 833 qid = fp->qid; 834 deletefid(c, fp); 835 f.type = Rclunk; 836 if(open && ops->close && (f.ename = ops->close(qid, mode)) != nil) 837 f.type = Rerror; 838 wr(c, &f); 839 break; 840 case Tremove: 841 if(Debug) 842 fprint(2, "Tremove %d\n", f.fid); 843 if(file != nil && file->parent != nil && !styxperm(file->parent, c->uname, OWRITE)){ 844 f.type = Rerror; 845 f.ename = Eperm; 846 deletefid(c, fp); 847 wr(c, &f); 848 break; 849 } 850 f.ename = Eperm; 851 if(ops->remove && (f.ename = ops->remove(fp->qid)) == nil) 852 f.type = Rremove; 853 else 854 f.type = Rerror; 855 deletefid(c, fp); 856 wr(c, &f); 857 break; 858 case Tstat: 859 if(Debug) 860 fprint(2, "Tstat %d qid=%llx\n", f.fid, fp->qid.path); 861 f.stat = styxmalloc(MAXSTAT); 862 f.ename = "stat error"; 863 if(ops->stat == nil && file != nil){ 864 f.type = Rstat; 865 f.nstat = convD2M(&file->d, f.stat, MAXSTAT); 866 } 867 else if(ops->stat && (f.ename = ops->stat(fp->qid, &dir)) == nil){ 868 f.type = Rstat; 869 f.nstat = convD2M(&dir, f.stat, MAXSTAT); 870 } 871 else 872 f.type = Rerror; 873 wr(c, &f); 874 styxfree(f.stat); 875 break; 876 case Twstat: 877 if(Debug) 878 fprint(2, "Twstat %d\n", f.fid); 879 f.ename = Eperm; 880 convM2D(f.stat, f.nstat, &dir, strs); 881 dir.name = nilconv(dir.name); 882 dir.uid = nilconv(dir.uid); 883 dir.gid = nilconv(dir.gid); 884 dir.muid = nilconv(dir.muid); 885 if(ops->wstat && (f.ename = ops->wstat(fp->qid, &dir)) == nil) 886 f.type = Rwstat; 887 else 888 f.type = Rerror; 889 wr(c, &f); 890 break; 891 case Tversion: 892 if(Debug) 893 fprint(2, "Tversion\n"); 894 f.type = Rversion; 895 f.tag = NOTAG; 896 wr(c, &f); 897 break; 898 case Tauth: 899 if(Debug) 900 fprint(2, "Tauth\n"); 901 f.type = Rauth; 902 wr(c, &f); 903 break; 904 case Tattach: 905 if(Debug) 906 fprint(2, "Tattach %d %s %s\n", f.fid, f.uname[0] ? f.uname : c->uname, f.aname[0]? f.aname: c->aname); 907 if(fp){ 908 f.type = Rerror; 909 f.ename = "fid in use"; 910 }else{ 911 Qid q; 912 913 if(f.uname[0]){ 914 free(c->uname); 915 c->uname = strdup(f.uname); 916 } 917 if(f.aname[0]){ 918 free(c->aname); 919 c->aname = strdup(f.aname); 920 } 921 q.path = Qroot; 922 q.type = QTDIR; 923 q.vers = 0; 924 fp = newfid(c, f.fid, q); 925 f.type = Rattach; 926 f.fid = fp->fid; 927 f.qid = q; 928 if(ops->attach && (f.ename = ops->attach(c->uname, c->aname)) != nil) 929 f.type = Rerror; 930 } 931 wr(c, &f); 932 break; 933 } 934 } 935 936 char * 937 styxinit(Styxserver *server, Styxops *ops, char *port, int perm, int needfile) 938 { 939 int i; 940 941 if(Debug) 942 fprint(2, "Initialising Styx server on port %s\n", port); 943 if(perm == -1) 944 perm = 0555; 945 server->ops = ops; 946 server->clients = nil; 947 server->root = nil; 948 server->ftab = (Styxfile**)malloc(TABSZ*sizeof(Styxfile*)); 949 for(i = 0; i < TABSZ; i++) 950 server->ftab[i] = nil; 951 server->qidgen = Qroot+1; 952 if(styxinitsocket() < 0) 953 return "styxinitsocket failed"; 954 server->connfd = styxannounce(server, port); 955 if(server->connfd < 0) 956 return "can't announce on network port"; 957 styxinitwait(server); 958 server->root = newfile(server, nil, 1, Qroot, "/", perm|DMDIR, eve); 959 server->needfile = needfile; 960 return nil; 961 } 962 963 char* 964 styxend(Styxserver *server) 965 { 966 USED(server); 967 styxendsocket(); 968 return nil; 969 } 970 971 char * 972 styxwait(Styxserver *server) 973 { 974 return styxwaitmsg(server); 975 } 976 977 char * 978 styxprocess(Styxserver *server) 979 { 980 Client *c; 981 int s; 982 983 if(styxnewcall(server)){ 984 s = styxaccept(server); 985 if(s >= 0){ 986 newclient(server, s); 987 styxnewclient(server, s); 988 } 989 } 990 for(c = server->clients; c != nil; ){ 991 Client *next = c->next; 992 993 server->curc = c; 994 if(c->fd >= 0 && styxnewmsg(server, c->fd)) 995 c->state |= CRECV; 996 if(c->state&(CNREAD|CRECV)){ 997 if(c->state&CDISC){ 998 styxfreeclient(server, c->fd); 999 freeclient(c); 1000 }else 1001 do 1002 run(c); 1003 while(c->state&CNREAD); 1004 } 1005 c = next; 1006 } 1007 1008 return nil; 1009 } 1010 1011 Client* 1012 styxclient(Styxserver *server) 1013 { 1014 return server->curc; 1015 } 1016 1017 Styxfile* 1018 styxaddfile(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner) 1019 { 1020 Styxfile *f, *parent; 1021 1022 parent = styxfindfile(server, pqid); 1023 if(parent == nil || (parent->d.qid.type&QTDIR) == 0) 1024 return nil; 1025 f = newfile(server, parent, 0, qid, name, mode, owner); 1026 return f; 1027 } 1028 1029 Styxfile* 1030 styxadddir(Styxserver *server, Path pqid, Path qid, char *name, int mode, char *owner) 1031 { 1032 Styxfile *f, *parent; 1033 1034 parent = styxfindfile(server, pqid); 1035 if(parent == nil || (parent->d.qid.type&QTDIR) == 0) 1036 return nil; 1037 f = newfile(server, parent, 1, qid, name, mode|DMDIR, owner); 1038 return f; 1039 } 1040 1041 long 1042 styxreadstr(ulong off, char *buf, ulong n, char *str) 1043 { 1044 int size; 1045 1046 size = strlen(str); 1047 if(off >= size) 1048 return 0; 1049 if(off+n > size) 1050 n = size-off; 1051 memmove(buf, str+off, n); 1052 return n; 1053 } 1054 1055 Qid 1056 styxqid(int path, int isdir) 1057 { 1058 Qid q; 1059 1060 q.path = path; 1061 q.vers = 0; 1062 if(isdir) 1063 q.type = QTDIR; 1064 else 1065 q.type = 0; 1066 return q; 1067 } 1068 1069 void 1070 styxsetowner(char *name) 1071 { 1072 eve = name; 1073 } 1074