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