1 #include "dat.h" 2 #include "fns.h" 3 #include "error.h" 4 #include "kernel.h" 5 6 static int 7 growfd(Fgrp *f, int fd) 8 { 9 int n; 10 Chan **nfd, **ofd; 11 12 if(fd < f->nfd) 13 return 0; 14 n = f->nfd+DELTAFD; 15 if(n > MAXNFD) 16 n = MAXNFD; 17 if(fd >= n) 18 return -1; 19 nfd = malloc(n*sizeof(Chan*)); 20 if(nfd == nil) 21 return -1; 22 ofd = f->fd; 23 memmove(nfd, ofd, f->nfd*sizeof(Chan *)); 24 f->fd = nfd; 25 f->nfd = n; 26 free(ofd); 27 return 0; 28 } 29 30 static int 31 newfd(Chan *c) 32 { 33 int i; 34 Fgrp *f = up->env->fgrp; 35 36 lock(&f->l); 37 for(i=f->minfd; i<f->nfd; i++) 38 if(f->fd[i] == 0) 39 break; 40 if(i >= f->nfd && growfd(f, i) < 0){ 41 unlock(&f->l); 42 exhausted("file descriptors"); 43 return -1; 44 } 45 f->minfd = i + 1; 46 if(i > f->maxfd) 47 f->maxfd = i; 48 f->fd[i] = c; 49 unlock(&f->l); 50 return i; 51 } 52 53 Chan* 54 fdtochan(Fgrp *f, int fd, int mode, int chkmnt, int iref) 55 { 56 Chan *c; 57 58 c = 0; 59 lock(&f->l); 60 if(fd<0 || f->maxfd<fd || (c = f->fd[fd])==0) { 61 unlock(&f->l); 62 error(Ebadfd); 63 } 64 if(iref) 65 incref(&c->r); 66 unlock(&f->l); 67 68 if(chkmnt && (c->flag&CMSG)) 69 goto bad; 70 if(mode<0 || c->mode==ORDWR) 71 return c; 72 if((mode&OTRUNC) && c->mode==OREAD) 73 goto bad; 74 if((mode&~OTRUNC) != c->mode) 75 goto bad; 76 return c; 77 bad: 78 if(iref) 79 cclose(c); 80 error(Ebadusefd); 81 return nil; 82 } 83 84 long 85 kchanio(void *vc, void *buf, int n, int mode) 86 { 87 int r; 88 Chan *c; 89 90 c = vc; 91 if(waserror()) 92 return -1; 93 94 if(mode == OREAD) 95 r = devtab[c->type]->read(c, buf, n, c->offset); 96 else 97 r = devtab[c->type]->write(c, buf, n, c->offset); 98 99 lock(&c->l); 100 c->offset += r; 101 unlock(&c->l); 102 poperror(); 103 return r; 104 } 105 106 int 107 openmode(ulong o) 108 { 109 if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC)) 110 error(Ebadarg); 111 o &= ~(OTRUNC|OCEXEC|ORCLOSE); 112 if(o > OEXEC) 113 error(Ebadarg); 114 if(o == OEXEC) 115 return OREAD; 116 return o; 117 } 118 119 static void 120 fdclose(Fgrp *f, int fd) 121 { 122 int i; 123 Chan *c; 124 125 lock(&f->l); 126 c = f->fd[fd]; 127 if(c == 0) { 128 /* can happen for users with shared fd tables */ 129 unlock(&f->l); 130 return; 131 } 132 f->fd[fd] = 0; 133 if(fd == f->maxfd) 134 for(i=fd; --i>=0 && f->fd[i]==0; ) 135 f->maxfd = i; 136 if(fd < f->minfd) 137 f->minfd = fd; 138 unlock(&f->l); 139 cclose(c); 140 } 141 142 int 143 kchdir(char *path) 144 { 145 Chan *c; 146 Pgrp *pg; 147 148 if(waserror()) 149 return -1; 150 151 c = namec(path, Atodir, 0, 0); 152 pg = up->env->pgrp; 153 cclose(pg->dot); 154 pg->dot = c; 155 poperror(); 156 return 0; 157 } 158 159 int 160 kfgrpclose(Fgrp *f, int fd) 161 { 162 if(waserror()) 163 return -1; 164 165 /* 166 * Take no reference on the chan because we don't really need the 167 * data structure, and are calling fdtochan only for error checks. 168 * fdclose takes care of processes racing through here. 169 */ 170 fdtochan(f, fd, -1, 0, 0); 171 fdclose(f, fd); 172 poperror(); 173 return 0; 174 } 175 176 int 177 kclose(int fd) 178 { 179 return kfgrpclose(up->env->fgrp, fd); 180 } 181 182 int 183 kcreate(char *path, int mode, ulong perm) 184 { 185 int fd; 186 volatile struct { Chan *c; } c; 187 188 c.c = nil; 189 if(waserror()) { 190 cclose(c.c); 191 return -1; 192 } 193 194 openmode(mode&~OEXCL); /* error check only; OEXCL okay here */ 195 c.c = namec(path, Acreate, mode, perm); 196 fd = newfd(c.c); 197 if(fd < 0) 198 error(Enofd); 199 poperror(); 200 return fd; 201 } 202 203 int 204 kdup(int old, int new) 205 { 206 int fd; 207 Chan *oc; 208 Fgrp *f = up->env->fgrp; 209 volatile struct { Chan *c; } c; 210 211 if(waserror()) 212 return -1; 213 214 c.c = fdtochan(up->env->fgrp, old, -1, 0, 1); 215 if(c.c->qid.type & QTAUTH) 216 error(Eperm); 217 fd = new; 218 if(fd != -1) { 219 lock(&f->l); 220 if(fd < 0 || growfd(f, fd) < 0) { 221 unlock(&f->l); 222 cclose(c.c); 223 error(Ebadfd); 224 } 225 if(fd > f->maxfd) 226 f->maxfd = fd; 227 oc = f->fd[fd]; 228 f->fd[fd] = c.c; 229 unlock(&f->l); 230 if(oc != 0) 231 cclose(oc); 232 } 233 else { 234 if(waserror()) { 235 cclose(c.c); 236 nexterror(); 237 } 238 fd = newfd(c.c); 239 if(fd < 0) 240 error(Enofd); 241 poperror(); 242 } 243 poperror(); 244 return fd; 245 } 246 247 int 248 kfstat(int fd, uchar *buf, int n) 249 { 250 volatile struct { Chan *c; } c; 251 252 c.c = nil; 253 if(waserror()) { 254 cclose(c.c); 255 return -1; 256 } 257 c.c = fdtochan(up->env->fgrp, fd, -1, 0, 1); 258 devtab[c.c->type]->stat(c.c, buf, n); 259 poperror(); 260 cclose(c.c); 261 return n; 262 } 263 264 char* 265 kfd2path(int fd) 266 { 267 Chan *c; 268 char *s; 269 270 if(waserror()) 271 return nil; 272 c = fdtochan(up->env->fgrp, fd, -1, 0, 1); 273 s = nil; 274 if(c->name != nil){ 275 s = malloc(c->name->len+1); 276 if(s == nil){ 277 cclose(c); 278 error(Enomem); 279 } 280 memmove(s, c->name->s, c->name->len+1); 281 cclose(c); 282 } 283 poperror(); 284 return s; 285 } 286 287 int 288 kfauth(int fd, char *aname) 289 { 290 Chan *c, *ac; 291 292 if(waserror()) 293 return -1; 294 295 validname(aname, 1); 296 c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1); 297 if(waserror()){ 298 cclose(c); 299 nexterror(); 300 } 301 302 ac = mntauth(c, aname); 303 304 /* at this point ac is responsible for keeping c alive */ 305 poperror(); /* c */ 306 cclose(c); 307 308 if(waserror()){ 309 cclose(ac); 310 nexterror(); 311 } 312 313 fd = newfd(ac); 314 if(fd < 0) 315 error(Enofd); 316 poperror(); /* ac */ 317 318 poperror(); 319 320 return fd; 321 } 322 323 int 324 kfversion(int fd, uint msize, char *vers, uint arglen) 325 { 326 int m; 327 Chan *c; 328 329 if(waserror()) 330 return -1; 331 332 /* check there's a NUL in the version string */ 333 if(arglen==0 || memchr(vers, 0, arglen)==0) 334 error(Ebadarg); 335 336 c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1); 337 if(waserror()){ 338 cclose(c); 339 nexterror(); 340 } 341 342 m = mntversion(c, vers, msize, arglen); 343 344 poperror(); 345 cclose(c); 346 347 poperror(); 348 return m; 349 } 350 351 int 352 kpipe(int fd[2]) 353 { 354 Dev *d; 355 Fgrp *f; 356 Chan *c[2]; 357 static char *names[] = {"data", "data1"}; 358 359 f = up->env->fgrp; 360 361 d = devtab[devno('|', 0)]; 362 c[0] = namec("#|", Atodir, 0, 0); 363 c[1] = 0; 364 fd[0] = -1; 365 fd[1] = -1; 366 if(waserror()) { 367 if(c[0] != 0) 368 cclose(c[0]); 369 if(c[1] != 0) 370 cclose(c[1]); 371 if(fd[0] >= 0) 372 f->fd[fd[0]]=0; 373 if(fd[1] >= 0) 374 f->fd[fd[1]]=0; 375 return -1; 376 } 377 c[1] = cclone(c[0]); 378 if(walk(&c[0], &names[0], 1, 1, nil) < 0) 379 error(Egreg); 380 if(walk(&c[1], &names[1], 1, 1, nil) < 0) 381 error(Egreg); 382 c[0] = d->open(c[0], ORDWR); 383 c[1] = d->open(c[1], ORDWR); 384 fd[0] = newfd(c[0]); 385 if(fd[0] < 0) 386 error(Enofd); 387 fd[1] = newfd(c[1]); 388 if(fd[1] < 0) 389 error(Enofd); 390 poperror(); 391 return 0; 392 } 393 394 int 395 kfwstat(int fd, uchar *buf, int n) 396 { 397 volatile struct { Chan *c; } c; 398 399 c.c = nil; 400 if(waserror()) { 401 cclose(c.c); 402 return -1; 403 } 404 validstat(buf, n); 405 c.c = fdtochan(up->env->fgrp, fd, -1, 1, 1); 406 n = devtab[c.c->type]->wstat(c.c, buf, n); 407 poperror(); 408 cclose(c.c); 409 return n; 410 } 411 412 long 413 bindmount(Chan *c, char *old, int flag, char *spec) 414 { 415 int ret; 416 volatile struct { Chan *c; } c1; 417 418 if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER)) 419 error(Ebadarg); 420 421 c1.c = namec(old, Amount, 0, 0); 422 if(waserror()){ 423 cclose(c1.c); 424 nexterror(); 425 } 426 ret = cmount(c, c1.c, flag, spec); 427 428 poperror(); 429 cclose(c1.c); 430 return ret; 431 } 432 433 int 434 kbind(char *new, char *old, int flags) 435 { 436 long r; 437 volatile struct { Chan *c; } c0; 438 439 c0.c = nil; 440 if(waserror()) { 441 cclose(c0.c); 442 return -1; 443 } 444 c0.c = namec(new, Abind, 0, 0); 445 r = bindmount(c0.c, old, flags, ""); 446 poperror(); 447 cclose(c0.c); 448 return r; 449 } 450 451 int 452 kmount(int fd, int afd, char *old, int flags, char *spec) 453 { 454 long r; 455 volatile struct { Chan *c; } c0; 456 volatile struct { Chan *c; } bc; 457 volatile struct { Chan *c; } ac; 458 Mntparam mntparam; 459 460 ac.c = nil; 461 bc.c = nil; 462 c0.c = nil; 463 if(waserror()) { 464 cclose(ac.c); 465 cclose(bc.c); 466 cclose(c0.c); 467 return -1; 468 } 469 bc.c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1); 470 if(afd >= 0) 471 ac.c = fdtochan(up->env->fgrp, afd, ORDWR, 0, 1); 472 mntparam.chan = bc.c; 473 mntparam.authchan = ac.c; 474 mntparam.spec = spec; 475 mntparam.flags = flags; 476 c0.c = devtab[devno('M', 0)]->attach((char*)&mntparam); 477 478 r = bindmount(c0.c, old, flags, spec); 479 poperror(); 480 cclose(ac.c); 481 cclose(bc.c); 482 cclose(c0.c); 483 484 return r; 485 } 486 487 int 488 kunmount(char *old, char *new) 489 { 490 volatile struct { Chan *c; } cmount; 491 volatile struct { Chan *c; } cmounted; 492 493 cmount.c = nil; 494 cmounted.c = nil; 495 if(waserror()) { 496 cclose(cmount.c); 497 cclose(cmounted.c); 498 return -1; 499 } 500 501 cmount.c = namec(new, Amount, 0, 0); 502 if(old != nil && old[0] != '\0') { 503 /* 504 * This has to be namec(..., Aopen, ...) because 505 * if arg[0] is something like /srv/cs or /fd/0, 506 * opening it is the only way to get at the real 507 * Chan underneath. 508 */ 509 cmounted.c = namec(old, Aopen, OREAD, 0); 510 } 511 512 cunmount(cmount.c, cmounted.c); 513 poperror(); 514 cclose(cmount.c); 515 cclose(cmounted.c); 516 return 0; 517 } 518 519 int 520 kopen(char *path, int mode) 521 { 522 int fd; 523 volatile struct { Chan *c; } c; 524 525 if(waserror()) 526 return -1; 527 528 openmode(mode); /* error check only */ 529 c.c = namec(path, Aopen, mode, 0); 530 if(waserror()){ 531 cclose(c.c); 532 nexterror(); 533 } 534 fd = newfd(c.c); 535 if(fd < 0) 536 error(Enofd); 537 poperror(); 538 539 poperror(); 540 return fd; 541 } 542 543 long 544 unionread(Chan *c, void *va, long n) 545 { 546 int i; 547 long nr; 548 Mhead *m; 549 Mount *mount; 550 551 qlock(&c->umqlock); 552 m = c->umh; 553 rlock(&m->lock); 554 mount = m->mount; 555 /* bring mount in sync with c->uri and c->umc */ 556 for(i = 0; mount != nil && i < c->uri; i++) 557 mount = mount->next; 558 559 nr = 0; 560 while(mount != nil) { 561 /* Error causes component of union to be skipped */ 562 if(mount->to && !waserror()) { 563 if(c->umc == nil){ 564 c->umc = cclone(mount->to); 565 c->umc = devtab[c->umc->type]->open(c->umc, OREAD); 566 } 567 568 nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset); 569 if(nr < 0) 570 nr = 0; /* dev.c can return -1 */ 571 c->umc->offset += nr; 572 poperror(); 573 } 574 if(nr > 0) 575 break; 576 577 /* Advance to next element */ 578 c->uri++; 579 if(c->umc) { 580 cclose(c->umc); 581 c->umc = nil; 582 } 583 mount = mount->next; 584 } 585 runlock(&m->lock); 586 qunlock(&c->umqlock); 587 return nr; 588 } 589 590 static void 591 unionrewind(Chan *c) 592 { 593 qlock(&c->umqlock); 594 c->uri = 0; 595 if(c->umc){ 596 cclose(c->umc); 597 c->umc = nil; 598 } 599 qunlock(&c->umqlock); 600 } 601 602 static long 603 rread(int fd, void *va, long n, vlong *offp) 604 { 605 int dir; 606 Lock *cl; 607 volatile struct { Chan *c; } c; 608 vlong off; 609 610 if(waserror()) 611 return -1; 612 613 c.c = fdtochan(up->env->fgrp, fd, OREAD, 1, 1); 614 if(waserror()){ 615 cclose(c.c); 616 nexterror(); 617 } 618 619 if(n < 0) 620 error(Etoosmall); 621 622 dir = c.c->qid.type & QTDIR; 623 if(dir && c.c->umh) 624 n = unionread(c.c, va, n); 625 else{ 626 cl = &c.c->l; 627 if(offp == nil){ 628 lock(cl); /* lock for vlong assignment */ 629 off = c.c->offset; 630 unlock(cl); 631 }else 632 off = *offp; 633 if(off < 0) 634 error(Enegoff); 635 if(off == 0){ 636 if(offp == nil){ 637 lock(cl); 638 c.c->offset = 0; 639 c.c->dri = 0; 640 unlock(cl); 641 } 642 unionrewind(c.c); 643 } 644 n = devtab[c.c->type]->read(c.c, va, n, off); 645 lock(cl); 646 c.c->offset += n; 647 unlock(cl); 648 } 649 650 poperror(); 651 cclose(c.c); 652 653 poperror(); 654 return n; 655 } 656 657 long 658 kread(int fd, void *va, long n) 659 { 660 return rread(fd, va, n, nil); 661 } 662 663 long 664 kpread(int fd, void *va, long n, vlong off) 665 { 666 return rread(fd, va, n, &off); 667 } 668 669 int 670 kremove(char *path) 671 { 672 volatile struct { Chan *c; } c; 673 674 if(waserror()) 675 return -1; 676 677 c.c = namec(path, Aremove, 0, 0); 678 if(waserror()){ 679 c.c->type = 0; /* see below */ 680 cclose(c.c); 681 nexterror(); 682 } 683 devtab[c.c->type]->remove(c.c); 684 /* 685 * Remove clunks the fid, but we need to recover the Chan 686 * so fake it up. rootclose() is known to be a nop. 687 */ 688 c.c->type = 0; 689 poperror(); 690 cclose(c.c); 691 692 poperror(); 693 return 0; 694 } 695 696 vlong 697 kseek(int fd, vlong off, int whence) 698 { 699 Dir *dir; 700 Chan *c; 701 702 if(waserror()) 703 return -1; 704 705 c = fdtochan(up->env->fgrp, fd, -1, 1, 1); 706 if(waserror()) { 707 cclose(c); 708 nexterror(); 709 } 710 711 if(devtab[c->type]->dc == '|') 712 error(Eisstream); 713 714 switch(whence) { 715 case 0: 716 if(c->qid.type & QTDIR){ 717 if(off != 0) 718 error(Eisdir); 719 unionrewind(c); 720 }else if(off < 0) 721 error(Enegoff); 722 lock(&c->l); /* lock for vlong assignment */ 723 c->offset = off; 724 unlock(&c->l); 725 break; 726 727 case 1: 728 if(c->qid.type & QTDIR) 729 error(Eisdir); 730 lock(&c->l); /* lock for read/write update */ 731 off += c->offset; 732 if(off < 0){ 733 unlock(&c->l); 734 error(Enegoff); 735 } 736 c->offset = off; 737 unlock(&c->l); 738 break; 739 740 case 2: 741 if(c->qid.type & QTDIR) 742 error(Eisdir); 743 dir = chandirstat(c); 744 if(dir == nil) 745 error("internal error: stat error in seek"); 746 off += dir->length; 747 free(dir); 748 if(off < 0) 749 error(Enegoff); 750 lock(&c->l); /* lock for read/write update */ 751 c->offset = off; 752 unlock(&c->l); 753 break; 754 755 default: 756 error(Ebadarg); 757 break; 758 } 759 poperror(); 760 c->dri = 0; 761 cclose(c); 762 poperror(); 763 return off; 764 } 765 766 void 767 validstat(uchar *s, int n) 768 { 769 int m; 770 char buf[64]; 771 772 if(statcheck(s, n) < 0) 773 error(Ebadstat); 774 /* verify that name entry is acceptable */ 775 s += STATFIXLEN - 4*BIT16SZ; /* location of first string */ 776 /* 777 * s now points at count for first string. 778 * if it's too long, let the server decide; this is 779 * only for his protection anyway. otherwise 780 * we'd have to allocate and waserror. 781 */ 782 m = GBIT16(s); 783 s += BIT16SZ; 784 if(m+1 > sizeof buf) 785 return; 786 memmove(buf, s, m); 787 buf[m] = '\0'; 788 /* name could be '/' */ 789 if(strcmp(buf, "/") != 0) 790 validname(buf, 0); 791 } 792 793 int 794 kstat(char *path, uchar *buf, int n) 795 { 796 volatile struct { Chan *c; } c; 797 798 c.c = nil; 799 if(waserror()){ 800 cclose(c.c); 801 return -1; 802 } 803 c.c = namec(path, Aaccess, 0, 0); 804 devtab[c.c->type]->stat(c.c, buf, n); 805 poperror(); 806 cclose(c.c); 807 return 0; 808 } 809 810 static long 811 rwrite(int fd, void *va, long n, vlong *offp) 812 { 813 Lock *cl; 814 volatile struct { Chan *c; } c; 815 vlong off; 816 long m; 817 818 if(waserror()) 819 return -1; 820 c.c = fdtochan(up->env->fgrp, fd, OWRITE, 1, 1); 821 if(waserror()){ 822 cclose(c.c); 823 nexterror(); 824 } 825 if(c.c->qid.type & QTDIR) 826 error(Eisdir); 827 828 if(n < 0) 829 error(Etoosmall); 830 831 cl = &c.c->l; 832 if(offp == nil){ 833 lock(cl); 834 off = c.c->offset; 835 c.c->offset += n; 836 unlock(cl); 837 }else 838 off = *offp; 839 840 if(waserror()){ 841 if(offp == nil){ 842 lock(cl); 843 c.c->offset -= n; 844 unlock(cl); 845 } 846 nexterror(); 847 } 848 if(off < 0) 849 error(Enegoff); 850 m = devtab[c.c->type]->write(c.c, va, n, off); 851 poperror(); 852 853 if(offp == nil && m < n){ 854 lock(cl); 855 c.c->offset -= n - m; 856 unlock(cl); 857 } 858 859 poperror(); 860 cclose(c.c); 861 862 poperror(); 863 return m; 864 } 865 866 long 867 kwrite(int fd, void *va, long n) 868 { 869 return rwrite(fd, va, n, nil); 870 } 871 872 long 873 kpwrite(int fd, void *va, long n, vlong off) 874 { 875 return rwrite(fd, va, n, &off); 876 } 877 878 int 879 kwstat(char *path, uchar *buf, int n) 880 { 881 volatile struct { Chan *c; } c; 882 883 c.c = nil; 884 if(waserror()){ 885 cclose(c.c); 886 return -1; 887 } 888 validstat(buf, n); 889 c.c = namec(path, Aaccess, 0, 0); 890 n = devtab[c.c->type]->wstat(c.c, buf, n); 891 poperror(); 892 cclose(c.c); 893 return n; 894 } 895 896 enum 897 { 898 DIRSIZE = STATFIXLEN + 32 * 4, 899 DIRREADLIM = 2048, /* should handle the largest reasonable directory entry */ 900 }; 901 902 Dir* 903 chandirstat(Chan *c) 904 { 905 Dir *d; 906 uchar *buf; 907 int n, nd, i; 908 909 nd = DIRSIZE; 910 for(i=0; i<2; i++){ /* should work by the second try */ 911 d = smalloc(sizeof(Dir) + nd); 912 buf = (uchar*)&d[1]; 913 if(waserror()){ 914 free(d); 915 return nil; 916 } 917 n = devtab[c->type]->stat(c, buf, nd); 918 poperror(); 919 if(n < BIT16SZ){ 920 free(d); 921 return nil; 922 } 923 nd = GBIT16((uchar*)buf) + BIT16SZ; /* size needed to store whole stat buffer including count */ 924 if(nd <= n){ 925 convM2D(buf, n, d, (char*)&d[1]); 926 return d; 927 } 928 /* else sizeof(Dir)+nd is plenty */ 929 free(d); 930 } 931 return nil; 932 933 } 934 935 Dir* 936 kdirstat(char *name) 937 { 938 volatile struct {Chan *c;} c; 939 Dir *d; 940 941 c.c = nil; 942 if(waserror()){ 943 cclose(c.c); 944 return nil; 945 } 946 c.c = namec(name, Aaccess, 0, 0); 947 d = chandirstat(c.c); 948 poperror(); 949 cclose(c.c); 950 return d; 951 } 952 953 Dir* 954 kdirfstat(int fd) 955 { 956 volatile struct { Chan *c; } c; 957 Dir *d; 958 959 c.c = nil; 960 if(waserror()) { 961 cclose(c.c); 962 return nil; 963 } 964 c.c = fdtochan(up->env->fgrp, fd, -1, 0, 1); 965 d = chandirstat(c.c); 966 poperror(); 967 cclose(c.c); 968 return d; 969 } 970 971 int 972 kdirwstat(char *name, Dir *dir) 973 { 974 uchar *buf; 975 int r; 976 977 r = sizeD2M(dir); 978 buf = smalloc(r); 979 convD2M(dir, buf, r); 980 r = kwstat(name, buf, r); 981 free(buf); 982 return r < 0? r: 0; 983 } 984 985 int 986 kdirfwstat(int fd, Dir *dir) 987 { 988 uchar *buf; 989 int r; 990 991 r = sizeD2M(dir); 992 buf = smalloc(r); 993 convD2M(dir, buf, r); 994 r = kfwstat(fd, buf, r); 995 free(buf); 996 return r < 0? r: 0; 997 } 998 999 static long 1000 dirpackage(uchar *buf, long ts, Dir **d) 1001 { 1002 char *s; 1003 long ss, i, n, nn, m; 1004 1005 *d = nil; 1006 if(ts <= 0) 1007 return ts; 1008 1009 /* 1010 * first find number of all stats, check they look like stats, & size all associated strings 1011 */ 1012 ss = 0; 1013 n = 0; 1014 for(i = 0; i < ts; i += m){ 1015 m = BIT16SZ + GBIT16(&buf[i]); 1016 if(statcheck(&buf[i], m) < 0) 1017 break; 1018 ss += m; 1019 n++; 1020 } 1021 1022 if(i != ts) 1023 error("bad directory format"); 1024 1025 *d = malloc(n * sizeof(Dir) + ss); 1026 if(*d == nil) 1027 error(Enomem); 1028 1029 /* 1030 * then convert all buffers 1031 */ 1032 s = (char*)*d + n * sizeof(Dir); 1033 nn = 0; 1034 for(i = 0; i < ts; i += m){ 1035 m = BIT16SZ + GBIT16((uchar*)&buf[i]); 1036 if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){ 1037 free(*d); 1038 *d = nil; 1039 error("bad directory entry"); 1040 } 1041 nn++; 1042 s += m; 1043 } 1044 1045 return nn; 1046 } 1047 1048 long 1049 kdirread(int fd, Dir **d) 1050 { 1051 uchar *buf; 1052 long ts; 1053 1054 *d = nil; 1055 if(waserror()) 1056 return -1; 1057 buf = malloc(DIRREADLIM); 1058 if(buf == nil) 1059 error(Enomem); 1060 if(waserror()){ 1061 free(buf); 1062 nexterror(); 1063 } 1064 ts = kread(fd, buf, DIRREADLIM); 1065 if(ts > 0) 1066 ts = dirpackage(buf, ts, d); 1067 1068 poperror(); 1069 free(buf); 1070 poperror(); 1071 return ts; 1072 } 1073 1074 int 1075 kiounit(int fd) 1076 { 1077 Chan *c; 1078 int n; 1079 1080 c = fdtochan(up->env->fgrp, fd, -1, 0, 1); 1081 if(waserror()){ 1082 cclose(c); 1083 return 0; /* n.b. */ 1084 } 1085 n = c->iounit; 1086 poperror(); 1087 cclose(c); 1088 return n; 1089 } 1090