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