1 #include "u.h" 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <dirent.h> 5 #include <fcntl.h> 6 #include <errno.h> 7 #include <stdio.h> /* for remove, rename */ 8 #include <limits.h> 9 10 #ifndef NAME_MAX 11 # define NAME_MAX 256 12 #endif 13 #include "lib.h" 14 #include "dat.h" 15 #include "fns.h" 16 #include "error.h" 17 18 19 typedef struct Ufsinfo Ufsinfo; 20 21 enum 22 { 23 NUID = 256, 24 NGID = 256, 25 MAXPATH = 1024, 26 MAXCOMP = 128 27 }; 28 29 struct Ufsinfo 30 { 31 int mode; 32 int fd; 33 int uid; 34 int gid; 35 DIR* dir; 36 vlong offset; 37 QLock oq; 38 char nextname[NAME_MAX]; 39 }; 40 41 char *base = "/"; 42 43 static Qid fsqid(char*, struct stat *); 44 static void fspath(Chan*, char*, char*); 45 static ulong fsdirread(Chan*, uchar*, int, ulong); 46 static int fsomode(int); 47 48 /* clumsy hack, but not worse than the Path stuff in the last one */ 49 static char* 50 uc2name(Chan *c) 51 { 52 char *s; 53 54 if(c->name == nil) 55 return "/"; 56 s = c2name(c); 57 if(s[0]=='#' && s[1]=='U') 58 return s+2; 59 return s; 60 } 61 62 static char* 63 lastelem(Chan *c) 64 { 65 char *s, *t; 66 67 s = uc2name(c); 68 if((t = strrchr(s, '/')) == nil) 69 return s; 70 if(t[1] == 0) 71 return t; 72 return t+1; 73 } 74 75 static Chan* 76 fsattach(char *spec) 77 { 78 Chan *c; 79 struct stat stbuf; 80 static int devno; 81 Ufsinfo *uif; 82 83 if(stat(base, &stbuf) < 0) 84 error(strerror(errno)); 85 86 c = devattach('U', spec); 87 88 uif = mallocz(sizeof(Ufsinfo), 1); 89 uif->mode = stbuf.st_mode; 90 uif->uid = stbuf.st_uid; 91 uif->gid = stbuf.st_gid; 92 93 c->aux = uif; 94 c->dev = devno++; 95 c->qid.type = QTDIR; 96 /*print("fsattach %s\n", c2name(c));*/ 97 98 return c; 99 } 100 101 static Chan* 102 fsclone(Chan *c, Chan *nc) 103 { 104 Ufsinfo *uif; 105 106 uif = mallocz(sizeof(Ufsinfo), 1); 107 *uif = *(Ufsinfo*)c->aux; 108 nc->aux = uif; 109 110 return nc; 111 } 112 113 static int 114 fswalk1(Chan *c, char *name) 115 { 116 struct stat stbuf; 117 char path[MAXPATH]; 118 Ufsinfo *uif; 119 120 fspath(c, name, path); 121 122 /*print("** fs walk '%s' -> %s\n", path, name); */ 123 124 if(stat(path, &stbuf) < 0) 125 return 0; 126 127 uif = c->aux; 128 129 uif->mode = stbuf.st_mode; 130 uif->uid = stbuf.st_uid; 131 uif->gid = stbuf.st_gid; 132 133 c->qid = fsqid(path, &stbuf); 134 135 return 1; 136 } 137 138 extern Cname* addelem(Cname*, char*); 139 140 static Walkqid* 141 fswalk(Chan *c, Chan *nc, char **name, int nname) 142 { 143 int i; 144 Cname *cname; 145 Walkqid *wq; 146 147 if(nc != nil) 148 panic("fswalk: nc != nil"); 149 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); 150 nc = devclone(c); 151 cname = c->name; 152 incref(&cname->ref); 153 154 fsclone(c, nc); 155 wq->clone = nc; 156 for(i=0; i<nname; i++){ 157 nc->name = cname; 158 if(fswalk1(nc, name[i]) == 0) 159 break; 160 cname = addelem(cname, name[i]); 161 wq->qid[i] = nc->qid; 162 } 163 nc->name = cname; 164 if(i != nname){ 165 cclose(nc); 166 wq->clone = nil; 167 } 168 wq->nqid = i; 169 return wq; 170 } 171 172 static int 173 fsstat(Chan *c, uchar *buf, int n) 174 { 175 Dir d; 176 struct stat stbuf; 177 char path[MAXPATH]; 178 179 if(n < BIT16SZ) 180 error(Eshortstat); 181 182 fspath(c, 0, path); 183 if(stat(path, &stbuf) < 0) 184 error(strerror(errno)); 185 186 d.name = lastelem(c); 187 d.uid = "unknown"; 188 d.gid = "unknown"; 189 d.muid = "unknown"; 190 d.qid = c->qid; 191 d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777); 192 d.atime = stbuf.st_atime; 193 d.mtime = stbuf.st_mtime; 194 d.length = stbuf.st_size; 195 d.type = 'U'; 196 d.dev = c->dev; 197 return convD2M(&d, buf, n); 198 } 199 200 static Chan* 201 fsopen(Chan *c, int mode) 202 { 203 char path[MAXPATH]; 204 int m, isdir; 205 Ufsinfo *uif; 206 207 /*print("fsopen %s\n", c2name(c));*/ 208 m = mode & (OTRUNC|3); 209 switch(m) { 210 case 0: 211 break; 212 case 1: 213 case 1|16: 214 break; 215 case 2: 216 case 0|16: 217 case 2|16: 218 break; 219 case 3: 220 break; 221 default: 222 error(Ebadarg); 223 } 224 225 isdir = c->qid.type & QTDIR; 226 227 if(isdir && mode != OREAD) 228 error(Eperm); 229 230 m = fsomode(m & 3); 231 c->mode = openmode(mode); 232 233 uif = c->aux; 234 235 fspath(c, 0, path); 236 if(isdir) { 237 uif->dir = opendir(path); 238 if(uif->dir == 0) 239 error(strerror(errno)); 240 } 241 else { 242 if(mode & OTRUNC) 243 m |= O_TRUNC; 244 uif->fd = open(path, m, 0666); 245 246 if(uif->fd < 0) 247 error(strerror(errno)); 248 } 249 uif->offset = 0; 250 251 c->offset = 0; 252 c->flag |= COPEN; 253 return c; 254 } 255 256 static void 257 fscreate(Chan *c, char *name, int mode, ulong perm) 258 { 259 int fd, m; 260 char path[MAXPATH]; 261 struct stat stbuf; 262 Ufsinfo *uif; 263 264 m = fsomode(mode&3); 265 266 fspath(c, name, path); 267 268 uif = c->aux; 269 270 if(perm & DMDIR) { 271 if(m) 272 error(Eperm); 273 274 if(mkdir(path, perm & 0777) < 0) 275 error(strerror(errno)); 276 277 fd = open(path, 0); 278 if(fd >= 0) { 279 chmod(path, perm & 0777); 280 chown(path, uif->uid, uif->uid); 281 } 282 close(fd); 283 284 uif->dir = opendir(path); 285 if(uif->dir == 0) 286 error(strerror(errno)); 287 } 288 else { 289 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666); 290 if(fd >= 0) { 291 if(m != 1) { 292 close(fd); 293 fd = open(path, m); 294 } 295 chmod(path, perm & 0777); 296 chown(path, uif->uid, uif->gid); 297 } 298 if(fd < 0) 299 error(strerror(errno)); 300 uif->fd = fd; 301 } 302 303 if(stat(path, &stbuf) < 0) 304 error(strerror(errno)); 305 c->qid = fsqid(path, &stbuf); 306 c->offset = 0; 307 c->flag |= COPEN; 308 c->mode = openmode(mode); 309 } 310 311 static void 312 fsclose(Chan *c) 313 { 314 Ufsinfo *uif; 315 316 uif = c->aux; 317 318 if(c->flag & COPEN) { 319 if(c->qid.type & QTDIR) 320 closedir(uif->dir); 321 else 322 close(uif->fd); 323 } 324 325 free(uif); 326 } 327 328 static long 329 fsread(Chan *c, void *va, long n, vlong offset) 330 { 331 int fd, r; 332 Ufsinfo *uif; 333 334 /*print("fsread %s\n", c2name(c));*/ 335 if(c->qid.type & QTDIR) 336 return fsdirread(c, va, n, offset); 337 338 uif = c->aux; 339 qlock(&uif->oq); 340 if(waserror()) { 341 qunlock(&uif->oq); 342 nexterror(); 343 } 344 fd = uif->fd; 345 if(uif->offset != offset) { 346 r = lseek(fd, offset, 0); 347 if(r < 0) 348 error(strerror(errno)); 349 uif->offset = offset; 350 } 351 352 n = read(fd, va, n); 353 if(n < 0) 354 error(strerror(errno)); 355 356 uif->offset += n; 357 qunlock(&uif->oq); 358 poperror(); 359 360 return n; 361 } 362 363 static long 364 fswrite(Chan *c, void *va, long n, vlong offset) 365 { 366 int fd, r; 367 Ufsinfo *uif; 368 369 uif = c->aux; 370 371 qlock(&uif->oq); 372 if(waserror()) { 373 qunlock(&uif->oq); 374 nexterror(); 375 } 376 fd = uif->fd; 377 if(uif->offset != offset) { 378 r = lseek(fd, offset, 0); 379 if(r < 0) 380 error(strerror(errno)); 381 uif->offset = offset; 382 } 383 384 n = write(fd, va, n); 385 if(n < 0) 386 error(strerror(errno)); 387 388 uif->offset += n; 389 qunlock(&uif->oq); 390 poperror(); 391 392 return n; 393 } 394 395 static void 396 fsremove(Chan *c) 397 { 398 int n; 399 char path[MAXPATH]; 400 401 fspath(c, 0, path); 402 if(c->qid.type & QTDIR) 403 n = rmdir(path); 404 else 405 n = remove(path); 406 if(n < 0) 407 error(strerror(errno)); 408 } 409 410 int 411 fswstat(Chan *c, uchar *buf, int n) 412 { 413 Dir d; 414 struct stat stbuf; 415 char old[MAXPATH], new[MAXPATH]; 416 char strs[MAXPATH*3], *p; 417 Ufsinfo *uif; 418 419 if(convM2D(buf, n, &d, strs) != n) 420 error(Ebadstat); 421 422 fspath(c, 0, old); 423 if(stat(old, &stbuf) < 0) 424 error(strerror(errno)); 425 426 uif = c->aux; 427 428 fspath(c, 0, old); 429 if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) { 430 if(chmod(old, d.mode&0777) < 0) 431 error(strerror(errno)); 432 uif->mode &= ~0777; 433 uif->mode |= d.mode&0777; 434 } 435 436 if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) { 437 fspath(c, 0, old); 438 strcpy(new, old); 439 p = strrchr(new, '/'); 440 strcpy(p+1, d.name); 441 if(rename(old, new) < 0) 442 error(strerror(errno)); 443 } 444 445 /* 446 p = name2pass(gid, d.gid); 447 if(p == 0) 448 error(Eunknown); 449 450 if(p->id != stbuf.st_gid) { 451 if(chown(old, stbuf.st_uid, p->id) < 0) 452 error(strerror(errno)); 453 454 uif->gid = p->id; 455 } 456 */ 457 return n; 458 } 459 460 static Qid 461 fsqid(char *p, struct stat *st) 462 { 463 Qid q; 464 int dev; 465 ulong h; 466 static int nqdev; 467 static uchar *qdev; 468 469 if(qdev == 0) 470 qdev = mallocz(65536U, 1); 471 472 q.type = 0; 473 if((st->st_mode&S_IFMT) == S_IFDIR) 474 q.type = QTDIR; 475 476 dev = st->st_dev & 0xFFFFUL; 477 if(qdev[dev] == 0) 478 qdev[dev] = ++nqdev; 479 480 h = 0; 481 while(*p != '\0') 482 h += *p++ * 13; 483 484 q.path = (vlong)qdev[dev]<<32; 485 q.path |= h; 486 q.vers = st->st_mtime; 487 488 return q; 489 } 490 491 static void 492 fspath(Chan *c, char *ext, char *path) 493 { 494 strcpy(path, base); 495 strcat(path, "/"); 496 strcat(path, uc2name(c)); 497 if(ext){ 498 strcat(path, "/"); 499 strcat(path, ext); 500 } 501 cleanname(path); 502 } 503 504 static int 505 isdots(char *name) 506 { 507 if(name[0] != '.') 508 return 0; 509 if(name[1] == '\0') 510 return 1; 511 if(name[1] != '.') 512 return 0; 513 if(name[2] == '\0') 514 return 1; 515 return 0; 516 } 517 518 static int 519 p9readdir(char *name, Ufsinfo *uif) 520 { 521 struct dirent *de; 522 523 if(uif->nextname[0]){ 524 strcpy(name, uif->nextname); 525 uif->nextname[0] = 0; 526 return 1; 527 } 528 529 de = readdir(uif->dir); 530 if(de == NULL) 531 return 0; 532 533 strcpy(name, de->d_name); 534 return 1; 535 } 536 537 static ulong 538 fsdirread(Chan *c, uchar *va, int count, ulong offset) 539 { 540 int i; 541 Dir d; 542 long n; 543 char de[NAME_MAX]; 544 struct stat stbuf; 545 char path[MAXPATH], dirpath[MAXPATH]; 546 Ufsinfo *uif; 547 548 /*print("fsdirread %s\n", c2name(c));*/ 549 i = 0; 550 uif = c->aux; 551 552 errno = 0; 553 if(uif->offset != offset) { 554 if(offset != 0) 555 error("bad offset in fsdirread"); 556 uif->offset = offset; /* sync offset */ 557 uif->nextname[0] = 0; 558 rewinddir(uif->dir); 559 } 560 561 fspath(c, 0, dirpath); 562 563 while(i+BIT16SZ < count) { 564 if(!p9readdir(de, uif)) 565 break; 566 567 if(de[0]==0 || isdots(de)) 568 continue; 569 570 d.name = de; 571 sprint(path, "%s/%s", dirpath, de); 572 memset(&stbuf, 0, sizeof stbuf); 573 574 if(stat(path, &stbuf) < 0) { 575 /* fprint(2, "dir: bad path %s\n", path); */ 576 /* but continue... probably a bad symlink */ 577 } 578 579 d.uid = "unknown"; 580 d.gid = "unknown"; 581 d.muid = "unknown"; 582 d.qid = fsqid(path, &stbuf); 583 d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777); 584 d.atime = stbuf.st_atime; 585 d.mtime = stbuf.st_mtime; 586 d.length = stbuf.st_size; 587 d.type = 'U'; 588 d.dev = c->dev; 589 n = convD2M(&d, (uchar*)va+i, count-i); 590 if(n == BIT16SZ){ 591 strcpy(uif->nextname, de); 592 break; 593 } 594 i += n; 595 } 596 /*print("got %d\n", i);*/ 597 uif->offset += i; 598 return i; 599 } 600 601 static int 602 fsomode(int m) 603 { 604 switch(m) { 605 case 0: /* OREAD */ 606 case 3: /* OEXEC */ 607 return 0; 608 case 1: /* OWRITE */ 609 return 1; 610 case 2: /* ORDWR */ 611 return 2; 612 } 613 error(Ebadarg); 614 return 0; 615 } 616 617 Dev fsdevtab = { 618 'U', 619 "fs", 620 621 devreset, 622 devinit, 623 devshutdown, 624 fsattach, 625 fswalk, 626 fsstat, 627 fsopen, 628 fscreate, 629 fsclose, 630 fsread, 631 devbread, 632 fswrite, 633 devbwrite, 634 fsremove, 635 fswstat, 636 }; 637