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