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