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