refuse.c revision 1.18 1 /* $NetBSD: refuse.c,v 1.18 2007/02/16 00:35:06 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.18 2007/02/16 00:35:06 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 * We run into a slight problemette here - puffs provides
566 * setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
567 * functionality. So that we don't miss out on anything when calling a
568 * fuse operation, we have to get the vattr from the existing file,
569 * find out what's changed, and then switch on that to call the fuse
570 * function accordingly.
571 */
572 /* ARGSUSED3 */
573 static int
574 puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
575 const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
576 {
577 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
578 struct puffs_node *pn = opc;
579 struct fuse *fuse;
580 const char *path = PNPATH(pn);
581 mode_t mode;
582 uid_t uid;
583 gid_t gid;
584 int ret;
585
586 fuse = (struct fuse *)pu->pu_privdata;
587
588 ret = -1;
589
590 mode = va->va_mode;
591 uid = va->va_uid;
592 gid = va->va_gid;
593
594 if (mode != (mode_t)PUFFS_VNOVAL) {
595 if (fuse->op.chmod == NULL) {
596 return ENOSYS;
597 }
598 ret = (*fuse->op.chmod)(path, mode);
599 }
600 if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
601 if (fuse->op.chown == NULL) {
602 return ENOSYS;
603 }
604 ret = (*fuse->op.chown)(path, uid, gid);
605 }
606
607 if (ret == 0) {
608 }
609
610 return -ret;
611 }
612
613 /* ARGSUSED2 */
614 static int
615 puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
616 const struct puffs_cred *cred, pid_t pid)
617 {
618 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
619 struct puffs_node *pn = opc;
620 struct refusenode *rn = pn->pn_data;
621 struct fuse *fuse;
622 struct stat st;
623 const char *path = PNPATH(pn);
624 int ret;
625
626 fuse = (struct fuse *)pu->pu_privdata;
627 if (fuse->op.open == NULL) {
628 return ENOSYS;
629 }
630
631 /* examine type - if directory, return 0 rather than open */
632 ret = (fuse->op.getattr == NULL) ?
633 stat(path, &st) :
634 (*fuse->op.getattr)(path, &st);
635 if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
636 return 0;
637 }
638
639 if (strcmp(path, "/") == 0) {
640 return 0;
641 }
642
643 ret = (*fuse->op.open)(path, &rn->file_info);
644
645 if (ret == 0) {
646 }
647
648 return -ret;
649 }
650
651 /* read some more from the file */
652 /* ARGSUSED5 */
653 static int
654 puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
655 off_t offset, size_t *resid, const struct puffs_cred *pcr,
656 int ioflag)
657 {
658 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
659 struct puffs_node *pn = opc;
660 struct refusenode *rn = pn->pn_data;
661 struct fuse *fuse;
662 const char *path = PNPATH(pn);
663 int ret;
664
665 fuse = (struct fuse *)pu->pu_privdata;
666 if (fuse->op.read == NULL) {
667 return ENOSYS;
668 }
669
670 ret = (*fuse->op.read)(path, (char *)buf, *resid, offset,
671 &rn->file_info);
672
673 if (ret > 0) {
674 *resid -= ret;
675 ret = 0;
676 }
677
678 return -ret;
679 }
680
681 /* write to the file */
682 /* ARGSUSED0 */
683 static int
684 puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
685 off_t offset, size_t *resid, const struct puffs_cred *pcr,
686 int ioflag)
687 {
688 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
689 struct puffs_node *pn = opc;
690 struct refusenode *rn = pn->pn_data;
691 struct fuse *fuse;
692 const char *path = PNPATH(pn);
693 int ret;
694
695 fuse = (struct fuse *)pu->pu_privdata;
696 if (fuse->op.write == NULL) {
697 return ENOSYS;
698 }
699
700 if (ioflag & PUFFS_IO_APPEND)
701 offset = pn->pn_va.va_size;
702
703 ret = (*fuse->op.write)(path, (char *)buf, *resid, offset,
704 &rn->file_info);
705
706 if (ret > 0) {
707 *resid -= ret;
708 ret = 0;
709 }
710
711 return -ret;
712 }
713
714
715 /* ARGSUSED3 */
716 static int
717 puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
718 struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
719 size_t *reslen)
720 {
721 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
722 struct puffs_node *pn = opc;
723 struct refusenode *rn = pn->pn_data;
724 struct fuse *fuse;
725 const char *path = PNPATH(pn);
726 struct fuse_dirh deh;
727 int ret;
728
729 fuse = (struct fuse *)pu->pu_privdata;
730 if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
731 return ENOSYS;
732 }
733
734 /* XXX: how to handle this??? */
735 if (*readoff != 0) {
736 return 0;
737 }
738
739 deh.dent = dent;
740 deh.reslen = *reslen;
741 deh.readoff = *readoff;
742
743 if (fuse->op.readdir)
744 ret = fuse->op.readdir(path, &deh, puffs_fuse_fill_dir,
745 *readoff, &rn->file_info);
746 else
747 ret = fuse->op.getdir(path, &deh, puffs_fuse_dirfil);
748 *reslen = deh.reslen;
749 *readoff = 1;
750
751 if (ret == 0) {
752 }
753
754 return -ret;
755 }
756
757 /* ARGSUSED */
758 static int
759 puffs_fuse_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
760 {
761 struct puffs_node *pn = opc;
762
763 nukern(pn);
764
765 return 0;
766 }
767
768 /* ARGSUSED1 */
769 static int
770 puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
771 {
772 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
773 struct fuse *fuse;
774
775 fuse = (struct fuse *)pu->pu_privdata;
776 if (fuse->op.destroy == NULL) {
777 return 0;
778 }
779 (*fuse->op.destroy)(fuse);
780 return 0;
781 }
782
783 /* ARGSUSED0 */
784 static int
785 puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
786 const struct puffs_cred *cr, pid_t pid)
787 {
788 return 0;
789 }
790
791 /* ARGSUSED2 */
792 static int
793 puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
794 {
795 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
796 struct fuse *fuse;
797 int ret;
798
799 fuse = (struct fuse *)pu->pu_privdata;
800 if (fuse->op.statfs == NULL) {
801 if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
802 return errno;
803 }
804 } else {
805 ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
806 }
807
808 return ret;
809 }
810
811
812
813
814 /* End of puffs_fuse operations */
815
816 /*
817 * XXX: do this otherwise if/when we grow thread support
818 *
819 * XXX2: does not supply uid, gid or pid currently
820 */
821 static struct fuse_context fcon;
822
823 /* ARGSUSED3 */
824 int
825 fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
826 size_t size, void *userdata)
827 {
828 struct puffs_usermount *pu;
829 struct puffs_pathobj *po_root;
830 struct puffs_ops *pops;
831 struct statvfs svfsb;
832 struct fuse *fuse;
833 char name[64];
834 char *slash;
835 int ret;
836
837 /* initialise the puffs operations structure */
838 PUFFSOP_INIT(pops);
839
840 PUFFSOP_SET(pops, puffs_fuse, fs, sync);
841 PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
842 PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
843
844 /*
845 * XXX: all of these don't possibly need to be
846 * unconditionally set
847 */
848 PUFFSOP_SET(pops, puffs_fuse, node, lookup);
849 PUFFSOP_SET(pops, puffs_fuse, node, getattr);
850 PUFFSOP_SET(pops, puffs_fuse, node, setattr);
851 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
852 PUFFSOP_SET(pops, puffs_fuse, node, readlink);
853 PUFFSOP_SET(pops, puffs_fuse, node, mknod);
854 PUFFSOP_SET(pops, puffs_fuse, node, create);
855 PUFFSOP_SET(pops, puffs_fuse, node, remove);
856 PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
857 PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
858 PUFFSOP_SET(pops, puffs_fuse, node, symlink);
859 PUFFSOP_SET(pops, puffs_fuse, node, rename);
860 PUFFSOP_SET(pops, puffs_fuse, node, link);
861 PUFFSOP_SET(pops, puffs_fuse, node, open);
862 PUFFSOP_SET(pops, puffs_fuse, node, read);
863 PUFFSOP_SET(pops, puffs_fuse, node, write);
864 PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
865
866 NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
867
868 /* copy fuse ops to their own stucture */
869 (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
870
871 fcon.fuse = fuse;
872 fcon.private_data = userdata;
873
874 /* whilst this (assigning the pu_privdata in the puffs
875 * usermount struct to be the fuse struct) might seem like
876 * we are chasing our tail here, the logic is as follows:
877 + the operation wrapper gets called with the puffs
878 calling conventions
879 + we need to fix up args first
880 + then call the fuse user-supplied operation
881 + then we fix up any values on return that we need to
882 + and fix up any nodes, etc
883 * so we need to be able to get at the fuse ops from within the
884 * puffs_usermount struct
885 */
886 if ((slash = strrchr(*argv, '/')) == NULL) {
887 slash = *argv;
888 } else {
889 slash += 1;
890 }
891 (void) snprintf(name, sizeof(name), "refuse:%s", slash);
892 pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
893 name, fuse,
894 PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
895 if (pu == NULL) {
896 err(EXIT_FAILURE, "puffs_mount");
897 }
898
899 fuse->pu = pu;
900 pu->pu_pn_root = puffs_pn_new(pu, NULL);
901 po_root = puffs_getrootpathobj(pu);
902 po_root->po_path = strdup("/");
903 po_root->po_len = 1;
904
905 if (fuse->op.init)
906 fcon.private_data = fuse->op.init(NULL); /* XXX */
907
908 statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
909 if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
910 err(EXIT_FAILURE, "puffs_start");
911 }
912
913 ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
914
915 (void) free(po_root->po_path);
916 FREE(fuse);
917 return ret;
918 }
919
920 /* ARGSUSED0 */
921 int
922 fuse_opt_parse(struct fuse_args *args, void *data,
923 const struct fuse_opt *opts, fuse_opt_proc_t proc)
924 {
925 return 0;
926 }
927
928 /* XXX: threads */
929 struct fuse_context *
930 fuse_get_context()
931 {
932
933 return &fcon;
934 }
935