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