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