Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
};