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