1 /* 2 * Unix file system interface 3 */ 4 #define _LARGEFILE64_SOURCE 1 5 #define _FILE_OFFSET_BITS 64 6 #include "dat.h" 7 #include "fns.h" 8 #include "error.h" 9 10 #include <sys/types.h> 11 #include <sys/stat.h> 12 #include <sys/fcntl.h> 13 #include <sys/socket.h> 14 #include <sys/un.h> 15 #include <utime.h> 16 #include <dirent.h> 17 #include <stdio.h> 18 #define __EXTENSIONS__ 19 #undef getwd 20 #include <unistd.h> 21 #include <pwd.h> 22 #include <grp.h> 23 24 typedef struct Fsinfo Fsinfo; 25 struct Fsinfo 26 { 27 int uid; 28 int gid; 29 int mode; /* Unix mode */ 30 DIR* dir; /* open directory */ 31 struct dirent* de; /* directory reading */ 32 int fd; /* open files */ 33 ulong offset; /* offset when reading directory */ 34 int eod; /* end of directory */ 35 int issocket; 36 QLock oq; /* mutex for offset */ 37 char* spec; 38 Cname* name; /* Unix's name for file */ 39 Qid rootqid; /* Plan 9's qid for Inferno's root */ 40 }; 41 42 #define FS(c) ((Fsinfo*)(c)->aux) 43 44 enum 45 { 46 IDSHIFT = 8, 47 NID = 1 << IDSHIFT, 48 IDMASK = NID - 1, 49 MAXPATH = 1024 /* TO DO: eliminate this */ 50 }; 51 52 typedef struct User User; 53 struct User 54 { 55 int id; /* might be user or group ID */ 56 int gid; /* if it's a user not a group, the group ID (only for setid) */ 57 char* name; 58 int nmem; 59 int* mem; /* member array, if nmem != 0 */ 60 User* next; 61 }; 62 63 char rootdir[MAXROOT] = ROOT; 64 65 static User* uidmap[NID]; 66 static User* gidmap[NID]; 67 static QLock idl; 68 static User* name2user(User**, char*, User* (*get)(char*)); 69 static User* id2user(User**, int, User* (*get)(int)); 70 static User* newuid(int); 71 static User* newgid(int); 72 static User* newuname(char*); 73 static User* newgname(char*); 74 75 static Qid fsqid(struct stat *); 76 static void fspath(Cname*, char*, char*); 77 static int fsdirconv(Chan*, char*, struct stat*, uchar*, int, int); 78 static Cname* fswalkpath(Cname*, char*, int); 79 static char* fslastelem(Cname*); 80 static int ingroup(int id, int gid); 81 static void fsperm(Chan*, int); 82 static long fsdirread(Chan*, uchar*, int, vlong); 83 static int fsomode(int); 84 static void fsremove(Chan*); 85 86 /* 87 * make invalid symbolic links visible; less confusing, and at least you can then delete them. 88 */ 89 static int 90 xstat(char *f, struct stat *sb) 91 { 92 if(stat(f, sb) >= 0) 93 return 0; 94 /* could possibly generate ->name as rob once suggested */ 95 return lstat(f, sb); 96 } 97 98 static void 99 fsfree(Chan *c) 100 { 101 cnameclose(FS(c)->name); 102 free(FS(c)); 103 } 104 105 Chan* 106 fsattach(char *spec) 107 { 108 Chan *c; 109 struct stat st; 110 static int devno; 111 static Lock l; 112 113 if(!emptystr(spec) && strcmp(spec, "*") != 0) 114 error(Ebadspec); 115 if(stat(rootdir, &st) < 0) 116 oserror(); 117 if(!S_ISDIR(st.st_mode)) 118 error(Enotdir); 119 120 c = devattach('U', spec); 121 c->qid = fsqid(&st); 122 c->aux = smalloc(sizeof(Fsinfo)); 123 FS(c)->dir = nil; 124 FS(c)->de = nil; 125 FS(c)->fd = -1; 126 FS(c)->issocket = 0; 127 FS(c)->gid = st.st_gid; 128 FS(c)->uid = st.st_uid; 129 FS(c)->mode = st.st_mode; 130 lock(&l); 131 c->dev = devno++; 132 unlock(&l); 133 if(!emptystr(spec)){ 134 FS(c)->spec = "/"; 135 FS(c)->name = newcname(FS(c)->spec); 136 }else 137 FS(c)->name = newcname(rootdir); 138 FS(c)->rootqid = c->qid; 139 140 return c; 141 } 142 143 Walkqid* 144 fswalk(Chan *c, Chan *nc, char **name, int nname) 145 { 146 int j; 147 volatile int alloc; 148 Walkqid *wq; 149 struct stat st; 150 char *n; 151 Cname *next; 152 Cname *volatile current; 153 Qid rootqid; 154 155 if(nname > 0) 156 isdir(c); 157 158 alloc = 0; 159 current = nil; 160 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); 161 if(waserror()){ 162 if(alloc && wq->clone != nil) 163 cclose(wq->clone); 164 cnameclose(current); 165 free(wq); 166 return nil; 167 } 168 if(nc == nil){ 169 nc = devclone(c); 170 nc->type = 0; 171 alloc = 1; 172 } 173 wq->clone = nc; 174 rootqid = FS(c)->rootqid; 175 current = FS(c)->name; 176 if(current != nil) 177 incref(¤t->r); 178 for(j = 0; j < nname; j++){ 179 if(!(nc->qid.type&QTDIR)){ 180 if(j==0) 181 error(Enotdir); 182 break; 183 } 184 n = name[j]; 185 if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){ 186 next = current; 187 incref(&next->r); 188 next = addelem(current, n); 189 //print("** ufs walk '%s' -> %s [%s]\n", current->s, n, next->s); 190 if(xstat(next->s, &st) < 0){ 191 cnameclose(next); 192 if(j == 0) 193 error(Enonexist); 194 strcpy(up->env->errstr, Enonexist); 195 break; 196 } 197 nc->qid = fsqid(&st); 198 cnameclose(current); 199 current = next; 200 } 201 wq->qid[wq->nqid++] = nc->qid; 202 } 203 poperror(); 204 if(wq->nqid < nname){ 205 cnameclose(current); 206 if(alloc) 207 cclose(wq->clone); 208 wq->clone = nil; 209 }else if(wq->clone){ 210 nc->aux = smalloc(sizeof(Fsinfo)); 211 nc->type = c->type; 212 if(nname > 0) { 213 FS(nc)->gid = st.st_gid; 214 FS(nc)->uid = st.st_uid; 215 FS(nc)->mode = st.st_mode; 216 FS(nc)->issocket = S_ISSOCK(st.st_mode); 217 } else { 218 FS(nc)->gid = FS(c)->gid; 219 FS(nc)->uid = FS(c)->uid; 220 FS(nc)->mode = FS(c)->mode; 221 FS(nc)->issocket = FS(c)->issocket; 222 } 223 FS(nc)->name = current; 224 FS(nc)->spec = FS(c)->spec; 225 FS(nc)->rootqid = rootqid; 226 FS(nc)->fd = -1; 227 FS(nc)->dir = nil; 228 FS(nc)->de = nil; 229 } 230 return wq; 231 } 232 233 static int 234 fsstat(Chan *c, uchar *dp, int n) 235 { 236 struct stat st; 237 char *p; 238 239 if(xstat(FS(c)->name->s, &st) < 0) 240 oserror(); 241 p = fslastelem(FS(c)->name); 242 if(*p == 0) 243 p = "/"; 244 qlock(&idl); 245 n = fsdirconv(c, p, &st, dp, n, 0); 246 qunlock(&idl); 247 return n; 248 } 249 250 static int 251 opensocket(char *path) 252 { 253 int fd; 254 struct sockaddr_un su; 255 256 memset(&su, 0, sizeof su); 257 su.sun_family = AF_UNIX; 258 if(strlen(path)+1 > sizeof su.sun_path) 259 error("unix socket name too long"); 260 strcpy(su.sun_path, path); 261 if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 262 return -1; 263 if(connect(fd, (struct sockaddr*)&su, sizeof su) >= 0) 264 return fd; 265 close(fd); 266 return -1; 267 } 268 269 static Chan* 270 fsopen(Chan *c, int mode) 271 { 272 int m, isdir; 273 274 m = mode & (OTRUNC|3); 275 switch(m) { 276 case 0: 277 fsperm(c, 4); 278 break; 279 case 1: 280 case 1|16: 281 fsperm(c, 2); 282 break; 283 case 2: 284 case 0|16: 285 case 2|16: 286 fsperm(c, 4); 287 fsperm(c, 2); 288 break; 289 case 3: 290 fsperm(c, 1); 291 break; 292 default: 293 error(Ebadarg); 294 } 295 296 isdir = c->qid.type & QTDIR; 297 298 if(isdir && mode != OREAD) 299 error(Eperm); 300 301 m = fsomode(m & 3); 302 c->mode = openmode(mode); 303 304 if(isdir) { 305 FS(c)->dir = opendir(FS(c)->name->s); 306 if(FS(c)->dir == nil) 307 oserror(); 308 FS(c)->eod = 0; 309 } 310 else { 311 if(!FS(c)->issocket){ 312 if(mode & OTRUNC) 313 m |= O_TRUNC; 314 FS(c)->fd = open(FS(c)->name->s, m, 0666); 315 }else 316 FS(c)->fd = opensocket(FS(c)->name->s); 317 if(FS(c)->fd < 0) 318 oserror(); 319 } 320 321 c->offset = 0; 322 FS(c)->offset = 0; 323 c->flag |= COPEN; 324 return c; 325 } 326 327 static void 328 fscreate(Chan *c, char *name, int mode, ulong perm) 329 { 330 int fd, m, o; 331 struct stat st; 332 Cname *n; 333 334 fsperm(c, 2); 335 336 m = fsomode(mode&3); 337 openmode(mode); /* get the errors out of the way */ 338 339 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) 340 error(Efilename); 341 n = fswalkpath(FS(c)->name, name, 1); 342 if(waserror()){ 343 cnameclose(n); 344 nexterror(); 345 } 346 if(perm & DMDIR) { 347 if(m) 348 error(Eperm); 349 350 perm &= ~0777 | (FS(c)->mode & 0777); 351 if(mkdir(n->s, perm) < 0) 352 oserror(); 353 354 fd = open(n->s, 0); 355 if(fd < 0) 356 oserror(); 357 fchmod(fd, perm); 358 fchown(fd, up->env->uid, FS(c)->gid); 359 if(fstat(fd, &st) <0){ 360 close(fd); 361 oserror(); 362 } 363 close(fd); 364 FS(c)->dir = opendir(n->s); 365 if(FS(c)->dir == nil) 366 oserror(); 367 FS(c)->eod = 0; 368 } else { 369 o = (O_CREAT | O_EXCL) | (mode&3); 370 if(mode & OTRUNC) 371 o |= O_TRUNC; 372 perm &= ~0666 | (FS(c)->mode & 0666); 373 fd = open(n->s, o, perm); 374 if(fd < 0) 375 oserror(); 376 fchmod(fd, perm); 377 fchown(fd, up->env->uid, FS(c)->gid); 378 if(fstat(fd, &st) < 0){ 379 close(fd); 380 oserror(); 381 } 382 FS(c)->fd = fd; 383 } 384 cnameclose(FS(c)->name); 385 FS(c)->name = n; 386 poperror(); 387 388 c->qid = fsqid(&st); 389 FS(c)->gid = st.st_gid; 390 FS(c)->uid = st.st_uid; 391 FS(c)->mode = st.st_mode; 392 c->mode = openmode(mode); 393 c->offset = 0; 394 FS(c)->offset = 0; 395 FS(c)->issocket = 0; 396 c->flag |= COPEN; 397 } 398 399 static void 400 fsclose(Chan *c) 401 { 402 if((c->flag & COPEN) != 0){ 403 if(c->qid.type & QTDIR) 404 closedir(FS(c)->dir); 405 else 406 close(FS(c)->fd); 407 } 408 if(c->flag & CRCLOSE) { 409 if(!waserror()) { 410 fsremove(c); 411 poperror(); 412 } 413 return; 414 } 415 fsfree(c); 416 } 417 418 static long 419 fsread(Chan *c, void *va, long n, vlong offset) 420 { 421 long r; 422 423 if(c->qid.type & QTDIR){ 424 qlock(&FS(c)->oq); 425 if(waserror()) { 426 qunlock(&FS(c)->oq); 427 nexterror(); 428 } 429 r = fsdirread(c, va, n, offset); 430 poperror(); 431 qunlock(&FS(c)->oq); 432 }else{ 433 if(!FS(c)->issocket){ 434 r = pread(FS(c)->fd, va, n, offset); 435 if(r >= 0) 436 return r; 437 if(errno != ESPIPE && errno != EPIPE) 438 oserror(); 439 } 440 r = read(FS(c)->fd, va, n); 441 if(r < 0) 442 oserror(); 443 } 444 return r; 445 } 446 447 static long 448 fswrite(Chan *c, void *va, long n, vlong offset) 449 { 450 long r; 451 452 if(!FS(c)->issocket){ 453 r = pwrite(FS(c)->fd, va, n, offset); 454 if(r >= 0) 455 return r; 456 if(errno != ESPIPE && errno != EPIPE) 457 oserror(); 458 } 459 r = write(FS(c)->fd, va, n); 460 if(r < 0) 461 oserror(); 462 return r; 463 } 464 465 static void 466 fswchk(Cname *c) 467 { 468 struct stat st; 469 470 if(stat(c->s, &st) < 0) 471 oserror(); 472 473 if(st.st_uid == up->env->uid) 474 st.st_mode >>= 6; 475 else if(st.st_gid == up->env->gid || ingroup(up->env->uid, st.st_gid)) 476 st.st_mode >>= 3; 477 478 if(st.st_mode & S_IWOTH) 479 return; 480 481 error(Eperm); 482 } 483 484 static void 485 fsremove(Chan *c) 486 { 487 int n; 488 Cname *volatile dir; 489 490 if(waserror()){ 491 fsfree(c); 492 nexterror(); 493 } 494 dir = fswalkpath(FS(c)->name, "..", 1); 495 if(waserror()){ 496 cnameclose(dir); 497 nexterror(); 498 } 499 fswchk(dir); 500 cnameclose(dir); 501 poperror(); 502 if(c->qid.type & QTDIR) 503 n = rmdir(FS(c)->name->s); 504 else 505 n = remove(FS(c)->name->s); 506 if(n < 0) 507 oserror(); 508 poperror(); 509 fsfree(c); 510 } 511 512 static int 513 fswstat(Chan *c, uchar *buf, int nb) 514 { 515 Dir *d; 516 User *p; 517 Cname *volatile ph; 518 struct stat st; 519 struct utimbuf utbuf; 520 int tsync; 521 522 if(FS(c)->fd >= 0){ 523 if(fstat(FS(c)->fd, &st) < 0) 524 oserror(); 525 }else{ 526 if(stat(FS(c)->name->s, &st) < 0) 527 oserror(); 528 } 529 d = malloc(sizeof(*d)+nb); 530 if(d == nil) 531 error(Enomem); 532 if(waserror()){ 533 free(d); 534 nexterror(); 535 } 536 tsync = 1; 537 nb = convM2D(buf, nb, d, (char*)&d[1]); 538 if(nb == 0) 539 error(Eshortstat); 540 if(!emptystr(d->name) && strcmp(d->name, fslastelem(FS(c)->name)) != 0) { 541 tsync = 0; 542 validname(d->name, 0); 543 ph = fswalkpath(FS(c)->name, "..", 1); 544 if(waserror()){ 545 cnameclose(ph); 546 nexterror(); 547 } 548 fswchk(ph); 549 ph = fswalkpath(ph, d->name, 0); 550 if(rename(FS(c)->name->s, ph->s) < 0) 551 oserror(); 552 cnameclose(FS(c)->name); 553 poperror(); 554 FS(c)->name = ph; 555 } 556 557 if(d->mode != ~0 && (d->mode&0777) != (st.st_mode&0777)) { 558 tsync = 0; 559 if(up->env->uid != st.st_uid) 560 error(Eowner); 561 if(FS(c)->fd >= 0){ 562 if(fchmod(FS(c)->fd, d->mode&0777) < 0) 563 oserror(); 564 }else{ 565 if(chmod(FS(c)->name->s, d->mode&0777) < 0) 566 oserror(); 567 } 568 FS(c)->mode &= ~0777; 569 FS(c)->mode |= d->mode&0777; 570 } 571 572 if(d->atime != ~0 && d->atime != st.st_atime || 573 d->mtime != ~0 && d->mtime != st.st_mtime) { 574 tsync = 0; 575 if(up->env->uid != st.st_uid) 576 error(Eowner); 577 if(d->mtime != ~0) 578 utbuf.modtime = d->mtime; 579 else 580 utbuf.modtime = st.st_mtime; 581 if(d->atime != ~0) 582 utbuf.actime = d->atime; 583 else 584 utbuf.actime = st.st_atime; 585 if(utime(FS(c)->name->s, &utbuf) < 0) /* TO DO: futimes isn't portable */ 586 oserror(); 587 } 588 589 if(*d->gid){ 590 tsync = 0; 591 qlock(&idl); 592 if(waserror()){ 593 qunlock(&idl); 594 nexterror(); 595 } 596 p = name2user(gidmap, d->gid, newgname); 597 if(p == 0) 598 error(Eunknown); 599 if(p->id != st.st_gid) { 600 if(up->env->uid != st.st_uid) 601 error(Eowner); 602 if(FS(c)->fd >= 0){ 603 if(fchown(FS(c)->fd, st.st_uid, p->id) < 0) 604 oserror(); 605 }else{ 606 if(chown(FS(c)->name->s, st.st_uid, p->id) < 0) 607 oserror(); 608 } 609 FS(c)->gid = p->id; 610 } 611 poperror(); 612 qunlock(&idl); 613 } 614 615 if(d->length != ~(uvlong)0){ 616 tsync = 0; 617 if(FS(c)->fd >= 0){ 618 fsperm(c, 2); 619 if(ftruncate(FS(c)->fd, d->length) < 0) 620 oserror(); 621 }else{ 622 fswchk(FS(c)->name); 623 if(truncate(FS(c)->name->s, d->length) < 0) 624 oserror(); 625 } 626 } 627 628 poperror(); 629 free(d); 630 if(tsync && FS(c)->fd >= 0 && fsync(FS(c)->fd) < 0) 631 oserror(); 632 return nb; 633 } 634 635 #define QDEVBITS 4 /* 16 devices should be plenty */ 636 #define MAXDEV (1<<QDEVBITS) 637 #define QDEVSHIFT (64-QDEVBITS) 638 #define QINOMASK (((uvlong)1<<QDEVSHIFT)-1) 639 #define QPATH(d,i) (((uvlong)(d)<<QDEVSHIFT)|((uvlong)(i)&QINOMASK)) 640 641 static Qid 642 fsqid(struct stat *st) 643 { 644 Qid q; 645 ulong dev; 646 int idev; 647 static int nqdev = 0; 648 static ulong qdev[MAXDEV]; 649 static Lock l; 650 651 q.type = QTFILE; 652 if(S_ISDIR(st->st_mode)) 653 q.type = QTDIR; 654 655 dev = st->st_dev; 656 lock(&l); 657 for(idev = 0; idev < nqdev; idev++) 658 if(qdev[idev] == dev) 659 break; 660 if(idev == nqdev) { 661 if(nqdev == MAXDEV) { 662 unlock(&l); 663 error("too many devices"); 664 } 665 qdev[nqdev++] = dev; 666 } 667 unlock(&l); 668 669 if(0) /* we'll just let it be masked off */ 670 if((uvlong)st->st_ino & ~QINOMASK) 671 error("inode number too large"); 672 673 q.path = QPATH(idev, st->st_ino); 674 q.vers = st->st_mtime; 675 676 return q; 677 } 678 679 static void 680 fspath(Cname *c, char *name, char *path) 681 { 682 int n; 683 684 if(c->len+strlen(name) >= MAXPATH) 685 panic("fspath: name too long"); 686 memmove(path, c->s, c->len); 687 n = c->len; 688 if(path[n-1] != '/') 689 path[n++] = '/'; 690 strcpy(path+n, name); 691 if(isdotdot(name)) 692 cleanname(path); 693 /*print("->%s\n", path);*/ 694 } 695 696 static Cname * 697 fswalkpath(Cname *c, char *name, int dup) 698 { 699 if(dup) 700 c = newcname(c->s); 701 c = addelem(c, name); 702 if(isdotdot(name)) 703 cleancname(c); 704 return c; 705 } 706 707 static char * 708 fslastelem(Cname *c) 709 { 710 char *p; 711 712 p = c->s + c->len; 713 while(p > c->s && p[-1] != '/') 714 p--; 715 return p; 716 } 717 718 static void 719 fsperm(Chan *c, int mask) 720 { 721 int m; 722 723 m = FS(c)->mode; 724 /* 725 print("fsperm: %o %o uuid %d ugid %d cuid %d cgid %d\n", 726 m, mask, up->env->uid, up->env->gid, FS(c)->uid, FS(c)->gid); 727 */ 728 if(FS(c)->uid == up->env->uid) 729 m >>= 6; 730 else if(FS(c)->gid == up->env->gid || ingroup(up->env->uid, FS(c)->gid)) 731 m >>= 3; 732 733 m &= mask; 734 if(m == 0) 735 error(Eperm); 736 } 737 738 static int 739 isdots(char *name) 740 { 741 return name[0] == '.' && (name[1] == '\0' || name[1] == '.' && name[2] == '\0'); 742 } 743 744 static int 745 fsdirconv(Chan *c, char *name, struct stat *s, uchar *va, int nb, int indir) 746 { 747 Dir d; 748 char uidbuf[NUMSIZE], gidbuf[NUMSIZE]; 749 User *u; 750 751 memset(&d, 0, sizeof(d)); 752 d.name = name; 753 u = id2user(uidmap, s->st_uid, newuid); 754 if(u == nil){ 755 snprint(uidbuf, sizeof(uidbuf), "#%lud", (long)s->st_uid); 756 d.uid = uidbuf; 757 }else 758 d.uid = u->name; 759 u = id2user(gidmap, s->st_gid, newgid); 760 if(u == nil){ 761 snprint(gidbuf, sizeof(gidbuf), "#%lud", (long)s->st_gid); 762 d.gid = gidbuf; 763 }else 764 d.gid = u->name; 765 d.muid = ""; 766 d.qid = fsqid(s); 767 d.mode = (d.qid.type<<24)|(s->st_mode&0777); 768 d.atime = s->st_atime; 769 d.mtime = s->st_mtime; 770 d.length = s->st_size; 771 if(d.mode&DMDIR) 772 d.length = 0; 773 d.type = 'U'; 774 d.dev = c->dev; 775 if(indir && sizeD2M(&d) > nb) 776 return -1; /* directory reader needs to know it didn't fit */ 777 return convD2M(&d, va, nb); 778 } 779 780 static long 781 fsdirread(Chan *c, uchar *va, int count, vlong offset) 782 { 783 int i; 784 long n, r; 785 struct stat st; 786 char path[MAXPATH], *ep; 787 struct dirent *de; 788 static uchar slop[8192]; 789 790 i = 0; 791 fspath(FS(c)->name, "", path); 792 ep = path+strlen(path); 793 if(FS(c)->offset != offset) { 794 seekdir(FS(c)->dir, 0); 795 FS(c)->de = nil; 796 FS(c)->eod = 0; 797 for(n=0; n<offset; ) { 798 de = readdir(FS(c)->dir); 799 if(de == 0) { 800 /* EOF, so stash offset and return 0 */ 801 FS(c)->offset = n; 802 FS(c)->eod = 1; 803 return 0; 804 } 805 if(de->d_ino==0 || de->d_name[0]==0 || isdots(de->d_name)) 806 continue; 807 strecpy(ep, path+sizeof(path), de->d_name); 808 if(xstat(path, &st) < 0) { 809 fprint(2, "dir: bad path %s\n", path); 810 continue; 811 } 812 qlock(&idl); 813 if(waserror()){ 814 qunlock(&idl); 815 nexterror(); 816 } 817 r = fsdirconv(c, de->d_name, &st, slop, sizeof(slop), 1); 818 poperror(); 819 qunlock(&idl); 820 if(r <= 0) { 821 FS(c)->offset = n; 822 return 0; 823 } 824 n += r; 825 } 826 FS(c)->offset = offset; 827 } 828 829 if(FS(c)->eod) 830 return 0; 831 832 /* 833 * Take idl on behalf of id2name. Stalling attach, which is a 834 * rare operation, until the readdir completes is probably 835 * preferable to adding lock round-trips. 836 */ 837 qlock(&idl); 838 while(i < count){ 839 de = FS(c)->de; 840 FS(c)->de = nil; 841 if(de == nil) 842 de = readdir(FS(c)->dir); 843 if(de == nil){ 844 FS(c)->eod = 1; 845 break; 846 } 847 848 if(de->d_ino==0 || de->d_name[0]==0 || isdots(de->d_name)) 849 continue; 850 851 strecpy(ep, path+sizeof(path), de->d_name); 852 if(xstat(path, &st) < 0) { 853 fprint(2, "dir: bad path %s\n", path); 854 continue; 855 } 856 r = fsdirconv(c, de->d_name, &st, va+i, count-i, 1); 857 if(r <= 0){ 858 FS(c)->de = de; 859 break; 860 } 861 i += r; 862 FS(c)->offset += r; 863 } 864 qunlock(&idl); 865 return i; 866 } 867 868 static int 869 fsomode(int m) 870 { 871 if(m < 0 || m > 3) 872 error(Ebadarg); 873 return m == 3? 0: m; 874 } 875 876 void 877 setid(char *name, int owner) 878 { 879 User *u; 880 881 if(owner && !iseve()) 882 return; 883 kstrdup(&up->env->user, name); 884 885 qlock(&idl); 886 u = name2user(uidmap, name, newuname); 887 if(u == nil){ 888 qunlock(&idl); 889 up->env->uid = -1; 890 up->env->gid = -1; 891 return; 892 } 893 894 up->env->uid = u->id; 895 up->env->gid = u->gid; 896 qunlock(&idl); 897 } 898 899 static User** 900 hashuser(User** tab, int id) 901 { 902 int i; 903 904 i = (id>>IDSHIFT) ^ id; 905 return &tab[i & IDMASK]; 906 } 907 908 /* 909 * the caller of the following functions must hold QLock idl. 910 */ 911 912 /* 913 * we could keep separate maps of user and group names to Users to 914 * speed this up, but the reverse lookup currently isn't common (ie, change group by wstat and setid) 915 */ 916 static User* 917 name2user(User **tab, char *name, User* (*get)(char*)) 918 { 919 int i; 920 User *u, **h; 921 static User *prevu; 922 static User **prevtab; 923 924 if(prevu != nil && prevtab == tab && strcmp(name, prevu->name) == 0) 925 return prevu; /* it's often the one we've just seen */ 926 927 for(i=0; i<NID; i++) 928 for(u = tab[i]; u != nil; u = u->next) 929 if(strcmp(name, u->name) == 0) { 930 prevtab = tab; 931 prevu = u; 932 return u; 933 } 934 935 u = get(name); 936 if(u == nil) 937 return nil; 938 h = hashuser(tab, u->id); 939 u->next = *h; 940 *h = u; 941 prevtab = tab; 942 prevu = u; 943 return u; 944 } 945 946 static void 947 freeuser(User *u) 948 { 949 if(u != nil){ 950 free(u->name); 951 free(u->mem); 952 free(u); 953 } 954 } 955 956 static User* 957 newuser(int id, int gid, char *name, int nmem) 958 { 959 User *u; 960 961 u = malloc(sizeof(*u)); 962 if(u == nil) 963 return nil; 964 u->name = strdup(name); 965 if(u->name == nil){ 966 free(u); 967 return nil; 968 } 969 u->nmem = nmem; 970 if(nmem){ 971 u->mem = malloc(nmem*sizeof(*u->mem)); 972 if(u->mem == nil){ 973 free(u->name); 974 free(u); 975 return nil; 976 } 977 }else 978 u->mem = nil; 979 u->id = id; 980 u->gid = gid; 981 u->next = nil; 982 return u; 983 } 984 985 static User* 986 newuname(char *name) 987 { 988 struct passwd *p; 989 990 p = getpwnam(name); 991 if(p == nil) 992 return nil; 993 return newuser(p->pw_uid, p->pw_gid, name, 0); 994 } 995 996 static User* 997 newuid(int id) 998 { 999 struct passwd *p; 1000 1001 p = getpwuid(id); 1002 if(p == nil) 1003 return nil; 1004 return newuser(p->pw_uid, p->pw_gid, p->pw_name, 0); 1005 } 1006 1007 static User* 1008 newgroup(struct group *g) 1009 { 1010 User *u, *gm; 1011 int n, o; 1012 1013 if(g == nil) 1014 return nil; 1015 for(n=0; g->gr_mem[n] != nil; n++) 1016 ; 1017 u = newuser(g->gr_gid, g->gr_gid, g->gr_name, n); 1018 if(u == nil) 1019 return nil; 1020 o = 0; 1021 for(n=0; g->gr_mem[n] != nil; n++){ 1022 gm = name2user(uidmap, g->gr_mem[n], newuname); 1023 if(gm != nil) 1024 u->mem[o++] = gm->id; 1025 /* ignore names that don't map to IDs */ 1026 } 1027 u->nmem = o; 1028 return u; 1029 } 1030 1031 static User* 1032 newgid(int id) 1033 { 1034 return newgroup(getgrgid(id)); 1035 } 1036 1037 static User* 1038 newgname(char *name) 1039 { 1040 return newgroup(getgrnam(name)); 1041 } 1042 1043 static User* 1044 id2user(User **tab, int id, User* (*get)(int)) 1045 { 1046 User *u, **h; 1047 1048 h = hashuser(tab, id); 1049 for(u = *h; u != nil; u = u->next) 1050 if(u->id == id) 1051 return u; 1052 u = get(id); 1053 if(u == nil) 1054 return nil; 1055 u->next = *h; 1056 *h = u; 1057 return u; 1058 } 1059 1060 static int 1061 ingroup(int id, int gid) 1062 { 1063 int i; 1064 User *g; 1065 1066 g = id2user(gidmap, gid, newgid); 1067 if(g == nil || g->mem == nil) 1068 return 0; 1069 for(i = 0; i < g->nmem; i++) 1070 if(g->mem[i] == id) 1071 return 1; 1072 return 0; 1073 } 1074 1075 Dev fsdevtab = { 1076 'U', 1077 "fs", 1078 1079 devinit, 1080 fsattach, 1081 fswalk, 1082 fsstat, 1083 fsopen, 1084 fscreate, 1085 fsclose, 1086 fsread, 1087 devbread, 1088 fswrite, 1089 devbwrite, 1090 fsremove, 1091 fswstat 1092 }; 1093