2 5551e51d 2006-07-23 devnull * 9P to FUSE translator. Acts as FUSE server, 9P client.
3 5551e51d 2006-07-23 devnull * Mounts 9P servers via FUSE kernel module.
5 5551e51d 2006-07-23 devnull * There are four procs in this threaded program
6 5551e51d 2006-07-23 devnull * (ignoring the one that runs main and then exits).
7 5551e51d 2006-07-23 devnull * The first proc reads FUSE requests from /dev/fuse.
8 5551e51d 2006-07-23 devnull * It sends the requests over a channel to a second proc,
9 5551e51d 2006-07-23 devnull * which serves the requests. Each request runs in a
10 5551e51d 2006-07-23 devnull * thread in that second proc. Those threads do write
11 5551e51d 2006-07-23 devnull * FUSE replies, which in theory might block, but in practice don't.
12 5551e51d 2006-07-23 devnull * The 9P interactions are handled by lib9pclient, which
13 5551e51d 2006-07-23 devnull * allocates two more procs, one for reading and one for
14 5551e51d 2006-07-23 devnull * writing the 9P connection. Thus the many threads in the
15 5551e51d 2006-07-23 devnull * request proc can do 9P interactions without blocking.
18 05f50fe6 2006-07-23 devnull #define _GNU_SOURCE 1 /* for O_DIRECTORY on Linux */
19 5551e51d 2006-07-23 devnull #include "a.h"
21 05f50fe6 2006-07-23 devnull /* GNUisms */
22 05f50fe6 2006-07-23 devnull #ifndef O_DIRECTORY
23 05f50fe6 2006-07-23 devnull #define O_DIRECTORY 0
25 05f50fe6 2006-07-23 devnull #ifndef O_LARGEFILE
26 05f50fe6 2006-07-23 devnull #define O_LARGEFILE 0
30 5551e51d 2006-07-23 devnull int debug;
31 5551e51d 2006-07-23 devnull char *argv0;
32 5551e51d 2006-07-23 devnull void fusedispatch(void*);
33 5551e51d 2006-07-23 devnull Channel *fusechan;
37 5551e51d 2006-07-23 devnull STACK = 8192
41 5551e51d 2006-07-23 devnull * The number of seconds that the kernel can cache
42 5551e51d 2006-07-23 devnull * returned file attributes. FUSE's default is 1.0.
43 5551e51d 2006-07-23 devnull * I haven't experimented with using 0.
45 5551e51d 2006-07-23 devnull double attrtimeout = 1.0;
48 5551e51d 2006-07-23 devnull * The number of seconds that the kernel can cache
49 5551e51d 2006-07-23 devnull * the returned entry nodeids returned by lookup.
50 5551e51d 2006-07-23 devnull * I haven't experimented with other values.
52 5551e51d 2006-07-23 devnull double entrytimeout = 1.0;
54 5551e51d 2006-07-23 devnull CFsys *fsys;
55 5551e51d 2006-07-23 devnull CFid *fsysroot;
56 5551e51d 2006-07-23 devnull void init9p(char*);
59 5551e51d 2006-07-23 devnull usage(void)
61 5551e51d 2006-07-23 devnull fprint(2, "usage: 9pfuse [-D] [-a attrtimeout] address mtpt\n");
65 5551e51d 2006-07-23 devnull void fusereader(void*);
68 5551e51d 2006-07-23 devnull threadmain(int argc, char **argv)
70 5551e51d 2006-07-23 devnull ARGBEGIN{
71 5551e51d 2006-07-23 devnull case 'D':
72 5551e51d 2006-07-23 devnull chatty9pclient++;
75 5551e51d 2006-07-23 devnull case 'a':
76 5551e51d 2006-07-23 devnull attrtimeout = atof(EARGF(usage()));
82 5551e51d 2006-07-23 devnull if(argc != 2)
85 5551e51d 2006-07-23 devnull quotefmtinstall();
86 5551e51d 2006-07-23 devnull fmtinstall('F', fcallfmt);
87 5551e51d 2006-07-23 devnull fmtinstall('M', dirmodefmt);
88 5551e51d 2006-07-23 devnull fmtinstall('G', fusefmt);
90 a695bc7d 2006-07-23 devnull setsid(); /* won't be able to use console, but can't be interrupted */
92 5551e51d 2006-07-23 devnull init9p(argv[0]);
93 5551e51d 2006-07-23 devnull initfuse(argv[1]);
95 5551e51d 2006-07-23 devnull fusechan = chancreate(sizeof(void*), 0);
96 5551e51d 2006-07-23 devnull proccreate(fusedispatch, nil, STACK);
97 5551e51d 2006-07-23 devnull sendp(fusechan, nil); /* sync */
99 5551e51d 2006-07-23 devnull proccreate(fusereader, nil, STACK);
100 5551e51d 2006-07-23 devnull threadexits(0);
104 5551e51d 2006-07-23 devnull fusereader(void *v)
106 5551e51d 2006-07-23 devnull FuseMsg *m;
108 5551e51d 2006-07-23 devnull while((m = readfusemsg()) != nil)
109 5551e51d 2006-07-23 devnull sendp(fusechan, m);
111 5551e51d 2006-07-23 devnull fusemtpt = nil; /* no need to unmount */
112 5551e51d 2006-07-23 devnull threadexitsall(0);
116 5551e51d 2006-07-23 devnull init9p(char *addr)
120 5551e51d 2006-07-23 devnull if((fd = dial(netmkaddr(addr, "tcp", "564"), nil, nil, nil)) < 0)
121 5551e51d 2006-07-23 devnull sysfatal("dial %s: %r", addr);
122 5551e51d 2006-07-23 devnull if((fsys = fsmount(fd, "")) == nil)
123 5551e51d 2006-07-23 devnull sysfatal("fsmount: %r");
124 5551e51d 2006-07-23 devnull fsysroot = fsroot(fsys);
128 5551e51d 2006-07-23 devnull * FUSE uses nodeids to refer to active "struct inodes"
129 5551e51d 2006-07-23 devnull * (9P's unopened fids). FUSE uses fhs to refer to active
130 5551e51d 2006-07-23 devnull * "struct fuse_files" (9P's opened fids). The choice of
131 5551e51d 2006-07-23 devnull * numbers is up to us except that nodeid 1 is the root directory.
132 5551e51d 2006-07-23 devnull * We use the same number space for both and call the
133 5551e51d 2006-07-23 devnull * bookkeeping structure a FuseFid.
135 5551e51d 2006-07-23 devnull * FUSE requires nodeids to have associated generation
136 5551e51d 2006-07-23 devnull * numbers. If we reuse a nodeid, we have to bump the
137 5551e51d 2006-07-23 devnull * generation number to guarantee that the nodeid,gen
138 5551e51d 2006-07-23 devnull * combination is never reused.
140 5551e51d 2006-07-23 devnull * There are also inode numbers returned in directory reads
141 5551e51d 2006-07-23 devnull * and file attributes, but these do NOT need to match the nodeids.
142 5551e51d 2006-07-23 devnull * We use a combination of qid.path and qid.type as the inode
143 5551e51d 2006-07-23 devnull * number.
146 5551e51d 2006-07-23 devnull * TO DO: reference count the fids.
148 5551e51d 2006-07-23 devnull typedef struct Fusefid Fusefid;
149 5551e51d 2006-07-23 devnull struct Fusefid
151 5551e51d 2006-07-23 devnull Fusefid *next;
152 5551e51d 2006-07-23 devnull CFid *fid;
153 5551e51d 2006-07-23 devnull int ref;
155 5551e51d 2006-07-23 devnull int gen;
156 5551e51d 2006-07-23 devnull int isnodeid;
158 5551e51d 2006-07-23 devnull /* directory read state */
159 5551e51d 2006-07-23 devnull Dir *d0;
162 5551e51d 2006-07-23 devnull int off;
165 5551e51d 2006-07-23 devnull Fusefid **fusefid;
166 5551e51d 2006-07-23 devnull int nfusefid;
167 5551e51d 2006-07-23 devnull Fusefid *freefusefidlist;
169 5551e51d 2006-07-23 devnull Fusefid*
170 5551e51d 2006-07-23 devnull allocfusefid(void)
172 5551e51d 2006-07-23 devnull Fusefid *f;
174 5551e51d 2006-07-23 devnull if((f = freefusefidlist) == nil){
175 5551e51d 2006-07-23 devnull f = emalloc(sizeof *f);
176 5551e51d 2006-07-23 devnull fusefid = erealloc(fusefid, (nfusefid+1)*sizeof *fusefid);
177 5551e51d 2006-07-23 devnull f->id = nfusefid;
178 5551e51d 2006-07-23 devnull fprint(2, "allocfusefid %d %p\n", f->id, f);
179 5551e51d 2006-07-23 devnull fusefid[f->id] = f;
180 5551e51d 2006-07-23 devnull nfusefid++;
182 5551e51d 2006-07-23 devnull freefusefidlist = f->next;
183 5551e51d 2006-07-23 devnull f->next = nil;
184 5551e51d 2006-07-23 devnull f->ref = 1;
185 5551e51d 2006-07-23 devnull f->isnodeid = -1;
186 5551e51d 2006-07-23 devnull return f;
190 5551e51d 2006-07-23 devnull freefusefid(Fusefid *f)
192 5551e51d 2006-07-23 devnull if(--f->ref > 0)
194 5551e51d 2006-07-23 devnull assert(f->ref == 0);
195 5551e51d 2006-07-23 devnull if(f->fid)
196 5551e51d 2006-07-23 devnull fsclose(f->fid);
197 5551e51d 2006-07-23 devnull if(f->d0)
198 5551e51d 2006-07-23 devnull free(f->d0);
199 5551e51d 2006-07-23 devnull f->off = 0;
200 5551e51d 2006-07-23 devnull f->d0 = nil;
201 5551e51d 2006-07-23 devnull f->fid = nil;
202 5551e51d 2006-07-23 devnull f->d = nil;
203 5551e51d 2006-07-23 devnull f->nd = 0;
204 5551e51d 2006-07-23 devnull f->next = freefusefidlist;
205 5551e51d 2006-07-23 devnull f->isnodeid = -1;
206 5551e51d 2006-07-23 devnull freefusefidlist = f;
210 5551e51d 2006-07-23 devnull _alloc(CFid *fid, int isnodeid)
212 5551e51d 2006-07-23 devnull Fusefid *ff;
214 5551e51d 2006-07-23 devnull ff = allocfusefid();
215 5551e51d 2006-07-23 devnull ff->fid = fid;
216 5551e51d 2006-07-23 devnull ff->isnodeid = isnodeid;
217 5551e51d 2006-07-23 devnull ff->gen++;
218 5551e51d 2006-07-23 devnull return ff->id+2; /* skip 0 and 1 */
222 5551e51d 2006-07-23 devnull allocfh(CFid *fid)
224 5551e51d 2006-07-23 devnull return _alloc(fid, 0);
227 5551e51d 2006-07-23 devnull allocnodeid(CFid *fid)
229 5551e51d 2006-07-23 devnull return _alloc(fid, 1);
232 5551e51d 2006-07-23 devnull Fusefid*
233 5551e51d 2006-07-23 devnull lookupfusefid(uvlong id, int isnodeid)
235 5551e51d 2006-07-23 devnull Fusefid *ff;
236 5551e51d 2006-07-23 devnull if(id < 2 || id >= nfusefid+2)
237 5551e51d 2006-07-23 devnull return nil;
238 5551e51d 2006-07-23 devnull ff = fusefid[(int)id-2];
239 5551e51d 2006-07-23 devnull if(ff->isnodeid != isnodeid)
240 5551e51d 2006-07-23 devnull return nil;
241 5551e51d 2006-07-23 devnull return ff;
245 5551e51d 2006-07-23 devnull _lookupcfid(uvlong id, int isnodeid)
247 5551e51d 2006-07-23 devnull Fusefid *ff;
249 5551e51d 2006-07-23 devnull if((ff = lookupfusefid(id, isnodeid)) == nil)
250 5551e51d 2006-07-23 devnull return nil;
251 5551e51d 2006-07-23 devnull return ff->fid;
255 5551e51d 2006-07-23 devnull fh2fid(uvlong fh)
257 5551e51d 2006-07-23 devnull return _lookupcfid(fh, 0);
261 5551e51d 2006-07-23 devnull nodeid2fid(uvlong nodeid)
263 5551e51d 2006-07-23 devnull if(nodeid == 1)
264 5551e51d 2006-07-23 devnull return fsysroot;
265 5551e51d 2006-07-23 devnull return _lookupcfid(nodeid, 1);
269 5551e51d 2006-07-23 devnull qid2inode(Qid q)
271 5551e51d 2006-07-23 devnull return q.path | ((uvlong)q.type<<56);
275 5551e51d 2006-07-23 devnull dir2attr(Dir *d, struct fuse_attr *attr)
277 5551e51d 2006-07-23 devnull attr->ino = qid2inode(d->qid);
278 5551e51d 2006-07-23 devnull attr->size = d->length;
279 5551e51d 2006-07-23 devnull attr->blocks = (d->length+8191)/8192;
280 5551e51d 2006-07-23 devnull attr->atime = d->atime;
281 5551e51d 2006-07-23 devnull attr->mtime = d->mtime;
282 5551e51d 2006-07-23 devnull attr->ctime = d->mtime; /* not right */
283 5551e51d 2006-07-23 devnull attr->atimensec = 0;
284 5551e51d 2006-07-23 devnull attr->mtimensec = 0;
285 5551e51d 2006-07-23 devnull attr->ctimensec = 0;
286 5551e51d 2006-07-23 devnull attr->mode = d->mode&0777;
287 5551e51d 2006-07-23 devnull if(d->mode&DMDIR)
288 5551e51d 2006-07-23 devnull attr->mode |= S_IFDIR;
290 5551e51d 2006-07-23 devnull attr->mode |= S_IFREG;
291 5551e51d 2006-07-23 devnull attr->nlink = 1; /* works for directories! - see FUSE FAQ */
292 5551e51d 2006-07-23 devnull attr->uid = getuid();
293 5551e51d 2006-07-23 devnull attr->gid = getgid();
294 5551e51d 2006-07-23 devnull attr->rdev = 0;
298 5551e51d 2006-07-23 devnull f2timeout(double f, __u64 *s, __u32 *ns)
301 5551e51d 2006-07-23 devnull *ns = (f - (int)f)*1e9;
305 5551e51d 2006-07-23 devnull dir2attrout(Dir *d, struct fuse_attr_out *out)
307 5551e51d 2006-07-23 devnull f2timeout(attrtimeout, &out->attr_valid, &out->attr_valid_nsec);
308 5551e51d 2006-07-23 devnull dir2attr(d, &out->attr);
312 5551e51d 2006-07-23 devnull * Lookup. Walk to the name given as the argument.
313 5551e51d 2006-07-23 devnull * The response is a fuse_entry_out giving full stat info.
316 5551e51d 2006-07-23 devnull fuselookup(FuseMsg *m)
318 5551e51d 2006-07-23 devnull char *name;
319 5551e51d 2006-07-23 devnull Fusefid *ff;
320 5551e51d 2006-07-23 devnull CFid *fid, *newfid;
322 5551e51d 2006-07-23 devnull struct fuse_entry_out out;
324 5551e51d 2006-07-23 devnull name = m->tx;
325 5551e51d 2006-07-23 devnull if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
326 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
329 5551e51d 2006-07-23 devnull if(strchr(name, '/')){
330 5551e51d 2006-07-23 devnull replyfuseerrno(m, ENOENT);
333 5551e51d 2006-07-23 devnull if((newfid = fswalk(fid, name)) == nil){
334 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
337 5551e51d 2006-07-23 devnull if((d = fsdirfstat(newfid)) == nil){
338 5551e51d 2006-07-23 devnull fsclose(newfid);
339 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
342 5551e51d 2006-07-23 devnull out.nodeid = allocnodeid(newfid);
343 5551e51d 2006-07-23 devnull ff = lookupfusefid(out.nodeid, 1);
344 5551e51d 2006-07-23 devnull out.generation = ff->gen;
345 5551e51d 2006-07-23 devnull f2timeout(attrtimeout, &out.attr_valid, &out.attr_valid_nsec);
346 5551e51d 2006-07-23 devnull f2timeout(entrytimeout, &out.entry_valid, &out.entry_valid_nsec);
347 5551e51d 2006-07-23 devnull dir2attr(d, &out.attr);
348 5551e51d 2006-07-23 devnull free(d);
349 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
353 5551e51d 2006-07-23 devnull * Forget. Reference-counted clunk for nodeids.
354 5551e51d 2006-07-23 devnull * Does not send a reply.
355 5551e51d 2006-07-23 devnull * Each lookup response gives the kernel an additional reference
356 5551e51d 2006-07-23 devnull * to the returned nodeid. Forget says "drop this many references
357 5551e51d 2006-07-23 devnull * to this nodeid". Our fuselookup, when presented with the same query,
358 5551e51d 2006-07-23 devnull * does not return the same results (it allocates a new nodeid for each
359 5551e51d 2006-07-23 devnull * call), but if that ever changes, fuseforget already handles the ref
360 5551e51d 2006-07-23 devnull * counts properly.
363 5551e51d 2006-07-23 devnull fuseforget(FuseMsg *m)
365 5551e51d 2006-07-23 devnull struct fuse_forget_in *in;
366 5551e51d 2006-07-23 devnull Fusefid *ff;
368 5551e51d 2006-07-23 devnull in = m->tx;
369 5551e51d 2006-07-23 devnull if((ff = lookupfusefid(m->hdr->nodeid, 1)) == nil)
371 5551e51d 2006-07-23 devnull if(ff->ref > in->nlookup){
372 5551e51d 2006-07-23 devnull ff->ref -= in->nlookup;
375 5551e51d 2006-07-23 devnull if(ff->ref < in->nlookup)
376 5551e51d 2006-07-23 devnull fprint(2, "bad count in forget\n");
377 5551e51d 2006-07-23 devnull ff->ref = 1;
378 5551e51d 2006-07-23 devnull freefusefid(ff);
382 5551e51d 2006-07-23 devnull * Getattr.
383 5551e51d 2006-07-23 devnull * Replies with a fuse_attr_out structure giving the
384 5551e51d 2006-07-23 devnull * attr for the requested nodeid in out.attr.
385 5551e51d 2006-07-23 devnull * Out.attr_valid and out.attr_valid_nsec give
386 5551e51d 2006-07-23 devnull * the amount of time that the attributes can
387 5551e51d 2006-07-23 devnull * be cached.
389 5551e51d 2006-07-23 devnull * Empirically, though, if I run ls -ld on the root
390 5551e51d 2006-07-23 devnull * twice back to back, I still get two getattrs,
391 5551e51d 2006-07-23 devnull * even with a one second attribute timeout!
394 5551e51d 2006-07-23 devnull fusegetattr(FuseMsg *m)
396 5551e51d 2006-07-23 devnull CFid *fid;
397 5551e51d 2006-07-23 devnull struct fuse_attr_out out;
400 5551e51d 2006-07-23 devnull if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
401 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
404 5551e51d 2006-07-23 devnull if((d = fsdirfstat(fid)) == nil){
405 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
408 5551e51d 2006-07-23 devnull memset(&out, 0, sizeof out);
409 5551e51d 2006-07-23 devnull dir2attrout(d, &out);
410 5551e51d 2006-07-23 devnull free(d);
411 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
415 5551e51d 2006-07-23 devnull * Setattr.
416 5551e51d 2006-07-23 devnull * FUSE treats the many Unix attribute setting routines
417 5551e51d 2006-07-23 devnull * more or less like 9P does, with a single message.
420 5551e51d 2006-07-23 devnull fusesetattr(FuseMsg *m)
422 5551e51d 2006-07-23 devnull CFid *fid, *nfid;
423 5551e51d 2006-07-23 devnull Dir d, *dd;
424 5551e51d 2006-07-23 devnull struct fuse_setattr_in *in;
425 5551e51d 2006-07-23 devnull struct fuse_attr_out out;
427 5551e51d 2006-07-23 devnull in = m->tx;
428 5551e51d 2006-07-23 devnull if(in->valid&FATTR_FH){
429 5551e51d 2006-07-23 devnull if((fid = fh2fid(in->fh)) == nil){
430 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
434 5551e51d 2006-07-23 devnull if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
435 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
439 5551e51d 2006-07-23 devnull * Special case: Linux issues a size change to
440 5551e51d 2006-07-23 devnull * truncate a file before opening it OTRUNC.
441 5551e51d 2006-07-23 devnull * Synthetic file servers (e.g., plumber) honor
442 5551e51d 2006-07-23 devnull * open(OTRUNC) but not wstat.
444 5551e51d 2006-07-23 devnull if(in->valid == FATTR_SIZE && in->size == 0){
445 5551e51d 2006-07-23 devnull if((nfid = fswalk(fid, nil)) == nil){
446 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
449 5551e51d 2006-07-23 devnull if(fsfopen(nfid, OWRITE|OTRUNC) < 0){
450 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
451 5551e51d 2006-07-23 devnull fsclose(nfid);
454 5551e51d 2006-07-23 devnull fsclose(nfid);
455 5551e51d 2006-07-23 devnull goto stat;
459 5551e51d 2006-07-23 devnull nulldir(&d);
460 5551e51d 2006-07-23 devnull if(in->valid&FATTR_SIZE)
461 5551e51d 2006-07-23 devnull d.length = in->size;
462 5551e51d 2006-07-23 devnull if(in->valid&FATTR_ATIME)
463 5551e51d 2006-07-23 devnull d.atime = in->atime;
464 5551e51d 2006-07-23 devnull if(in->valid&FATTR_MTIME)
465 5551e51d 2006-07-23 devnull d.mtime = in->mtime;
466 5551e51d 2006-07-23 devnull if(in->valid&FATTR_MODE)
467 5551e51d 2006-07-23 devnull d.mode = in->mode;
468 5551e51d 2006-07-23 devnull if((in->valid&FATTR_UID) || (in->valid&FATTR_GID)){
470 5551e51d 2006-07-23 devnull * I can't be bothered with these yet.
472 5551e51d 2006-07-23 devnull replyfuseerrno(m, EPERM);
475 5551e51d 2006-07-23 devnull if(fsdirfwstat(fid, &d) < 0){
476 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
480 5551e51d 2006-07-23 devnull if((dd = fsdirfstat(fid)) == nil){
481 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
484 5551e51d 2006-07-23 devnull memset(&out, 0, sizeof out);
485 5551e51d 2006-07-23 devnull dir2attrout(dd, &out);
486 5551e51d 2006-07-23 devnull free(dd);
487 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
491 5551e51d 2006-07-23 devnull _fuseopenfid(uvlong nodeid, int isdir, int openmode, int *err)
493 5551e51d 2006-07-23 devnull CFid *fid, *newfid;
495 5551e51d 2006-07-23 devnull if((fid = nodeid2fid(nodeid)) == nil){
496 5551e51d 2006-07-23 devnull *err = ESTALE;
497 5551e51d 2006-07-23 devnull return nil;
499 5551e51d 2006-07-23 devnull if(isdir && !(fsqid(fid).type&QTDIR)){
500 5551e51d 2006-07-23 devnull *err = ENOTDIR;
501 5551e51d 2006-07-23 devnull return nil;
503 5551e51d 2006-07-23 devnull if(openmode != OREAD && fsqid(fid).type&QTDIR){
504 5551e51d 2006-07-23 devnull *err = EISDIR;
505 5551e51d 2006-07-23 devnull return nil;
508 5551e51d 2006-07-23 devnull /* Clone fid to get one we can open. */
509 5551e51d 2006-07-23 devnull newfid = fswalk(fid, nil);
510 5551e51d 2006-07-23 devnull if(newfid == nil){
511 5551e51d 2006-07-23 devnull *err = errstr2errno();
512 5551e51d 2006-07-23 devnull return nil;
515 5551e51d 2006-07-23 devnull if(fsfopen(newfid, openmode) < 0){
516 5551e51d 2006-07-23 devnull *err = errstr2errno();
517 5551e51d 2006-07-23 devnull fsclose(newfid);
518 5551e51d 2006-07-23 devnull return nil;
521 5551e51d 2006-07-23 devnull return newfid;
525 5551e51d 2006-07-23 devnull * Open & Opendir.
526 5551e51d 2006-07-23 devnull * Argument is a struct fuse_open_in.
527 5551e51d 2006-07-23 devnull * The mode field is ignored (presumably permission bits)
528 5551e51d 2006-07-23 devnull * and flags is the open mode.
529 5551e51d 2006-07-23 devnull * Replies with a struct fuse_open_out.
532 5551e51d 2006-07-23 devnull _fuseopen(FuseMsg *m, int isdir)
534 5551e51d 2006-07-23 devnull struct fuse_open_in *in;
535 5551e51d 2006-07-23 devnull struct fuse_open_out out;
536 5551e51d 2006-07-23 devnull CFid *fid;
537 5551e51d 2006-07-23 devnull int openmode, flags, err;
539 5551e51d 2006-07-23 devnull in = m->tx;
540 5551e51d 2006-07-23 devnull flags = in->flags;
541 5551e51d 2006-07-23 devnull openmode = flags&3;
542 5551e51d 2006-07-23 devnull flags &= ~3;
543 5551e51d 2006-07-23 devnull flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE);
544 0d7fd011 2006-07-23 devnull if(flags & O_TRUNC){
545 0d7fd011 2006-07-23 devnull openmode |= OTRUNC;
546 0d7fd011 2006-07-23 devnull flags &= ~O_TRUNC;
549 0d7fd011 2006-07-23 devnull * Could translate but not standard 9P:
550 0d7fd011 2006-07-23 devnull * O_DIRECT -> ODIRECT
551 0d7fd011 2006-07-23 devnull * O_NONBLOCK -> ONONBLOCK
552 0d7fd011 2006-07-23 devnull * O_APPEND -> OAPPEND
554 5551e51d 2006-07-23 devnull if(flags){
555 5551e51d 2006-07-23 devnull fprint(2, "unexpected open flags %#uo", (uint)in->flags);
556 5551e51d 2006-07-23 devnull replyfuseerrno(m, EACCES);
559 5551e51d 2006-07-23 devnull if((fid = _fuseopenfid(m->hdr->nodeid, isdir, openmode, &err)) == nil){
560 5551e51d 2006-07-23 devnull replyfuseerrno(m, err);
563 5551e51d 2006-07-23 devnull out.fh = allocfh(fid);
564 5551e51d 2006-07-23 devnull out.open_flags = FOPEN_DIRECT_IO; /* no page cache */
565 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
569 5551e51d 2006-07-23 devnull fuseopen(FuseMsg *m)
571 5551e51d 2006-07-23 devnull _fuseopen(m, 0);
575 5551e51d 2006-07-23 devnull fuseopendir(FuseMsg *m)
577 5551e51d 2006-07-23 devnull _fuseopen(m, 1);
581 5551e51d 2006-07-23 devnull * Create & Mkdir.
584 5551e51d 2006-07-23 devnull _fusecreate(uvlong nodeid, char *name, int perm, int ismkdir, int omode, struct fuse_entry_out *out, int *err)
586 5551e51d 2006-07-23 devnull CFid *fid, *newfid, *newfid2;
588 5551e51d 2006-07-23 devnull Fusefid *ff;
590 5551e51d 2006-07-23 devnull if((fid = nodeid2fid(nodeid)) == nil){
591 5551e51d 2006-07-23 devnull *err = ESTALE;
592 5551e51d 2006-07-23 devnull return nil;
594 5551e51d 2006-07-23 devnull perm &= 0777;
595 5551e51d 2006-07-23 devnull if(ismkdir)
596 5551e51d 2006-07-23 devnull perm |= DMDIR;
597 5551e51d 2006-07-23 devnull if(ismkdir && omode != OREAD){
598 5551e51d 2006-07-23 devnull *err = EPERM;
599 5551e51d 2006-07-23 devnull return nil;
601 5551e51d 2006-07-23 devnull if((newfid = fswalk(fid, nil)) == nil){
602 5551e51d 2006-07-23 devnull *err = errstr2errno();
603 5551e51d 2006-07-23 devnull return nil;
605 5551e51d 2006-07-23 devnull if(fsfcreate(newfid, name, perm, omode) < 0){
606 5551e51d 2006-07-23 devnull *err = errstr2errno();
607 5551e51d 2006-07-23 devnull fsclose(newfid);
608 5551e51d 2006-07-23 devnull return nil;
610 5551e51d 2006-07-23 devnull if((d = fsdirfstat(newfid)) == nil){
611 5551e51d 2006-07-23 devnull *err = errstr2errno();
612 5551e51d 2006-07-23 devnull fsfremove(newfid);
613 5551e51d 2006-07-23 devnull return nil;
616 5551e51d 2006-07-23 devnull * This fid is no good, because it's open.
617 5551e51d 2006-07-23 devnull * We need an unopened fid. Sigh.
619 5551e51d 2006-07-23 devnull if((newfid2 = fswalk(fid, name)) == nil){
620 5551e51d 2006-07-23 devnull *err = errstr2errno();
621 5551e51d 2006-07-23 devnull free(d);
622 5551e51d 2006-07-23 devnull fsfremove(newfid);
623 5551e51d 2006-07-23 devnull return nil;
625 5551e51d 2006-07-23 devnull out->nodeid = allocnodeid(newfid2);
626 5551e51d 2006-07-23 devnull ff = lookupfusefid(out->nodeid, 1);
627 5551e51d 2006-07-23 devnull out->generation = ff->gen;
628 5551e51d 2006-07-23 devnull f2timeout(attrtimeout, &out->attr_valid, &out->attr_valid_nsec);
629 5551e51d 2006-07-23 devnull f2timeout(entrytimeout, &out->entry_valid, &out->entry_valid_nsec);
630 5551e51d 2006-07-23 devnull dir2attr(d, &out->attr);
631 5551e51d 2006-07-23 devnull free(d);
632 5551e51d 2006-07-23 devnull return newfid;
636 5551e51d 2006-07-23 devnull fusemkdir(FuseMsg *m)
638 5551e51d 2006-07-23 devnull struct fuse_mkdir_in *in;
639 5551e51d 2006-07-23 devnull struct fuse_entry_out out;
640 5551e51d 2006-07-23 devnull CFid *fid;
641 5551e51d 2006-07-23 devnull int err;
642 5551e51d 2006-07-23 devnull char *name;
644 5551e51d 2006-07-23 devnull in = m->tx;
645 5551e51d 2006-07-23 devnull name = (char*)(in+1);
646 5551e51d 2006-07-23 devnull if((fid = _fusecreate(m->hdr->nodeid, name, in->mode, 1, OREAD, &out, &err)) == nil){
647 5551e51d 2006-07-23 devnull replyfuseerrno(m, err);
650 5551e51d 2006-07-23 devnull /* Toss the open fid. */
651 5551e51d 2006-07-23 devnull fsclose(fid);
652 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
656 5551e51d 2006-07-23 devnull fusecreate(FuseMsg *m)
658 5551e51d 2006-07-23 devnull struct fuse_open_in *in;
659 5551e51d 2006-07-23 devnull struct fuse_create_out out;
660 5551e51d 2006-07-23 devnull CFid *fid;
661 5551e51d 2006-07-23 devnull int err, openmode, flags;
662 5551e51d 2006-07-23 devnull char *name;
664 5551e51d 2006-07-23 devnull in = m->tx;
665 5551e51d 2006-07-23 devnull flags = in->flags;
666 5551e51d 2006-07-23 devnull openmode = in->flags&3;
667 5551e51d 2006-07-23 devnull flags &= ~(O_DIRECTORY|O_NONBLOCK|O_LARGEFILE);
668 5551e51d 2006-07-23 devnull if(flags){
669 5551e51d 2006-07-23 devnull fprint(2, "bad mode %#uo\n", in->flags);
670 5551e51d 2006-07-23 devnull replyfuseerrno(m, EACCES);
673 5551e51d 2006-07-23 devnull name = (char*)(in+1);
674 5551e51d 2006-07-23 devnull if((fid = _fusecreate(m->hdr->nodeid, name, in->mode, 0, openmode, &out.e, &err)) == nil){
675 5551e51d 2006-07-23 devnull replyfuseerrno(m, err);
678 5551e51d 2006-07-23 devnull out.o.fh = allocfh(fid);
679 5551e51d 2006-07-23 devnull out.o.open_flags = FOPEN_DIRECT_IO; /* no page cache */
680 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
684 5551e51d 2006-07-23 devnull * Access.
685 5551e51d 2006-07-23 devnull * Lib9pclient implements this just as Plan 9 does,
686 5551e51d 2006-07-23 devnull * by opening the file (or not) and then closing it.
689 5551e51d 2006-07-23 devnull fuseaccess(FuseMsg *m)
691 5551e51d 2006-07-23 devnull struct fuse_access_in *in;
692 5551e51d 2006-07-23 devnull CFid *fid;
693 5551e51d 2006-07-23 devnull int err;
694 5551e51d 2006-07-23 devnull static int a2o[] = {
705 5551e51d 2006-07-23 devnull in = m->tx;
706 5551e51d 2006-07-23 devnull if(in->mask >= nelem(a2o)){
707 5551e51d 2006-07-23 devnull replyfuseerrno(m, EINVAL);
710 5551e51d 2006-07-23 devnull if((fid = _fuseopenfid(m->hdr->nodeid, 0, a2o[in->mask], &err)) == nil){
711 5551e51d 2006-07-23 devnull replyfuseerrno(m, err);
714 5551e51d 2006-07-23 devnull fsclose(fid);
715 5551e51d 2006-07-23 devnull replyfuse(m, nil, 0);
719 5551e51d 2006-07-23 devnull * Release.
720 5551e51d 2006-07-23 devnull * Equivalent of clunk for file handles.
721 5551e51d 2006-07-23 devnull * in->flags is the open mode used in Open or Opendir.
724 5551e51d 2006-07-23 devnull fuserelease(FuseMsg *m)
726 5551e51d 2006-07-23 devnull struct fuse_release_in *in;
727 5551e51d 2006-07-23 devnull Fusefid *ff;
729 5551e51d 2006-07-23 devnull in = m->tx;
730 5551e51d 2006-07-23 devnull if((ff = lookupfusefid(in->fh, 0)) != nil)
731 5551e51d 2006-07-23 devnull freefusefid(ff);
733 5551e51d 2006-07-23 devnull fprint(2, "fuserelease: fh not found\n");
734 5551e51d 2006-07-23 devnull replyfuse(m, nil, 0);
738 5551e51d 2006-07-23 devnull fusereleasedir(FuseMsg *m)
740 5551e51d 2006-07-23 devnull fuserelease(m);
745 5551e51d 2006-07-23 devnull * Read from file handle in->fh at offset in->offset for size in->size.
746 5551e51d 2006-07-23 devnull * We truncate size to maxwrite just to keep the buffer reasonable.
749 5551e51d 2006-07-23 devnull fuseread(FuseMsg *m)
752 5551e51d 2006-07-23 devnull uchar *buf;
753 5551e51d 2006-07-23 devnull CFid *fid;
754 5551e51d 2006-07-23 devnull struct fuse_read_in *in;
756 5551e51d 2006-07-23 devnull in = m->tx;
757 5551e51d 2006-07-23 devnull if((fid = fh2fid(in->fh)) == nil){
758 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
761 5551e51d 2006-07-23 devnull n = in->size;
762 5551e51d 2006-07-23 devnull if(n > fusemaxwrite)
763 5551e51d 2006-07-23 devnull n = fusemaxwrite;
764 5551e51d 2006-07-23 devnull buf = emalloc(n);
765 5551e51d 2006-07-23 devnull n = fsread(fid, buf, n);
766 5551e51d 2006-07-23 devnull if(n < 0){
767 5551e51d 2006-07-23 devnull free(buf);
768 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
770 5551e51d 2006-07-23 devnull replyfuse(m, buf, n);
771 5551e51d 2006-07-23 devnull free(buf);
775 5551e51d 2006-07-23 devnull * Readdir.
776 5551e51d 2006-07-23 devnull * Read from file handle in->fh at offset in->offset for size in->size.
777 5551e51d 2006-07-23 devnull * We truncate size to maxwrite just to keep the buffer reasonable.
778 5551e51d 2006-07-23 devnull * We assume 9P directory read semantics: a read at offset 0 rewinds
779 5551e51d 2006-07-23 devnull * and a read at any other offset starts where we left off.
780 5551e51d 2006-07-23 devnull * If it became necessary, we could implement a crude seek
781 5551e51d 2006-07-23 devnull * or cache the entire list of directory entries.
782 5551e51d 2006-07-23 devnull * Directory entries read from 9P but not yet handed to FUSE
783 5551e51d 2006-07-23 devnull * are stored in m->d,nd,d0.
785 5551e51d 2006-07-23 devnull int canpack(Dir*, uvlong, uchar**, uchar*);
787 5551e51d 2006-07-23 devnull fusereaddir(FuseMsg *m)
789 5551e51d 2006-07-23 devnull struct fuse_read_in *in;
790 5551e51d 2006-07-23 devnull uchar *buf, *p, *ep;
792 5551e51d 2006-07-23 devnull Fusefid *ff;
794 5551e51d 2006-07-23 devnull in = m->tx;
795 5551e51d 2006-07-23 devnull if((ff = lookupfusefid(in->fh, 0)) == nil){
796 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
799 5551e51d 2006-07-23 devnull if(in->offset == 0){
800 5551e51d 2006-07-23 devnull fsseek(ff->fid, 0, 0);
801 5551e51d 2006-07-23 devnull free(ff->d0);
802 5551e51d 2006-07-23 devnull ff->d0 = nil;
803 5551e51d 2006-07-23 devnull ff->d = nil;
804 5551e51d 2006-07-23 devnull ff->nd = 0;
806 5551e51d 2006-07-23 devnull n = in->size;
807 5551e51d 2006-07-23 devnull if(n > fusemaxwrite)
808 5551e51d 2006-07-23 devnull n = fusemaxwrite;
809 5551e51d 2006-07-23 devnull buf = emalloc(n);
810 5551e51d 2006-07-23 devnull p = buf;
811 5551e51d 2006-07-23 devnull ep = buf + n;
812 5551e51d 2006-07-23 devnull for(;;){
813 5551e51d 2006-07-23 devnull if(ff->nd == 0){
814 5551e51d 2006-07-23 devnull free(ff->d0);
815 5551e51d 2006-07-23 devnull ff->d0 = nil;
816 5551e51d 2006-07-23 devnull ff->d = nil;
817 5551e51d 2006-07-23 devnull if((ff->nd = fsdirread(ff->fid, &ff->d0)) < 0){
818 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
821 5551e51d 2006-07-23 devnull if(ff->nd == 0)
823 5551e51d 2006-07-23 devnull ff->d = ff->d0;
825 5551e51d 2006-07-23 devnull while(ff->nd > 0 && canpack(ff->d, ff->off, &p, ep)){
826 5551e51d 2006-07-23 devnull ff->off++;
827 5551e51d 2006-07-23 devnull ff->d++;
828 5551e51d 2006-07-23 devnull ff->nd--;
831 5551e51d 2006-07-23 devnull replyfuse(m, buf, p - buf);
832 5551e51d 2006-07-23 devnull free(buf);
836 5551e51d 2006-07-23 devnull canpack(Dir *d, uvlong off, uchar **pp, uchar *ep)
838 5551e51d 2006-07-23 devnull uchar *p;
839 5551e51d 2006-07-23 devnull struct fuse_dirent *de;
840 5551e51d 2006-07-23 devnull int pad, size;
842 5551e51d 2006-07-23 devnull p = *pp;
843 5551e51d 2006-07-23 devnull size = FUSE_NAME_OFFSET + strlen(d->name);
844 5551e51d 2006-07-23 devnull pad = 0;
845 5551e51d 2006-07-23 devnull if(size%8)
846 5551e51d 2006-07-23 devnull pad = 8 - size%8;
847 5551e51d 2006-07-23 devnull if(size+pad > ep - p)
848 5551e51d 2006-07-23 devnull return 0;
849 5551e51d 2006-07-23 devnull de = (struct fuse_dirent*)p;
850 5551e51d 2006-07-23 devnull de->ino = qid2inode(d->qid);
851 5551e51d 2006-07-23 devnull de->off = off;
852 5551e51d 2006-07-23 devnull de->namelen = strlen(d->name);
853 5551e51d 2006-07-23 devnull memmove(de->name, d->name, de->namelen);
854 5551e51d 2006-07-23 devnull if(pad > 0)
855 5551e51d 2006-07-23 devnull memset(de->name+de->namelen, 0, pad);
856 5551e51d 2006-07-23 devnull *pp = p+size+pad;
857 5551e51d 2006-07-23 devnull return 1;
861 5551e51d 2006-07-23 devnull * Write.
862 5551e51d 2006-07-23 devnull * Write from file handle in->fh at offset in->offset for size in->size.
863 5551e51d 2006-07-23 devnull * Don't know what in->write_flags means.
865 5551e51d 2006-07-23 devnull * Apparently implementations are allowed to buffer these writes
866 5551e51d 2006-07-23 devnull * and wait until Flush is sent, but FUSE docs say flush may be
867 5551e51d 2006-07-23 devnull * called zero, one, or even more times per close. So better do the
868 5551e51d 2006-07-23 devnull * actual writing here. Also, errors that happen during Flush just
869 5551e51d 2006-07-23 devnull * show up in the close() return status, which no one checks anyway.
872 5551e51d 2006-07-23 devnull fusewrite(FuseMsg *m)
874 5551e51d 2006-07-23 devnull struct fuse_write_in *in;
875 5551e51d 2006-07-23 devnull struct fuse_write_out out;
876 5551e51d 2006-07-23 devnull void *a;
877 5551e51d 2006-07-23 devnull CFid *fid;
880 5551e51d 2006-07-23 devnull in = m->tx;
881 5551e51d 2006-07-23 devnull a = in+1;
882 5551e51d 2006-07-23 devnull if((fid = fh2fid(in->fh)) == nil){
883 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
886 5551e51d 2006-07-23 devnull if(in->size > fusemaxwrite){
887 5551e51d 2006-07-23 devnull replyfuseerrno(m, EINVAL);
890 5551e51d 2006-07-23 devnull n = fswrite(fid, a, in->size);
891 5551e51d 2006-07-23 devnull if(n < 0){
892 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
895 5551e51d 2006-07-23 devnull out.size = n;
896 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
900 5551e51d 2006-07-23 devnull * Flush. Supposed to flush any buffered writes. Don't use this.
902 5551e51d 2006-07-23 devnull * Flush is a total crock. It gets called on close() of a file descriptor
903 5551e51d 2006-07-23 devnull * associated with this open file. Some open files have multiple file
904 5551e51d 2006-07-23 devnull * descriptors and thus multiple closes of those file descriptors.
905 5551e51d 2006-07-23 devnull * In those cases, Flush is called multiple times. Some open files
906 5551e51d 2006-07-23 devnull * have file descriptors that are closed on process exit instead of
907 5551e51d 2006-07-23 devnull * closed explicitly. For those files, Flush is never called.
908 5551e51d 2006-07-23 devnull * Even more amusing, Flush gets called before close() of read-only
909 5551e51d 2006-07-23 devnull * file descriptors too!
911 5551e51d 2006-07-23 devnull * This is just a bad idea.
914 5551e51d 2006-07-23 devnull fuseflush(FuseMsg *m)
916 5551e51d 2006-07-23 devnull replyfuse(m, nil, 0);
920 5551e51d 2006-07-23 devnull * Unlink & Rmdir.
923 5551e51d 2006-07-23 devnull _fuseremove(FuseMsg *m, int isdir)
925 5551e51d 2006-07-23 devnull char *name;
926 5551e51d 2006-07-23 devnull CFid *fid, *newfid;
928 5551e51d 2006-07-23 devnull name = m->tx;
929 5551e51d 2006-07-23 devnull if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
930 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
933 5551e51d 2006-07-23 devnull if(strchr(name, '/')){
934 5551e51d 2006-07-23 devnull replyfuseerrno(m, ENOENT);
937 5551e51d 2006-07-23 devnull if((newfid = fswalk(fid, name)) == nil){
938 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
941 5551e51d 2006-07-23 devnull if(isdir && !(fsqid(newfid).type&QTDIR)){
942 5551e51d 2006-07-23 devnull replyfuseerrno(m, ENOTDIR);
943 5551e51d 2006-07-23 devnull fsclose(newfid);
946 5551e51d 2006-07-23 devnull if(!isdir && (fsqid(newfid).type&QTDIR)){
947 5551e51d 2006-07-23 devnull replyfuseerrno(m, EISDIR);
948 5551e51d 2006-07-23 devnull fsclose(newfid);
951 5551e51d 2006-07-23 devnull if(fsfremove(newfid) < 0){
952 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
955 5551e51d 2006-07-23 devnull replyfuse(m, nil, 0);
959 5551e51d 2006-07-23 devnull fuseunlink(FuseMsg *m)
961 5551e51d 2006-07-23 devnull _fuseremove(m, 0);
965 5551e51d 2006-07-23 devnull fusermdir(FuseMsg *m)
967 5551e51d 2006-07-23 devnull _fuseremove(m, 1);
971 5551e51d 2006-07-23 devnull * Rename.
973 5551e51d 2006-07-23 devnull * FUSE sends the nodeid for the source and destination
974 5551e51d 2006-07-23 devnull * directory and then the before and after names as strings.
975 5551e51d 2006-07-23 devnull * 9P can only do the rename if the source and destination
976 5551e51d 2006-07-23 devnull * are the same. If the same nodeid is used for source and
977 5551e51d 2006-07-23 devnull * destination, we're fine, but if FUSE gives us different nodeids
978 5551e51d 2006-07-23 devnull * that happen to correspond to the same directory, we have
979 5551e51d 2006-07-23 devnull * no way of figuring that out. Let's hope it doesn't happen too often.
982 5551e51d 2006-07-23 devnull fuserename(FuseMsg *m)
984 5551e51d 2006-07-23 devnull struct fuse_rename_in *in;
985 5551e51d 2006-07-23 devnull char *before, *after;
986 5551e51d 2006-07-23 devnull CFid *fid, *newfid;
989 5551e51d 2006-07-23 devnull in = m->tx;
990 5551e51d 2006-07-23 devnull if(in->newdir != m->hdr->nodeid){
991 5551e51d 2006-07-23 devnull replyfuseerrno(m, EXDEV);
994 5551e51d 2006-07-23 devnull before = (char*)(in+1);
995 5551e51d 2006-07-23 devnull after = before + strlen(before) + 1;
996 5551e51d 2006-07-23 devnull if((fid = nodeid2fid(m->hdr->nodeid)) == nil){
997 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
1000 5551e51d 2006-07-23 devnull if(strchr(before, '/') || strchr(after, '/')){
1001 5551e51d 2006-07-23 devnull replyfuseerrno(m, ENOENT);
1002 5551e51d 2006-07-23 devnull return;
1004 5551e51d 2006-07-23 devnull if((newfid = fswalk(fid, before)) == nil){
1005 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
1006 5551e51d 2006-07-23 devnull return;
1008 5551e51d 2006-07-23 devnull nulldir(&d);
1009 5551e51d 2006-07-23 devnull d.name = after;
1010 5551e51d 2006-07-23 devnull if(fsdirfwstat(newfid, &d) < 0){
1011 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
1012 5551e51d 2006-07-23 devnull fsclose(newfid);
1013 5551e51d 2006-07-23 devnull return;
1015 5551e51d 2006-07-23 devnull fsclose(newfid);
1016 5551e51d 2006-07-23 devnull replyfuse(m, nil, 0);
1020 5551e51d 2006-07-23 devnull * Fsync. Commit file info to stable storage.
1021 5551e51d 2006-07-23 devnull * Not sure what in->fsync_flags are.
1024 5551e51d 2006-07-23 devnull fusefsync(FuseMsg *m)
1026 5551e51d 2006-07-23 devnull struct fuse_fsync_in *in;
1027 5551e51d 2006-07-23 devnull CFid *fid;
1030 5551e51d 2006-07-23 devnull in = m->tx;
1031 5551e51d 2006-07-23 devnull if((fid = fh2fid(in->fh)) == nil){
1032 5551e51d 2006-07-23 devnull replyfuseerrno(m, ESTALE);
1033 5551e51d 2006-07-23 devnull return;
1035 5551e51d 2006-07-23 devnull nulldir(&d);
1036 5551e51d 2006-07-23 devnull if(fsdirfwstat(fid, &d) < 0){
1037 5551e51d 2006-07-23 devnull replyfuseerrstr(m);
1038 5551e51d 2006-07-23 devnull return;
1040 5551e51d 2006-07-23 devnull replyfuse(m, nil, 0);
1044 5551e51d 2006-07-23 devnull * Fsyncdir. Commit dir info to stable storage?
1047 5551e51d 2006-07-23 devnull fusefsyncdir(FuseMsg *m)
1049 5551e51d 2006-07-23 devnull fusefsync(m);
1053 5551e51d 2006-07-23 devnull * Statfs. Send back information about file system.
1054 5551e51d 2006-07-23 devnull * Not really worth implementing, except that if we
1055 5551e51d 2006-07-23 devnull * reply with ENOSYS, programs like df print messages like
1056 5551e51d 2006-07-23 devnull * df: `/tmp/z': Function not implemented
1057 5551e51d 2006-07-23 devnull * and that gets annoying. Returning all zeros excludes
1058 5551e51d 2006-07-23 devnull * us from df without appearing to cause any problems.
1061 5551e51d 2006-07-23 devnull fusestatfs(FuseMsg *m)
1063 5551e51d 2006-07-23 devnull struct fuse_statfs_out out;
1065 5551e51d 2006-07-23 devnull memset(&out, 0, sizeof out);
1066 5551e51d 2006-07-23 devnull replyfuse(m, &out, sizeof out);
1069 5551e51d 2006-07-23 devnull void (*fusehandlers[100])(FuseMsg*);
1071 5551e51d 2006-07-23 devnull struct {
1072 5551e51d 2006-07-23 devnull int op;
1073 5551e51d 2006-07-23 devnull void (*fn)(FuseMsg*);
1074 5551e51d 2006-07-23 devnull } fuselist[] = {
1075 5551e51d 2006-07-23 devnull { FUSE_LOOKUP, fuselookup },
1076 5551e51d 2006-07-23 devnull { FUSE_FORGET, fuseforget },
1077 5551e51d 2006-07-23 devnull { FUSE_GETATTR, fusegetattr },
1078 5551e51d 2006-07-23 devnull { FUSE_SETATTR, fusesetattr },
1080 5551e51d 2006-07-23 devnull * FUSE_READLINK, FUSE_SYMLINK, FUSE_MKNOD are unimplemented.
1082 5551e51d 2006-07-23 devnull { FUSE_MKDIR, fusemkdir },
1083 5551e51d 2006-07-23 devnull { FUSE_UNLINK, fuseunlink },
1084 5551e51d 2006-07-23 devnull { FUSE_RMDIR, fusermdir },
1085 5551e51d 2006-07-23 devnull { FUSE_RENAME, fuserename },
1087 5551e51d 2006-07-23 devnull * FUSE_LINK is unimplemented.
1089 5551e51d 2006-07-23 devnull { FUSE_OPEN, fuseopen },
1090 5551e51d 2006-07-23 devnull { FUSE_READ, fuseread },
1091 5551e51d 2006-07-23 devnull { FUSE_WRITE, fusewrite },
1092 5551e51d 2006-07-23 devnull { FUSE_STATFS, fusestatfs },
1093 5551e51d 2006-07-23 devnull { FUSE_RELEASE, fuserelease },
1094 5551e51d 2006-07-23 devnull { FUSE_FSYNC, fusefsync },
1096 5551e51d 2006-07-23 devnull * FUSE_SETXATTR, FUSE_GETXATTR, FUSE_LISTXATTR, and
1097 5551e51d 2006-07-23 devnull * FUSE_REMOVEXATTR are unimplemented.
1098 5551e51d 2006-07-23 devnull * FUSE will stop sending these requests after getting
1099 5551e51d 2006-07-23 devnull * an -ENOSYS reply (see dispatch below).
1101 5551e51d 2006-07-23 devnull { FUSE_FLUSH, fuseflush },
1103 5551e51d 2006-07-23 devnull * FUSE_INIT is handled in initfuse and should not be seen again.
1105 5551e51d 2006-07-23 devnull { FUSE_OPENDIR, fuseopendir },
1106 5551e51d 2006-07-23 devnull { FUSE_READDIR, fusereaddir },
1107 5551e51d 2006-07-23 devnull { FUSE_RELEASEDIR, fusereleasedir },
1108 5551e51d 2006-07-23 devnull { FUSE_FSYNCDIR, fusefsyncdir },
1109 5551e51d 2006-07-23 devnull { FUSE_ACCESS, fuseaccess },
1110 5551e51d 2006-07-23 devnull { FUSE_CREATE, fusecreate },
1114 5551e51d 2006-07-23 devnull fusethread(void *v)
1116 5551e51d 2006-07-23 devnull FuseMsg *m;
1119 5551e51d 2006-07-23 devnull if((uint)m->hdr->opcode >= nelem(fusehandlers)
1120 5551e51d 2006-07-23 devnull || !fusehandlers[m->hdr->opcode]){
1121 5551e51d 2006-07-23 devnull replyfuseerrno(m, ENOSYS);
1122 5551e51d 2006-07-23 devnull return;
1124 5551e51d 2006-07-23 devnull fusehandlers[m->hdr->opcode](m);
1128 5551e51d 2006-07-23 devnull fusedispatch(void *v)
1131 5551e51d 2006-07-23 devnull FuseMsg *m;
1133 5551e51d 2006-07-23 devnull eofkill9pclient = 1; /* threadexitsall on 9P eof */
1134 5551e51d 2006-07-23 devnull atexit(unmountatexit);
1136 5551e51d 2006-07-23 devnull recvp(fusechan); /* sync */
1138 5551e51d 2006-07-23 devnull for(i=0; i<nelem(fuselist); i++){
1139 5551e51d 2006-07-23 devnull if(fuselist[i].op >= nelem(fusehandlers))
1140 5551e51d 2006-07-23 devnull sysfatal("make fusehandlers bigger op=%d", fuselist[i].op);
1141 5551e51d 2006-07-23 devnull fusehandlers[fuselist[i].op] = fuselist[i].fn;
1144 5551e51d 2006-07-23 devnull while((m = recvp(fusechan)) != nil)
1145 5551e51d 2006-07-23 devnull threadcreate(fusethread, m, STACK);
1149 5551e51d 2006-07-23 devnull emalloc(uint n)
1151 5551e51d 2006-07-23 devnull void *p;
1153 5551e51d 2006-07-23 devnull p = malloc(n);
1154 5551e51d 2006-07-23 devnull if(p == nil)
1155 5551e51d 2006-07-23 devnull sysfatal("malloc(%d): %r", n);
1156 5551e51d 2006-07-23 devnull memset(p, 0, n);
1157 5551e51d 2006-07-23 devnull return p;
1161 5551e51d 2006-07-23 devnull erealloc(void *p, uint n)
1163 5551e51d 2006-07-23 devnull p = realloc(p, n);
1164 5551e51d 2006-07-23 devnull if(p == nil)
1165 5551e51d 2006-07-23 devnull sysfatal("realloc(..., %d): %r", n);
1166 5551e51d 2006-07-23 devnull return p;
1170 5551e51d 2006-07-23 devnull estrdup(char *p)
1172 5551e51d 2006-07-23 devnull char *pp;
1173 5551e51d 2006-07-23 devnull pp = strdup(p);
1174 5551e51d 2006-07-23 devnull if(pp == nil)
1175 5551e51d 2006-07-23 devnull sysfatal("strdup(%.20s): %r", p);
1176 5551e51d 2006-07-23 devnull return pp;