xref: /plan9/sys/src/cmd/usb/lib/fsdir.c (revision 906943f9f6b8411972abb5e3a03ed19f74be7ccc)
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include "usb.h"
6 #include "usbfs.h"
7 
8 typedef struct Rpc Rpc;
9 
10 enum
11 {
12 	Incr = 3,	/* increments for fs array */
13 	Dtop = 0,	/* high 32 bits for / 	*/
14 	Qdir = 0,	/* low 32 bits for /devdir */
15 };
16 
17 QLock fslck;
18 static Usbfs** fs;
19 static int nfs;
20 static int fsused;
21 static int exitonclose = 1;
22 
23 void
24 usbfsexits(int y)
25 {
26 	exitonclose = y;
27 }
28 
29 static int
30 qiddev(uvlong path)
31 {
32 	return (int)(path>>32) & 0xFF;
33 }
34 
35 static int
36 qidfile(uvlong path)
37 {
38 	return (int)(path & 0xFFFFFFFFULL);
39 }
40 
41 static uvlong
42 mkqid(int qd, int qf)
43 {
44 	return ((uvlong)qd << 32) | (uvlong)qf;
45 }
46 
47 void
48 usbfsdirdump(void)
49 {
50 	int i;
51 
52 	qlock(&fslck);
53 	fprint(2, "%s: fs list: (%d used %d total)\n", argv0, fsused, nfs);
54 	for(i = 1; i < nfs; i++)
55 		if(fs[i] != nil)
56 			if(fs[i]->dev != nil)
57 				fprint(2, "%s\t%s dev %#p refs %ld\n",
58 					argv0, fs[i]->name, fs[i]->dev, fs[i]->dev->ref);
59 			else
60 				fprint(2, "%s:\t%s\n", argv0, fs[i]->name);
61 	qunlock(&fslck);
62 }
63 
64 void
65 usbfsadd(Usbfs *dfs)
66 {
67 	int i, j;
68 
69 	dprint(2, "%s: fsadd %s\n", argv0, dfs->name);
70 	qlock(&fslck);
71 	for(i = 1; i < nfs; i++)
72 		if(fs[i] == nil)
73 			break;
74 	if(i >= nfs){
75 		if((nfs%Incr) == 0){
76 			fs = realloc(fs, sizeof(Usbfs*) * (nfs+Incr));
77 			if(fs == nil)
78 				sysfatal("realloc: %r");
79 			for(j = nfs; j < nfs+Incr; j++)
80 				fs[j] = nil;
81 		}
82 		if(nfs == 0)	/* do not use entry 0 */
83 			nfs++;
84 		fs[nfs++] = dfs;
85 	}else
86 		fs[i] = dfs;
87 	dfs->qid = mkqid(i, 0);
88 	fsused++;
89 	qunlock(&fslck);
90 }
91 
92 static void
93 usbfsdelnth(int i)
94 {
95 	if(fs[i] != nil){
96 		dprint(2, "%s: fsdel %s", argv0, fs[i]->name);
97 		if(fs[i]->dev != nil){
98 			dprint(2, " dev %#p ref %ld\n",
99 				fs[i]->dev, fs[i]->dev->ref);
100 		}else
101 			dprint(2, "no dev\n");
102 		if(fs[i]->end != nil)
103 			fs[i]->end(fs[i]);
104 		else
105 			closedev(fs[i]->dev);
106 		fsused--;
107 	}
108 	fs[i] = nil;
109 	if(fsused == 0 && exitonclose != 0){
110 		fprint(2, "%s: all file systems gone: exiting\n", argv0);
111 		threadexitsall(nil);
112 	}
113 }
114 
115 void
116 usbfsdel(Usbfs *dfs)
117 {
118 	int i;
119 
120 	qlock(&fslck);
121 	for(i = 0; i < nfs; i++)
122 		if(dfs == nil || fs[i] == dfs){
123 			usbfsdelnth(i);
124 			if(dfs != nil)
125 				break;
126 		}
127 	qunlock(&fslck);
128 }
129 
130 static void
131 fsend(Usbfs*)
132 {
133 	dprint(2, "%s: fsend\n", argv0);
134 	usbfsdel(nil);
135 }
136 
137 void
138 usbfsgone(char *dir)
139 {
140 	int i;
141 
142 	qlock(&fslck);
143 	/* devices may have more than one fs */
144 	for(i = 0; i < nfs; i++)
145 		if(fs[i] != nil && fs[i]->dev != nil)
146 		if(strcmp(fs[i]->dev->dir, dir) == 0)
147 			usbfsdelnth(i);
148 	qunlock(&fslck);
149 }
150 
151 static void
152 fsclone(Usbfs*, Fid *o, Fid *n)
153 {
154 	int qd;
155 	Dev *dev;
156 	void (*xfsclone)(Usbfs *fs, Fid *of, Fid *nf);
157 
158 	xfsclone = nil;
159 	dev = nil;
160 	qd = qiddev(o->qid.path);
161 	qlock(&fslck);
162 	if(qd != Dtop && fs[qd] != nil && fs[qd]->clone != nil){
163 		dev = fs[qd]->dev;
164 		if(dev != nil)
165 			incref(dev);
166 		xfsclone = fs[qd]->clone;
167 	}
168 	qunlock(&fslck);
169 	if(xfsclone != nil){
170 		xfsclone(fs[qd], o, n);
171 	}
172 	if(dev != nil)
173 		closedev(dev);
174 }
175 
176 static int
177 fswalk(Usbfs*, Fid *fid, char *name)
178 {
179 	Qid q;
180 	int qd, qf;
181 	int i;
182 	int rc;
183 	Dev *dev;
184 	Dir d;
185 	int (*xfswalk)(Usbfs *fs, Fid *f, char *name);
186 
187 	q = fid->qid;
188 	qd = qiddev(q.path);
189 	qf = qidfile(q.path);
190 
191 	q.type = QTDIR;
192 	q.vers = 0;
193 	if(strcmp(name, "..") == 0)
194 		if(qd == Dtop || qf == Qdir){
195 			q.path = mkqid(Dtop, Qdir);
196 			fid->qid = q;
197 			return 0;
198 		}
199 	if(qd != 0){
200 		qlock(&fslck);
201 		if(fs[qd] == nil){
202 			qunlock(&fslck);
203 			werrstr(Eio);
204 			return -1;
205 		}
206 		dev = fs[qd]->dev;
207 		if(dev != nil)
208 			incref(dev);
209 		xfswalk = fs[qd]->walk;
210 		qunlock(&fslck);
211 		rc = xfswalk(fs[qd], fid, name);
212 		if(dev != nil)
213 			closedev(dev);
214 		return rc;
215 	}
216 	qlock(&fslck);
217 	for(i = 0; i < nfs; i++)
218 		if(fs[i] != nil && strcmp(name, fs[i]->name) == 0){
219 			q.path = mkqid(i, Qdir);
220 			fs[i]->stat(fs[i], q, &d); /* may be a file */
221 			fid->qid = d.qid;
222 			qunlock(&fslck);
223 			return 0;
224 		}
225 	qunlock(&fslck);
226 	werrstr(Enotfound);
227 	return -1;
228 }
229 
230 static int
231 fsopen(Usbfs*, Fid *fid, int mode)
232 {
233 	int qd;
234 	int rc;
235 	Dev *dev;
236 	int (*xfsopen)(Usbfs *fs, Fid *f, int mode);
237 
238 	qd = qiddev(fid->qid.path);
239 	if(qd == Dtop)
240 		return 0;
241 	qlock(&fslck);
242 	if(fs[qd] == nil){
243 		qunlock(&fslck);
244 		werrstr(Eio);
245 		return -1;
246 	}
247 	dev = fs[qd]->dev;
248 	if(dev != nil)
249 		incref(dev);
250 	xfsopen = fs[qd]->open;
251 	qunlock(&fslck);
252 	if(xfsopen != nil)
253 		rc = xfsopen(fs[qd], fid, mode);
254 	else
255 		rc = 0;
256 	if(dev != nil)
257 		closedev(dev);
258 	return rc;
259 }
260 
261 static int
262 dirgen(Usbfs*, Qid, int n, Dir *d, void *)
263 {
264 	int i;
265 	Dev *dev;
266 	char *nm;
267 
268 	qlock(&fslck);
269 	for(i = 0; i < nfs; i++)
270 		if(fs[i] != nil && n-- == 0){
271 			d->qid.type = QTDIR;
272 			d->qid.path = mkqid(i, Qdir);
273 			d->qid.vers = 0;
274 			dev = fs[i]->dev;
275 			if(dev != nil)
276 				incref(dev);
277 			nm = d->name;
278 			fs[i]->stat(fs[i], d->qid, d);
279 			d->name = nm;
280 			strncpy(d->name, fs[i]->name, Namesz);
281 			if(dev != nil)
282 				closedev(dev);
283 			qunlock(&fslck);
284 			return 0;
285 		}
286 	qunlock(&fslck);
287 	return -1;
288 }
289 
290 static long
291 fsread(Usbfs*, Fid *fid, void *data, long cnt, vlong off)
292 {
293 	int qd;
294 	int rc;
295 	Dev *dev;
296 	Qid q;
297 	long (*xfsread)(Usbfs *fs, Fid *f, void *data, long count, vlong );
298 
299 	q = fid->qid;
300 	qd = qiddev(q.path);
301 	if(qd == Dtop)
302 		return usbdirread(nil, q, data, cnt, off, dirgen, nil);
303 	qlock(&fslck);
304 	if(fs[qd] == nil){
305 		qunlock(&fslck);
306 		werrstr(Eio);
307 		return -1;
308 	}
309 	dev = fs[qd]->dev;
310 	if(dev != nil)
311 		incref(dev);
312 	xfsread = fs[qd]->read;
313 	qunlock(&fslck);
314 	rc = xfsread(fs[qd], fid, data, cnt, off);
315 	if(dev != nil)
316 		closedev(dev);
317 	return rc;
318 }
319 
320 static long
321 fswrite(Usbfs*, Fid *fid, void *data, long cnt, vlong off)
322 {
323 	int qd;
324 	int rc;
325 	Dev *dev;
326 	long (*xfswrite)(Usbfs *fs, Fid *f, void *data, long count, vlong );
327 
328 	qd = qiddev(fid->qid.path);
329 	if(qd == Dtop)
330 		sysfatal("fswrite: not for usbd /");
331 	qlock(&fslck);
332 	if(fs[qd] == nil){
333 		qunlock(&fslck);
334 		werrstr(Eio);
335 		return -1;
336 	}
337 	dev = fs[qd]->dev;
338 	if(dev != nil)
339 		incref(dev);
340 	xfswrite = fs[qd]->write;
341 	qunlock(&fslck);
342 	rc = xfswrite(fs[qd], fid, data, cnt, off);
343 	if(dev != nil)
344 		closedev(dev);
345 	return rc;
346 }
347 
348 
349 static void
350 fsclunk(Usbfs*, Fid* fid)
351 {
352 	int qd;
353 	Dev *dev;
354 	void (*xfsclunk)(Usbfs *fs, Fid *f);
355 
356 	dev = nil;
357 	qd = qiddev(fid->qid.path);
358 	qlock(&fslck);
359 	if(qd != Dtop && fs[qd] != nil){
360 		dev=fs[qd]->dev;
361 		if(dev != nil)
362 			incref(dev);
363 		xfsclunk = fs[qd]->clunk;
364 	}else
365 		xfsclunk = nil;
366 	qunlock(&fslck);
367 	if(xfsclunk != nil){
368 		xfsclunk(fs[qd], fid);
369 	}
370 	if(dev != nil)
371 		closedev(dev);
372 }
373 
374 static int
375 fsstat(Usbfs*, Qid qid, Dir *d)
376 {
377 	int qd;
378 	int rc;
379 	Dev *dev;
380 	int (*xfsstat)(Usbfs *fs, Qid q, Dir *d);
381 
382 	qd = qiddev(qid.path);
383 	if(qd == Dtop){
384 		d->qid = qid;
385 		d->name = "usb";
386 		d->length = 0;
387 		d->mode = 0555|DMDIR;
388 		return 0;
389 	}
390 	qlock(&fslck);
391 	if(fs[qd] == nil){
392 		qunlock(&fslck);
393 		werrstr(Eio);
394 		return -1;
395 	}
396 	xfsstat = fs[qd]->stat;
397 	dev = fs[qd]->dev;
398 	if(dev != nil)
399 		incref(dev);
400 	qunlock(&fslck);
401 	rc = xfsstat(fs[qd], qid, d);
402 	if(dev != nil)
403 		closedev(dev);
404 	return rc;
405 }
406 
407 Usbfs usbdirfs =
408 {
409 	.walk = fswalk,
410 	.clone = fsclone,
411 	.clunk = fsclunk,
412 	.open = fsopen,
413 	.read = fsread,
414 	.write = fswrite,
415 	.stat = fsstat,
416 	.end = fsend,
417 };
418 
419