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*
uc2name(Chan * c)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*
lastelem(Chan * c)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*
fsattach(char * spec)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*
fsclone(Chan * c,Chan * nc)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
fswalk1(Chan * c,char * name)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*
fswalk(Chan * c,Chan * nc,char ** name,int nname)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
fsstat(Chan * c,uchar * buf,int n)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*
fsopen(Chan * c,int mode)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
fscreate(Chan * c,char * name,int mode,ulong perm)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
fsclose(Chan * c)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
fsread(Chan * c,void * va,long n,vlong offset)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
fswrite(Chan * c,void * va,long n,vlong offset)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
fsremove(Chan * c)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
fswstat(Chan * c,uchar * buf,int n)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
fsqid(char * p,struct stat * st)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
fspath(Chan * c,char * ext,char * path)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
isdots(char * name)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
p9readdir(char * name,Ufsinfo * uif)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
fsdirread(Chan * c,uchar * va,int count,ulong offset)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
fsomode(int m)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
closedir(DIR * d)629 closedir(DIR *d)
630 {
631 FindClose(d->handle);
632 free(d->path);
633 }
634
635 int
readdir(char * name,DIR * d)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
rewinddir(DIR * d)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
chown(char * path,int uid,int perm)657 chown(char *path, int uid, int perm)
658 {
659 /* panic("chown"); */
660 return 0;
661 }
662
663 DIR*
opendir(char * p)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