tmain.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tmain.c (26392B) | |
--- | |
1 /* | |
2 * 9P to FUSE translator. Acts as FUSE server, 9P client. | |
3 * Mounts 9P servers via FUSE kernel module. | |
4 * | |
5 * There are four procs in this threaded program | |
6 * (ignoring the one that runs main and then exits). | |
7 * The first proc reads FUSE requests from /dev/fuse. | |
8 * It sends the requests over a channel to a second proc, | |
9 * which serves the requests. Each request runs in a | |
10 * thread in that second proc. Those threads do write | |
11 * FUSE replies, which in theory might block, but in practice don't. | |
12 * The 9P interactions are handled by lib9pclient, which | |
13 * allocates two more procs, one for reading and one for | |
14 * writing the 9P connection. Thus the many threads in the | |
15 * request proc can do 9P interactions without blocking. | |
16 */ | |
17 | |
18 #define _GNU_SOURCE 1 /* for O_DIRECTORY on Linux */ | |
19 #include "a.h" | |
20 | |
21 /* GNUisms */ | |
22 #ifndef O_DIRECTORY | |
23 #define O_DIRECTORY 0 | |
24 #endif | |
25 | |
26 #ifndef O_LARGEFILE | |
27 # define O_LARGEFILE 0 | |
28 #endif | |
29 | |
30 /* | |
31 * Work around glibc's broken <bits/fcntl.h> which defines | |
32 * O_LARGEFILE to 0 on 64 bit architectures. But, on those same | |
33 * architectures, linux _forces_ O_LARGEFILE (which is always | |
34 * 0100000 in the kernel) at each file open. FUSE is all too | |
35 * happy to pass the flag onto us, where we'd have no idea what | |
36 * to do with it if we trusted glibc. | |
37 * | |
38 * On ARM however, the O_LARGEFILE is set correctly. | |
39 */ | |
40 | |
41 #if defined(__linux__) && !defined(__arm__) | |
42 # undef O_LARGEFILE | |
43 # define O_LARGEFILE 0100000 | |
44 #endif | |
45 | |
46 #ifndef O_CLOEXEC | |
47 # if defined(__linux__) | |
48 # define O_CLOEXEC 02000000 /* Sigh */ | |
49 # else | |
50 # define O_CLOEXEC 0 | |
51 # endif | |
52 #endif | |
53 | |
54 #ifndef FMODE_EXEC | |
55 # if defined(__linux__) | |
56 # define FMODE_EXEC 040 | |
57 # else | |
58 # define FMODE_EXEC 0 | |
59 # endif | |
60 #endif | |
61 | |
62 int debug; | |
63 char *argv0; | |
64 char *aname = ""; | |
65 void fusedispatch(void*); | |
66 Channel *fusechan; | |
67 | |
68 enum | |
69 { | |
70 STACK = 8192 | |
71 }; | |
72 | |
73 /* | |
74 * The number of seconds that the kernel can cache | |
75 * returned file attributes. FUSE's default is 1.0. | |
76 * I haven't experimented with using 0. | |
77 */ | |
78 double attrtimeout = 1.0; | |
79 | |
80 /* | |
81 * The number of seconds that the kernel can cache | |
82 * the returned entry nodeids returned by lookup. | |
83 * I haven't experimented with other values. | |
84 */ | |
85 double entrytimeout = 1.0; | |
86 | |
87 CFsys *fsys; | |
88 CFid *fsysroot; | |
89 void init9p(char*, char*); | |
90 | |
91 void | |
92 usage(void) | |
93 { | |
94 fprint(2, "usage: 9pfuse [-D] [-A attrtimeout] [-a aname] addres… | |
95 exit(1); | |
96 } | |
97 | |
98 void fusereader(void*); | |
99 void watchfd(void*); | |
100 | |
101 int | |
102 threadmaybackground(void) | |
103 { | |
104 return 1; | |
105 } | |
106 | |
107 void | |
108 threadmain(int argc, char **argv) | |
109 { | |
110 ARGBEGIN{ | |
111 case 'D': | |
112 chatty9pclient++; | |
113 debug++; | |
114 break; | |
115 case 'A': | |
116 attrtimeout = atof(EARGF(usage())); | |
117 break; | |
118 case 'a': | |
119 aname = EARGF(usage()); | |
120 break; | |
121 default: | |
122 usage(); | |
123 }ARGEND | |
124 | |
125 if(argc != 2) | |
126 usage(); | |
127 | |
128 quotefmtinstall(); | |
129 fmtinstall('F', fcallfmt); | |
130 fmtinstall('M', dirmodefmt); | |
131 fmtinstall('G', fusefmt); | |
132 | |
133 setsid(); /* won't be able to use console, but can't be i… | |
134 | |
135 init9p(argv[0], aname); | |
136 initfuse(argv[1]); | |
137 | |
138 fusechan = chancreate(sizeof(void*), 0); | |
139 proccreate(fusedispatch, nil, STACK); | |
140 sendp(fusechan, nil); /* sync */ | |
141 | |
142 proccreate(fusereader, nil, STACK); | |
143 /* | |
144 * Now that we're serving FUSE, we can wait | |
145 * for the mount to finish and exit back to the user. | |
146 */ | |
147 waitfuse(); | |
148 threadexits(0); | |
149 } | |
150 | |
151 void | |
152 fusereader(void *v) | |
153 { | |
154 FuseMsg *m; | |
155 | |
156 while((m = readfusemsg()) != nil) | |
157 sendp(fusechan, m); | |
158 | |
159 fusemtpt = nil; /* no need to unmount */ | |
160 threadexitsall(0); | |
161 } | |
162 | |
163 void | |
164 init9p(char *addr, char *spec) | |
165 { | |
166 int fd; | |
167 | |
168 if(strcmp(addr, "-") == 0) | |
169 fd = 0; | |
170 else | |
171 if((fd = dial(netmkaddr(addr, "tcp", "564"), nil, nil, n… | |
172 sysfatal("dial %s: %r", addr); | |
173 proccreate(watchfd, (void*)(uintptr)fd, STACK); | |
174 if((fsys = fsmount(fd, spec)) == nil) | |
175 sysfatal("fsmount: %r"); | |
176 fsysroot = fsroot(fsys); | |
177 } | |
178 | |
179 /* | |
180 * FUSE uses nodeids to refer to active "struct inodes" | |
181 * (9P's unopened fids). FUSE uses fhs to refer to active | |
182 * "struct fuse_files" (9P's opened fids). The choice of | |
183 * numbers is up to us except that nodeid 1 is the root directory. | |
184 * We use the same number space for both and call the | |
185 * bookkeeping structure a FuseFid. | |
186 * | |
187 * FUSE requires nodeids to have associated generation | |
188 * numbers. If we reuse a nodeid, we have to bump the | |
189 * generation number to guarantee that the nodeid,gen | |
190 * combination is never reused. | |
191 * | |
192 * There are also inode numbers returned in directory reads | |
193 * and file attributes, but these do NOT need to match the nodeids. | |
194 * We use a combination of qid.path and qid.type as the inode | |
195 * number. | |
196 */ | |
197 /* | |
198 * TO DO: reference count the fids. | |
199 */ | |
200 typedef struct Fusefid Fusefid; | |
201 struct Fusefid | |
202 { | |
203 Fusefid *next; | |
204 CFid *fid; | |
205 int ref; | |
206 int id; | |
207 int gen; | |
208 int isnodeid; | |
209 | |
210 /* directory read state */ | |
211 Dir *d0; | |
212 Dir *d; | |
213 int nd; | |
214 int off; | |
215 }; | |
216 | |
217 Fusefid **fusefid; | |
218 int nfusefid; | |
219 Fusefid *freefusefidlist; | |
220 | |
221 Fusefid* | |
222 allocfusefid(void) | |
223 { | |
224 Fusefid *f; | |
225 | |
226 if((f = freefusefidlist) == nil){ | |
227 f = emalloc(sizeof *f); | |
228 fusefid = erealloc(fusefid, (nfusefid+1)*sizeof *fusefid… | |
229 f->id = nfusefid; | |
230 fusefid[f->id] = f; | |
231 nfusefid++; | |
232 }else | |
233 freefusefidlist = f->next; | |
234 f->next = nil; | |
235 f->ref = 1; | |
236 f->isnodeid = -1; | |
237 return f; | |
238 } | |
239 | |
240 void | |
241 freefusefid(Fusefid *f) | |
242 { | |
243 if(--f->ref > 0) | |
244 return; | |
245 assert(f->ref == 0); | |
246 if(f->fid) | |
247 fsclose(f->fid); | |
248 if(f->d0) | |
249 free(f->d0); | |
250 f->off = 0; | |
251 f->d0 = nil; | |
252 f->fid = nil; | |
253 f->d = nil; | |
254 f->nd = 0; | |
255 f->next = freefusefidlist; | |
256 f->isnodeid = -1; | |
257 freefusefidlist = f; | |
258 } | |
259 | |
260 uvlong | |
261 _alloc(CFid *fid, int isnodeid) | |
262 { | |
263 Fusefid *ff; | |
264 | |
265 ff = allocfusefid(); | |
266 ff->fid = fid; | |
267 ff->isnodeid = isnodeid; | |
268 ff->gen++; | |
269 return ff->id+2; /* skip 0 and 1 */ | |
270 } | |
271 | |
272 uvlong | |
273 allocfh(CFid *fid) | |
274 { | |
275 return _alloc(fid, 0); | |
276 } | |
277 | |
278 uvlong | |
279 allocnodeid(CFid *fid) | |
280 { | |
281 return _alloc(fid, 1); | |
282 } | |
283 | |
284 Fusefid* | |
285 lookupfusefid(uvlong id, int isnodeid) | |
286 { | |
287 Fusefid *ff; | |
288 if(id < 2 || id >= nfusefid+2) | |
289 return nil; | |
290 ff = fusefid[(int)id-2]; | |
291 if(ff->isnodeid != isnodeid) | |
292 return nil; | |
293 return ff; | |
294 } | |
295 | |
296 CFid* | |
297 _lookupcfid(uvlong id, int isnodeid) | |
298 { | |
299 Fusefid *ff; | |
300 | |
301 if((ff = lookupfusefid(id, isnodeid)) == nil) | |
302 return nil; | |
303 return ff->fid; | |
304 } | |
305 | |
306 CFid* | |
307 fh2fid(uvlong fh) | |
308 { | |
309 return _lookupcfid(fh, 0); | |
310 } | |
311 | |
312 CFid* | |
313 nodeid2fid(uvlong nodeid) | |
314 { | |
315 if(nodeid == 1) | |
316 return fsysroot; | |
317 return _lookupcfid(nodeid, 1); | |
318 } | |
319 | |
320 uvlong | |
321 qid2inode(Qid q) | |
322 { | |
323 return q.path | ((uvlong)q.type<<56); | |
324 } | |
325 | |
326 void | |
327 dir2attr(Dir *d, struct fuse_attr *attr) | |
328 { | |
329 attr->ino = qid2inode(d->qid); | |
330 attr->size = d->length; | |
331 attr->blocks = (d->length+8191)/8192; | |
332 attr->atime = d->atime; | |
333 attr->mtime = d->mtime; | |
334 attr->ctime = d->mtime; /* not right */ | |
335 attr->atimensec = 0; | |
336 attr->mtimensec = 0; | |
337 attr->ctimensec = 0; | |
338 attr->mode = d->mode&0777; | |
339 if(d->mode&DMDIR) | |
340 attr->mode |= S_IFDIR; | |
341 else if(d->mode&DMSYMLINK) | |
342 attr->mode |= S_IFLNK; | |
343 else | |
344 attr->mode |= S_IFREG; | |
345 attr->nlink = 1; /* works for directories! - see FUSE FAQ… | |
346 attr->uid = getuid(); | |
347 attr->gid = getgid(); | |
348 attr->rdev = 0; | |
349 } | |
350 | |
351 void | |
352 f2timeout(double f, __u64 *s, __u32 *ns) | |
353 { | |
354 *s = f; | |
355 *ns = (f - (int)f)*1e9; | |
356 } | |
357 | |
358 void | |
359 dir2attrout(Dir *d, struct fuse_attr_out *out) | |
360 { | |
361 f2timeout(attrtimeout, &out->attr_valid, &out->attr_valid_nsec); | |
362 dir2attr(d, &out->attr); | |
363 } | |
364 | |
365 /* | |
366 * Lookup. Walk to the name given as the argument. | |
367 * The response is a fuse_entry_out giving full stat info. | |
368 */ | |
369 void | |
370 fuselookup(FuseMsg *m) | |
371 { | |
372 char *name; | |
373 Fusefid *ff; | |
374 CFid *fid, *newfid; | |
375 Dir *d; | |
376 struct fuse_entry_out out; | |
377 | |
378 name = m->tx; | |
379 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){ | |
380 replyfuseerrno(m, ESTALE); | |
381 return; | |
382 } | |
383 if(strchr(name, '/')){ | |
384 replyfuseerrno(m, ENOENT); | |
385 return; | |
386 } | |
387 if((newfid = fswalk(fid, name)) == nil){ | |
388 replyfuseerrstr(m); | |
389 return; | |
390 } | |
391 if((d = fsdirfstat(newfid)) == nil){ | |
392 fsclose(newfid); | |
393 replyfuseerrstr(m); | |
394 return; | |
395 } | |
396 out.nodeid = allocnodeid(newfid); | |
397 ff = lookupfusefid(out.nodeid, 1); | |
398 out.generation = ff->gen; | |
399 f2timeout(attrtimeout, &out.attr_valid, &out.attr_valid_nsec); | |
400 f2timeout(entrytimeout, &out.entry_valid, &out.entry_valid_nsec); | |
401 dir2attr(d, &out.attr); | |
402 free(d); | |
403 replyfuse(m, &out, sizeof out); | |
404 } | |
405 | |
406 /* | |
407 * Forget. Reference-counted clunk for nodeids. | |
408 * Does not send a reply. | |
409 * Each lookup response gives the kernel an additional reference | |
410 * to the returned nodeid. Forget says "drop this many references | |
411 * to this nodeid". Our fuselookup, when presented with the same query, | |
412 * does not return the same results (it allocates a new nodeid for each | |
413 * call), but if that ever changes, fuseforget already handles the ref | |
414 * counts properly. | |
415 */ | |
416 void | |
417 fuseforget(FuseMsg *m) | |
418 { | |
419 struct fuse_forget_in *in; | |
420 Fusefid *ff; | |
421 | |
422 in = m->tx; | |
423 if((ff = lookupfusefid(m->hdr->nodeid, 1)) == nil) | |
424 return; | |
425 if(ff->ref > in->nlookup){ | |
426 ff->ref -= in->nlookup; | |
427 return; | |
428 } | |
429 if(ff->ref < in->nlookup) | |
430 fprint(2, "bad count in forget\n"); | |
431 ff->ref = 1; | |
432 freefusefid(ff); | |
433 freefusemsg(m); | |
434 } | |
435 | |
436 /* | |
437 * Getattr. | |
438 * Replies with a fuse_attr_out structure giving the | |
439 * attr for the requested nodeid in out.attr. | |
440 * Out.attr_valid and out.attr_valid_nsec give | |
441 * the amount of time that the attributes can | |
442 * be cached. | |
443 * | |
444 * Empirically, though, if I run ls -ld on the root | |
445 * twice back to back, I still get two getattrs, | |
446 * even with a one second attribute timeout! | |
447 */ | |
448 void | |
449 fusegetattr(FuseMsg *m) | |
450 { | |
451 CFid *fid; | |
452 struct fuse_attr_out out; | |
453 Dir *d; | |
454 | |
455 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){ | |
456 replyfuseerrno(m, ESTALE); | |
457 return; | |
458 } | |
459 if((d = fsdirfstat(fid)) == nil){ | |
460 replyfuseerrstr(m); | |
461 return; | |
462 } | |
463 memset(&out, 0, sizeof out); | |
464 dir2attrout(d, &out); | |
465 free(d); | |
466 replyfuse(m, &out, sizeof out); | |
467 } | |
468 | |
469 /* | |
470 * Setattr. | |
471 * FUSE treats the many Unix attribute setting routines | |
472 * more or less like 9P does, with a single message. | |
473 */ | |
474 void | |
475 fusesetattr(FuseMsg *m) | |
476 { | |
477 CFid *fid, *nfid; | |
478 Dir d, *dd; | |
479 struct fuse_setattr_in *in; | |
480 struct fuse_attr_out out; | |
481 | |
482 in = m->tx; | |
483 if(in->valid&FATTR_FH){ | |
484 if((fid = fh2fid(in->fh)) == nil){ | |
485 replyfuseerrno(m, ESTALE); | |
486 return; | |
487 } | |
488 }else{ | |
489 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){ | |
490 replyfuseerrno(m, ESTALE); | |
491 return; | |
492 } | |
493 /* | |
494 * Special case: Linux issues a size change to | |
495 * truncate a file before opening it OTRUNC. | |
496 * Synthetic file servers (e.g., plumber) honor | |
497 * open(OTRUNC) but not wstat. | |
498 */ | |
499 if(in->valid == FATTR_SIZE && in->size == 0){ | |
500 if((nfid = fswalk(fid, nil)) == nil){ | |
501 replyfuseerrstr(m); | |
502 return; | |
503 } | |
504 if(fsfopen(nfid, OWRITE|OTRUNC) < 0){ | |
505 replyfuseerrstr(m); | |
506 fsclose(nfid); | |
507 return; | |
508 } | |
509 fsclose(nfid); | |
510 goto stat; | |
511 } | |
512 } | |
513 | |
514 nulldir(&d); | |
515 if(in->valid&FATTR_SIZE) | |
516 d.length = in->size; | |
517 if(in->valid&FATTR_ATIME) | |
518 d.atime = in->atime; | |
519 if(in->valid&FATTR_MTIME) | |
520 d.mtime = in->mtime; | |
521 if(in->valid&FATTR_MODE) | |
522 d.mode = in->mode & 0777; | |
523 if((in->mode&S_IFMT) == S_IFDIR) | |
524 d.mode |= DMDIR; | |
525 if((in->valid&FATTR_UID) || (in->valid&FATTR_GID)){ | |
526 /* | |
527 * I can't be bothered with these yet. | |
528 */ | |
529 replyfuseerrno(m, EPERM); | |
530 return; | |
531 } | |
532 if(fsdirfwstat(fid, &d) < 0){ | |
533 replyfuseerrstr(m); | |
534 return; | |
535 } | |
536 stat: | |
537 if((dd = fsdirfstat(fid)) == nil){ | |
538 replyfuseerrstr(m); | |
539 return; | |
540 } | |
541 memset(&out, 0, sizeof out); | |
542 dir2attrout(dd, &out); | |
543 free(dd); | |
544 replyfuse(m, &out, sizeof out); | |
545 } | |
546 | |
547 CFid* | |
548 _fuseopenfid(uvlong nodeid, int isdir, int openmode, int *err) | |
549 { | |
550 CFid *fid, *newfid; | |
551 | |
552 if((fid = nodeid2fid(nodeid)) == nil){ | |
553 *err = ESTALE; | |
554 return nil; | |
555 } | |
556 if(isdir && !(fsqid(fid).type&QTDIR)){ | |
557 *err = ENOTDIR; | |
558 return nil; | |
559 } | |
560 if(openmode != OREAD && fsqid(fid).type&QTDIR){ | |
561 *err = EISDIR; | |
562 return nil; | |
563 } | |
564 | |
565 /* Clone fid to get one we can open. */ | |
566 newfid = fswalk(fid, nil); | |
567 if(newfid == nil){ | |
568 *err = errstr2errno(); | |
569 return nil; | |
570 } | |
571 | |
572 if(fsfopen(newfid, openmode) < 0){ | |
573 *err = errstr2errno(); | |
574 fsclose(newfid); | |
575 return nil; | |
576 } | |
577 | |
578 return newfid; | |
579 } | |
580 | |
581 /* | |
582 * Open & Opendir. | |
583 * Argument is a struct fuse_open_in. | |
584 * The mode field is ignored (presumably permission bits) | |
585 * and flags is the open mode. | |
586 * Replies with a struct fuse_open_out. | |
587 */ | |
588 void | |
589 _fuseopen(FuseMsg *m, int isdir) | |
590 { | |
591 struct fuse_open_in *in; | |
592 struct fuse_open_out out; | |
593 CFid *fid; | |
594 int openmode, flags, err; | |
595 | |
596 in = m->tx; | |
597 flags = in->flags; | |
598 openmode = flags&3; | |
599 flags &= ~3; | |
600 flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC|FMODE_EX… | |
601 #ifdef O_NOFOLLOW | |
602 flags &= ~O_NOFOLLOW; | |
603 #endif | |
604 #ifdef O_LARGEFILE | |
605 flags &= ~O_LARGEFILE; | |
606 #endif | |
607 | |
608 /* | |
609 * Discarding O_APPEND here is not completely wrong, | |
610 * because the host kernel will rewrite the offsets | |
611 * of write system calls for us. That's the best we | |
612 * can do on Unix anyway. | |
613 */ | |
614 flags &= ~O_APPEND; | |
615 if(flags & O_TRUNC){ | |
616 openmode |= OTRUNC; | |
617 flags &= ~O_TRUNC; | |
618 } | |
619 | |
620 /* | |
621 * Could translate but not standard 9P: | |
622 * O_DIRECT -> ODIRECT | |
623 * O_NONBLOCK -> ONONBLOCK | |
624 */ | |
625 if(flags){ | |
626 fprint(2, "unexpected open flags requested=%#uo unhandle… | |
627 replyfuseerrno(m, EACCES); | |
628 return; | |
629 } | |
630 if((fid = _fuseopenfid(m->hdr->nodeid, isdir, openmode, &err)) =… | |
631 replyfuseerrno(m, err); | |
632 return; | |
633 } | |
634 out.fh = allocfh(fid); | |
635 out.open_flags = FOPEN_DIRECT_IO; /* no page cache */ | |
636 replyfuse(m, &out, sizeof out); | |
637 } | |
638 | |
639 void | |
640 fuseopen(FuseMsg *m) | |
641 { | |
642 _fuseopen(m, 0); | |
643 } | |
644 | |
645 void | |
646 fuseopendir(FuseMsg *m) | |
647 { | |
648 _fuseopen(m, 1); | |
649 } | |
650 | |
651 /* | |
652 * Create & Mkdir. | |
653 */ | |
654 CFid* | |
655 _fusecreate(uvlong nodeid, char *name, int perm, int ismkdir, int omode,… | |
656 { | |
657 CFid *fid, *newfid, *newfid2; | |
658 Dir *d; | |
659 Fusefid *ff; | |
660 | |
661 if((fid = nodeid2fid(nodeid)) == nil){ | |
662 *err = ESTALE; | |
663 return nil; | |
664 } | |
665 perm &= 0777; | |
666 if(ismkdir) | |
667 perm |= DMDIR; | |
668 if(ismkdir && omode != OREAD){ | |
669 *err = EPERM; | |
670 return nil; | |
671 } | |
672 if((newfid = fswalk(fid, nil)) == nil){ | |
673 *err = errstr2errno(); | |
674 return nil; | |
675 } | |
676 if(fsfcreate(newfid, name, omode, perm) < 0){ | |
677 *err = errstr2errno(); | |
678 fsclose(newfid); | |
679 return nil; | |
680 } | |
681 if((d = fsdirfstat(newfid)) == nil){ | |
682 *err = errstr2errno(); | |
683 fsfremove(newfid); | |
684 return nil; | |
685 } | |
686 /* | |
687 * This fid is no good, because it's open. | |
688 * We need an unopened fid. Sigh. | |
689 */ | |
690 if((newfid2 = fswalk(fid, name)) == nil){ | |
691 *err = errstr2errno(); | |
692 free(d); | |
693 fsfremove(newfid); | |
694 return nil; | |
695 } | |
696 out->nodeid = allocnodeid(newfid2); | |
697 ff = lookupfusefid(out->nodeid, 1); | |
698 out->generation = ff->gen; | |
699 f2timeout(attrtimeout, &out->attr_valid, &out->attr_valid_nsec); | |
700 f2timeout(entrytimeout, &out->entry_valid, &out->entry_valid_nse… | |
701 dir2attr(d, &out->attr); | |
702 free(d); | |
703 return newfid; | |
704 } | |
705 | |
706 void | |
707 fusemkdir(FuseMsg *m) | |
708 { | |
709 struct fuse_mkdir_in *in; | |
710 struct fuse_entry_out out; | |
711 CFid *fid; | |
712 int err; | |
713 char *name; | |
714 | |
715 in = m->tx; | |
716 name = (char*)(in+1); | |
717 if((fid = _fusecreate(m->hdr->nodeid, name, in->mode, 1, OREAD, … | |
718 replyfuseerrno(m, err); | |
719 return; | |
720 } | |
721 /* Toss the open fid. */ | |
722 fsclose(fid); | |
723 replyfuse(m, &out, sizeof out); | |
724 } | |
725 | |
726 void | |
727 fusecreate(FuseMsg *m) | |
728 { | |
729 struct fuse_open_in *in; | |
730 struct fuse_create_out out; | |
731 CFid *fid; | |
732 int err, openmode, flags; | |
733 char *name; | |
734 | |
735 in = m->tx; | |
736 flags = in->flags; | |
737 openmode = in->flags&3; | |
738 flags &= ~3; | |
739 flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE|O_EXCL); | |
740 flags &= ~O_APPEND; /* see comment in _fuseopen */ | |
741 flags &= ~(O_CREAT|O_TRUNC); /* huh? */ | |
742 if(flags){ | |
743 fprint(2, "bad mode %#uo\n", in->flags); | |
744 replyfuseerrno(m, EACCES); | |
745 return; | |
746 } | |
747 name = (char*)(in+1); | |
748 if((fid = _fusecreate(m->hdr->nodeid, name, in->mode, 0, openmod… | |
749 replyfuseerrno(m, err); | |
750 return; | |
751 } | |
752 out.o.fh = allocfh(fid); | |
753 out.o.open_flags = FOPEN_DIRECT_IO; /* no page cache */ | |
754 replyfuse(m, &out, sizeof out); | |
755 } | |
756 | |
757 /* | |
758 * Access. | |
759 * Lib9pclient implements this just as Plan 9 does, | |
760 * by opening the file (or not) and then closing it. | |
761 */ | |
762 void | |
763 fuseaccess(FuseMsg *m) | |
764 { | |
765 struct fuse_access_in *in; | |
766 CFid *fid; | |
767 int err, omode; | |
768 static int a2o[] = { | |
769 0, | |
770 OEXEC, | |
771 OWRITE, | |
772 ORDWR, | |
773 OREAD, | |
774 OEXEC, | |
775 ORDWR, | |
776 ORDWR | |
777 }; | |
778 | |
779 in = m->tx; | |
780 if(in->mask >= nelem(a2o)){ | |
781 replyfuseerrno(m, EINVAL); | |
782 return; | |
783 } | |
784 omode = a2o[in->mask]; | |
785 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){ | |
786 replyfuseerrno(m, ESTALE); | |
787 return; | |
788 } | |
789 if(fsqid(fid).type&QTDIR) | |
790 omode = OREAD; | |
791 if((fid = _fuseopenfid(m->hdr->nodeid, 0, omode, &err)) == nil){ | |
792 replyfuseerrno(m, err); | |
793 return; | |
794 } | |
795 fsclose(fid); | |
796 replyfuse(m, nil, 0); | |
797 } | |
798 | |
799 /* | |
800 * Release. | |
801 * Equivalent of clunk for file handles. | |
802 * in->flags is the open mode used in Open or Opendir. | |
803 */ | |
804 void | |
805 fuserelease(FuseMsg *m) | |
806 { | |
807 struct fuse_release_in *in; | |
808 Fusefid *ff; | |
809 | |
810 in = m->tx; | |
811 if((ff = lookupfusefid(in->fh, 0)) != nil) | |
812 freefusefid(ff); | |
813 else | |
814 fprint(2, "fuserelease: fh not found\n"); | |
815 replyfuse(m, nil, 0); | |
816 } | |
817 | |
818 void | |
819 fusereleasedir(FuseMsg *m) | |
820 { | |
821 fuserelease(m); | |
822 } | |
823 | |
824 /* | |
825 * Read. | |
826 * Read from file handle in->fh at offset in->offset for size in->size. | |
827 * We truncate size to maxwrite just to keep the buffer reasonable. | |
828 */ | |
829 void | |
830 fuseread(FuseMsg *m) | |
831 { | |
832 int n; | |
833 uchar *buf; | |
834 CFid *fid; | |
835 struct fuse_read_in *in; | |
836 | |
837 in = m->tx; | |
838 if((fid = fh2fid(in->fh)) == nil){ | |
839 replyfuseerrno(m, ESTALE); | |
840 return; | |
841 } | |
842 n = in->size; | |
843 if(n > fusemaxwrite) | |
844 n = fusemaxwrite; | |
845 buf = emalloc(n); | |
846 n = fspread(fid, buf, n, in->offset); | |
847 if(n < 0){ | |
848 free(buf); | |
849 replyfuseerrstr(m); | |
850 return; | |
851 } | |
852 replyfuse(m, buf, n); | |
853 free(buf); | |
854 } | |
855 | |
856 /* | |
857 * Readlink. | |
858 */ | |
859 void | |
860 fusereadlink(FuseMsg *m) | |
861 { | |
862 Dir *d; | |
863 CFid *fid; | |
864 | |
865 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){ | |
866 replyfuseerrno(m, ESTALE); | |
867 return; | |
868 } | |
869 if((d = fsdirfstat(fid)) == nil){ | |
870 replyfuseerrstr(m); | |
871 return; | |
872 } | |
873 if(!(d->mode&DMSYMLINK)){ | |
874 replyfuseerrno(m, EINVAL); | |
875 return; | |
876 } | |
877 replyfuse(m, d->ext, strlen(d->ext)); | |
878 free(d); | |
879 return; | |
880 } | |
881 | |
882 /* | |
883 * Readdir. | |
884 * Read from file handle in->fh at offset in->offset for size in->size. | |
885 * We truncate size to maxwrite just to keep the buffer reasonable. | |
886 * We assume 9P directory read semantics: a read at offset 0 rewinds | |
887 * and a read at any other offset starts where we left off. | |
888 * If it became necessary, we could implement a crude seek | |
889 * or cache the entire list of directory entries. | |
890 * Directory entries read from 9P but not yet handed to FUSE | |
891 * are stored in m->d,nd,d0. | |
892 */ | |
893 int canpack(Dir*, uvlong, uchar**, uchar*); | |
894 Dir *dotdir(CFid*); | |
895 void | |
896 fusereaddir(FuseMsg *m) | |
897 { | |
898 struct fuse_read_in *in; | |
899 uchar *buf, *p, *ep; | |
900 int n; | |
901 Fusefid *ff; | |
902 | |
903 in = m->tx; | |
904 if((ff = lookupfusefid(in->fh, 0)) == nil){ | |
905 replyfuseerrno(m, ESTALE); | |
906 return; | |
907 } | |
908 if(in->offset == 0){ | |
909 fsseek(ff->fid, 0, 0); | |
910 free(ff->d0); | |
911 ff->d0 = ff->d = dotdir(ff->fid); | |
912 ff->nd = 1; | |
913 } | |
914 n = in->size; | |
915 if(n > fusemaxwrite) | |
916 n = fusemaxwrite; | |
917 buf = emalloc(n); | |
918 p = buf; | |
919 ep = buf + n; | |
920 for(;;){ | |
921 while(ff->nd > 0){ | |
922 if(!canpack(ff->d, ff->off, &p, ep)) | |
923 goto out; | |
924 ff->off++; | |
925 ff->d++; | |
926 ff->nd--; | |
927 } | |
928 free(ff->d0); | |
929 ff->d0 = nil; | |
930 ff->d = nil; | |
931 if((ff->nd = fsdirread(ff->fid, &ff->d0)) < 0){ | |
932 replyfuseerrstr(m); | |
933 free(buf); | |
934 return; | |
935 } | |
936 if(ff->nd == 0) | |
937 break; | |
938 ff->d = ff->d0; | |
939 } | |
940 out: | |
941 replyfuse(m, buf, p - buf); | |
942 free(buf); | |
943 } | |
944 | |
945 /* | |
946 * Fuse assumes that it can always read two directory entries. | |
947 * If it gets just one, it will double it in the dirread results. | |
948 * Thus if a directory contains just "a", you see "a" twice. | |
949 * Adding . as the first directory entry works around this. | |
950 * We could add .. too, but it isn't necessary. | |
951 */ | |
952 Dir* | |
953 dotdir(CFid *f) | |
954 { | |
955 Dir *d; | |
956 | |
957 d = emalloc(1*sizeof *d); | |
958 d[0].name = "."; | |
959 d[0].qid = fsqid(f); | |
960 return d; | |
961 } | |
962 | |
963 int | |
964 canpack(Dir *d, uvlong off, uchar **pp, uchar *ep) | |
965 { | |
966 uchar *p; | |
967 struct fuse_dirent *de; | |
968 int pad, size; | |
969 | |
970 p = *pp; | |
971 size = FUSE_NAME_OFFSET + strlen(d->name); | |
972 pad = 0; | |
973 if(size%8) | |
974 pad = 8 - size%8; | |
975 if(size+pad > ep - p) | |
976 return 0; | |
977 de = (struct fuse_dirent*)p; | |
978 de->ino = qid2inode(d->qid); | |
979 de->off = off; | |
980 de->namelen = strlen(d->name); | |
981 memmove(de->name, d->name, de->namelen); | |
982 if(pad > 0) | |
983 memset(de->name+de->namelen, 0, pad); | |
984 *pp = p+size+pad; | |
985 return 1; | |
986 } | |
987 | |
988 /* | |
989 * Write. | |
990 * Write from file handle in->fh at offset in->offset for size in->size. | |
991 * Don't know what in->write_flags means. | |
992 * | |
993 * Apparently implementations are allowed to buffer these writes | |
994 * and wait until Flush is sent, but FUSE docs say flush may be | |
995 * called zero, one, or even more times per close. So better do the | |
996 * actual writing here. Also, errors that happen during Flush just | |
997 * show up in the close() return status, which no one checks anyway. | |
998 */ | |
999 void | |
1000 fusewrite(FuseMsg *m) | |
1001 { | |
1002 struct fuse_write_in *in; | |
1003 struct fuse_write_out out; | |
1004 void *a; | |
1005 CFid *fid; | |
1006 int n; | |
1007 | |
1008 in = m->tx; | |
1009 a = in+1; | |
1010 if((fid = fh2fid(in->fh)) == nil){ | |
1011 replyfuseerrno(m, ESTALE); | |
1012 return; | |
1013 } | |
1014 if(in->size > fusemaxwrite){ | |
1015 replyfuseerrno(m, EINVAL); | |
1016 return; | |
1017 } | |
1018 n = fspwrite(fid, a, in->size, in->offset); | |
1019 if(n < 0){ | |
1020 replyfuseerrstr(m); | |
1021 return; | |
1022 } | |
1023 out.size = n; | |
1024 replyfuse(m, &out, sizeof out); | |
1025 } | |
1026 | |
1027 /* | |
1028 * Flush. Supposed to flush any buffered writes. Don't use this. | |
1029 * | |
1030 * Flush is a total crock. It gets called on close() of a file descript… | |
1031 * associated with this open file. Some open files have multiple file | |
1032 * descriptors and thus multiple closes of those file descriptors. | |
1033 * In those cases, Flush is called multiple times. Some open files | |
1034 * have file descriptors that are closed on process exit instead of | |
1035 * closed explicitly. For those files, Flush is never called. | |
1036 * Even more amusing, Flush gets called before close() of read-only | |
1037 * file descriptors too! | |
1038 * | |
1039 * This is just a bad idea. | |
1040 */ | |
1041 void | |
1042 fuseflush(FuseMsg *m) | |
1043 { | |
1044 replyfuse(m, nil, 0); | |
1045 } | |
1046 | |
1047 /* | |
1048 * Unlink & Rmdir. | |
1049 */ | |
1050 void | |
1051 _fuseremove(FuseMsg *m, int isdir) | |
1052 { | |
1053 char *name; | |
1054 CFid *fid, *newfid; | |
1055 | |
1056 name = m->tx; | |
1057 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){ | |
1058 replyfuseerrno(m, ESTALE); | |
1059 return; | |
1060 } | |
1061 if(strchr(name, '/')){ | |
1062 replyfuseerrno(m, ENOENT); | |
1063 return; | |
1064 } | |
1065 if((newfid = fswalk(fid, name)) == nil){ | |
1066 replyfuseerrstr(m); | |
1067 return; | |
1068 } | |
1069 if(isdir && !(fsqid(newfid).type&QTDIR)){ | |
1070 replyfuseerrno(m, ENOTDIR); | |
1071 fsclose(newfid); | |
1072 return; | |
1073 } | |
1074 if(!isdir && (fsqid(newfid).type&QTDIR)){ | |
1075 replyfuseerrno(m, EISDIR); | |
1076 fsclose(newfid); | |
1077 return; | |
1078 } | |
1079 if(fsfremove(newfid) < 0){ | |
1080 replyfuseerrstr(m); | |
1081 return; | |
1082 } | |
1083 replyfuse(m, nil, 0); | |
1084 } | |
1085 | |
1086 void | |
1087 fuseunlink(FuseMsg *m) | |
1088 { | |
1089 _fuseremove(m, 0); | |
1090 } | |
1091 | |
1092 void | |
1093 fusermdir(FuseMsg *m) | |
1094 { | |
1095 _fuseremove(m, 1); | |
1096 } | |
1097 | |
1098 /* | |
1099 * Rename. | |
1100 * | |
1101 * FUSE sends the nodeid for the source and destination | |
1102 * directory and then the before and after names as strings. | |
1103 * 9P can only do the rename if the source and destination | |
1104 * are the same. If the same nodeid is used for source and | |
1105 * destination, we're fine, but if FUSE gives us different nodeids | |
1106 * that happen to correspond to the same directory, we have | |
1107 * no way of figuring that out. Let's hope it doesn't happen too often. | |
1108 */ | |
1109 void | |
1110 fuserename(FuseMsg *m) | |
1111 { | |
1112 struct fuse_rename_in *in; | |
1113 char *before, *after; | |
1114 CFid *fid, *newfid; | |
1115 Dir d; | |
1116 | |
1117 in = m->tx; | |
1118 if(in->newdir != m->hdr->nodeid){ | |
1119 replyfuseerrno(m, EXDEV); | |
1120 return; | |
1121 } | |
1122 before = (char*)(in+1); | |
1123 after = before + strlen(before) + 1; | |
1124 if((fid = nodeid2fid(m->hdr->nodeid)) == nil){ | |
1125 replyfuseerrno(m, ESTALE); | |
1126 return; | |
1127 } | |
1128 if(strchr(before, '/') || strchr(after, '/')){ | |
1129 replyfuseerrno(m, ENOENT); | |
1130 return; | |
1131 } | |
1132 if((newfid = fswalk(fid, before)) == nil){ | |
1133 replyfuseerrstr(m); | |
1134 return; | |
1135 } | |
1136 nulldir(&d); | |
1137 d.name = after; | |
1138 if(fsdirfwstat(newfid, &d) < 0){ | |
1139 replyfuseerrstr(m); | |
1140 fsclose(newfid); | |
1141 return; | |
1142 } | |
1143 fsclose(newfid); | |
1144 replyfuse(m, nil, 0); | |
1145 } | |
1146 | |
1147 /* | |
1148 * Fsync. Commit file info to stable storage. | |
1149 * Not sure what in->fsync_flags are. | |
1150 */ | |
1151 void | |
1152 fusefsync(FuseMsg *m) | |
1153 { | |
1154 struct fuse_fsync_in *in; | |
1155 CFid *fid; | |
1156 Dir d; | |
1157 | |
1158 in = m->tx; | |
1159 if((fid = fh2fid(in->fh)) == nil){ | |
1160 replyfuseerrno(m, ESTALE); | |
1161 return; | |
1162 } | |
1163 nulldir(&d); | |
1164 if(fsdirfwstat(fid, &d) < 0){ | |
1165 replyfuseerrstr(m); | |
1166 return; | |
1167 } | |
1168 replyfuse(m, nil, 0); | |
1169 } | |
1170 | |
1171 /* | |
1172 * Fsyncdir. Commit dir info to stable storage? | |
1173 */ | |
1174 void | |
1175 fusefsyncdir(FuseMsg *m) | |
1176 { | |
1177 fusefsync(m); | |
1178 } | |
1179 | |
1180 /* | |
1181 * Statfs. Send back information about file system. | |
1182 * Not really worth implementing, except that if we | |
1183 * reply with ENOSYS, programs like df print messages like | |
1184 * df: `/tmp/z': Function not implemented | |
1185 * and that gets annoying. Returning all zeros excludes | |
1186 * us from df without appearing to cause any problems. | |
1187 */ | |
1188 void | |
1189 fusestatfs(FuseMsg *m) | |
1190 { | |
1191 struct fuse_statfs_out out; | |
1192 | |
1193 memset(&out, 0, sizeof out); | |
1194 replyfuse(m, &out, sizeof out); | |
1195 } | |
1196 | |
1197 void (*fusehandlers[100])(FuseMsg*); | |
1198 | |
1199 struct { | |
1200 int op; | |
1201 void (*fn)(FuseMsg*); | |
1202 } fuselist[] = { | |
1203 { FUSE_LOOKUP, fuselookup }, | |
1204 { FUSE_FORGET, fuseforget }, | |
1205 { FUSE_GETATTR, fusegetattr }, | |
1206 { FUSE_SETATTR, fusesetattr }, | |
1207 /* | |
1208 * FUSE_SYMLINK, FUSE_MKNOD are unimplemented. | |
1209 */ | |
1210 { FUSE_READLINK, fusereadlink }, | |
1211 { FUSE_MKDIR, fusemkdir }, | |
1212 { FUSE_UNLINK, fuseunlink }, | |
1213 { FUSE_RMDIR, fusermdir }, | |
1214 { FUSE_RENAME, fuserename }, | |
1215 /* | |
1216 * FUSE_LINK is unimplemented. | |
1217 */ | |
1218 { FUSE_OPEN, fuseopen }, | |
1219 { FUSE_READ, fuseread }, | |
1220 { FUSE_WRITE, fusewrite }, | |
1221 { FUSE_STATFS, fusestatfs }, | |
1222 { FUSE_RELEASE, fuserelease }, | |
1223 { FUSE_FSYNC, fusefsync }, | |
1224 /* | |
1225 * FUSE_SETXATTR, FUSE_GETXATTR, FUSE_LISTXATTR, and | |
1226 * FUSE_REMOVEXATTR are unimplemented. | |
1227 * FUSE will stop sending these requests after getting | |
1228 * an -ENOSYS reply (see dispatch below). | |
1229 */ | |
1230 { FUSE_FLUSH, fuseflush }, | |
1231 /* | |
1232 * FUSE_INIT is handled in initfuse and should not be seen again. | |
1233 */ | |
1234 { FUSE_OPENDIR, fuseopendir }, | |
1235 { FUSE_READDIR, fusereaddir }, | |
1236 { FUSE_RELEASEDIR, fusereleasedir }, | |
1237 { FUSE_FSYNCDIR, fusefsyncdir }, | |
1238 { FUSE_ACCESS, fuseaccess }, | |
1239 { FUSE_CREATE, fusecreate }, | |
1240 }; | |
1241 | |
1242 void | |
1243 fusethread(void *v) | |
1244 { | |
1245 FuseMsg *m; | |
1246 | |
1247 m = v; | |
1248 if((uint)m->hdr->opcode >= nelem(fusehandlers) | |
1249 || !fusehandlers[m->hdr->opcode]){ | |
1250 replyfuseerrno(m, ENOSYS); | |
1251 return; | |
1252 } | |
1253 fusehandlers[m->hdr->opcode](m); | |
1254 } | |
1255 | |
1256 void | |
1257 fusedispatch(void *v) | |
1258 { | |
1259 int i; | |
1260 FuseMsg *m; | |
1261 | |
1262 eofkill9pclient = 1; /* threadexitsall on 9P eof */ | |
1263 atexit(unmountatexit); | |
1264 | |
1265 recvp(fusechan); /* sync */ | |
1266 | |
1267 for(i=0; i<nelem(fuselist); i++){ | |
1268 if(fuselist[i].op >= nelem(fusehandlers)) | |
1269 sysfatal("make fusehandlers bigger op=%d", fusel… | |
1270 fusehandlers[fuselist[i].op] = fuselist[i].fn; | |
1271 } | |
1272 | |
1273 while((m = recvp(fusechan)) != nil) { | |
1274 switch(m->hdr->opcode) { | |
1275 case FUSE_FORGET: | |
1276 fusehandlers[m->hdr->opcode](m); | |
1277 break; | |
1278 default: | |
1279 threadcreate(fusethread, m, STACK); | |
1280 } | |
1281 } | |
1282 } | |
1283 | |
1284 void* | |
1285 emalloc(uint n) | |
1286 { | |
1287 void *p; | |
1288 | |
1289 p = malloc(n); | |
1290 if(p == nil) | |
1291 sysfatal("malloc(%d): %r", n); | |
1292 memset(p, 0, n); | |
1293 return p; | |
1294 } | |
1295 | |
1296 void* | |
1297 erealloc(void *p, uint n) | |
1298 { | |
1299 p = realloc(p, n); | |
1300 if(p == nil) | |
1301 sysfatal("realloc(..., %d): %r", n); | |
1302 return p; | |
1303 } | |
1304 | |
1305 char* | |
1306 estrdup(char *p) | |
1307 { | |
1308 char *pp; | |
1309 pp = strdup(p); | |
1310 if(pp == nil) | |
1311 sysfatal("strdup(%.20s): %r", p); | |
1312 return pp; | |
1313 } | |
1314 | |
1315 void | |
1316 watchfd(void *v) | |
1317 { | |
1318 int fd = (int)(uintptr)v; | |
1319 | |
1320 /* wait for exception (file closed) */ | |
1321 fd_set set; | |
1322 FD_ZERO(&set); | |
1323 FD_SET(fd, &set); | |
1324 if(select(fd+1, NULL, NULL, &set, NULL) >= 0) | |
1325 threadexitsall(nil); | |
1326 return; | |
1327 } |