Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <fcall.h>
4
#include <thread.h>
5
#include <9p.h>
6
#include <mp.h>
7
#include <libsec.h>
8
 
9
static void
10
usage(void)
11
{
12
	fprint(2, "mntgen [-s srvname] [mtpt]\n");
13
	exits("usage");
14
}
15
 
16
ulong time0;
17
 
18
typedef struct Tab Tab;
19
struct Tab
20
{
21
	char *name;
22
	vlong qid;
23
	ulong time;
24
	int ref;
25
};
26
 
27
Tab *tab;
28
int ntab;
29
int mtab;
30
 
31
static Tab*
32
findtab(vlong path)
33
{
34
	int i;
35
 
36
	for(i=0; i<ntab; i++)
37
		if(tab[i].qid == path)
38
			return &tab[i];
39
	return nil;
40
}
41
 
42
static vlong
43
hash(char *name)
44
{
45
	vlong digest[MD5dlen / sizeof(vlong) + 1];
46
	md5((uchar *)name, strlen(name), (uchar *)digest, nil);
47
	return digest[0] & ((1ULL<<48)-1);
48
}
49
 
50
static void
51
fsopen(Req *r)
52
{
53
	if(r->ifcall.mode != OREAD)
54
		respond(r, "permission denied");
55
	else
56
		respond(r, nil);
57
}
58
 
59
static int
60
dirgen(int i, Dir *d, void*)
61
{
62
	if(i >= ntab)
63
		return -1;
64
	memset(d, 0, sizeof *d);
65
	d->qid.type = QTDIR;
66
	d->uid = estrdup9p("sys");
67
	d->gid = estrdup9p("sys");
68
	d->mode = DMDIR|0555;
69
	d->length = 0;
70
	if(i == -1){
71
		d->name = estrdup9p("/");
72
		d->atime = d->mtime = time0;
73
	}else{
74
		d->qid.path = tab[i].qid;
75
		d->name = estrdup9p(tab[i].name);
76
		d->atime = d->mtime = tab[i].time;
77
	}
78
	return 0;
79
}
80
 
81
static void
82
fsread(Req *r)
83
{
84
	if(r->fid->qid.path == 0)
85
		dirread9p(r, dirgen, nil);
86
	else
87
		r->ofcall.count = 0;
88
	respond(r, nil);
89
}
90
 
91
static void
92
fsstat(Req *r)
93
{
94
	Tab *t;
95
	vlong qid;
96
 
97
	qid = r->fid->qid.path;
98
	if(qid == 0)
99
		dirgen(-1, &r->d, nil);
100
	else{
101
		if((t = findtab(qid)) == nil){
102
			respond(r, "path not found (???)");
103
			return;
104
		}
105
		dirgen(t-tab, &r->d, nil);
106
	}
107
	respond(r, nil);
108
}
109
 
110
static char*
111
fswalk1(Fid *fid, char *name, void*)
112
{
113
	int i;
114
	Tab *t;
115
	vlong h;
116
 
117
	if(fid->qid.path != 0){
118
		/* nothing in child directory */
119
		if(strcmp(name, "..") == 0){
120
			if((t = findtab(fid->qid.path)) != nil)
121
				t->ref--;
122
			fid->qid.path = 0;
123
			return nil;
124
		}
125
		return "path not found";
126
	}
127
	/* root */
128
	if(strcmp(name, "..") == 0)
129
		return nil;
130
	for(i=0; i<ntab; i++)
131
		if(strcmp(tab[i].name, name) == 0){
132
			tab[i].ref++;
133
			fid->qid.path = tab[i].qid;
134
			return nil;
135
		}
136
	h = hash(name);
137
	if(findtab(h) != nil)
138
		return "hash collision";
139
 
140
	/* create it */
141
	if(ntab == mtab){
142
		if(mtab == 0)
143
			mtab = 16;
144
		else
145
			mtab *= 2;
146
		tab = erealloc9p(tab, sizeof(tab[0])*mtab);
147
	}
148
	tab[ntab].qid = h;
149
	fid->qid.path = tab[ntab].qid;
150
	tab[ntab].name = estrdup9p(name);
151
	tab[ntab].time = time(0);
152
	tab[ntab].ref = 1;
153
	ntab++;
154
 
155
	return nil;
156
}
157
 
158
static char*
159
fsclone(Fid *fid, Fid*, void*)
160
{
161
	Tab *t;
162
 
163
	if((t = findtab(fid->qid.path)) != nil)
164
		t->ref++;
165
	return nil;
166
}
167
 
168
static void
169
fswalk(Req *r)
170
{
171
	walkandclone(r, fswalk1, fsclone, nil);
172
}
173
 
174
static void
175
fsclunk(Fid *fid)
176
{
177
	Tab *t;
178
	vlong qid;
179
 
180
	qid = fid->qid.path;
181
	if(qid == 0)
182
		return;
183
	if((t = findtab(qid)) == nil){
184
		fprint(2, "warning: cannot find %llux\n", qid);
185
		return;
186
	}
187
	if(--t->ref == 0){
188
		free(t->name);
189
		tab[t-tab] = tab[--ntab];
190
	}else if(t->ref < 0)
191
		fprint(2, "warning: negative ref count for %s\n", t->name);
192
}
193
 
194
static void
195
fsattach(Req *r)
196
{
197
	char *spec;
198
 
199
	spec = r->ifcall.aname;
200
	if(spec && spec[0]){
201
		respond(r, "invalid attach specifier");
202
		return;
203
	}
204
 
205
	r->ofcall.qid = (Qid){0, 0, QTDIR};
206
	r->fid->qid = r->ofcall.qid;
207
	respond(r, nil);
208
}
209
 
210
Srv fs=
211
{
212
.attach=	fsattach,
213
.open=	fsopen,
214
.read=	fsread,
215
.stat=	fsstat,
216
.walk=	fswalk,
217
.destroyfid=	fsclunk
218
};
219
 
220
void
221
main(int argc, char **argv)
222
{
223
	char *service;
224
 
225
	time0 = time(0);
226
	service = nil;
227
	ARGBEGIN{
228
	case 'D':
229
		chatty9p++;
230
		break;
231
	case 's':
232
		service = EARGF(usage());
233
		break;
234
	default:
235
		usage();
236
	}ARGEND
237
 
238
	if(argc > 1)
239
		usage();
240
	postmountsrv(&fs, service, argc ? argv[0] : "/n", MAFTER);
241
	exits(nil);
242
}