Annotation of src/lib/librefuse/refuse.c, Revision 1.52
1.52 ! agc 1: /* $NetBSD: refuse.c,v 1.51 2007/05/03 21:02:54 agc Exp $ */
1.7 pooka 2:
1.1 agc 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: */
1.7 pooka 30:
31: #include <sys/cdefs.h>
32: #if !defined(lint)
1.52 ! agc 33: __RCSID("$NetBSD: refuse.c,v 1.51 2007/05/03 21:02:54 agc Exp $");
1.7 pooka 34: #endif /* !lint */
35:
1.25 pooka 36: #include <assert.h>
1.1 agc 37: #include <err.h>
38: #include <errno.h>
39: #include <fuse.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:
1.38 pooka 69: struct fuse_chan {
1.51 agc 70: const char *dir;
71: struct fuse_args *args;
72: struct puffs_usermount *pu;
1.38 pooka 73: };
74:
1.1 agc 75: /* this is the private fuse structure */
76: struct fuse {
1.38 pooka 77: struct fuse_chan *fc; /* fuse channel pointer */
1.1 agc 78: struct fuse_operations op; /* switch table of operations */
1.7 pooka 79: int compat; /* compat level -
80: * not used in puffs_fuse */
1.1 agc 81: struct node **name_table;
82: size_t name_table_size;
83: struct node **id_table;
84: size_t id_table_size;
85: fuse_ino_t ctr;
86: unsigned int generation;
87: unsigned int hidectr;
88: pthread_mutex_t lock;
89: pthread_rwlock_t tree_lock;
90: void *user_data;
91: struct fuse_config conf;
92: int intr_installed;
93: };
94:
1.36 pooka 95: struct puffs_fuse_dirh {
1.43 agc 96: void *dbuf;
97: struct dirent *d;
98:
99: size_t reslen;
100: size_t bufsize;
1.36 pooka 101: };
102:
1.43 agc 103: struct refusenode {
104: struct fuse_file_info file_info;
105: struct puffs_fuse_dirh dirh;
106: int opencount;
107: int flags;
108: };
1.30 pooka 109: #define RN_ROOT 0x01
1.31 pooka 110: #define RN_OPEN 0x02 /* XXX: could just use opencount */
1.5 pooka 111:
1.43 agc 112: static int fuse_setattr(struct fuse *, struct puffs_node *,
113: const char *, const struct vattr *);
1.26 pooka 114:
1.5 pooka 115: static struct puffs_node *
116: newrn(struct puffs_usermount *pu)
117: {
118: struct puffs_node *pn;
119: struct refusenode *rn;
120:
1.38 pooka 121: NEW(struct refusenode, rn, "newrn", exit(EXIT_FAILURE));
1.5 pooka 122: pn = puffs_pn_new(pu, rn);
123:
124: return pn;
125: }
126:
127: static void
128: nukern(struct puffs_node *pn)
129: {
1.36 pooka 130: struct refusenode *rn = pn->pn_data;
1.5 pooka 131:
1.36 pooka 132: free(rn->dirh.dbuf);
133: free(rn);
1.5 pooka 134: puffs_pn_put(pn);
135: }
136:
1.1 agc 137: static ino_t fakeino = 3;
138:
1.21 pooka 139: /*
1.43 agc 140: * XXX: do this otherwise if/when we grow thread support
1.21 pooka 141: *
142: * XXX2: does not consistently supply uid, gid or pid currently
143: */
144: static struct fuse_context fcon;
145:
1.36 pooka 146: #define DIR_CHUNKSIZE 4096
147: static int
148: fill_dirbuf(struct puffs_fuse_dirh *dh, const char *name, ino_t dino,
149: uint8_t dtype)
150: {
151:
152: /* initial? */
153: if (dh->bufsize == 0) {
154: dh->dbuf = malloc(DIR_CHUNKSIZE);
1.43 agc 155: if (dh->dbuf == NULL)
156: err(1, "fill_dirbuf");
1.36 pooka 157: dh->d = dh->dbuf;
158: dh->reslen = dh->bufsize = DIR_CHUNKSIZE;
159: }
1.21 pooka 160:
1.43 agc 161: if (puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen))
1.36 pooka 162: return 0;
163:
164: /* try to increase buffer space */
165: dh->dbuf = realloc(dh->dbuf, dh->bufsize + DIR_CHUNKSIZE);
1.43 agc 166: if (dh->dbuf == NULL)
167: err(1, "fill_dirbuf realloc");
1.36 pooka 168: dh->d = (void *)((uint8_t *)dh->dbuf + (dh->bufsize - dh->reslen));
169: dh->reslen += DIR_CHUNKSIZE;
170: dh->bufsize += DIR_CHUNKSIZE;
171:
172: return !puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen);
173: }
1.1 agc 174:
1.36 pooka 175: /* ARGSUSED3 */
176: /* XXX: I have no idea how "off" is supposed to be used */
1.1 agc 177: static int
1.4 pooka 178: puffs_fuse_fill_dir(void *buf, const char *name,
1.1 agc 179: const struct stat *stbuf, off_t off)
180: {
1.36 pooka 181: struct puffs_fuse_dirh *deh = buf;
1.13 pooka 182: ino_t dino;
1.1 agc 183: uint8_t dtype;
184:
1.13 pooka 185: if (stbuf == NULL) {
186: dtype = DT_UNKNOWN;
187: dino = fakeino++;
188: } else {
189: dtype = puffs_vtype2dt(puffs_mode2vt(stbuf->st_mode));
190: dino = stbuf->st_ino;
1.50 pooka 191:
192: /*
193: * Some FUSE file systems like to always use 0 as the
194: * inode number. Our readdir() doesn't like to show
195: * directory entries with inode number 0 ==> workaround.
196: */
197: if (dino == 0)
198: dino = fakeino++;
1.13 pooka 199: }
1.1 agc 200:
1.36 pooka 201: return fill_dirbuf(deh, name, dino, dtype);
1.4 pooka 202: }
203:
204: static int
205: puffs_fuse_dirfil(fuse_dirh_t h, const char *name, int type, ino_t ino)
206: {
1.43 agc 207: ino_t dino;
208: int dtype;
1.4 pooka 209:
1.43 agc 210: if (type == 0)
1.13 pooka 211: dtype = DT_UNKNOWN;
1.43 agc 212: else
213: dtype = type;
214:
215: if (ino)
216: dino = ino;
217: else
1.4 pooka 218: dino = fakeino++;
219:
1.36 pooka 220: return fill_dirbuf(h, name, dino, dtype);
1.1 agc 221: }
222:
1.51 agc 223: static struct fuse_args *
224: deep_copy_args(int argc, char **argv)
225: {
226: struct fuse_args *ap;
227: int i;
228:
229: NEW(struct fuse_args, ap, "deep_copy_args", return NULL);
230: /* deep copy args structure into channel args */
231: ap->allocated = ((argc / 10) + 1) * 10;
232: NEWARRAY(char *, ap->argv, ap->allocated, "deep_copy_args",
233: return NULL);
234: for (i = 0 ; i < argc ; i++) {
235: ap->argv[i] = strdup(argv[i]);
236: }
237: return ap;
238: }
239:
240: static void
241: free_args(struct fuse_args *ap)
242: {
243: int i;
244:
245: for (i = 0 ; i < ap->argc ; i++) {
246: free(ap->argv[i]);
247: }
248: free(ap);
249: }
250:
251: /* this function exposes struct fuse to userland */
252: struct fuse *
253: fuse_setup(int argc, char **argv, const struct fuse_operations *ops,
254: size_t size, char **mountpoint, int *multithreaded, int *fd)
255: {
256: struct fuse_chan *fc;
257: struct fuse_args *args;
258: struct fuse *fuse;
259: char name[64];
260: char *slash;
261:
262: /* whilst this (assigning the pu_privdata in the puffs
263: * usermount struct to be the fuse struct) might seem like
264: * we are chasing our tail here, the logic is as follows:
265: + the operation wrapper gets called with the puffs
266: calling conventions
267: + we need to fix up args first
268: + then call the fuse user-supplied operation
269: + then we fix up any values on return that we need to
270: + and fix up any nodes, etc
271: * so we need to be able to get at the fuse ops from within the
272: * puffs_usermount struct
273: */
274: if (argv == NULL || *argv == NULL) {
275: (void) strlcpy(name, "refuse", sizeof(name));
276: } else {
277: if ((slash = strrchr(*argv, '/')) == NULL) {
278: slash = *argv;
279: } else {
280: slash += 1;
281: }
282: (void) snprintf(name, sizeof(name), "refuse:%s", slash);
283: }
284:
285: /* stuff name into fuse_args */
286: args = deep_copy_args(argc, argv);
287: if (args->argc > 0) {
288: FREE(args->argv[0]);
289: }
290: args->argv[0] = strdup(name);
291:
292: fc = fuse_mount(*mountpoint = argv[argc - 1], args);
293: fuse = fuse_new(fc, args, ops, size, NULL);
294:
295: free_args(args);
296:
297: /* XXX - wait for puffs to become multi-threaded */
298: if (multithreaded) {
299: *multithreaded = 0;
300: }
301:
302: /* XXX - this is unused */
303: if (fd) {
304: *fd = 0;
305: }
306:
307: return fuse;
308: }
309:
1.18 pooka 310: #define FUSE_ERR_UNLINK(fuse, file) if (fuse->op.unlink) fuse->op.unlink(file)
311: #define FUSE_ERR_RMDIR(fuse, dir) if (fuse->op.rmdir) fuse->op.rmdir(dir)
312:
1.26 pooka 313: /* ARGSUSED1 */
314: static int
315: fuse_getattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
316: struct vattr *va)
317: {
318: struct stat st;
319: int ret;
320:
321: if (fuse->op.getattr == NULL) {
322: return ENOSYS;
323: }
324:
325: /* wrap up return code */
326: ret = (*fuse->op.getattr)(path, &st);
327:
328: if (ret == 0) {
329: puffs_stat2vattr(va, &st);
330: }
331:
332: return -ret;
333: }
334:
335: static int
336: fuse_setattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
337: const struct vattr *va)
338: {
339: struct refusenode *rn = pn->pn_data;
340: mode_t mode;
341: uid_t uid;
342: gid_t gid;
343: int error, ret;
344:
345: error = 0;
346:
347: mode = va->va_mode;
348: uid = va->va_uid;
349: gid = va->va_gid;
350:
351: if (mode != (mode_t)PUFFS_VNOVAL) {
352: ret = 0;
353:
354: if (fuse->op.chmod == NULL) {
355: error = -ENOSYS;
356: } else {
357: ret = fuse->op.chmod(path, mode);
358: if (ret)
359: error = ret;
360: }
361: }
362: if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
363: ret = 0;
364:
365: if (fuse->op.chown == NULL) {
366: error = -ENOSYS;
367: } else {
368: ret = fuse->op.chown(path, uid, gid);
369: if (ret)
370: error = ret;
371: }
372: }
373: if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
374: || va->va_mtime.tv_sec != (long)PUFFS_VNOVAL) {
375: ret = 0;
376:
377: if (fuse->op.utimens) {
378: struct timespec tv[2];
379:
380: tv[0].tv_sec = va->va_atime.tv_sec;
381: tv[0].tv_nsec = va->va_atime.tv_nsec;
382: tv[1].tv_sec = va->va_mtime.tv_sec;
383: tv[1].tv_nsec = va->va_mtime.tv_nsec;
384:
385: ret = fuse->op.utimens(path, tv);
386: } else if (fuse->op.utime) {
387: struct utimbuf timbuf;
388:
389: timbuf.actime = va->va_atime.tv_sec;
390: timbuf.modtime = va->va_mtime.tv_sec;
391:
392: ret = fuse->op.utime(path, &timbuf);
393: } else {
394: error = -ENOSYS;
395: }
396:
397: if (ret)
398: error = ret;
399: }
400: if (va->va_size != (u_quad_t)PUFFS_VNOVAL) {
401: ret = 0;
402:
403: if (fuse->op.truncate) {
404: ret = fuse->op.truncate(path, (off_t)va->va_size);
405: } else if (fuse->op.ftruncate) {
406: ret = fuse->op.ftruncate(path, (off_t)va->va_size,
407: &rn->file_info);
408: } else {
409: error = -ENOSYS;
410: }
411:
412: if (ret)
413: error = ret;
414: }
415: /* XXX: no reflection with reality */
416: puffs_setvattr(&pn->pn_va, va);
417:
418: return -error;
419:
420: }
421:
422: static int
423: fuse_newnode(struct puffs_usermount *pu, const char *path,
424: const struct vattr *va, struct fuse_file_info *fi, void **newnode)
425: {
426: struct vattr newva;
427: struct fuse *fuse;
428: struct puffs_node *pn;
429: struct refusenode *rn;
430:
1.46 pooka 431: fuse = puffs_getspecific(pu);
1.26 pooka 432:
433: /* fix up nodes */
434: pn = newrn(pu);
435: if (pn == NULL) {
436: if (va->va_type == VDIR) {
437: FUSE_ERR_RMDIR(fuse, path);
438: } else {
439: FUSE_ERR_UNLINK(fuse, path);
440: }
441: return ENOMEM;
442: }
443: fuse_setattr(fuse, pn, path, va);
444: if (fuse_getattr(fuse, pn, path, &newva) == 0)
445: puffs_setvattr(&pn->pn_va, &newva);
446:
447: rn = pn->pn_data;
448: if (fi)
449: memcpy(&rn->file_info, fi, sizeof(struct fuse_file_info));
450:
451: *newnode = pn;
452:
453: return 0;
454: }
455:
456:
1.1 agc 457: /* operation wrappers start here */
458:
459: /* lookup the path */
460: /* ARGSUSED1 */
461: static int
462: puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
463: enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
464: const struct puffs_cn *pcn)
465: {
466: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
1.12 pooka 467: struct puffs_node *pn_res;
1.1 agc 468: struct stat st;
469: struct fuse *fuse;
470: const char *path = PCNPATH(pcn);
471: int ret;
472:
1.46 pooka 473: fuse = puffs_getspecific(pu);
1.1 agc 474: ret = fuse->op.getattr(path, &st);
1.12 pooka 475:
1.1 agc 476: if (ret != 0) {
1.18 pooka 477: return -ret;
1.12 pooka 478: }
479:
480: /* XXX: fiXXXme unconst */
481: pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
482: __UNCONST(&pcn->pcn_po_full));
483: if (pn_res == NULL) {
484: pn_res = newrn(pu);
485: if (pn_res == NULL)
486: return errno;
1.26 pooka 487: puffs_stat2vattr(&pn_res->pn_va, &st);
1.1 agc 488: }
1.12 pooka 489:
490: *newnode = pn_res;
491: *newtype = pn_res->pn_va.va_type;
492: *newsize = pn_res->pn_va.va_size;
493: *newrdev = pn_res->pn_va.va_rdev;
494:
495: return 0;
1.1 agc 496: }
497:
498: /* get attributes for the path name */
499: /* ARGSUSED3 */
500: static int
501: puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
502: const struct puffs_cred *pcr, pid_t pid)
503: {
504: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
505: struct puffs_node *pn = opc;
506: struct fuse *fuse;
507: const char *path = PNPATH(pn);
508:
1.46 pooka 509: fuse = puffs_getspecific(pu);
1.26 pooka 510: return fuse_getattr(fuse, pn, path, va);
1.1 agc 511: }
512:
513: /* read the contents of the symbolic link */
514: /* ARGSUSED2 */
515: static int
516: puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
517: const struct puffs_cred *cred, char *linkname, size_t *linklen)
518: {
519: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
520: struct puffs_node *pn = opc;
521: struct fuse *fuse;
1.13 pooka 522: const char *path = PNPATH(pn), *p;
1.1 agc 523: int ret;
524:
1.46 pooka 525: fuse = puffs_getspecific(pu);
1.1 agc 526: if (fuse->op.readlink == NULL) {
527: return ENOSYS;
528: }
529:
530: /* wrap up return code */
531: ret = (*fuse->op.readlink)(path, linkname, *linklen);
532:
533: if (ret == 0) {
1.43 agc 534: p = memchr(linkname, '\0', *linklen);
1.13 pooka 535: if (!p)
536: return EINVAL;
537:
1.14 pooka 538: *linklen = p - linkname;
1.1 agc 539: }
540:
1.13 pooka 541: return -ret;
1.1 agc 542: }
543:
544: /* make the special node */
545: /* ARGSUSED1 */
546: static int
547: puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
548: const struct puffs_cn *pcn, const struct vattr *va)
549: {
550: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
551: struct fuse *fuse;
1.44 pooka 552: mode_t mode;
1.1 agc 553: const char *path = PCNPATH(pcn);
554: int ret;
555:
1.46 pooka 556: fuse = puffs_getspecific(pu);
1.1 agc 557: if (fuse->op.mknod == NULL) {
558: return ENOSYS;
559: }
560:
561: /* wrap up return code */
1.44 pooka 562: mode = puffs_addvtype2mode(va->va_mode, va->va_type);
1.1 agc 563: ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
564:
565: if (ret == 0) {
1.26 pooka 566: ret = fuse_newnode(pu, path, va, NULL, newnode);
1.1 agc 567: }
568:
1.18 pooka 569: return -ret;
1.1 agc 570: }
571:
572: /* make a directory */
573: /* ARGSUSED1 */
574: static int
575: puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
576: const struct puffs_cn *pcn, const struct vattr *va)
577: {
578: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
579: struct fuse *fuse;
580: mode_t mode = va->va_mode;
581: const char *path = PCNPATH(pcn);
582: int ret;
583:
1.46 pooka 584: fuse = puffs_getspecific(pu);
1.1 agc 585: if (fuse->op.mkdir == NULL) {
586: return ENOSYS;
587: }
588:
589: /* wrap up return code */
590: ret = (*fuse->op.mkdir)(path, mode);
591:
592: if (ret == 0) {
1.26 pooka 593: ret = fuse_newnode(pu, path, va, NULL, newnode);
1.1 agc 594: }
595:
1.18 pooka 596: return -ret;
1.1 agc 597: }
598:
1.21 pooka 599: /*
600: * create a regular file
601: *
602: * since linux/fuse sports using mknod for creating regular files
603: * instead of having a separate call for it in some versions, if
604: * we don't have create, just jump to op->mknod.
605: */
1.16 pooka 606: /*ARGSUSED1*/
607: static int
608: puffs_fuse_node_create(struct puffs_cc *pcc, void *opc, void **newnode,
609: const struct puffs_cn *pcn, const struct vattr *va)
610: {
611: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
612: struct fuse *fuse;
613: struct fuse_file_info fi;
614: mode_t mode = va->va_mode;
615: const char *path = PCNPATH(pcn);
1.31 pooka 616: int ret, created;
1.16 pooka 617:
1.46 pooka 618: fuse = puffs_getspecific(pu);
1.21 pooka 619:
1.31 pooka 620: created = 0;
1.21 pooka 621: if (fuse->op.create) {
622: ret = fuse->op.create(path, mode, &fi);
1.31 pooka 623: if (ret == 0)
624: created = 1;
1.21 pooka 625:
626: } else if (fuse->op.mknod) {
627: fcon.uid = va->va_uid; /*XXX*/
628: fcon.gid = va->va_gid; /*XXX*/
629:
630: ret = fuse->op.mknod(path, mode | S_IFREG, 0);
631:
632: } else {
633: ret = -ENOSYS;
1.16 pooka 634: }
635:
636: if (ret == 0) {
1.26 pooka 637: ret = fuse_newnode(pu, path, va, &fi, newnode);
1.31 pooka 638:
639: /* sweet.. create also open the file */
640: if (created) {
641: struct puffs_node *pn;
642: struct refusenode *rn;
643:
644: pn = *newnode;
645: rn = pn->pn_data;
646: rn->flags |= RN_OPEN;
647: rn->opencount++;
648: }
1.16 pooka 649: }
650:
1.18 pooka 651: return -ret;
1.16 pooka 652: }
653:
1.1 agc 654: /* remove the directory entry */
1.23 pooka 655: /* ARGSUSED1 */
1.1 agc 656: static int
657: puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
658: const struct puffs_cn *pcn)
659: {
660: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
1.23 pooka 661: struct puffs_node *pn_targ = targ;
1.1 agc 662: struct fuse *fuse;
1.23 pooka 663: const char *path = PNPATH(pn_targ);
1.1 agc 664: int ret;
665:
1.46 pooka 666: fuse = puffs_getspecific(pu);
1.1 agc 667: if (fuse->op.unlink == NULL) {
668: return ENOSYS;
669: }
670:
671: /* wrap up return code */
672: ret = (*fuse->op.unlink)(path);
673:
1.18 pooka 674: return -ret;
1.1 agc 675: }
676:
677: /* remove the directory */
678: /* ARGSUSED1 */
679: static int
680: puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
681: const struct puffs_cn *pcn)
682: {
683: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
1.23 pooka 684: struct puffs_node *pn_targ = targ;
1.1 agc 685: struct fuse *fuse;
1.23 pooka 686: const char *path = PNPATH(pn_targ);
1.1 agc 687: int ret;
688:
1.46 pooka 689: fuse = puffs_getspecific(pu);
1.1 agc 690: if (fuse->op.rmdir == NULL) {
691: return ENOSYS;
692: }
693:
694: /* wrap up return code */
695: ret = (*fuse->op.rmdir)(path);
696:
1.18 pooka 697: return -ret;
1.1 agc 698: }
699:
700: /* create a symbolic link */
701: /* ARGSUSED1 */
702: static int
703: puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
704: const struct puffs_cn *pcn_src, const struct vattr *va,
705: const char *link_target)
706: {
707: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
708: struct fuse *fuse;
709: const char *path = PCNPATH(pcn_src);
710: int ret;
711:
1.46 pooka 712: fuse = puffs_getspecific(pu);
1.1 agc 713: if (fuse->op.symlink == NULL) {
714: return ENOSYS;
715: }
716:
717: /* wrap up return code */
1.32 pooka 718: ret = fuse->op.symlink(link_target, path);
1.1 agc 719:
720: if (ret == 0) {
1.26 pooka 721: ret = fuse_newnode(pu, path, va, NULL, newnode);
1.1 agc 722: }
723:
1.18 pooka 724: return -ret;
1.1 agc 725: }
726:
727: /* rename a directory entry */
728: /* ARGSUSED1 */
729: static int
730: puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
731: const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
732: const struct puffs_cn *pcn_targ)
733: {
734: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
735: struct fuse *fuse;
1.24 pooka 736: const char *path_src = PCNPATH(pcn_src);
737: const char *path_dest = PCNPATH(pcn_targ);
1.1 agc 738: int ret;
739:
1.46 pooka 740: fuse = puffs_getspecific(pu);
1.1 agc 741: if (fuse->op.rename == NULL) {
742: return ENOSYS;
743: }
744:
1.24 pooka 745: ret = fuse->op.rename(path_src, path_dest);
1.1 agc 746:
747: if (ret == 0) {
748: }
749:
1.18 pooka 750: return -ret;
1.1 agc 751: }
752:
753: /* create a link in the file system */
754: /* ARGSUSED1 */
755: static int
756: puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
757: const struct puffs_cn *pcn)
758: {
759: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
760: struct puffs_node *pn = targ;
761: struct fuse *fuse;
762: int ret;
763:
1.46 pooka 764: fuse = puffs_getspecific(pu);
1.1 agc 765: if (fuse->op.link == NULL) {
766: return ENOSYS;
767: }
768:
769: /* wrap up return code */
770: ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
771:
1.18 pooka 772: return -ret;
1.1 agc 773: }
774:
775: /*
1.19 pooka 776: * fuse's regular interface provides chmod(), chown(), utimes()
777: * and truncate() + some variations, so try to fit the square block
778: * in the circle hole and the circle block .... something like that
1.7 pooka 779: */
1.1 agc 780: /* ARGSUSED3 */
781: static int
782: puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
783: const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
784: {
785: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
786: struct puffs_node *pn = opc;
787: struct fuse *fuse;
788: const char *path = PNPATH(pn);
789:
1.46 pooka 790: fuse = puffs_getspecific(pu);
1.1 agc 791:
1.26 pooka 792: return fuse_setattr(fuse, pn, path, va);
1.1 agc 793: }
794:
795: /* ARGSUSED2 */
796: static int
1.31 pooka 797: puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int mode,
1.1 agc 798: const struct puffs_cred *cred, pid_t pid)
799: {
800: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
801: struct puffs_node *pn = opc;
1.5 pooka 802: struct refusenode *rn = pn->pn_data;
1.31 pooka 803: struct fuse_file_info *fi = &rn->file_info;
1.1 agc 804: struct fuse *fuse;
805: const char *path = PNPATH(pn);
806:
1.46 pooka 807: fuse = puffs_getspecific(pu);
1.1 agc 808:
1.30 pooka 809: /* if open, don't open again, lest risk nuking file private info */
1.31 pooka 810: if (rn->flags & RN_OPEN) {
811: rn->opencount++;
1.1 agc 812: return 0;
1.31 pooka 813: }
1.1 agc 814:
1.37 pooka 815: /* OFLAGS(), need to convert FREAD/FWRITE to O_RD/WR */
816: fi->flags = (mode & ~(O_CREAT | O_EXCL | O_TRUNC)) - 1;
817:
1.30 pooka 818: if (pn->pn_va.va_type == VDIR) {
819: if (fuse->op.opendir)
1.33 pooka 820: fuse->op.opendir(path, fi);
1.30 pooka 821: } else {
822: if (fuse->op.open)
1.33 pooka 823: fuse->op.open(path, fi);
1.30 pooka 824: }
1.1 agc 825:
1.33 pooka 826: rn->flags |= RN_OPEN;
827: rn->opencount++;
1.1 agc 828:
1.33 pooka 829: return 0;
1.1 agc 830: }
831:
1.31 pooka 832: /* ARGSUSED2 */
833: static int
834: puffs_fuse_node_close(struct puffs_cc *pcc, void *opc, int fflag,
835: const struct puffs_cred *pcr, pid_t pid)
836: {
837: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
838: struct puffs_node *pn = opc;
839: struct refusenode *rn = pn->pn_data;
840: struct fuse *fuse;
841: struct fuse_file_info *fi;
842: const char *path = PNPATH(pn);
843: int ret;
844:
1.46 pooka 845: fuse = puffs_getspecific(pu);
1.31 pooka 846: fi = &rn->file_info;
847: ret = 0;
848:
849: if (rn->flags & RN_OPEN) {
850: if (pn->pn_va.va_type == VDIR) {
851: if (fuse->op.releasedir)
852: ret = fuse->op.releasedir(path, fi);
853: } else {
854: if (fuse->op.release)
855: ret = fuse->op.release(path, fi);
856: }
857: }
858: rn->flags &= ~RN_OPEN;
859: rn->opencount--;
860:
861: return ret;
862: }
863:
1.1 agc 864: /* read some more from the file */
865: /* ARGSUSED5 */
866: static int
867: puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
868: off_t offset, size_t *resid, const struct puffs_cred *pcr,
869: int ioflag)
870: {
871: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
872: struct puffs_node *pn = opc;
1.5 pooka 873: struct refusenode *rn = pn->pn_data;
1.1 agc 874: struct fuse *fuse;
875: const char *path = PNPATH(pn);
1.25 pooka 876: size_t maxread;
1.1 agc 877: int ret;
878:
1.46 pooka 879: fuse = puffs_getspecific(pu);
1.1 agc 880: if (fuse->op.read == NULL) {
881: return ENOSYS;
882: }
883:
1.25 pooka 884: maxread = *resid;
1.26 pooka 885: if (maxread > pn->pn_va.va_size - offset) {
886: /*LINTED*/
1.25 pooka 887: maxread = pn->pn_va.va_size - offset;
1.26 pooka 888: }
1.25 pooka 889: if (maxread == 0)
890: return 0;
891:
892: ret = (*fuse->op.read)(path, (char *)buf, maxread, offset,
1.7 pooka 893: &rn->file_info);
1.1 agc 894:
895: if (ret > 0) {
896: *resid -= ret;
1.16 pooka 897: ret = 0;
1.1 agc 898: }
899:
1.16 pooka 900: return -ret;
1.1 agc 901: }
902:
903: /* write to the file */
904: /* ARGSUSED0 */
905: static int
906: puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
907: off_t offset, size_t *resid, const struct puffs_cred *pcr,
908: int ioflag)
909: {
910: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
911: struct puffs_node *pn = opc;
1.8 pooka 912: struct refusenode *rn = pn->pn_data;
1.1 agc 913: struct fuse *fuse;
914: const char *path = PNPATH(pn);
915: int ret;
916:
1.46 pooka 917: fuse = puffs_getspecific(pu);
1.1 agc 918: if (fuse->op.write == NULL) {
919: return ENOSYS;
920: }
921:
1.17 pooka 922: if (ioflag & PUFFS_IO_APPEND)
923: offset = pn->pn_va.va_size;
924:
1.8 pooka 925: ret = (*fuse->op.write)(path, (char *)buf, *resid, offset,
926: &rn->file_info);
1.1 agc 927:
928: if (ret > 0) {
1.23 pooka 929: if (offset + ret > pn->pn_va.va_size)
930: pn->pn_va.va_size = offset + ret;
1.26 pooka 931: *resid -= ret;
1.16 pooka 932: ret = 0;
1.1 agc 933: }
934:
1.16 pooka 935: return -ret;
1.1 agc 936: }
937:
938:
939: /* ARGSUSED3 */
940: static int
1.45 pooka 941: puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc, struct dirent *dent,
942: off_t *readoff, size_t *reslen, const struct puffs_cred *pcr,
943: int *eofflag, off_t *cookies, size_t *ncookies)
1.1 agc 944: {
945: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
946: struct puffs_node *pn = opc;
1.8 pooka 947: struct refusenode *rn = pn->pn_data;
1.43 agc 948: struct puffs_fuse_dirh *dirh;
949: struct fuse *fuse;
1.41 agc 950: struct dirent *fromdent;
1.1 agc 951: const char *path = PNPATH(pn);
952: int ret;
953:
1.46 pooka 954: fuse = puffs_getspecific(pu);
1.4 pooka 955: if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
1.1 agc 956: return ENOSYS;
957: }
958:
1.36 pooka 959: if (pn->pn_va.va_type != VDIR)
960: return ENOTDIR;
961:
962: dirh = &rn->dirh;
963:
964: /*
965: * if we are starting from the beginning, slurp entire directory
966: * into our buffers
967: */
968: if (*readoff == 0) {
969: /* free old buffers */
970: free(dirh->dbuf);
971: memset(dirh, 0, sizeof(struct puffs_fuse_dirh));
972:
973: if (fuse->op.readdir)
974: ret = fuse->op.readdir(path, dirh, puffs_fuse_fill_dir,
975: 0, &rn->file_info);
976: else
977: ret = fuse->op.getdir(path, dirh, puffs_fuse_dirfil);
978: if (ret)
979: return -ret;
1.35 pooka 980: }
981:
1.36 pooka 982: /* now, stuff results into the kernel buffers */
983: while (*readoff < dirh->bufsize - dirh->reslen) {
984: /*LINTED*/
985: fromdent = (struct dirent *)((uint8_t *)dirh->dbuf + *readoff);
986:
987: if (*reslen < _DIRENT_SIZE(fromdent))
988: break;
989:
990: memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
991: *readoff += _DIRENT_SIZE(fromdent);
992: *reslen -= _DIRENT_SIZE(fromdent);
1.1 agc 993:
1.36 pooka 994: dent = _DIRENT_NEXT(dent);
1.1 agc 995: }
996:
1.36 pooka 997: return 0;
1.1 agc 998: }
999:
1.26 pooka 1000: /* ARGSUSED */
1001: static int
1002: puffs_fuse_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
1003: {
1004: struct puffs_node *pn = opc;
1.3 pooka 1005:
1.5 pooka 1006: nukern(pn);
1.3 pooka 1007:
1.26 pooka 1008: return 0;
1.3 pooka 1009: }
1010:
1.1 agc 1011: /* ARGSUSED1 */
1012: static int
1013: puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
1014: {
1015: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
1016: struct fuse *fuse;
1017:
1.46 pooka 1018: fuse = puffs_getspecific(pu);
1.1 agc 1019: if (fuse->op.destroy == NULL) {
1.2 pooka 1020: return 0;
1.1 agc 1021: }
1022: (*fuse->op.destroy)(fuse);
1023: return 0;
1024: }
1025:
1026: /* ARGSUSED0 */
1027: static int
1028: puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
1029: const struct puffs_cred *cr, pid_t pid)
1030: {
1031: return 0;
1032: }
1033:
1034: /* ARGSUSED2 */
1035: static int
1036: puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
1037: {
1038: struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
1039: struct fuse *fuse;
1040: int ret;
1041:
1.46 pooka 1042: fuse = puffs_getspecific(pu);
1.1 agc 1043: if (fuse->op.statfs == NULL) {
1.46 pooka 1044: if ((ret = statvfs(PNPATH(puffs_getroot(pu)), svfsb)) == -1) {
1.1 agc 1045: return errno;
1046: }
1047: } else {
1.46 pooka 1048: ret = fuse->op.statfs(PNPATH(puffs_getroot(pu)), svfsb);
1.1 agc 1049: }
1050:
1051: return ret;
1052: }
1053:
1054:
1055: /* End of puffs_fuse operations */
1056: /* ARGSUSED3 */
1057: int
1058: fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
1059: size_t size, void *userdata)
1060: {
1.51 agc 1061: struct fuse *fuse;
1062: char *mountpoint;
1063: int multithreaded;
1064: int fd;
1.38 pooka 1065:
1.51 agc 1066: fuse = fuse_setup(argc, argv, ops, size, &mountpoint, &multithreaded,
1067: &fd);
1.38 pooka 1068:
1.51 agc 1069: return fuse_loop(fuse);
1.38 pooka 1070: }
1071:
1072: /*
1073: * XXX: just defer the operation until fuse_new() when we have more
1074: * info on our hands. The real beef is why's this separate in fuse in
1075: * the first place?
1076: */
1077: /* ARGSUSED1 */
1078: struct fuse_chan *
1079: fuse_mount(const char *dir, struct fuse_args *args)
1080: {
1.48 agc 1081: struct fuse_chan *fc;
1.38 pooka 1082:
1.43 agc 1083: NEW(struct fuse_chan, fc, "fuse_mount", exit(EXIT_FAILURE));
1.38 pooka 1084:
1.43 agc 1085: fc->dir = strdup(dir);
1.48 agc 1086:
1087: /*
1088: * we need to deep copy the args struct - some fuse file
1089: * systems "clean up" the argument vector for "security
1090: * reasons"
1091: */
1092: fc->args = deep_copy_args(args->argc, args->argv);
1.43 agc 1093:
1.38 pooka 1094: return fc;
1095: }
1096:
1097: /* ARGSUSED1 */
1098: struct fuse *
1099: fuse_new(struct fuse_chan *fc, struct fuse_args *args,
1100: const struct fuse_operations *ops, size_t size, void *userdata)
1101: {
1.1 agc 1102: struct puffs_usermount *pu;
1103: struct puffs_pathobj *po_root;
1.46 pooka 1104: struct puffs_node *pn_root;
1.43 agc 1105: struct puffs_ops *pops;
1.41 agc 1106: struct refusenode *rn_root;
1.1 agc 1107: struct statvfs svfsb;
1.25 pooka 1108: struct stat st;
1.1 agc 1109: struct fuse *fuse;
1.38 pooka 1110:
1111: NEW(struct fuse, fuse, "fuse_new", exit(EXIT_FAILURE));
1112:
1113: /* copy fuse ops to their own stucture */
1114: (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
1115:
1116: fcon.fuse = fuse;
1117: fcon.private_data = userdata;
1118:
1119: fuse->fc = fc;
1.1 agc 1120:
1121: /* initialise the puffs operations structure */
1122: PUFFSOP_INIT(pops);
1123:
1124: PUFFSOP_SET(pops, puffs_fuse, fs, sync);
1125: PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
1126: PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
1127:
1.2 pooka 1128: /*
1129: * XXX: all of these don't possibly need to be
1130: * unconditionally set
1131: */
1.1 agc 1132: PUFFSOP_SET(pops, puffs_fuse, node, lookup);
1133: PUFFSOP_SET(pops, puffs_fuse, node, getattr);
1.15 pooka 1134: PUFFSOP_SET(pops, puffs_fuse, node, setattr);
1.1 agc 1135: PUFFSOP_SET(pops, puffs_fuse, node, readdir);
1136: PUFFSOP_SET(pops, puffs_fuse, node, readlink);
1137: PUFFSOP_SET(pops, puffs_fuse, node, mknod);
1.16 pooka 1138: PUFFSOP_SET(pops, puffs_fuse, node, create);
1.15 pooka 1139: PUFFSOP_SET(pops, puffs_fuse, node, remove);
1.1 agc 1140: PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
1141: PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
1142: PUFFSOP_SET(pops, puffs_fuse, node, symlink);
1143: PUFFSOP_SET(pops, puffs_fuse, node, rename);
1144: PUFFSOP_SET(pops, puffs_fuse, node, link);
1145: PUFFSOP_SET(pops, puffs_fuse, node, open);
1.31 pooka 1146: PUFFSOP_SET(pops, puffs_fuse, node, close);
1.1 agc 1147: PUFFSOP_SET(pops, puffs_fuse, node, read);
1148: PUFFSOP_SET(pops, puffs_fuse, node, write);
1.3 pooka 1149: PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
1.1 agc 1150:
1.38 pooka 1151: pu = puffs_mount(pops, fc->dir, MNT_NODEV | MNT_NOSUID,
1.48 agc 1152: args->argv[0], fuse,
1.38 pooka 1153: PUFFS_FLAG_BUILDPATH
1.49 pooka 1154: | PUFFS_FLAG_HASHPATH
1.38 pooka 1155: | PUFFS_FLAG_OPDUMP
1.47 pooka 1156: | PUFFS_KFLAG_NOCACHE);
1.1 agc 1157: if (pu == NULL) {
1.52 ! agc 1158: err(EXIT_FAILURE, "puffs_mount: directory \"%s\"", fc->dir);
1.1 agc 1159: }
1.38 pooka 1160: fc->pu = pu;
1.1 agc 1161:
1.46 pooka 1162: pn_root = newrn(pu);
1163: puffs_setroot(pu, pn_root);
1164: rn_root = pn_root->pn_data;
1.30 pooka 1165: rn_root->flags |= RN_ROOT;
1166:
1.1 agc 1167: po_root = puffs_getrootpathobj(pu);
1168: po_root->po_path = strdup("/");
1169: po_root->po_len = 1;
1170:
1.25 pooka 1171: /* sane defaults */
1.46 pooka 1172: puffs_vattr_null(&pn_root->pn_va);
1173: pn_root->pn_va.va_type = VDIR;
1174: pn_root->pn_va.va_mode = 0755;
1.25 pooka 1175: if (fuse->op.getattr)
1176: if (fuse->op.getattr(po_root->po_path, &st) == 0)
1.46 pooka 1177: puffs_stat2vattr(&pn_root->pn_va, &st);
1178: assert(pn_root->pn_va.va_type == VDIR);
1.25 pooka 1179:
1.11 pooka 1180: if (fuse->op.init)
1181: fcon.private_data = fuse->op.init(NULL); /* XXX */
1182:
1.38 pooka 1183: puffs_zerostatvfs(&svfsb);
1.46 pooka 1184: if (puffs_start(pu, pn_root, &svfsb) == -1) {
1.1 agc 1185: err(EXIT_FAILURE, "puffs_start");
1186: }
1187:
1.38 pooka 1188: return fuse;
1189: }
1190:
1191: int
1192: fuse_loop(struct fuse *fuse)
1193: {
1194:
1195: return puffs_mainloop(fuse->fc->pu, PUFFSLOOP_NODAEMON);
1196: }
1197:
1198: void
1199: fuse_destroy(struct fuse *fuse)
1200: {
1201:
1.1 agc 1202:
1.38 pooka 1203: /* XXXXXX: missing stuff */
1.1 agc 1204: FREE(fuse);
1205: }
1206:
1.11 pooka 1207: /* XXX: threads */
1208: struct fuse_context *
1209: fuse_get_context()
1210: {
1211:
1212: return &fcon;
1213: }
1.20 agc 1214:
1215: void
1.38 pooka 1216: fuse_exit(struct fuse *fuse)
1.20 agc 1217: {
1218:
1.38 pooka 1219: puffs_exit(fuse->fc->pu, 1);
1.20 agc 1220: }
1.29 pooka 1221:
1222: /*
1223: * XXX: obviously not the most perfect of functions, but needs some
1224: * puffs tweaking for a better tomorrow
1225: */
1.31 pooka 1226: /*ARGSUSED*/
1.29 pooka 1227: void
1.38 pooka 1228: fuse_unmount(const char *mp, struct fuse_chan *fc)
1229: {
1230:
1231: puffs_exit(fc->pu, 1);
1232: }
1233:
1234: /*ARGSUSED*/
1235: void
1236: fuse_unmount_compat22(const char *mp)
1.29 pooka 1237: {
1238:
1239: return;
1240: }
1.51 agc 1241:
1242: /* The next function "exposes" struct fuse to userland. Not much
1243: * that we can do about this, as we're conforming to a defined
1244: * interface. */
1245:
1246: void
1247: fuse_teardown(struct fuse *fuse, char *mountpoint)
1248: {
1249: fuse_unmount(mountpoint, fuse->fc);
1250: fuse_destroy(fuse);
1251: }
CVSweb <webmaster@jp.NetBSD.org>