xref: /plan9-contrib/sys/src/cmd/unix/drawterm/kern/devfs-win32.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
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