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