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