1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include "9p1.h" 6 7 char *user; 8 int newfd; 9 int roldfd; 10 int woldfd; 11 int debug; 12 int dofcall; 13 QLock servelock; 14 QLock fidlock; 15 QLock taglock; 16 int mainpid; 17 int ntag; 18 int nfork; 19 char FLUSHED[] = "FLUSHED"; 20 21 enum{ 22 Maxfdata = 8192 23 }; 24 25 enum{ 26 Command, 27 Network, 28 File, 29 Stdio, 30 }; 31 32 typedef struct Tag Tag; 33 struct Tag 34 { 35 int tag; 36 int flushed; 37 int received; 38 int ref; 39 Tag *next; 40 }; 41 42 typedef struct Message Message; 43 struct Message 44 { 45 char *data; 46 int n; 47 }; 48 49 typedef struct Fid Fid; 50 51 struct Fid 52 { 53 short busy; 54 short allocated; 55 int fid; 56 Qid qid; 57 ulong newoffset; 58 ulong oldoffset; 59 Fid *next; 60 }; 61 62 Fid *fids; 63 Tag *tags; 64 65 char *rflush(Fcall*, Fcall*, char*), 66 *rversion(Fcall*, Fcall*, char*), 67 *rauth(Fcall*, Fcall*, char*), 68 *rattach(Fcall*, Fcall*, char*), 69 *rwalk(Fcall*, Fcall*, char*), 70 *ropen(Fcall*, Fcall*, char*), 71 *rcreate(Fcall*, Fcall*, char*), 72 *rread(Fcall*, Fcall*, char*), 73 *rwrite(Fcall*, Fcall*, char*), 74 *rclunk(Fcall*, Fcall*, char*), 75 *rremove(Fcall*, Fcall*, char*), 76 *rstat(Fcall*, Fcall*, char*), 77 *rwstat(Fcall*, Fcall*, char*); 78 79 char *(*fcalls[])(Fcall*, Fcall*, char*) = { 80 [Tversion] rversion, 81 [Tflush] rflush, 82 [Tauth] rauth, 83 [Tattach] rattach, 84 [Twalk] rwalk, 85 [Topen] ropen, 86 [Tcreate] rcreate, 87 [Tread] rread, 88 [Twrite] rwrite, 89 [Tclunk] rclunk, 90 [Tremove] rremove, 91 [Tstat] rstat, 92 [Twstat] rwstat, 93 }; 94 95 char Etoolong[] = "name too long"; 96 97 void connect(int, char*); 98 void post(int, char*); 99 void serve(void); 100 void demux(void); 101 void* emalloc(ulong); 102 char* transact9p1(Fcall9p1*, Fcall9p1*, char*); 103 Fid* newfid(int); 104 105 struct 106 { 107 char chal[CHALLEN]; /* my challenge */ 108 char rchal[CHALLEN]; /* his challenge */ 109 char authid[NAMEREC]; 110 char authdom[DOMLEN]; 111 int id; 112 } ai; 113 114 void 115 usage(void) 116 { 117 fprint(2, "usage: srvold9p [-abcCd] [-u user] [-s | [-m mountpoint]] [-x 'command' | -n network-addr | -f file] [-F] [-p servicename]\n"); 118 exits("usage"); 119 } 120 121 void 122 main(int argc, char *argv[]) 123 { 124 int method; 125 char *oldstring; 126 char *mountpoint, *postname; 127 int mountflag, mountfd; 128 int p[2]; 129 int i; 130 131 fmtinstall('F', fcallfmt); 132 fmtinstall('G', fcallfmt9p1); 133 fmtinstall('D', dirfmt); 134 135 user = getuser(); 136 mountpoint = nil; 137 mountflag = 0; 138 postname = nil; 139 oldstring = nil; 140 method = -1; 141 mountfd = -1; 142 143 ARGBEGIN{ 144 case 'a': 145 mountflag |= MAFTER; 146 break; 147 case 'b': 148 mountflag |= MBEFORE; 149 break; 150 case 'c': 151 mountflag |= MCREATE; 152 break; 153 case 'C': 154 mountflag |= MCACHE; 155 break; 156 case 'd': 157 debug++; 158 break; 159 case 'f': 160 method = File; 161 oldstring = ARGF(); 162 break; 163 case 'F': 164 dofcall++; 165 break; 166 case 'm': 167 mountpoint = EARGF(usage()); 168 break; 169 case 'n': 170 method = Network; 171 oldstring = ARGF(); 172 break; 173 case 'p': 174 postname = ARGF(); 175 if(postname == nil) 176 usage(); 177 break; 178 case 's': 179 method = Stdio; 180 break; 181 case 'u': 182 user = EARGF(usage()); 183 break; 184 case 'x': 185 method = Command; 186 oldstring = ARGF(); 187 break; 188 default: 189 usage(); 190 }ARGEND; 191 192 if(method == Stdio){ 193 if(mountpoint!=nil || argc!=0) 194 usage(); 195 }else{ 196 if(oldstring == nil || argc != 0 || (mountflag!=0 && mountpoint==nil)) 197 usage(); 198 } 199 200 rfork(RFNOTEG|RFREND); 201 202 connect(method, oldstring); 203 204 if(method == Stdio) 205 newfd = 0; 206 else{ 207 if(pipe(p) < 0) 208 fatal("pipe: %r"); 209 if(postname != nil) 210 post(p[0], postname); 211 mountfd = p[0]; 212 newfd = p[1]; 213 } 214 if(debug) 215 fprint(2, "connected and posted\n"); 216 217 switch(rfork(RFPROC|RFMEM|RFNAMEG|RFFDG)){ 218 case 0: 219 mainpid = getpid(); 220 /* child does all the work */ 221 if(mountfd >= 0) 222 close(mountfd); 223 switch(rfork(RFPROC|RFMEM|RFFDG)){ 224 case 0: 225 for(i = 0; i < 20; i++) 226 if (i != roldfd) close(i); 227 demux(); 228 return; 229 case -1: 230 fatal("fork error: %r"); 231 break; 232 } 233 for(i = 0; i < 20; i++) 234 if (i != newfd && i != woldfd && (debug == 0 || i != 2)) close(i); 235 serve(); 236 break; 237 case -1: 238 fatal("fork error: %r"); 239 break; 240 default: 241 /* parent mounts if required, then exits */ 242 if(mountpoint){ 243 if(mount(mountfd, -1, mountpoint, mountflag, "") < 0) 244 fatal("can't mount: %r"); 245 } 246 break; 247 } 248 exits(nil); 249 } 250 251 void 252 connect(int method, char *oldstring) 253 { 254 char *s; 255 char dir[256]; 256 257 switch(method){ 258 default: 259 roldfd = -1; 260 woldfd = -1; 261 fatal("can't handle method type %d", method); 262 break; 263 case Network: 264 s = netmkaddr(oldstring, 0, "9fs"); 265 roldfd = dial(s, 0, dir, 0); 266 if(roldfd < 0) 267 fatal("dial %s: %r", s); 268 woldfd = roldfd; 269 if(dofcall) 270 roldfd = fcall(woldfd); 271 break; 272 case File: 273 roldfd = open(oldstring, ORDWR); 274 if(roldfd < 0) 275 fatal("can't open %s: %r", oldstring); 276 woldfd = roldfd; 277 if(dofcall) 278 roldfd = fcall(woldfd); 279 break; 280 case Stdio: 281 roldfd = fcall(1); 282 woldfd = 1; 283 break; 284 } 285 } 286 287 void 288 post(int fd, char *srv) 289 { 290 int f; 291 char buf[128]; 292 293 snprint(buf, sizeof buf, "/srv/%s", srv); 294 f = create(buf, OWRITE, 0666); 295 if(f < 0) 296 fatal("can't create %s: %r", buf); 297 sprint(buf, "%d", fd); 298 if(write(f, buf, strlen(buf)) != strlen(buf)) 299 fatal("post write: %r"); 300 close(f); 301 } 302 303 Fid * 304 newfid(int fid) 305 { 306 Fid *f, *ff; 307 308 ff = 0; 309 qlock(&fidlock); 310 for(f = fids; f; f = f->next) 311 if(f->fid == fid){ 312 f->allocated = 1; 313 qunlock(&fidlock); 314 return f; 315 } 316 else if(!ff && !f->allocated) 317 ff = f; 318 if(ff){ 319 ff->fid = fid; 320 ff->allocated = 1; 321 qunlock(&fidlock); 322 return ff; 323 } 324 f = emalloc(sizeof *f); 325 f->fid = fid; 326 f->next = fids; 327 f->allocated = 1; 328 fids = f; 329 qunlock(&fidlock); 330 return f; 331 } 332 333 /* 334 * Reads returning 9P1 messages and demultiplexes them. 335 * BUG: assumes one read per message. 336 */ 337 void 338 demux(void) 339 { 340 int m, n; 341 char *data; 342 Fcall9p1 r; 343 Message *msg; 344 Tag *t; 345 346 for(;;){ 347 data = malloc(IOHDRSZ+Maxfdata); /* no need to clear memory */ 348 if(data == nil) 349 fatal("demux malloc: %r"); 350 m = read(roldfd, data, IOHDRSZ+Maxfdata); 351 if(m <= 0) 352 fatal("read error talking to old system: %r"); 353 n = convM2S9p1(data, &r, m); 354 if(n == 0) 355 fatal("bad conversion receiving from old system"); 356 if(debug) 357 fprint(2, "srvold9p:<=%G\n", &r); 358 qlock(&taglock); 359 for(t=tags; t!=nil; t=t->next) 360 if(t->tag == r.tag){ 361 t->received = 1; 362 break; 363 } 364 qunlock(&taglock); 365 /* 366 * Fcall9p1 tag is used to rendezvous. 367 * Recipient converts message a second time, but that's OK. 368 */ 369 msg = emalloc(sizeof(Message)); 370 msg->data = data; 371 msg->n = n; 372 rendezvous(r.tag, (ulong)msg); 373 } 374 } 375 376 Tag* 377 newtag(int tag) 378 { 379 Tag *t; 380 381 t = emalloc(sizeof(Tag)); 382 t->tag = tag; 383 t->flushed = 0; 384 t->received = 0; 385 t->ref = 1; 386 qlock(&taglock); 387 t->next = tags; 388 tags = t; 389 qunlock(&taglock); 390 return t; 391 } 392 393 void 394 freetag(Tag *tag) /* called with taglock set */ 395 { 396 Tag *t, *prev; 397 398 if(tag->ref-- == 1){ 399 prev = nil; 400 for(t=tags; t!=nil; t=t->next){ 401 if(t == tag){ 402 if(prev == nil) 403 tags = t->next; 404 else 405 prev->next = t->next; 406 break; 407 } 408 prev = t; 409 } 410 if(t == nil) 411 sysfatal("freetag"); 412 free(tag); 413 } 414 } 415 416 void 417 serve(void) 418 { 419 char *err; 420 int n; 421 Fcall thdr; 422 Fcall rhdr; 423 uchar mdata[IOHDRSZ+Maxfdata]; 424 char mdata9p1[IOHDRSZ+Maxfdata]; 425 Tag *tag; 426 427 for(;;){ 428 qlock(&servelock); 429 for(;;){ 430 n = read9pmsg(newfd, mdata, sizeof mdata); 431 432 if(n == 0) 433 continue; 434 if(n < 0) 435 break; 436 if(n > 0 && convM2S(mdata, n, &thdr) > 0) 437 break; 438 } 439 if(n>0 && servelock.head==nil) /* no other processes waiting to read */ 440 switch(rfork(RFPROC|RFMEM)){ 441 case 0: 442 /* child starts serving */ 443 continue; 444 break; 445 case -1: 446 fatal("fork error: %r"); 447 break; 448 default: 449 break; 450 } 451 qunlock(&servelock); 452 453 if(n < 0) 454 fatal(nil); /* exit quietly; remote end has just hung up */ 455 456 if(debug) 457 fprint(2, "srvold9p:<-%F\n", &thdr); 458 459 tag = newtag(thdr.tag); 460 461 if(!fcalls[thdr.type]) 462 err = "bad fcall type"; 463 else 464 err = (*fcalls[thdr.type])(&thdr, &rhdr, mdata9p1); 465 466 qlock(&taglock); 467 if(tag->flushed){ 468 freetag(tag); 469 qunlock(&taglock); 470 continue; 471 } 472 qunlock(&taglock); 473 474 if(err){ 475 rhdr.type = Rerror; 476 rhdr.ename = err; 477 }else{ 478 rhdr.type = thdr.type + 1; 479 rhdr.fid = thdr.fid; 480 } 481 rhdr.tag = thdr.tag; 482 if(debug) 483 fprint(2, "srvold9p:->%F\n", &rhdr);/**/ 484 n = convS2M(&rhdr, mdata, sizeof mdata); 485 if(n == 0) 486 fatal("convS2M error on write"); 487 if(write(newfd, mdata, n) != n) 488 fatal("mount write"); 489 490 qlock(&taglock); 491 freetag(tag); 492 qunlock(&taglock); 493 } 494 } 495 496 void 497 send9p1(Fcall9p1 *t, char *data) 498 { 499 int m, n; 500 501 if(debug) 502 fprint(2, "srvold9p:=>%G\n", t); 503 n = convS2M9p1(t, data); 504 if(n == 0) 505 fatal("bad conversion sending to old system"); 506 m = write(woldfd, data, n); 507 if(m != n) 508 fatal("wrote %d to old system; should be %d", m, n); 509 } 510 511 int 512 recv9p1(Fcall9p1 *r, int tag, char *data) 513 { 514 int n; 515 Message *msg; 516 517 msg = (Message*)rendezvous(tag, 0); 518 if((ulong)msg == ~0UL) 519 fatal("rendezvous: %r"); 520 if(msg == nil){ 521 if(debug) 522 fprint(2, "recv flushed\n"); 523 return -1; 524 } 525 /* copy data to local buffer */ 526 memmove(data, msg->data, msg->n); 527 n = convM2S9p1(data, r, msg->n); 528 if(n == 0) 529 fatal("bad conversion receiving from old system"); 530 free(msg->data); 531 free(msg); 532 return 1; 533 } 534 535 char* 536 transact9p1(Fcall9p1 *t, Fcall9p1 *r, char *mdata9p1) 537 { 538 send9p1(t, mdata9p1); 539 if(recv9p1(r, t->tag, mdata9p1) < 0) 540 return FLUSHED; 541 if(r->type == Rerror9p1) 542 return r->ename; 543 if(r->type != t->type+1) 544 fatal("bad message type; expected %d got %d", t->type+1, r->type); 545 return nil; 546 } 547 548 char* 549 rflush(Fcall *t, Fcall *, char *mdata9p1) 550 { 551 Fcall9p1 t9, r9; 552 Tag *oldt; 553 554 t9.type = Tflush9p1; 555 t9.tag = t->tag; 556 t9.oldtag = t->oldtag; 557 qlock(&taglock); 558 for(oldt=tags; oldt!=nil; oldt=oldt->next) 559 if(oldt->tag == t->oldtag){ 560 oldt->flushed = 1; 561 oldt->ref++; 562 break; 563 } 564 qunlock(&taglock); 565 566 if(oldt == nil){ /* nothing to flush */ 567 if(debug) 568 fprint(2, "no such tag to flush\n"); 569 return 0; 570 } 571 572 transact9p1(&t9, &r9, mdata9p1); /* can't error */ 573 574 qlock(&taglock); 575 if(oldt->received == 0){ /* wake up receiver */ 576 if(debug) 577 fprint(2, "wake up receiver\n"); 578 oldt->received = 1; 579 rendezvous(t->oldtag, 0); 580 } 581 freetag(oldt); 582 qunlock(&taglock); 583 return 0; 584 } 585 586 char* 587 rversion(Fcall *t, Fcall *r, char*) 588 { 589 Fid *f; 590 591 /* just ack; this one doesn't go to old service */ 592 if(t->msize > IOHDRSZ+Maxfdata) 593 r->msize = IOHDRSZ+Maxfdata; 594 else 595 r->msize = t->msize; 596 if(strncmp(t->version, "9P2000", 6) != 0) 597 return "unknown 9P version"; 598 r->version = "9P2000"; 599 600 qlock(&fidlock); 601 for(f = fids; f; f = f->next){ 602 f->busy = 0; 603 f->allocated = 0; 604 } 605 qunlock(&fidlock); 606 607 return 0; 608 } 609 610 char* 611 rauth(Fcall *, Fcall *, char *) 612 { 613 return "srvold9p: authentication not supported"; 614 } 615 616 #ifdef asdf 617 618 void 619 memrandom(void *p, int n) 620 { 621 ulong *lp; 622 uchar *cp; 623 624 for(lp = p; n >= sizeof(ulong); n -= sizeof(ulong)) 625 *lp++ = fastrand(); 626 for(cp = (uchar*)lp; n > 0; n--) 627 *cp++ = fastrand(); 628 } 629 630 char* 631 rsession(Fcall *t, Fcall *r, char *mdata9p1) 632 { 633 char *err; 634 Fcall9p1 t9, r9; 635 Fid *f; 636 637 t9.type = Tsession9p1; 638 t9.tag = t->tag; 639 if(doauth) 640 memrandom(t9.chal, sizeof t9.chal); 641 else 642 memset(t9.chal, 0, sizeof t9.chal); 643 err = transact9p1(&t9, &r9, mdata9p1); 644 if(err) 645 return err; 646 647 qlock(&fidlock); 648 for(f = fids; f; f = f->next){ 649 f->busy = 0; 650 f->allocated = 0; 651 } 652 qunlock(&fidlock); 653 654 if(doauth){ 655 memmove(ai.authid, r9.authid, sizeof ai.authid); 656 memmove(ai.authdom, r9.authdom, sizeof ai.authid); 657 memmove(ai.rchal, r9.chal, sizeof ai.rchal); 658 memmove(ai.chal, t9.chal, sizeof ai.chal); 659 r->authid = ai.authid; 660 r->authdom = ai.authdom; 661 r->chal = (uchar*)ai.rchal; 662 r->nchal = CHALLEN; 663 } else { 664 r->authid = ""; 665 r->authdom = ""; 666 r->nchal = 0; 667 r->chal = nil; 668 } 669 return 0; 670 } 671 #endif 672 673 char* 674 rattach(Fcall *t, Fcall *r, char *mdata9p1) 675 { 676 char *err; 677 Fcall9p1 t9, r9; 678 Fid *f; 679 680 f = newfid(t->fid); 681 if(f->busy) 682 return "attach: fid in use"; 683 /* no authentication! */ 684 t9.type = Tattach9p1; 685 t9.tag = t->tag; 686 t9.fid = t->fid; 687 strncpy(t9.uname, t->uname, NAMEREC); 688 if(strcmp(user, "none") == 0) 689 strncpy(t9.uname, user, NAMEREC); 690 strncpy(t9.aname, t->aname, NAMEREC); 691 memset(t9.ticket, 0, sizeof t9.ticket); 692 memset(t9.auth, 0, sizeof t9.auth); 693 err = transact9p1(&t9, &r9, mdata9p1); 694 if(err) 695 return err; 696 697 r->qid.path = r9.qid.path & ~0x80000000; 698 r->qid.vers = r9.qid.version; 699 r->qid.type = QTDIR; 700 f->busy = 1; 701 f->qid = r->qid; 702 return 0; 703 } 704 705 char* 706 rwalk(Fcall *t, Fcall *r, char *mdata9p1) 707 { 708 char *err; 709 Fcall9p1 t9, r9; 710 int i, fid; 711 Qid *q; 712 Fid *f, *nf; 713 714 f = newfid(t->fid); 715 if(!f->busy) 716 return "walk: bad fid"; 717 718 fid = t->fid; 719 nf = nil; 720 if(t->fid != t->newfid){ 721 nf = newfid(t->newfid); 722 if(nf->busy) 723 return "walk: newfid in use"; 724 t9.type = Tclone9p1; 725 t9.tag = t->tag; 726 t9.fid = t->fid; 727 t9.newfid = t->newfid; 728 err = transact9p1(&t9, &r9, mdata9p1); 729 if(err){ 730 nf->busy = 0; 731 nf->allocated = 0; 732 return err; 733 } 734 fid = t->newfid; 735 nf->busy = 1; 736 } 737 738 err = nil; 739 r->nwqid = 0; 740 for(i=0; i<t->nwname && err==nil; i++){ 741 if(i > MAXWELEM) 742 break; 743 t9.type = Twalk9p1; 744 t9.tag = t->tag; 745 t9.fid = fid; 746 strncpy(t9.name, t->wname[i], NAMEREC); 747 err = transact9p1(&t9, &r9, mdata9p1); 748 if(err == FLUSHED){ 749 i = -1; /* guarantee cleanup */ 750 break; 751 } 752 if(err == nil){ 753 q = &r->wqid[r->nwqid++]; 754 q->type = QTFILE; 755 if(r9.qid.path & 0x80000000) 756 q->type = QTDIR; 757 q->vers = r9.qid.version; 758 q->path = r9.qid.path & ~0x80000000; 759 } 760 } 761 762 if(nf!=nil && (err!=nil || i<t->nwname)){ 763 /* clunk the new fid */ 764 t9.type = Tclunk9p1; 765 t9.tag = t->tag; 766 t9.fid = t->newfid; 767 transact9p1(&t9, &r9, mdata9p1); 768 /* ignore more errors */ 769 nf->busy = 0; 770 nf->allocated = 0; 771 } 772 773 if(i>0 && i==t->nwname && err==nil) 774 f->qid = r->wqid[r->nwqid-1]; 775 if(i > 0) 776 return 0; 777 return err; 778 } 779 780 char* 781 ropen(Fcall *t, Fcall *r, char *mdata9p1) 782 { 783 char *err; 784 Fcall9p1 t9, r9; 785 Fid *f; 786 787 f = newfid(t->fid); 788 if(!f->busy) 789 return "open: bad fid"; 790 791 t9.type = Topen9p1; 792 t9.tag = t->tag; 793 t9.fid = t->fid; 794 t9.mode = t->mode; 795 err = transact9p1(&t9, &r9, mdata9p1); 796 if(err) 797 return err; 798 799 r->qid.path = r9.qid.path & ~0x80000000; 800 r->qid.vers = r9.qid.version; 801 r->qid.type = QTFILE; 802 if(r9.qid.path & 0x80000000) 803 r->qid.type = QTDIR; 804 f->qid = r->qid; 805 f->newoffset = 0; 806 f->oldoffset = 0; 807 r->iounit = 0; 808 return 0; 809 } 810 811 char* 812 rcreate(Fcall *t, Fcall *r, char *mdata9p1) 813 { 814 char *err; 815 Fcall9p1 t9, r9; 816 Fid *f; 817 818 f = newfid(t->fid); 819 if(!f->busy) 820 return "create: bad fid"; 821 822 t9.type = Tcreate9p1; 823 t9.tag = t->tag; 824 t9.fid = t->fid; 825 if(strlen(t->name)+1 >= NAMEREC) 826 return "file name element too long"; 827 strncpy(t9.name, t->name, NAMEREC); 828 t9.perm = t->perm; 829 t9.mode = t->mode; 830 err = transact9p1(&t9, &r9, mdata9p1); 831 if(err) 832 return err; 833 834 r->qid.path = r9.qid.path & ~0x80000000; 835 r->qid.vers = r9.qid.version; 836 r->qid.type = QTFILE; 837 if(r9.qid.path & 0x80000000) 838 r->qid.type = QTDIR; 839 if(r9.qid.path & 0x40000000) 840 r->qid.type |= QTAPPEND; 841 if(r9.qid.path & 0x20000000) 842 r->qid.type |= QTEXCL; 843 f->qid = r->qid; 844 r->iounit = 0; 845 return 0; 846 } 847 848 char* 849 dirrread(Fcall *t, Fcall *r, char *mdata9p1) 850 { 851 char *err; 852 Fcall9p1 t9, r9; 853 Fid *f; 854 int i, ndir, n, count; 855 Dir d; 856 uchar buf[Maxfdata]; 857 char *old; 858 859 f = newfid(t->fid); 860 if(!f->busy) 861 return "dirread: bad fid"; 862 863 if(f->newoffset != t->offset) 864 return "seek in directory disallowed"; 865 866 t9.type = Tread9p1; 867 t9.tag = t->tag; 868 t9.fid = t->fid; 869 t9.offset = f->oldoffset; 870 t9.count = t->count; /* new directories tend to be smaller, so this may overshoot */ 871 err = transact9p1(&t9, &r9, mdata9p1); 872 if(err) 873 return err; 874 875 ndir = r9.count/DIRREC; 876 old = r9.data; 877 count = 0; 878 for(i=0; i<ndir; i++){ 879 if(convM2D9p1(old, &d) != DIRREC) 880 return "bad dir conversion in read"; 881 n = convD2M(&d, buf+count, sizeof buf-count); 882 if(n<=BIT16SZ || count+n>t->count) 883 break; 884 old += DIRREC; 885 f->oldoffset += DIRREC; 886 f->newoffset += n; 887 count += n; 888 } 889 memmove(r9.data, buf, count); /* put it back in stable storage */ 890 r->data = r9.data; 891 r->count = count; 892 return 0; 893 } 894 895 char* 896 rread(Fcall *t, Fcall *r, char *mdata9p1) 897 { 898 char *err; 899 Fcall9p1 t9, r9; 900 Fid *f; 901 902 f = newfid(t->fid); 903 if(!f->busy) 904 return "read: bad fid"; 905 906 if(f->qid.type & QTDIR) 907 return dirrread(t, r, mdata9p1); 908 909 t9.type = Tread9p1; 910 t9.tag = t->tag; 911 t9.fid = t->fid; 912 t9.offset = t->offset; 913 t9.count = t->count; 914 err = transact9p1(&t9, &r9, mdata9p1); 915 if(err) 916 return err; 917 918 r->count = r9.count; 919 r->data = r9.data; /* points to stable storage */ 920 return 0; 921 } 922 923 char* 924 rwrite(Fcall *t, Fcall *r, char *mdata9p1) 925 { 926 char *err; 927 Fcall9p1 t9, r9; 928 Fid *f; 929 930 f = newfid(t->fid); 931 if(!f->busy) 932 return "write: bad fid"; 933 934 t9.type = Twrite9p1; 935 t9.tag = t->tag; 936 t9.fid = t->fid; 937 t9.offset = t->offset; 938 t9.count = t->count; 939 t9.data = t->data; 940 err = transact9p1(&t9, &r9, mdata9p1); 941 if(err) 942 return err; 943 944 r->count = r9.count; 945 return 0; 946 } 947 948 char* 949 rclunk(Fcall *t, Fcall *, char *mdata9p1) 950 { 951 Fcall9p1 t9, r9; 952 Fid *f; 953 954 f = newfid(t->fid); 955 if(!f->busy) 956 return "clunk: bad fid"; 957 t9.type = Tclunk9p1; 958 t9.tag = t->tag; 959 t9.fid = t->fid; 960 transact9p1(&t9, &r9, mdata9p1); 961 f->busy = 0; 962 f->allocated = 0; 963 /* disregard error */ 964 return 0; 965 } 966 967 char* 968 rremove(Fcall *t, Fcall*, char *mdata9p1) 969 { 970 char *err; 971 Fcall9p1 t9, r9; 972 Fid *f; 973 974 f = newfid(t->fid); 975 if(!f->busy) 976 return "remove: bad fid"; 977 t9.type = Tremove9p1; 978 t9.tag = t->tag; 979 t9.fid = t->fid; 980 err = transact9p1(&t9, &r9, mdata9p1); 981 f->busy = 0; 982 f->allocated = 0; 983 return err; 984 } 985 986 char* 987 rstat(Fcall *t, Fcall *r, char *mdata9p1) 988 { 989 Fcall9p1 t9, r9; 990 char *err; 991 Fid *f; 992 Dir d; 993 uchar buf[256]; /* big enough; there's no long names */ 994 995 f = newfid(t->fid); 996 if(!f->busy) 997 return "stat: bad fid"; 998 999 t9.type = Tstat9p1; 1000 t9.tag = t->tag; 1001 t9.fid = t->fid; 1002 err = transact9p1(&t9, &r9, mdata9p1); 1003 if(err) 1004 return err; 1005 1006 if(convM2D9p1(r9.stat, &d) != DIRREC) 1007 return "bad conversion in stat"; 1008 r->stat = buf; 1009 r->nstat = convD2M(&d, buf, sizeof buf); 1010 return 0; 1011 } 1012 1013 int 1014 anydefault(Dir *d) 1015 { 1016 if(d->name[0] == '\0') 1017 return 1; 1018 if(d->uid[0] == '\0') 1019 return 1; 1020 if(d->gid[0] == '\0') 1021 return 1; 1022 if(d->mode == ~0) 1023 return 1; 1024 if(d->mtime == ~0) 1025 return 1; 1026 return 0; 1027 } 1028 1029 char* 1030 rwstat(Fcall *t, Fcall *, char *mdata9p1) 1031 { 1032 Fcall9p1 t9, r9; 1033 char strs[DIRREC]; 1034 char *err; 1035 Fid *f; 1036 Dir d, cd; 1037 1038 f = newfid(t->fid); 1039 if(!f->busy) 1040 return "wstat: bad fid"; 1041 1042 convM2D(t->stat, t->nstat, &d, strs); 1043 cd = d; 1044 if(anydefault(&d)){ 1045 /* must first stat file so we can copy current values */ 1046 t9.type = Tstat9p1; 1047 t9.tag = t->tag; 1048 t9.fid = t->fid; 1049 err = transact9p1(&t9, &r9, mdata9p1); 1050 if(err) 1051 return err; 1052 if(convM2D9p1(r9.stat, &cd) != DIRREC) 1053 return "bad in conversion in wstat"; 1054 1055 /* fill in default values */ 1056 if(d.name[0] != '\0'){ 1057 if(strlen(d.name) >= NAMEREC) 1058 return Etoolong; 1059 cd.name = d.name; 1060 } 1061 if(d.uid[0] != '\0'){ 1062 if(strlen(d.uid) >= NAMEREC) 1063 return Etoolong; 1064 cd.uid = d.uid; 1065 } 1066 if(d.gid[0] != '\0'){ 1067 if(strlen(d.gid) >= NAMEREC) 1068 return Etoolong; 1069 cd.gid = d.gid; 1070 } 1071 if(d.mode != ~0) 1072 cd.mode = d.mode; 1073 if(d.mtime != ~0) 1074 cd.mtime = d.mtime; 1075 if(d.length != ~0LL) 1076 cd.length = d.length; 1077 } 1078 1079 if(convD2M9p1(&cd, t9.stat) != DIRREC) 1080 return "bad out conversion in wstat"; 1081 1082 t9.type = Twstat9p1; 1083 t9.tag = t->tag; 1084 t9.fid = t->fid; 1085 err = transact9p1(&t9, &r9, mdata9p1); 1086 if(err) 1087 return err; 1088 return 0; 1089 } 1090 1091 void * 1092 emalloc(ulong n) 1093 { 1094 void *p; 1095 1096 p = malloc(n); 1097 if(!p) 1098 fatal("out of memory: %r"); 1099 memset(p, 0, n); 1100 return p; 1101 } 1102 1103 void 1104 fatal(char *fmt, ...) 1105 { 1106 char buf[1024]; 1107 va_list arg; 1108 1109 if(fmt){ 1110 va_start(arg, fmt); 1111 vseprint(buf, buf+sizeof(buf), fmt, arg); 1112 va_end(arg); 1113 fprint(2, "%s: (pid %d) %s\n", argv0, getpid(), buf); 1114 }else 1115 buf[0] = '\0'; 1116 if(mainpid){ 1117 /* two hits are sometimes needed */ 1118 postnote(PNGROUP, mainpid, "die1 - from srvold9p"); 1119 postnote(PNGROUP, mainpid, "die2 - from srvold9p"); 1120 } 1121 exits(buf); 1122 } 1123