refuse.c revision 1.12 1 /* $NetBSD: refuse.c,v 1.12 2007/02/15 17:06:24 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.12 2007/02/15 17:06:24 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 uint8_t dtype;
134
135 /* XXX: this is hacked *purely* for hellofs, so fiXXXme */
136 if (*name == '.')
137 dtype = DT_DIR;
138 else
139 dtype = DT_REG;
140
141 return !puffs_nextdent(&deh->dent, name, fakeino++, dtype,&deh->reslen);
142 }
143
144 static int
145 puffs_fuse_dirfil(fuse_dirh_t h, const char *name, int type, ino_t ino)
146 {
147 ino_t dino;
148 int dtype;
149
150 /* XXX: this is hacked *purely* for cddafs, so fiXXXme */
151 if (type == 0) {
152 if (*name == '.')
153 dtype = DT_DIR;
154 else
155 dtype = DT_REG;
156 } else
157 dtype = type;
158
159 if (ino)
160 dino = ino;
161 else
162 dino = fakeino++;
163
164 return !puffs_nextdent(&h->dent, name, dino, dtype, &h->reslen);
165 }
166
167 int
168 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
169 {
170 char **oldargv;
171 int oldargc;
172
173 if (args->allocated) {
174 RENEW(char *, args->argv, args->argc + 1,
175 "fuse_opt_add_arg1", return 0);
176 } else {
177 oldargv = args->argv;
178 oldargc = args->argc;
179 NEWARRAY(char *, args->argv, oldargc + 1,
180 "fuse_opt_add_arg2", return 0);
181 (void) memcpy(args->argv, oldargv, oldargc * sizeof(char *));
182 args->allocated = 1;
183 }
184 args->argv[args->argc++] = strdup(arg);
185 return 1;
186 }
187
188 /* operation wrappers start here */
189
190 /* lookup the path */
191 /* ARGSUSED1 */
192 static int
193 puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
194 enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
195 const struct puffs_cn *pcn)
196 {
197 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
198 struct puffs_node *pn_res;
199 struct stat st;
200 struct fuse *fuse;
201 const char *path = PCNPATH(pcn);
202 int ret;
203
204 fuse = (struct fuse *)pu->pu_privdata;
205 ret = fuse->op.getattr(path, &st);
206
207 if (ret != 0) {
208 return -ret; /* XXX: linux foo */
209 }
210
211 /* XXX: fiXXXme unconst */
212 pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
213 __UNCONST(&pcn->pcn_po_full));
214 if (pn_res == NULL) {
215 pn_res = newrn(pu);
216 if (pn_res == NULL)
217 return errno;
218 puffs_stat2vattr(&pn_res->pn_va, &st);
219 }
220
221 *newnode = pn_res;
222 *newtype = pn_res->pn_va.va_type;
223 *newsize = pn_res->pn_va.va_size;
224 *newrdev = pn_res->pn_va.va_rdev;
225
226 return 0;
227 }
228
229 /* get attributes for the path name */
230 /* ARGSUSED3 */
231 static int
232 puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
233 const struct puffs_cred *pcr, pid_t pid)
234 {
235 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
236 struct puffs_node *pn = opc;
237 struct stat st;
238 struct fuse *fuse;
239 const char *path = PNPATH(pn);
240 int ret;
241
242 fuse = (struct fuse *)pu->pu_privdata;
243 if (fuse->op.getattr == NULL) {
244 return ENOSYS;
245 }
246
247 /* wrap up return code */
248 ret = (*fuse->op.getattr)(path, &st);
249
250 if (ret == 0) {
251 /* fill in va from st */
252 va->va_mode = st.st_mode;
253 va->va_nlink = st.st_nlink;
254 va->va_uid = st.st_uid;
255 va->va_gid = st.st_gid;
256 va->va_fsid = st.st_rdev;
257 va->va_fileid = st.st_ino;
258 va->va_size = st.st_size;
259 va->va_blocksize = st.st_blksize;
260 va->va_atime = st.st_atimespec;
261 va->va_mtime = st.st_mtimespec;
262 va->va_ctime = st.st_ctimespec;
263 va->va_birthtime = st.st_birthtimespec;
264 va->va_gen = st.st_gen;
265 va->va_flags = st.st_flags;
266 va->va_rdev = st.st_rdev;
267 va->va_bytes = st.st_size;
268 va->va_filerev = st.st_gen;
269 va->va_vaflags = st.st_flags;
270
271 }
272
273 return ret;
274 }
275
276 /* read the contents of the symbolic link */
277 /* ARGSUSED2 */
278 static int
279 puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
280 const struct puffs_cred *cred, char *linkname, size_t *linklen)
281 {
282 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
283 struct puffs_node *pn = opc;
284 struct fuse *fuse;
285 const char *path = PNPATH(pn);
286 int ret;
287
288 fuse = (struct fuse *)pu->pu_privdata;
289 if (fuse->op.readlink == NULL) {
290 return ENOSYS;
291 }
292
293 /* wrap up return code */
294 ret = (*fuse->op.readlink)(path, linkname, *linklen);
295
296 if (ret == 0) {
297 }
298
299 return ret;
300 }
301
302 /* make the special node */
303 /* ARGSUSED1 */
304 static int
305 puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
306 const struct puffs_cn *pcn, const struct vattr *va)
307 {
308 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
309 struct puffs_node *pn;
310 struct fuse *fuse;
311 mode_t mode = va->va_mode;
312 const char *path = PCNPATH(pcn);
313 int ret;
314
315 fuse = (struct fuse *)pu->pu_privdata;
316 if (fuse->op.mknod == NULL) {
317 return ENOSYS;
318 }
319
320 /* wrap up return code */
321 ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
322
323 if (ret == 0) {
324 /* fix up nodes */
325 pn = newrn(pu);
326 if (pn == NULL) {
327 unlink(PCNPATH(pcn));
328 return ENOMEM;
329 }
330 puffs_setvattr(&pn->pn_va, va);
331
332 *newnode = pn;
333 }
334
335 return ret;
336 }
337
338 /* make a directory */
339 /* ARGSUSED1 */
340 static int
341 puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
342 const struct puffs_cn *pcn, const struct vattr *va)
343 {
344 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
345 struct puffs_node *pn;
346 struct fuse *fuse;
347 mode_t mode = va->va_mode;
348 const char *path = PCNPATH(pcn);
349 int ret;
350
351 fuse = (struct fuse *)pu->pu_privdata;
352 if (fuse->op.mkdir == NULL) {
353 return ENOSYS;
354 }
355
356 /* wrap up return code */
357 ret = (*fuse->op.mkdir)(path, mode);
358
359 if (ret == 0) {
360 /* fix up nodes */
361 pn = newrn(pu);
362 if (pn == NULL) {
363 rmdir(PCNPATH(pcn));
364 return ENOMEM;
365 }
366 puffs_setvattr(&pn->pn_va, va);
367
368 *newnode = pn;
369 }
370
371 return ret;
372 }
373
374 /* remove the directory entry */
375 /* ARGSUSED1 */
376 static int
377 puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
378 const struct puffs_cn *pcn)
379 {
380 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
381 struct fuse *fuse;
382 const char *path = PCNPATH(pcn);
383 int ret;
384
385 fuse = (struct fuse *)pu->pu_privdata;
386 if (fuse->op.unlink == NULL) {
387 return ENOSYS;
388 }
389
390 /* wrap up return code */
391 ret = (*fuse->op.unlink)(path);
392
393 return ret;
394 }
395
396 /* remove the directory */
397 /* ARGSUSED1 */
398 static int
399 puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
400 const struct puffs_cn *pcn)
401 {
402 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
403 struct fuse *fuse;
404 const char *path = PCNPATH(pcn);
405 int ret;
406
407 fuse = (struct fuse *)pu->pu_privdata;
408 if (fuse->op.rmdir == NULL) {
409 return ENOSYS;
410 }
411
412 /* wrap up return code */
413 ret = (*fuse->op.rmdir)(path);
414
415 return ret;
416 }
417
418 /* create a symbolic link */
419 /* ARGSUSED1 */
420 static int
421 puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
422 const struct puffs_cn *pcn_src, const struct vattr *va,
423 const char *link_target)
424 {
425 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
426 struct puffs_node *pn;
427 struct fuse *fuse;
428 const char *path = PCNPATH(pcn_src);
429 int ret;
430
431 fuse = (struct fuse *)pu->pu_privdata;
432 if (fuse->op.symlink == NULL) {
433 return ENOSYS;
434 }
435
436 /* wrap up return code */
437 ret = (*fuse->op.symlink)(path, link_target);
438 /* XXX - check I haven't transposed these args */
439
440 if (ret == 0) {
441 /* fix up nodes */
442 pn = newrn(pu);
443 if (pn == NULL) {
444 unlink(link_target);
445 return ENOMEM;
446 }
447 puffs_setvattr(&pn->pn_va, va);
448
449 *newnode = pn;
450 }
451
452 return ret;
453 }
454
455 /* rename a directory entry */
456 /* ARGSUSED1 */
457 static int
458 puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
459 const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
460 const struct puffs_cn *pcn_targ)
461 {
462 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
463 struct puffs_node *pn = opc;
464 struct vattr va;
465 struct fuse *fuse;
466 const char *path = PCNPATH(pcn_src);
467 int ret;
468
469 fuse = (struct fuse *)pu->pu_privdata;
470 if (fuse->op.rename == NULL) {
471 return ENOSYS;
472 }
473
474 /* wrap up return code */
475 ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
476
477 /* XXX: what's this guy doing??? */
478 if (ret == 0) {
479 (void) memcpy(&va, &pn->pn_va, sizeof(va));
480
481 puffs_pn_put(pn);
482
483 pn = puffs_pn_new(pu, NULL);
484 if (pn == NULL) {
485 return ENOMEM;
486 }
487 puffs_setvattr(&pn->pn_va, &va);
488
489 }
490
491 return ret;
492 }
493
494 /* create a link in the file system */
495 /* ARGSUSED1 */
496 static int
497 puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
498 const struct puffs_cn *pcn)
499 {
500 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
501 struct puffs_node *pn = targ;
502 struct fuse *fuse;
503 int ret;
504
505 fuse = (struct fuse *)pu->pu_privdata;
506 if (fuse->op.link == NULL) {
507 return ENOSYS;
508 }
509
510 /* wrap up return code */
511 ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
512
513 return ret;
514 }
515
516 /*
517 * We run into a slight problemette here - puffs provides
518 * setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
519 * functionality. So that we don't miss out on anything when calling a
520 * fuse operation, we have to get the vattr from the existing file,
521 * find out what's changed, and then switch on that to call the fuse
522 * function accordingly.
523 */
524 /* ARGSUSED3 */
525 static int
526 puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
527 const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
528 {
529 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
530 struct puffs_node *pn = opc;
531 struct fuse *fuse;
532 const char *path = PNPATH(pn);
533 mode_t mode;
534 uid_t uid;
535 gid_t gid;
536 int ret;
537
538 fuse = (struct fuse *)pu->pu_privdata;
539
540 ret = -1;
541
542 mode = va->va_mode;
543 uid = va->va_uid;
544 gid = va->va_gid;
545
546 if (mode != (mode_t)PUFFS_VNOVAL) {
547 if (fuse->op.chmod == NULL) {
548 return ENOSYS;
549 }
550 ret = (*fuse->op.chmod)(path, mode);
551 }
552 if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
553 if (fuse->op.chown == NULL) {
554 return ENOSYS;
555 }
556 ret = (*fuse->op.chown)(path, uid, gid);
557 }
558
559 if (ret == 0) {
560 }
561
562 return ret;
563 }
564
565 /* ARGSUSED2 */
566 static int
567 puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
568 const struct puffs_cred *cred, pid_t pid)
569 {
570 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
571 struct puffs_node *pn = opc;
572 struct refusenode *rn = pn->pn_data;
573 struct fuse *fuse;
574 struct stat st;
575 const char *path = PNPATH(pn);
576 int ret;
577
578 fuse = (struct fuse *)pu->pu_privdata;
579 if (fuse->op.open == NULL) {
580 return ENOSYS;
581 }
582
583 /* examine type - if directory, return 0 rather than open */
584 ret = (fuse->op.getattr == NULL) ?
585 stat(path, &st) :
586 (*fuse->op.getattr)(path, &st);
587 if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
588 return 0;
589 }
590
591 if (strcmp(path, "/") == 0) {
592 return 0;
593 }
594
595 ret = (*fuse->op.open)(path, &rn->file_info);
596
597 if (ret == 0) {
598 }
599
600 return ret;
601 }
602
603 /* read some more from the file */
604 /* ARGSUSED5 */
605 static int
606 puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
607 off_t offset, size_t *resid, const struct puffs_cred *pcr,
608 int ioflag)
609 {
610 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
611 struct puffs_node *pn = opc;
612 struct refusenode *rn = pn->pn_data;
613 struct fuse *fuse;
614 const char *path = PNPATH(pn);
615 int ret;
616
617 fuse = (struct fuse *)pu->pu_privdata;
618 if (fuse->op.read == NULL) {
619 return ENOSYS;
620 }
621
622 ret = (*fuse->op.read)(path, (char *)buf, *resid, offset,
623 &rn->file_info);
624
625 if (ret > 0) {
626 *resid -= ret;
627 }
628
629 return 0;
630 }
631
632 /* write to the file */
633 /* ARGSUSED0 */
634 static int
635 puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
636 off_t offset, size_t *resid, const struct puffs_cred *pcr,
637 int ioflag)
638 {
639 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
640 struct puffs_node *pn = opc;
641 struct refusenode *rn = pn->pn_data;
642 struct fuse *fuse;
643 const char *path = PNPATH(pn);
644 int ret;
645
646 fuse = (struct fuse *)pu->pu_privdata;
647 if (fuse->op.write == NULL) {
648 return ENOSYS;
649 }
650
651 ret = (*fuse->op.write)(path, (char *)buf, *resid, offset,
652 &rn->file_info);
653
654 if (ret > 0) {
655 *resid -= ret;
656 }
657
658 return ret;
659 }
660
661
662 /* ARGSUSED3 */
663 static int
664 puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
665 struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
666 size_t *reslen)
667 {
668 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
669 struct puffs_node *pn = opc;
670 struct refusenode *rn = pn->pn_data;
671 struct fuse *fuse;
672 const char *path = PNPATH(pn);
673 struct fuse_dirh deh;
674 int ret;
675
676 fuse = (struct fuse *)pu->pu_privdata;
677 if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
678 return ENOSYS;
679 }
680
681 /* XXX: how to handle this??? */
682 if (*readoff != 0) {
683 return 0;
684 }
685
686 deh.dent = dent;
687 deh.reslen = *reslen;
688 deh.readoff = *readoff;
689
690 if (fuse->op.readdir)
691 ret = fuse->op.readdir(path, &deh, puffs_fuse_fill_dir,
692 *readoff, &rn->file_info);
693 else
694 ret = fuse->op.getdir(path, &deh, puffs_fuse_dirfil);
695 *reslen = deh.reslen;
696 *readoff = 1;
697
698 if (ret == 0) {
699 }
700
701 return ret;
702 }
703
704 /* ARGSUSED */
705 static int
706 puffs_fuse_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
707 {
708 struct puffs_node *pn = opc;
709
710 nukern(pn);
711
712 return 0;
713 }
714
715 /* ARGSUSED1 */
716 static int
717 puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
718 {
719 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
720 struct fuse *fuse;
721
722 fuse = (struct fuse *)pu->pu_privdata;
723 if (fuse->op.destroy == NULL) {
724 return 0;
725 }
726 (*fuse->op.destroy)(fuse);
727 return 0;
728 }
729
730 /* ARGSUSED0 */
731 static int
732 puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
733 const struct puffs_cred *cr, pid_t pid)
734 {
735 return 0;
736 }
737
738 /* ARGSUSED2 */
739 static int
740 puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
741 {
742 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
743 struct fuse *fuse;
744 int ret;
745
746 fuse = (struct fuse *)pu->pu_privdata;
747 if (fuse->op.statfs == NULL) {
748 if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
749 return errno;
750 }
751 } else {
752 ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
753 }
754
755 return ret;
756 }
757
758
759
760
761 /* End of puffs_fuse operations */
762
763 /*
764 * XXX: do this otherwise if/when we grow thread support
765 *
766 * XXX2: does not supply uid, gid or pid currently
767 */
768 static struct fuse_context fcon;
769
770 /* ARGSUSED3 */
771 int
772 fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
773 size_t size, void *userdata)
774 {
775 struct puffs_usermount *pu;
776 struct puffs_pathobj *po_root;
777 struct puffs_ops *pops;
778 struct statvfs svfsb;
779 struct fuse *fuse;
780 char name[64];
781 char *slash;
782 int ret;
783
784 /* initialise the puffs operations structure */
785 PUFFSOP_INIT(pops);
786
787 PUFFSOP_SET(pops, puffs_fuse, fs, sync);
788 PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
789 PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
790
791 /*
792 * XXX: all of these don't possibly need to be
793 * unconditionally set
794 */
795 PUFFSOP_SET(pops, puffs_fuse, node, lookup);
796 PUFFSOP_SET(pops, puffs_fuse, node, getattr);
797 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
798 PUFFSOP_SET(pops, puffs_fuse, node, readlink);
799 PUFFSOP_SET(pops, puffs_fuse, node, mknod);
800 PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
801 PUFFSOP_SET(pops, puffs_fuse, node, remove);
802 PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
803 PUFFSOP_SET(pops, puffs_fuse, node, symlink);
804 PUFFSOP_SET(pops, puffs_fuse, node, rename);
805 PUFFSOP_SET(pops, puffs_fuse, node, link);
806 PUFFSOP_SET(pops, puffs_fuse, node, setattr);
807 PUFFSOP_SET(pops, puffs_fuse, node, open);
808 PUFFSOP_SET(pops, puffs_fuse, node, read);
809 PUFFSOP_SET(pops, puffs_fuse, node, write);
810 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
811 PUFFSOP_SET(pops, puffs_fuse, node, read);
812 PUFFSOP_SET(pops, puffs_fuse, node, write);
813 PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
814
815 NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
816
817 /* copy fuse ops to their own stucture */
818 (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
819
820 fcon.fuse = fuse;
821 fcon.private_data = userdata;
822
823 /* whilst this (assigning the pu_privdata in the puffs
824 * usermount struct to be the fuse struct) might seem like
825 * we are chasing our tail here, the logic is as follows:
826 + the operation wrapper gets called with the puffs
827 calling conventions
828 + we need to fix up args first
829 + then call the fuse user-supplied operation
830 + then we fix up any values on return that we need to
831 + and fix up any nodes, etc
832 * so we need to be able to get at the fuse ops from within the
833 * puffs_usermount struct
834 */
835 if ((slash = strrchr(*argv, '/')) == NULL) {
836 slash = *argv;
837 } else {
838 slash += 1;
839 }
840 (void) snprintf(name, sizeof(name), "refuse:%s", slash);
841 pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
842 name, fuse,
843 PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
844 if (pu == NULL) {
845 err(EXIT_FAILURE, "puffs_mount");
846 }
847
848 fuse->pu = pu;
849 pu->pu_pn_root = puffs_pn_new(pu, NULL);
850 po_root = puffs_getrootpathobj(pu);
851 po_root->po_path = strdup("/");
852 po_root->po_len = 1;
853
854 if (fuse->op.init)
855 fcon.private_data = fuse->op.init(NULL); /* XXX */
856
857 statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
858 if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
859 err(EXIT_FAILURE, "puffs_start");
860 }
861
862 ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
863
864 (void) free(po_root->po_path);
865 FREE(fuse);
866 return ret;
867 }
868
869 /* ARGSUSED0 */
870 int
871 fuse_opt_parse(struct fuse_args *args, void *data,
872 const struct fuse_opt *opts, fuse_opt_proc_t proc)
873 {
874 return 0;
875 }
876
877 /* XXX: threads */
878 struct fuse_context *
879 fuse_get_context()
880 {
881
882 return &fcon;
883 }
884