refuse.c revision 1.19 1 /* $NetBSD: refuse.c,v 1.19 2007/02/18 00:01:18 pooka Exp $ */
2
3 /*
4 * Copyright 2007 Alistair Crooks. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 #if !defined(lint)
33 __RCSID("$NetBSD: refuse.c,v 1.19 2007/02/18 00:01:18 pooka Exp $");
34 #endif /* !lint */
35
36 #include <err.h>
37 #include <errno.h>
38 #include <fuse.h>
39 #include <ucontext.h>
40 #include <unistd.h>
41
42 #include "defs.h"
43
44 typedef uint64_t fuse_ino_t;
45
46 struct fuse_config {
47 uid_t uid;
48 gid_t gid;
49 mode_t umask;
50 double entry_timeout;
51 double negative_timeout;
52 double attr_timeout;
53 double ac_attr_timeout;
54 int ac_attr_timeout_set;
55 int debug;
56 int hard_remove;
57 int use_ino;
58 int readdir_ino;
59 int set_mode;
60 int set_uid;
61 int set_gid;
62 int direct_io;
63 int kernel_cache;
64 int auto_cache;
65 int intr;
66 int intr_signal;
67 };
68
69 /* this is the private fuse structure */
70 struct fuse {
71 struct fuse_session *se; /* fuse session pointer */
72 struct fuse_operations op; /* switch table of operations */
73 int compat; /* compat level -
74 * not used in puffs_fuse */
75 struct node **name_table;
76 size_t name_table_size;
77 struct node **id_table;
78 size_t id_table_size;
79 fuse_ino_t ctr;
80 unsigned int generation;
81 unsigned int hidectr;
82 pthread_mutex_t lock;
83 pthread_rwlock_t tree_lock;
84 void *user_data;
85 struct fuse_config conf;
86 int intr_installed;
87 struct puffs_usermount *pu;
88 };
89
90 struct refusenode {
91 struct fuse_file_info file_info;
92 };
93
94 static struct puffs_node *
95 newrn(struct puffs_usermount *pu)
96 {
97 struct puffs_node *pn;
98 struct refusenode *rn;
99
100 rn = malloc(sizeof(struct refusenode));
101 if (!rn)
102 abort(); /*XXX*/
103
104 memset(rn, 0, sizeof(struct refusenode));
105 pn = puffs_pn_new(pu, rn);
106
107 return pn;
108 }
109
110 static void
111 nukern(struct puffs_node *pn)
112 {
113
114 free(pn->pn_data);
115 puffs_pn_put(pn);
116 }
117
118 static ino_t fakeino = 3;
119
120 /* XXX: rethinkme */
121 struct fuse_dirh {
122 struct dirent *dent;
123 size_t reslen;
124 off_t readoff;
125 };
126
127 /* ARGSUSED2 */
128 static int
129 puffs_fuse_fill_dir(void *buf, const char *name,
130 const struct stat *stbuf, off_t off)
131 {
132 struct fuse_dirh *deh = buf;
133 ino_t dino;
134 uint8_t dtype;
135
136 if (stbuf == NULL) {
137 dtype = DT_UNKNOWN;
138 dino = fakeino++;
139 } else {
140 dtype = puffs_vtype2dt(puffs_mode2vt(stbuf->st_mode));
141 dino = stbuf->st_ino;
142 }
143
144 return !puffs_nextdent(&deh->dent, name, dino, dtype, &deh->reslen);
145 }
146
147 static int
148 puffs_fuse_dirfil(fuse_dirh_t h, const char *name, int type, ino_t ino)
149 {
150 ino_t dino;
151 int dtype;
152
153 if (type == 0)
154 dtype = DT_UNKNOWN;
155 else
156 dtype = type;
157
158 if (ino)
159 dino = ino;
160 else
161 dino = fakeino++;
162
163 return !puffs_nextdent(&h->dent, name, dino, dtype, &h->reslen);
164 }
165
166 int
167 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
168 {
169 char **oldargv;
170 int oldargc;
171
172 if (args->allocated) {
173 RENEW(char *, args->argv, args->argc + 1,
174 "fuse_opt_add_arg1", return 0);
175 } else {
176 oldargv = args->argv;
177 oldargc = args->argc;
178 NEWARRAY(char *, args->argv, oldargc + 1,
179 "fuse_opt_add_arg2", return 0);
180 (void) memcpy(args->argv, oldargv, oldargc * sizeof(char *));
181 args->allocated = 1;
182 }
183 args->argv[args->argc++] = strdup(arg);
184 return 1;
185 }
186
187 #define FUSE_ERR_UNLINK(fuse, file) if (fuse->op.unlink) fuse->op.unlink(file)
188 #define FUSE_ERR_RMDIR(fuse, dir) if (fuse->op.rmdir) fuse->op.rmdir(dir)
189
190 /* operation wrappers start here */
191
192 /* lookup the path */
193 /* ARGSUSED1 */
194 static int
195 puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
196 enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
197 const struct puffs_cn *pcn)
198 {
199 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
200 struct puffs_node *pn_res;
201 struct stat st;
202 struct fuse *fuse;
203 const char *path = PCNPATH(pcn);
204 int ret;
205
206 fuse = (struct fuse *)pu->pu_privdata;
207 ret = fuse->op.getattr(path, &st);
208
209 if (ret != 0) {
210 return -ret;
211 }
212
213 /* XXX: fiXXXme unconst */
214 pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
215 __UNCONST(&pcn->pcn_po_full));
216 if (pn_res == NULL) {
217 pn_res = newrn(pu);
218 if (pn_res == NULL)
219 return errno;
220 puffs_stat2vattr(&pn_res->pn_va, &st);
221 }
222
223 *newnode = pn_res;
224 *newtype = pn_res->pn_va.va_type;
225 *newsize = pn_res->pn_va.va_size;
226 *newrdev = pn_res->pn_va.va_rdev;
227
228 return 0;
229 }
230
231 /* get attributes for the path name */
232 /* ARGSUSED3 */
233 static int
234 puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
235 const struct puffs_cred *pcr, pid_t pid)
236 {
237 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
238 struct puffs_node *pn = opc;
239 struct stat st;
240 struct fuse *fuse;
241 const char *path = PNPATH(pn);
242 int ret;
243
244 fuse = (struct fuse *)pu->pu_privdata;
245 if (fuse->op.getattr == NULL) {
246 return ENOSYS;
247 }
248
249 /* wrap up return code */
250 ret = (*fuse->op.getattr)(path, &st);
251
252 if (ret == 0) {
253 /* fill in va from st */
254 va->va_mode = st.st_mode;
255 va->va_nlink = st.st_nlink;
256 va->va_uid = st.st_uid;
257 va->va_gid = st.st_gid;
258 va->va_fsid = st.st_rdev;
259 va->va_fileid = st.st_ino;
260 va->va_size = st.st_size;
261 va->va_blocksize = st.st_blksize;
262 va->va_atime = st.st_atimespec;
263 va->va_mtime = st.st_mtimespec;
264 va->va_ctime = st.st_ctimespec;
265 va->va_birthtime = st.st_birthtimespec;
266 va->va_gen = st.st_gen;
267 va->va_flags = st.st_flags;
268 va->va_rdev = st.st_rdev;
269 va->va_bytes = st.st_size;
270 va->va_filerev = st.st_gen;
271 va->va_vaflags = st.st_flags;
272
273 }
274
275 return -ret;
276 }
277
278 /* read the contents of the symbolic link */
279 /* ARGSUSED2 */
280 static int
281 puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
282 const struct puffs_cred *cred, char *linkname, size_t *linklen)
283 {
284 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
285 struct puffs_node *pn = opc;
286 struct fuse *fuse;
287 const char *path = PNPATH(pn), *p;
288 int ret;
289
290 fuse = (struct fuse *)pu->pu_privdata;
291 if (fuse->op.readlink == NULL) {
292 return ENOSYS;
293 }
294
295 /* wrap up return code */
296 ret = (*fuse->op.readlink)(path, linkname, *linklen);
297
298 if (ret == 0) {
299 p = memchr(linkname, '\0', *linklen);
300 if (!p)
301 return EINVAL;
302
303 *linklen = p - linkname;
304 }
305
306 return -ret;
307 }
308
309 /* make the special node */
310 /* ARGSUSED1 */
311 static int
312 puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
313 const struct puffs_cn *pcn, const struct vattr *va)
314 {
315 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
316 struct puffs_node *pn;
317 struct fuse *fuse;
318 mode_t mode = va->va_mode;
319 const char *path = PCNPATH(pcn);
320 int ret;
321
322 fuse = (struct fuse *)pu->pu_privdata;
323 if (fuse->op.mknod == NULL) {
324 return ENOSYS;
325 }
326
327 /* wrap up return code */
328 ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
329
330 if (ret == 0) {
331 /* fix up nodes */
332 pn = newrn(pu);
333 if (pn == NULL) {
334 FUSE_ERR_UNLINK(fuse, path);
335 return ENOMEM;
336 }
337 puffs_setvattr(&pn->pn_va, va);
338
339 *newnode = pn;
340 }
341
342 return -ret;
343 }
344
345 /* make a directory */
346 /* ARGSUSED1 */
347 static int
348 puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
349 const struct puffs_cn *pcn, const struct vattr *va)
350 {
351 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
352 struct puffs_node *pn;
353 struct fuse *fuse;
354 mode_t mode = va->va_mode;
355 const char *path = PCNPATH(pcn);
356 int ret;
357
358 fuse = (struct fuse *)pu->pu_privdata;
359 if (fuse->op.mkdir == NULL) {
360 return ENOSYS;
361 }
362
363 /* wrap up return code */
364 ret = (*fuse->op.mkdir)(path, mode);
365
366 if (ret == 0) {
367 /* fix up nodes */
368 pn = newrn(pu);
369 if (pn == NULL) {
370 FUSE_ERR_RMDIR(fuse, path);
371 return ENOMEM;
372 }
373 puffs_setvattr(&pn->pn_va, va);
374
375 *newnode = pn;
376 }
377
378 return -ret;
379 }
380
381 /* create a regular file */
382 /*ARGSUSED1*/
383 static int
384 puffs_fuse_node_create(struct puffs_cc *pcc, void *opc, void **newnode,
385 const struct puffs_cn *pcn, const struct vattr *va)
386 {
387 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
388 struct puffs_node *pn;
389 struct refusenode *rn;
390 struct fuse *fuse;
391 struct fuse_file_info fi;
392 mode_t mode = va->va_mode;
393 const char *path = PCNPATH(pcn);
394 int ret;
395
396 fuse = (struct fuse *)pu->pu_privdata;
397 if (fuse->op.create == NULL) {
398 return ENOSYS;
399 }
400
401 /* wrap up return code */
402 ret = (*fuse->op.create)(path, mode, &fi);
403
404 if (ret == 0) {
405 /* fix up nodes */
406 pn = newrn(pu);
407 if (pn == NULL) {
408 FUSE_ERR_UNLINK(fuse, path);
409 return ENOMEM;
410 }
411 puffs_setvattr(&pn->pn_va, va);
412
413 rn = pn->pn_data;
414 memcpy(&rn->file_info, &fi, sizeof(struct fuse_file_info));
415
416 *newnode = pn;
417 }
418
419 return -ret;
420 }
421
422 /* remove the directory entry */
423 /* ARGSUSED1 */
424 static int
425 puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
426 const struct puffs_cn *pcn)
427 {
428 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
429 struct fuse *fuse;
430 const char *path = PCNPATH(pcn);
431 int ret;
432
433 fuse = (struct fuse *)pu->pu_privdata;
434 if (fuse->op.unlink == NULL) {
435 return ENOSYS;
436 }
437
438 /* wrap up return code */
439 ret = (*fuse->op.unlink)(path);
440
441 return -ret;
442 }
443
444 /* remove the directory */
445 /* ARGSUSED1 */
446 static int
447 puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
448 const struct puffs_cn *pcn)
449 {
450 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
451 struct fuse *fuse;
452 const char *path = PCNPATH(pcn);
453 int ret;
454
455 fuse = (struct fuse *)pu->pu_privdata;
456 if (fuse->op.rmdir == NULL) {
457 return ENOSYS;
458 }
459
460 /* wrap up return code */
461 ret = (*fuse->op.rmdir)(path);
462
463 return -ret;
464 }
465
466 /* create a symbolic link */
467 /* ARGSUSED1 */
468 static int
469 puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
470 const struct puffs_cn *pcn_src, const struct vattr *va,
471 const char *link_target)
472 {
473 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
474 struct puffs_node *pn;
475 struct fuse *fuse;
476 const char *path = PCNPATH(pcn_src);
477 int ret;
478
479 fuse = (struct fuse *)pu->pu_privdata;
480 if (fuse->op.symlink == NULL) {
481 return ENOSYS;
482 }
483
484 /* wrap up return code */
485 ret = (*fuse->op.symlink)(path, link_target);
486 /* XXX - check I haven't transposed these args */
487
488 if (ret == 0) {
489 /* fix up nodes */
490 pn = newrn(pu);
491 if (pn == NULL) {
492 FUSE_ERR_UNLINK(fuse, path);
493 return ENOMEM;
494 }
495 puffs_setvattr(&pn->pn_va, va);
496
497 *newnode = pn;
498 }
499
500 return -ret;
501 }
502
503 /* rename a directory entry */
504 /* ARGSUSED1 */
505 static int
506 puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
507 const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
508 const struct puffs_cn *pcn_targ)
509 {
510 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
511 struct puffs_node *pn = opc;
512 struct vattr va;
513 struct fuse *fuse;
514 const char *path = PCNPATH(pcn_src);
515 int ret;
516
517 fuse = (struct fuse *)pu->pu_privdata;
518 if (fuse->op.rename == NULL) {
519 return ENOSYS;
520 }
521
522 /* wrap up return code */
523 ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
524
525 /* XXX: what's this guy doing??? */
526 if (ret == 0) {
527 (void) memcpy(&va, &pn->pn_va, sizeof(va));
528
529 puffs_pn_put(pn);
530
531 pn = puffs_pn_new(pu, NULL);
532 if (pn == NULL) {
533 return ENOMEM;
534 }
535 puffs_setvattr(&pn->pn_va, &va);
536
537 }
538
539 return -ret;
540 }
541
542 /* create a link in the file system */
543 /* ARGSUSED1 */
544 static int
545 puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
546 const struct puffs_cn *pcn)
547 {
548 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
549 struct puffs_node *pn = targ;
550 struct fuse *fuse;
551 int ret;
552
553 fuse = (struct fuse *)pu->pu_privdata;
554 if (fuse->op.link == NULL) {
555 return ENOSYS;
556 }
557
558 /* wrap up return code */
559 ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
560
561 return -ret;
562 }
563
564 /*
565 * fuse's regular interface provides chmod(), chown(), utimes()
566 * and truncate() + some variations, so try to fit the square block
567 * in the circle hole and the circle block .... something like that
568 */
569 /* ARGSUSED3 */
570 static int
571 puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
572 const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
573 {
574 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
575 struct puffs_node *pn = opc;
576 struct refusenode *rn = pn->pn_data;
577 struct fuse *fuse;
578 const char *path = PNPATH(pn);
579 mode_t mode;
580 uid_t uid;
581 gid_t gid;
582 int error, ret;
583
584 fuse = (struct fuse *)pu->pu_privdata;
585
586 error = 0;
587
588 mode = va->va_mode;
589 uid = va->va_uid;
590 gid = va->va_gid;
591
592 if (mode != (mode_t)PUFFS_VNOVAL) {
593 ret = 0;
594
595 if (fuse->op.chmod == NULL) {
596 error = -ENOSYS;
597 } else {
598 ret = fuse->op.chmod(path, mode);
599 if (ret)
600 error = ret;
601 }
602 }
603 if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
604 ret = 0;
605
606 if (fuse->op.chown == NULL) {
607 error = -ENOSYS;
608 } else {
609 ret = fuse->op.chown(path, uid, gid);
610 if (ret)
611 error = ret;
612 }
613 }
614 if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
615 || va->va_mtime.tv_sec != (long)PUFFS_VNOVAL) {
616 ret = 0;
617
618 if (fuse->op.utimens) {
619 struct timespec tv[2];
620
621 tv[0].tv_sec = va->va_atime.tv_sec;
622 tv[0].tv_nsec = va->va_atime.tv_nsec;
623 tv[1].tv_sec = va->va_mtime.tv_sec;
624 tv[1].tv_nsec = va->va_mtime.tv_nsec;
625
626 ret = fuse->op.utimens(path, tv);
627 } else if (fuse->op.utime) {
628 struct utimbuf timbuf;
629
630 timbuf.actime = va->va_atime.tv_sec;
631 timbuf.modtime = va->va_mtime.tv_sec;
632
633 ret = fuse->op.utime(path, &timbuf);
634 } else {
635 error = -ENOSYS;
636 }
637
638 if (ret)
639 error = ret;
640 }
641 if (va->va_size != (u_quad_t)PUFFS_VNOVAL) {
642 ret = 0;
643
644 if (fuse->op.truncate) {
645 ret = fuse->op.truncate(path, (off_t)va->va_size);
646 } else if (fuse->op.ftruncate) {
647 ret = fuse->op.ftruncate(path, (off_t)va->va_size,
648 &rn->file_info);
649 } else {
650 error = -ENOSYS;
651 }
652
653 if (ret)
654 error = ret;
655 }
656
657 return -error;
658 }
659
660 /* ARGSUSED2 */
661 static int
662 puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
663 const struct puffs_cred *cred, pid_t pid)
664 {
665 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
666 struct puffs_node *pn = opc;
667 struct refusenode *rn = pn->pn_data;
668 struct fuse *fuse;
669 struct stat st;
670 const char *path = PNPATH(pn);
671 int ret;
672
673 fuse = (struct fuse *)pu->pu_privdata;
674 if (fuse->op.open == NULL) {
675 return ENOSYS;
676 }
677
678 /* examine type - if directory, return 0 rather than open */
679 ret = (fuse->op.getattr == NULL) ?
680 stat(path, &st) :
681 (*fuse->op.getattr)(path, &st);
682 if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
683 return 0;
684 }
685
686 if (strcmp(path, "/") == 0) {
687 return 0;
688 }
689
690 ret = (*fuse->op.open)(path, &rn->file_info);
691
692 if (ret == 0) {
693 }
694
695 return -ret;
696 }
697
698 /* read some more from the file */
699 /* ARGSUSED5 */
700 static int
701 puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
702 off_t offset, size_t *resid, const struct puffs_cred *pcr,
703 int ioflag)
704 {
705 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
706 struct puffs_node *pn = opc;
707 struct refusenode *rn = pn->pn_data;
708 struct fuse *fuse;
709 const char *path = PNPATH(pn);
710 int ret;
711
712 fuse = (struct fuse *)pu->pu_privdata;
713 if (fuse->op.read == NULL) {
714 return ENOSYS;
715 }
716
717 ret = (*fuse->op.read)(path, (char *)buf, *resid, offset,
718 &rn->file_info);
719
720 if (ret > 0) {
721 *resid -= ret;
722 ret = 0;
723 }
724
725 return -ret;
726 }
727
728 /* write to the file */
729 /* ARGSUSED0 */
730 static int
731 puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
732 off_t offset, size_t *resid, const struct puffs_cred *pcr,
733 int ioflag)
734 {
735 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
736 struct puffs_node *pn = opc;
737 struct refusenode *rn = pn->pn_data;
738 struct fuse *fuse;
739 const char *path = PNPATH(pn);
740 int ret;
741
742 fuse = (struct fuse *)pu->pu_privdata;
743 if (fuse->op.write == NULL) {
744 return ENOSYS;
745 }
746
747 if (ioflag & PUFFS_IO_APPEND)
748 offset = pn->pn_va.va_size;
749
750 ret = (*fuse->op.write)(path, (char *)buf, *resid, offset,
751 &rn->file_info);
752
753 if (ret > 0) {
754 *resid -= ret;
755 ret = 0;
756 }
757
758 return -ret;
759 }
760
761
762 /* ARGSUSED3 */
763 static int
764 puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
765 struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
766 size_t *reslen)
767 {
768 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
769 struct puffs_node *pn = opc;
770 struct refusenode *rn = pn->pn_data;
771 struct fuse *fuse;
772 const char *path = PNPATH(pn);
773 struct fuse_dirh deh;
774 int ret;
775
776 fuse = (struct fuse *)pu->pu_privdata;
777 if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
778 return ENOSYS;
779 }
780
781 /* XXX: how to handle this??? */
782 if (*readoff != 0) {
783 return 0;
784 }
785
786 deh.dent = dent;
787 deh.reslen = *reslen;
788 deh.readoff = *readoff;
789
790 if (fuse->op.readdir)
791 ret = fuse->op.readdir(path, &deh, puffs_fuse_fill_dir,
792 *readoff, &rn->file_info);
793 else
794 ret = fuse->op.getdir(path, &deh, puffs_fuse_dirfil);
795 *reslen = deh.reslen;
796 *readoff = 1;
797
798 if (ret == 0) {
799 }
800
801 return -ret;
802 }
803
804 /* ARGSUSED */
805 static int
806 puffs_fuse_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
807 {
808 struct puffs_node *pn = opc;
809
810 nukern(pn);
811
812 return 0;
813 }
814
815 /* ARGSUSED1 */
816 static int
817 puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
818 {
819 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
820 struct fuse *fuse;
821
822 fuse = (struct fuse *)pu->pu_privdata;
823 if (fuse->op.destroy == NULL) {
824 return 0;
825 }
826 (*fuse->op.destroy)(fuse);
827 return 0;
828 }
829
830 /* ARGSUSED0 */
831 static int
832 puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
833 const struct puffs_cred *cr, pid_t pid)
834 {
835 return 0;
836 }
837
838 /* ARGSUSED2 */
839 static int
840 puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
841 {
842 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
843 struct fuse *fuse;
844 int ret;
845
846 fuse = (struct fuse *)pu->pu_privdata;
847 if (fuse->op.statfs == NULL) {
848 if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
849 return errno;
850 }
851 } else {
852 ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
853 }
854
855 return ret;
856 }
857
858
859
860
861 /* End of puffs_fuse operations */
862
863 /*
864 * XXX: do this otherwise if/when we grow thread support
865 *
866 * XXX2: does not supply uid, gid or pid currently
867 */
868 static struct fuse_context fcon;
869
870 /* ARGSUSED3 */
871 int
872 fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
873 size_t size, void *userdata)
874 {
875 struct puffs_usermount *pu;
876 struct puffs_pathobj *po_root;
877 struct puffs_ops *pops;
878 struct statvfs svfsb;
879 struct fuse *fuse;
880 char name[64];
881 char *slash;
882 int ret;
883
884 /* initialise the puffs operations structure */
885 PUFFSOP_INIT(pops);
886
887 PUFFSOP_SET(pops, puffs_fuse, fs, sync);
888 PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
889 PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
890
891 /*
892 * XXX: all of these don't possibly need to be
893 * unconditionally set
894 */
895 PUFFSOP_SET(pops, puffs_fuse, node, lookup);
896 PUFFSOP_SET(pops, puffs_fuse, node, getattr);
897 PUFFSOP_SET(pops, puffs_fuse, node, setattr);
898 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
899 PUFFSOP_SET(pops, puffs_fuse, node, readlink);
900 PUFFSOP_SET(pops, puffs_fuse, node, mknod);
901 PUFFSOP_SET(pops, puffs_fuse, node, create);
902 PUFFSOP_SET(pops, puffs_fuse, node, remove);
903 PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
904 PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
905 PUFFSOP_SET(pops, puffs_fuse, node, symlink);
906 PUFFSOP_SET(pops, puffs_fuse, node, rename);
907 PUFFSOP_SET(pops, puffs_fuse, node, link);
908 PUFFSOP_SET(pops, puffs_fuse, node, open);
909 PUFFSOP_SET(pops, puffs_fuse, node, read);
910 PUFFSOP_SET(pops, puffs_fuse, node, write);
911 PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
912
913 NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
914
915 /* copy fuse ops to their own stucture */
916 (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
917
918 fcon.fuse = fuse;
919 fcon.private_data = userdata;
920
921 /* whilst this (assigning the pu_privdata in the puffs
922 * usermount struct to be the fuse struct) might seem like
923 * we are chasing our tail here, the logic is as follows:
924 + the operation wrapper gets called with the puffs
925 calling conventions
926 + we need to fix up args first
927 + then call the fuse user-supplied operation
928 + then we fix up any values on return that we need to
929 + and fix up any nodes, etc
930 * so we need to be able to get at the fuse ops from within the
931 * puffs_usermount struct
932 */
933 if ((slash = strrchr(*argv, '/')) == NULL) {
934 slash = *argv;
935 } else {
936 slash += 1;
937 }
938 (void) snprintf(name, sizeof(name), "refuse:%s", slash);
939 pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
940 name, fuse,
941 PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
942 if (pu == NULL) {
943 err(EXIT_FAILURE, "puffs_mount");
944 }
945
946 fuse->pu = pu;
947 pu->pu_pn_root = puffs_pn_new(pu, NULL);
948 po_root = puffs_getrootpathobj(pu);
949 po_root->po_path = strdup("/");
950 po_root->po_len = 1;
951
952 if (fuse->op.init)
953 fcon.private_data = fuse->op.init(NULL); /* XXX */
954
955 statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
956 if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
957 err(EXIT_FAILURE, "puffs_start");
958 }
959
960 ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
961
962 (void) free(po_root->po_path);
963 FREE(fuse);
964 return ret;
965 }
966
967 /* ARGSUSED0 */
968 int
969 fuse_opt_parse(struct fuse_args *args, void *data,
970 const struct fuse_opt *opts, fuse_opt_proc_t proc)
971 {
972 return 0;
973 }
974
975 /* XXX: threads */
976 struct fuse_context *
977 fuse_get_context()
978 {
979
980 return &fcon;
981 }
982