[BACK]Return to refuse.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / librefuse

Annotation of src/lib/librefuse/refuse.c, Revision 1.97

1.97    ! pho         1: /*     $NetBSD: refuse.c,v 1.96 2012/12/30 10:04:22 tron Exp $ */
1.7       pooka       2:
1.1       agc         3: /*
                      4:  * Copyright © 2007 Alistair Crooks.  All rights reserved.
1.83      pooka       5:  * Copyright © 2007 Antti Kantee.  All rights reserved.
1.1       agc         6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. The name of the author may not be used to endorse or promote
                     16:  *    products derived from this software without specific prior written
                     17:  *    permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
                     20:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     21:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
                     23:  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
                     25:  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     27:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                     28:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                     29:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     30:  */
1.7       pooka      31:
                     32: #include <sys/cdefs.h>
                     33: #if !defined(lint)
1.97    ! pho        34: __RCSID("$NetBSD: refuse.c,v 1.96 2012/12/30 10:04:22 tron Exp $");
1.7       pooka      35: #endif /* !lint */
                     36:
1.81      pooka      37: #include <sys/types.h>
                     38:
1.25      pooka      39: #include <assert.h>
1.1       agc        40: #include <err.h>
                     41: #include <errno.h>
                     42: #include <fuse.h>
1.72      pooka      43: #include <paths.h>
1.81      pooka      44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <string.h>
1.78      pooka      47: #include <unistd.h>
                     48: #ifdef MULTITHREADED_REFUSE
1.77      pooka      49: #include <pthread.h>
1.78      pooka      50: #endif
1.1       agc        51:
                     52: typedef uint64_t        fuse_ino_t;
                     53:
                     54: struct fuse_config {
                     55:        uid_t           uid;
                     56:        gid_t           gid;
                     57:        mode_t          umask;
                     58:        double          entry_timeout;
                     59:        double          negative_timeout;
                     60:        double          attr_timeout;
                     61:        double          ac_attr_timeout;
                     62:        int             ac_attr_timeout_set;
                     63:        int             debug;
                     64:        int             hard_remove;
                     65:        int             use_ino;
                     66:        int             readdir_ino;
                     67:        int             set_mode;
                     68:        int             set_uid;
                     69:        int             set_gid;
                     70:        int             direct_io;
                     71:        int             kernel_cache;
                     72:        int             auto_cache;
                     73:        int             intr;
                     74:        int             intr_signal;
                     75: };
                     76:
1.38      pooka      77: struct fuse_chan {
1.51      agc        78:        const char              *dir;
                     79:        struct fuse_args        *args;
                     80:        struct puffs_usermount  *pu;
1.60      pooka      81:        int                     dead;
1.38      pooka      82: };
                     83:
1.1       agc        84: /* this is the private fuse structure */
                     85: struct fuse {
1.38      pooka      86:        struct fuse_chan        *fc;            /* fuse channel pointer */
1.1       agc        87:        struct fuse_operations  op;             /* switch table of operations */
1.7       pooka      88:        int                     compat;         /* compat level -
                     89:                                                 * not used in puffs_fuse */
1.1       agc        90:        struct node             **name_table;
                     91:        size_t                  name_table_size;
                     92:        struct node             **id_table;
                     93:        size_t                  id_table_size;
                     94:        fuse_ino_t              ctr;
                     95:        unsigned int            generation;
                     96:        unsigned int            hidectr;
                     97:        pthread_mutex_t         lock;
                     98:        pthread_rwlock_t        tree_lock;
                     99:        void                    *user_data;
                    100:        struct fuse_config      conf;
                    101:        int                     intr_installed;
                    102: };
                    103:
1.36      pooka     104: struct puffs_fuse_dirh {
1.43      agc       105:        void *dbuf;
                    106:        struct dirent *d;
                    107:
                    108:        size_t reslen;
                    109:        size_t bufsize;
1.36      pooka     110: };
                    111:
1.43      agc       112: struct refusenode {
                    113:        struct fuse_file_info   file_info;
                    114:        struct puffs_fuse_dirh  dirh;
                    115:        int opencount;
                    116:        int flags;
                    117: };
1.30      pooka     118: #define RN_ROOT                0x01
1.31      pooka     119: #define RN_OPEN                0x02    /* XXX: could just use opencount */
1.5       pooka     120:
1.43      agc       121: static int fuse_setattr(struct fuse *, struct puffs_node *,
                    122:                        const char *, const struct vattr *);
1.26      pooka     123:
1.5       pooka     124: static struct puffs_node *
                    125: newrn(struct puffs_usermount *pu)
                    126: {
                    127:        struct puffs_node *pn;
                    128:        struct refusenode *rn;
                    129:
1.62      agc       130:        if ((rn = calloc(1, sizeof(*rn))) == NULL) {
                    131:                err(EXIT_FAILURE, "newrn");
                    132:        }
1.5       pooka     133:        pn = puffs_pn_new(pu, rn);
                    134:
                    135:        return pn;
                    136: }
                    137:
                    138: static void
                    139: nukern(struct puffs_node *pn)
                    140: {
1.36      pooka     141:        struct refusenode *rn = pn->pn_data;
1.5       pooka     142:
1.36      pooka     143:        free(rn->dirh.dbuf);
                    144:        free(rn);
1.5       pooka     145:        puffs_pn_put(pn);
                    146: }
                    147:
1.66      agc       148: /* XXX - not threadsafe */
1.1       agc       149: static ino_t fakeino = 3;
                    150:
1.66      agc       151: /***************** start of pthread context routines ************************/
                    152:
1.21      pooka     153: /*
1.66      agc       154:  * Notes on fuse_context:
                    155:  * we follow fuse's lead and use the pthread specific information to hold
                    156:  * a reference to the fuse_context structure for this thread.
1.21      pooka     157:  */
1.78      pooka     158: #ifdef MULTITHREADED_REFUSE
1.66      agc       159: static pthread_mutex_t         context_mutex = PTHREAD_MUTEX_INITIALIZER;
                    160: static pthread_key_t           context_key;
1.80      pooka     161: static unsigned long           context_refc;
1.78      pooka     162: #endif
1.66      agc       163:
                    164: /* return the fuse_context struct related to this thread */
                    165: struct fuse_context *
                    166: fuse_get_context(void)
                    167: {
1.78      pooka     168: #ifdef MULTITHREADED_REFUSE
1.66      agc       169:        struct fuse_context     *ctxt;
                    170:
                    171:        if ((ctxt = pthread_getspecific(context_key)) == NULL) {
                    172:                if ((ctxt = calloc(1, sizeof(struct fuse_context))) == NULL) {
1.80      pooka     173:                        abort();
1.66      agc       174:                }
                    175:                pthread_setspecific(context_key, ctxt);
                    176:        }
                    177:        return ctxt;
1.78      pooka     178: #else
                    179:        static struct fuse_context      fcon;
                    180:
                    181:        return &fcon;
                    182: #endif
1.66      agc       183: }
                    184:
                    185: /* used as a callback function */
1.78      pooka     186: #ifdef MULTITHREADED_REFUSE
1.66      agc       187: static void
                    188: free_context(void *ctxt)
                    189: {
                    190:        free(ctxt);
                    191: }
1.78      pooka     192: #endif
1.66      agc       193:
1.80      pooka     194: /*
                    195:  * Create the pthread key.  The reason for the complexity is to
                    196:  * enable use of multiple fuse instances within a single process.
                    197:  */
1.66      agc       198: static int
                    199: create_context_key(void)
                    200: {
1.78      pooka     201: #ifdef MULTITHREADED_REFUSE
1.80      pooka     202:        int rv;
                    203:
                    204:        rv = pthread_mutex_lock(&context_mutex);
                    205:        assert(rv == 0);
                    206:
                    207:        if (context_refc == 0) {
1.66      agc       208:                if (pthread_key_create(&context_key, free_context) != 0) {
                    209:                        warnx("create_context_key: pthread_key_create failed");
                    210:                        pthread_mutex_unlock(&context_mutex);
                    211:                        return 0;
                    212:                }
                    213:        }
                    214:        context_refc += 1;
                    215:        pthread_mutex_unlock(&context_mutex);
                    216:        return 1;
1.78      pooka     217: #else
                    218:        return 1;
                    219: #endif
1.66      agc       220: }
                    221:
                    222: static void
                    223: delete_context_key(void)
                    224: {
1.78      pooka     225: #ifdef MULTITHREADED_REFUSE
1.66      agc       226:        pthread_mutex_lock(&context_mutex);
1.80      pooka     227:        /* If we are the last fuse instances using the key, delete it */
1.66      agc       228:        if (--context_refc == 0) {
                    229:                free(pthread_getspecific(context_key));
                    230:                pthread_key_delete(context_key);
                    231:        }
                    232:        pthread_mutex_unlock(&context_mutex);
1.78      pooka     233: #endif
1.66      agc       234: }
                    235:
                    236: /* set the uid and gid of the calling process in the current fuse context */
                    237: static void
                    238: set_fuse_context_uid_gid(const struct puffs_cred *cred)
                    239: {
                    240:        struct fuse_context     *fusectx;
                    241:        uid_t                    uid;
                    242:        gid_t                    gid;
                    243:
                    244:        fusectx = fuse_get_context();
                    245:        if (puffs_cred_getuid(cred, &uid) == 0) {
                    246:                fusectx->uid = uid;
                    247:        }
                    248:        if (puffs_cred_getgid(cred, &gid) == 0) {
                    249:                fusectx->gid = gid;
                    250:        }
                    251: }
                    252:
                    253: /* set the pid of the calling process in the current fuse context */
                    254: static void
1.85      pooka     255: set_fuse_context_pid(struct puffs_usermount *pu)
1.66      agc       256: {
1.85      pooka     257:        struct puffs_cc         *pcc = puffs_cc_getcc(pu);
1.66      agc       258:        struct fuse_context     *fusectx;
1.21      pooka     259:
1.66      agc       260:        fusectx = fuse_get_context();
1.76      pooka     261:        puffs_cc_getcaller(pcc, &fusectx->pid, NULL);
1.66      agc       262: }
                    263:
                    264: /***************** end of pthread context routines ************************/
1.62      agc       265:
1.36      pooka     266: #define DIR_CHUNKSIZE 4096
                    267: static int
                    268: fill_dirbuf(struct puffs_fuse_dirh *dh, const char *name, ino_t dino,
                    269:        uint8_t dtype)
                    270: {
                    271:
                    272:        /* initial? */
                    273:        if (dh->bufsize == 0) {
1.65      agc       274:                if ((dh->dbuf = calloc(1, DIR_CHUNKSIZE)) == NULL) {
1.80      pooka     275:                        abort();
1.62      agc       276:                }
1.36      pooka     277:                dh->d = dh->dbuf;
                    278:                dh->reslen = dh->bufsize = DIR_CHUNKSIZE;
                    279:        }
1.21      pooka     280:
1.62      agc       281:        if (puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen)) {
1.36      pooka     282:                return 0;
1.62      agc       283:        }
1.36      pooka     284:
                    285:        /* try to increase buffer space */
                    286:        dh->dbuf = realloc(dh->dbuf, dh->bufsize + DIR_CHUNKSIZE);
1.62      agc       287:        if (dh->dbuf == NULL) {
1.80      pooka     288:                abort();
1.62      agc       289:        }
1.36      pooka     290:        dh->d = (void *)((uint8_t *)dh->dbuf + (dh->bufsize - dh->reslen));
                    291:        dh->reslen += DIR_CHUNKSIZE;
                    292:        dh->bufsize += DIR_CHUNKSIZE;
                    293:
                    294:        return !puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen);
                    295: }
1.1       agc       296:
1.36      pooka     297: /* ARGSUSED3 */
                    298: /* XXX: I have no idea how "off" is supposed to be used */
1.1       agc       299: static int
1.4       pooka     300: puffs_fuse_fill_dir(void *buf, const char *name,
1.1       agc       301:        const struct stat *stbuf, off_t off)
                    302: {
1.36      pooka     303:        struct puffs_fuse_dirh *deh = buf;
1.13      pooka     304:        ino_t dino;
1.1       agc       305:        uint8_t dtype;
                    306:
1.13      pooka     307:        if (stbuf == NULL) {
                    308:                dtype = DT_UNKNOWN;
                    309:                dino = fakeino++;
                    310:        } else {
                    311:                dtype = puffs_vtype2dt(puffs_mode2vt(stbuf->st_mode));
                    312:                dino = stbuf->st_ino;
1.50      pooka     313:
                    314:                /*
                    315:                 * Some FUSE file systems like to always use 0 as the
                    316:                 * inode number.   Our readdir() doesn't like to show
                    317:                 * directory entries with inode number 0 ==> workaround.
                    318:                 */
1.62      agc       319:                if (dino == 0) {
1.50      pooka     320:                        dino = fakeino++;
1.62      agc       321:                }
1.13      pooka     322:        }
1.1       agc       323:
1.36      pooka     324:        return fill_dirbuf(deh, name, dino, dtype);
1.4       pooka     325: }
                    326:
                    327: static int
                    328: puffs_fuse_dirfil(fuse_dirh_t h, const char *name, int type, ino_t ino)
                    329: {
1.43      agc       330:        ino_t dino;
                    331:        int dtype;
1.4       pooka     332:
1.62      agc       333:        if ((dtype = type) == 0) {
1.13      pooka     334:                dtype = DT_UNKNOWN;
1.62      agc       335:        }
1.43      agc       336:
1.62      agc       337:        dino = (ino) ? ino : fakeino++;
1.4       pooka     338:
1.36      pooka     339:        return fill_dirbuf(h, name, dino, dtype);
1.1       agc       340: }
                    341:
1.62      agc       342: /* place the refuse file system name into `name' */
1.53      agc       343: static void
                    344: set_refuse_mount_name(char **argv, char *name, size_t size)
                    345: {
                    346:        char    *slash;
                    347:
                    348:        if (argv == NULL || *argv == NULL) {
                    349:                (void) strlcpy(name, "refuse", size);
                    350:        } else {
                    351:                if ((slash = strrchr(*argv, '/')) == NULL) {
                    352:                        slash = *argv;
                    353:                } else {
                    354:                        slash += 1;
                    355:                }
                    356:                if (strncmp(*argv, "refuse:", 7) == 0) {
                    357:                        /* we've already done this */
                    358:                        (void) strlcpy(name, *argv, size);
                    359:                } else {
                    360:                        (void) snprintf(name, size, "refuse:%s", slash);
                    361:                }
                    362:        }
                    363: }
                    364:
                    365:
1.51      agc       366: /* this function exposes struct fuse to userland */
1.89      dillo     367: static struct fuse *
                    368: fuse_setup_real(int argc, char **argv, const struct fuse_operations *ops,
                    369:        size_t size, char **mountpoint, int *multithreaded, int *fd,
                    370:         void *user_data)
1.51      agc       371: {
                    372:        struct fuse_chan        *fc;
                    373:        struct fuse_args        *args;
                    374:        struct fuse             *fuse;
                    375:        char                     name[64];
1.53      agc       376:        int                      i;
1.51      agc       377:
1.66      agc       378:        /* set up the proper name */
1.53      agc       379:        set_refuse_mount_name(argv, name, sizeof(name));
1.51      agc       380:
1.66      agc       381:        /* grab the pthread context key */
                    382:        if (!create_context_key()) {
1.80      pooka     383:                return NULL;
1.66      agc       384:        }
                    385:
1.51      agc       386:        /* stuff name into fuse_args */
1.56      christos  387:        args = fuse_opt_deep_copy_args(argc, argv);
1.51      agc       388:        if (args->argc > 0) {
1.55      christos  389:                free(args->argv[0]);
1.51      agc       390:        }
1.66      agc       391:        if ((args->argv[0] = strdup(name)) == NULL) {
1.80      pooka     392:                fuse_opt_free_args(args);
                    393:                return NULL;
1.66      agc       394:        }
1.51      agc       395:
1.62      agc       396:        /* count back from the end over arguments starting with '-' */
1.53      agc       397:        for (i = argc - 1 ; i > 0 && *argv[i] == '-' ; --i) {
                    398:        }
                    399:
                    400:        fc = fuse_mount(*mountpoint = argv[i], args);
1.89      dillo     401:        fuse = fuse_new(fc, args, ops, size, user_data);
1.51      agc       402:
1.56      christos  403:        fuse_opt_free_args(args);
                    404:        free(args);
1.51      agc       405:
                    406:        /* XXX - wait for puffs to become multi-threaded */
                    407:        if (multithreaded) {
                    408:                *multithreaded = 0;
                    409:        }
                    410:
                    411:        /* XXX - this is unused */
                    412:        if (fd) {
                    413:                *fd = 0;
                    414:        }
                    415:
                    416:        return fuse;
                    417: }
                    418:
1.89      dillo     419: #ifdef fuse_setup
                    420: #undef fuse_setup
                    421: #endif
                    422:
                    423: struct fuse *
                    424: fuse_setup(int argc, char **argv, const struct fuse_operations *ops,
                    425:        size_t size, char **mountpoint, int *multithreaded, int *fd)
                    426: {
                    427:     return fuse_setup_real(argc, argv, ops, size, mountpoint,
                    428:        multithreaded, fd, NULL);
                    429: }
                    430:
                    431: struct fuse *
                    432: fuse_setup26(int argc, char **argv, const struct fuse_operations *ops,
                    433:        size_t size, char **mountpoint, int *multithreaded, void *user_data)
                    434: {
                    435:     return fuse_setup_real(argc, argv, ops, size, mountpoint,
                    436:        multithreaded, NULL, user_data);
                    437: }
                    438:
1.18      pooka     439: #define FUSE_ERR_UNLINK(fuse, file) if (fuse->op.unlink) fuse->op.unlink(file)
                    440: #define FUSE_ERR_RMDIR(fuse, dir) if (fuse->op.rmdir) fuse->op.rmdir(dir)
                    441:
1.26      pooka     442: /* ARGSUSED1 */
                    443: static int
                    444: fuse_getattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
                    445:        struct vattr *va)
                    446: {
                    447:        struct stat              st;
                    448:        int                     ret;
                    449:
                    450:        if (fuse->op.getattr == NULL) {
                    451:                return ENOSYS;
                    452:        }
                    453:
                    454:        /* wrap up return code */
1.74      pooka     455:        memset(&st, 0, sizeof(st));
1.26      pooka     456:        ret = (*fuse->op.getattr)(path, &st);
                    457:
                    458:        if (ret == 0) {
1.74      pooka     459:                if (st.st_blksize == 0)
                    460:                        st.st_blksize = DEV_BSIZE;
1.26      pooka     461:                puffs_stat2vattr(va, &st);
                    462:        }
                    463:
                    464:        return -ret;
                    465: }
                    466:
1.66      agc       467: /* utility function to set various elements of the attribute */
1.26      pooka     468: static int
                    469: fuse_setattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
                    470:        const struct vattr *va)
                    471: {
                    472:        struct refusenode       *rn = pn->pn_data;
                    473:        mode_t                  mode;
                    474:        uid_t                   uid;
                    475:        gid_t                   gid;
                    476:        int                     error, ret;
                    477:
                    478:        error = 0;
                    479:
                    480:        mode = va->va_mode;
                    481:        uid = va->va_uid;
                    482:        gid = va->va_gid;
                    483:
                    484:        if (mode != (mode_t)PUFFS_VNOVAL) {
                    485:                ret = 0;
                    486:
                    487:                if (fuse->op.chmod == NULL) {
                    488:                        error = -ENOSYS;
                    489:                } else {
                    490:                        ret = fuse->op.chmod(path, mode);
                    491:                        if (ret)
                    492:                                error = ret;
                    493:                }
                    494:        }
                    495:        if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
                    496:                ret = 0;
                    497:
                    498:                if (fuse->op.chown == NULL) {
                    499:                        error = -ENOSYS;
                    500:                } else {
                    501:                        ret = fuse->op.chown(path, uid, gid);
                    502:                        if (ret)
                    503:                                error = ret;
                    504:                }
                    505:        }
                    506:        if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
                    507:            || va->va_mtime.tv_sec != (long)PUFFS_VNOVAL) {
                    508:                ret = 0;
                    509:
                    510:                if (fuse->op.utimens) {
                    511:                        struct timespec tv[2];
                    512:
                    513:                        tv[0].tv_sec = va->va_atime.tv_sec;
                    514:                        tv[0].tv_nsec = va->va_atime.tv_nsec;
                    515:                        tv[1].tv_sec = va->va_mtime.tv_sec;
                    516:                        tv[1].tv_nsec = va->va_mtime.tv_nsec;
                    517:
                    518:                        ret = fuse->op.utimens(path, tv);
                    519:                } else if (fuse->op.utime) {
                    520:                        struct utimbuf timbuf;
                    521:
                    522:                        timbuf.actime = va->va_atime.tv_sec;
                    523:                        timbuf.modtime = va->va_mtime.tv_sec;
                    524:
                    525:                        ret = fuse->op.utime(path, &timbuf);
                    526:                } else {
                    527:                        error = -ENOSYS;
                    528:                }
                    529:
                    530:                if (ret)
                    531:                        error = ret;
                    532:        }
                    533:        if (va->va_size != (u_quad_t)PUFFS_VNOVAL) {
                    534:                ret = 0;
                    535:
                    536:                if (fuse->op.truncate) {
                    537:                        ret = fuse->op.truncate(path, (off_t)va->va_size);
                    538:                } else if (fuse->op.ftruncate) {
                    539:                        ret = fuse->op.ftruncate(path, (off_t)va->va_size,
                    540:                            &rn->file_info);
                    541:                } else {
                    542:                        error = -ENOSYS;
                    543:                }
                    544:
                    545:                if (ret)
                    546:                        error = ret;
                    547:        }
                    548:        /* XXX: no reflection with reality */
                    549:        puffs_setvattr(&pn->pn_va, va);
                    550:
                    551:        return -error;
                    552:
                    553: }
                    554:
                    555: static int
                    556: fuse_newnode(struct puffs_usermount *pu, const char *path,
1.71      pooka     557:        const struct vattr *va, struct fuse_file_info *fi,
                    558:        struct puffs_newinfo *pni, struct puffs_node **pn_new)
1.26      pooka     559: {
                    560:        struct puffs_node       *pn;
                    561:        struct refusenode       *rn;
1.66      agc       562:        struct vattr             newva;
                    563:        struct fuse             *fuse;
1.26      pooka     564:
1.46      pooka     565:        fuse = puffs_getspecific(pu);
1.26      pooka     566:
                    567:        /* fix up nodes */
                    568:        pn = newrn(pu);
                    569:        if (pn == NULL) {
                    570:                if (va->va_type == VDIR) {
                    571:                        FUSE_ERR_RMDIR(fuse, path);
                    572:                } else {
                    573:                        FUSE_ERR_UNLINK(fuse, path);
                    574:                }
                    575:                return ENOMEM;
                    576:        }
                    577:        fuse_setattr(fuse, pn, path, va);
                    578:        if (fuse_getattr(fuse, pn, path, &newva) == 0)
                    579:                puffs_setvattr(&pn->pn_va, &newva);
                    580:
                    581:        rn = pn->pn_data;
                    582:        if (fi)
                    583:                memcpy(&rn->file_info, fi, sizeof(struct fuse_file_info));
                    584:
1.71      pooka     585:        puffs_newinfo_setcookie(pni, pn);
                    586:        if (pn_new)
                    587:                *pn_new = pn;
1.26      pooka     588:
                    589:        return 0;
                    590: }
                    591:
                    592:
1.1       agc       593: /* operation wrappers start here */
                    594:
                    595: /* lookup the path */
                    596: /* ARGSUSED1 */
                    597: static int
1.85      pooka     598: puffs_fuse_node_lookup(struct puffs_usermount *pu, void *opc,
1.71      pooka     599:        struct puffs_newinfo *pni, const struct puffs_cn *pcn)
1.1       agc       600: {
1.12      pooka     601:        struct puffs_node       *pn_res;
1.66      agc       602:        struct stat              st;
1.1       agc       603:        struct fuse             *fuse;
                    604:        const char              *path = PCNPATH(pcn);
1.66      agc       605:        int                      ret;
1.1       agc       606:
1.46      pooka     607:        fuse = puffs_getspecific(pu);
1.62      agc       608:
1.69      pooka     609:        set_fuse_context_uid_gid(pcn->pcn_cred);
1.62      agc       610:
1.1       agc       611:        ret = fuse->op.getattr(path, &st);
1.12      pooka     612:
1.1       agc       613:        if (ret != 0) {
1.18      pooka     614:                return -ret;
1.12      pooka     615:        }
                    616:
                    617:        /* XXX: fiXXXme unconst */
                    618:        pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
                    619:            __UNCONST(&pcn->pcn_po_full));
                    620:        if (pn_res == NULL) {
                    621:                pn_res = newrn(pu);
                    622:                if (pn_res == NULL)
                    623:                        return errno;
1.26      pooka     624:                puffs_stat2vattr(&pn_res->pn_va, &st);
1.1       agc       625:        }
1.12      pooka     626:
1.71      pooka     627:        puffs_newinfo_setcookie(pni, pn_res);
                    628:        puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
                    629:        puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
                    630:        puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
1.12      pooka     631:
                    632:        return 0;
1.1       agc       633: }
                    634:
                    635: /* get attributes for the path name */
                    636: /* ARGSUSED3 */
                    637: static int
1.85      pooka     638: puffs_fuse_node_getattr(struct puffs_usermount *pu, void *opc, struct vattr *va,
1.84      pooka     639:        const struct puffs_cred *pcr)
1.1       agc       640: {
                    641:        struct puffs_node       *pn = opc;
                    642:        struct fuse             *fuse;
                    643:        const char              *path = PNPATH(pn);
                    644:
1.46      pooka     645:        fuse = puffs_getspecific(pu);
1.62      agc       646:
1.66      agc       647:        set_fuse_context_uid_gid(pcr);
1.62      agc       648:
1.26      pooka     649:        return fuse_getattr(fuse, pn, path, va);
1.1       agc       650: }
                    651:
                    652: /* read the contents of the symbolic link */
                    653: /* ARGSUSED2 */
                    654: static int
1.85      pooka     655: puffs_fuse_node_readlink(struct puffs_usermount *pu, void *opc,
1.1       agc       656:        const struct puffs_cred *cred, char *linkname, size_t *linklen)
                    657: {
                    658:        struct puffs_node       *pn = opc;
                    659:        struct fuse             *fuse;
1.13      pooka     660:        const char              *path = PNPATH(pn), *p;
1.1       agc       661:        int                     ret;
                    662:
1.46      pooka     663:        fuse = puffs_getspecific(pu);
1.1       agc       664:        if (fuse->op.readlink == NULL) {
                    665:                return ENOSYS;
                    666:        }
                    667:
1.66      agc       668:        set_fuse_context_uid_gid(cred);
1.62      agc       669:
1.1       agc       670:        /* wrap up return code */
                    671:        ret = (*fuse->op.readlink)(path, linkname, *linklen);
                    672:
                    673:        if (ret == 0) {
1.43      agc       674:                p = memchr(linkname, '\0', *linklen);
1.13      pooka     675:                if (!p)
                    676:                        return EINVAL;
                    677:
1.14      pooka     678:                *linklen = p - linkname;
1.1       agc       679:        }
                    680:
1.13      pooka     681:        return -ret;
1.1       agc       682: }
                    683:
                    684: /* make the special node */
                    685: /* ARGSUSED1 */
                    686: static int
1.85      pooka     687: puffs_fuse_node_mknod(struct puffs_usermount *pu, void *opc,
1.71      pooka     688:        struct puffs_newinfo *pni, const struct puffs_cn *pcn,
                    689:        const struct vattr *va)
1.1       agc       690: {
                    691:        struct fuse             *fuse;
1.44      pooka     692:        mode_t                   mode;
1.1       agc       693:        const char              *path = PCNPATH(pcn);
                    694:        int                     ret;
                    695:
1.46      pooka     696:        fuse = puffs_getspecific(pu);
1.1       agc       697:        if (fuse->op.mknod == NULL) {
                    698:                return ENOSYS;
                    699:        }
                    700:
1.69      pooka     701:        set_fuse_context_uid_gid(pcn->pcn_cred);
1.62      agc       702:
1.1       agc       703:        /* wrap up return code */
1.44      pooka     704:        mode = puffs_addvtype2mode(va->va_mode, va->va_type);
1.1       agc       705:        ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
                    706:
                    707:        if (ret == 0) {
1.71      pooka     708:                ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
1.1       agc       709:        }
                    710:
1.18      pooka     711:        return -ret;
1.1       agc       712: }
                    713:
                    714: /* make a directory */
                    715: /* ARGSUSED1 */
                    716: static int
1.85      pooka     717: puffs_fuse_node_mkdir(struct puffs_usermount *pu, void *opc,
1.71      pooka     718:        struct puffs_newinfo *pni, const struct puffs_cn *pcn,
                    719:        const struct vattr *va)
1.1       agc       720: {
                    721:        struct fuse             *fuse;
                    722:        mode_t                   mode = va->va_mode;
                    723:        const char              *path = PCNPATH(pcn);
                    724:        int                     ret;
                    725:
1.46      pooka     726:        fuse = puffs_getspecific(pu);
1.62      agc       727:
1.69      pooka     728:        set_fuse_context_uid_gid(pcn->pcn_cred);
1.62      agc       729:
1.1       agc       730:        if (fuse->op.mkdir == NULL) {
                    731:                return ENOSYS;
                    732:        }
                    733:
                    734:        /* wrap up return code */
                    735:        ret = (*fuse->op.mkdir)(path, mode);
                    736:
                    737:        if (ret == 0) {
1.71      pooka     738:                ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
1.1       agc       739:        }
                    740:
1.18      pooka     741:        return -ret;
1.1       agc       742: }
                    743:
1.21      pooka     744: /*
                    745:  * create a regular file
                    746:  *
                    747:  * since linux/fuse sports using mknod for creating regular files
                    748:  * instead of having a separate call for it in some versions, if
                    749:  * we don't have create, just jump to op->mknod.
                    750:  */
1.16      pooka     751: /*ARGSUSED1*/
                    752: static int
1.85      pooka     753: puffs_fuse_node_create(struct puffs_usermount *pu, void *opc,
1.71      pooka     754:        struct puffs_newinfo *pni, const struct puffs_cn *pcn,
                    755:        const struct vattr *va)
1.16      pooka     756: {
                    757:        struct fuse             *fuse;
                    758:        struct fuse_file_info   fi;
1.71      pooka     759:        struct puffs_node       *pn;
1.16      pooka     760:        mode_t                  mode = va->va_mode;
                    761:        const char              *path = PCNPATH(pcn);
1.31      pooka     762:        int                     ret, created;
1.16      pooka     763:
1.46      pooka     764:        fuse = puffs_getspecific(pu);
1.21      pooka     765:
1.69      pooka     766:        set_fuse_context_uid_gid(pcn->pcn_cred);
1.62      agc       767:
1.97    ! pho       768:        memset(&fi, 0, sizeof(fi));
1.31      pooka     769:        created = 0;
1.21      pooka     770:        if (fuse->op.create) {
1.97    ! pho       771:                /* In puffs "create" and "open" are two separate operations
        !           772:                 * with atomicity achieved by locking the parent vnode. In
        !           773:                 * fuse, on the other hand, "create" is actually a
        !           774:                 * create-and-open-atomically and the open flags (O_RDWR,
        !           775:                 * O_APPEND, ...) are passed via fi.flags. So the only way to
        !           776:                 * emulate the fuse semantics is to open the file with dummy
        !           777:                 * flags and then immediately close it.
        !           778:                 *
        !           779:                 * You might think that we could simply use fuse->op.mknod all
        !           780:                 * the time but no, that's not possible because most file
        !           781:                 * systems nowadays expect op.mknod to be called only for
        !           782:                 * non-regular files and many don't even support it. */
        !           783:                fi.flags = O_WRONLY | O_CREAT | O_EXCL;
1.86      xtraeme   784:                ret = fuse->op.create(path, mode | S_IFREG, &fi);
1.31      pooka     785:                if (ret == 0)
                    786:                        created = 1;
1.21      pooka     787:
                    788:        } else if (fuse->op.mknod) {
                    789:                ret = fuse->op.mknod(path, mode | S_IFREG, 0);
                    790:
                    791:        } else {
                    792:                ret = -ENOSYS;
1.16      pooka     793:        }
                    794:
                    795:        if (ret == 0) {
1.71      pooka     796:                ret = fuse_newnode(pu, path, va, &fi, pni, &pn);
1.31      pooka     797:
                    798:                /* sweet..  create also open the file */
1.97    ! pho       799:                if (created && fuse->op.release) {
        !           800:                        struct refusenode *rn = pn->pn_data;
        !           801:                        /* The return value of op.release is expected to be
        !           802:                         * discarded. */
        !           803:                        (void)fuse->op.release(path, &rn->file_info);
1.31      pooka     804:                }
1.16      pooka     805:        }
                    806:
1.18      pooka     807:        return -ret;
1.16      pooka     808: }
                    809:
1.1       agc       810: /* remove the directory entry */
1.23      pooka     811: /* ARGSUSED1 */
1.1       agc       812: static int
1.85      pooka     813: puffs_fuse_node_remove(struct puffs_usermount *pu, void *opc, void *targ,
1.1       agc       814:        const struct puffs_cn *pcn)
                    815: {
1.23      pooka     816:        struct puffs_node       *pn_targ = targ;
1.1       agc       817:        struct fuse             *fuse;
1.23      pooka     818:        const char              *path = PNPATH(pn_targ);
1.1       agc       819:        int                     ret;
                    820:
1.46      pooka     821:        fuse = puffs_getspecific(pu);
1.62      agc       822:
1.69      pooka     823:        set_fuse_context_uid_gid(pcn->pcn_cred);
1.62      agc       824:
1.1       agc       825:        if (fuse->op.unlink == NULL) {
                    826:                return ENOSYS;
                    827:        }
                    828:
                    829:        /* wrap up return code */
                    830:        ret = (*fuse->op.unlink)(path);
                    831:
1.18      pooka     832:        return -ret;
1.1       agc       833: }
                    834:
                    835: /* remove the directory */
                    836: /* ARGSUSED1 */
                    837: static int
1.85      pooka     838: puffs_fuse_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ,
1.1       agc       839:        const struct puffs_cn *pcn)
                    840: {
1.23      pooka     841:        struct puffs_node       *pn_targ = targ;
1.1       agc       842:        struct fuse             *fuse;
1.23      pooka     843:        const char              *path = PNPATH(pn_targ);
1.1       agc       844:        int                     ret;
                    845:
1.46      pooka     846:        fuse = puffs_getspecific(pu);
1.62      agc       847:
1.69      pooka     848:        set_fuse_context_uid_gid(pcn->pcn_cred);
1.62      agc       849:
1.1       agc       850:        if (fuse->op.rmdir == NULL) {
                    851:                return ENOSYS;
                    852:        }
                    853:
                    854:        /* wrap up return code */
                    855:        ret = (*fuse->op.rmdir)(path);
                    856:
1.18      pooka     857:        return -ret;
1.1       agc       858: }
                    859:
                    860: /* create a symbolic link */
                    861: /* ARGSUSED1 */
                    862: static int
1.85      pooka     863: puffs_fuse_node_symlink(struct puffs_usermount *pu, void *opc,
1.71      pooka     864:        struct puffs_newinfo *pni, const struct puffs_cn *pcn_src,
                    865:        const struct vattr *va, const char *link_target)
1.1       agc       866: {
                    867:        struct fuse             *fuse;
                    868:        const char              *path = PCNPATH(pcn_src);
                    869:        int                     ret;
                    870:
1.46      pooka     871:        fuse = puffs_getspecific(pu);
1.62      agc       872:
1.69      pooka     873:        set_fuse_context_uid_gid(pcn_src->pcn_cred);
1.62      agc       874:
1.1       agc       875:        if (fuse->op.symlink == NULL) {
                    876:                return ENOSYS;
                    877:        }
                    878:
                    879:        /* wrap up return code */
1.32      pooka     880:        ret = fuse->op.symlink(link_target, path);
1.1       agc       881:
                    882:        if (ret == 0) {
1.71      pooka     883:                ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
1.1       agc       884:        }
                    885:
1.18      pooka     886:        return -ret;
1.1       agc       887: }
                    888:
                    889: /* rename a directory entry */
                    890: /* ARGSUSED1 */
                    891: static int
1.85      pooka     892: puffs_fuse_node_rename(struct puffs_usermount *pu, void *opc, void *src,
1.1       agc       893:        const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
                    894:        const struct puffs_cn *pcn_targ)
                    895: {
                    896:        struct fuse             *fuse;
1.24      pooka     897:        const char              *path_src = PCNPATH(pcn_src);
                    898:        const char              *path_dest = PCNPATH(pcn_targ);
1.1       agc       899:        int                     ret;
                    900:
1.46      pooka     901:        fuse = puffs_getspecific(pu);
1.62      agc       902:
1.69      pooka     903:        set_fuse_context_uid_gid(pcn_targ->pcn_cred);
1.62      agc       904:
1.1       agc       905:        if (fuse->op.rename == NULL) {
                    906:                return ENOSYS;
                    907:        }
                    908:
1.24      pooka     909:        ret = fuse->op.rename(path_src, path_dest);
1.1       agc       910:
                    911:        if (ret == 0) {
                    912:        }
                    913:
1.18      pooka     914:        return -ret;
1.1       agc       915: }
                    916:
                    917: /* create a link in the file system */
                    918: /* ARGSUSED1 */
                    919: static int
1.85      pooka     920: puffs_fuse_node_link(struct puffs_usermount *pu, void *opc, void *targ,
1.1       agc       921:        const struct puffs_cn *pcn)
                    922: {
                    923:        struct puffs_node       *pn = targ;
                    924:        struct fuse             *fuse;
                    925:        int                     ret;
                    926:
1.46      pooka     927:        fuse = puffs_getspecific(pu);
1.62      agc       928:
1.69      pooka     929:        set_fuse_context_uid_gid(pcn->pcn_cred);
1.62      agc       930:
1.1       agc       931:        if (fuse->op.link == NULL) {
                    932:                return ENOSYS;
                    933:        }
                    934:
                    935:        /* wrap up return code */
                    936:        ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
                    937:
1.18      pooka     938:        return -ret;
1.1       agc       939: }
                    940:
                    941: /*
1.19      pooka     942:  * fuse's regular interface provides chmod(), chown(), utimes()
                    943:  * and truncate() + some variations, so try to fit the square block
                    944:  * in the circle hole and the circle block .... something like that
1.7       pooka     945:  */
1.1       agc       946: /* ARGSUSED3 */
                    947: static int
1.85      pooka     948: puffs_fuse_node_setattr(struct puffs_usermount *pu, void *opc,
1.84      pooka     949:        const struct vattr *va, const struct puffs_cred *pcr)
1.1       agc       950: {
                    951:        struct puffs_node       *pn = opc;
                    952:        struct fuse             *fuse;
                    953:        const char              *path = PNPATH(pn);
                    954:
1.46      pooka     955:        fuse = puffs_getspecific(pu);
1.1       agc       956:
1.66      agc       957:        set_fuse_context_uid_gid(pcr);
1.62      agc       958:
1.26      pooka     959:        return fuse_setattr(fuse, pn, path, va);
1.1       agc       960: }
                    961:
                    962: /* ARGSUSED2 */
                    963: static int
1.85      pooka     964: puffs_fuse_node_open(struct puffs_usermount *pu, void *opc, int mode,
1.84      pooka     965:        const struct puffs_cred *cred)
1.1       agc       966: {
                    967:        struct puffs_node       *pn = opc;
1.5       pooka     968:        struct refusenode       *rn = pn->pn_data;
1.31      pooka     969:        struct fuse_file_info   *fi = &rn->file_info;
1.1       agc       970:        struct fuse             *fuse;
                    971:        const char              *path = PNPATH(pn);
                    972:
1.46      pooka     973:        fuse = puffs_getspecific(pu);
1.1       agc       974:
1.66      agc       975:        set_fuse_context_uid_gid(cred);
1.62      agc       976:
1.30      pooka     977:        /* if open, don't open again, lest risk nuking file private info */
1.31      pooka     978:        if (rn->flags & RN_OPEN) {
                    979:                rn->opencount++;
1.1       agc       980:                return 0;
1.31      pooka     981:        }
1.1       agc       982:
1.37      pooka     983:        /* OFLAGS(), need to convert FREAD/FWRITE to O_RD/WR */
                    984:        fi->flags = (mode & ~(O_CREAT | O_EXCL | O_TRUNC)) - 1;
                    985:
1.30      pooka     986:        if (pn->pn_va.va_type == VDIR) {
                    987:                if (fuse->op.opendir)
1.33      pooka     988:                        fuse->op.opendir(path, fi);
1.30      pooka     989:        } else {
                    990:                if (fuse->op.open)
1.33      pooka     991:                        fuse->op.open(path, fi);
1.30      pooka     992:        }
1.1       agc       993:
1.33      pooka     994:        rn->flags |= RN_OPEN;
                    995:        rn->opencount++;
1.1       agc       996:
1.33      pooka     997:        return 0;
1.1       agc       998: }
                    999:
1.31      pooka    1000: /* ARGSUSED2 */
                   1001: static int
1.85      pooka    1002: puffs_fuse_node_close(struct puffs_usermount *pu, void *opc, int fflag,
1.84      pooka    1003:        const struct puffs_cred *pcr)
1.31      pooka    1004: {
                   1005:        struct puffs_node       *pn = opc;
                   1006:        struct refusenode       *rn = pn->pn_data;
                   1007:        struct fuse             *fuse;
                   1008:        struct fuse_file_info   *fi;
                   1009:        const char              *path = PNPATH(pn);
                   1010:        int                     ret;
                   1011:
1.46      pooka    1012:        fuse = puffs_getspecific(pu);
1.31      pooka    1013:        fi = &rn->file_info;
                   1014:        ret = 0;
                   1015:
1.66      agc      1016:        set_fuse_context_uid_gid(pcr);
1.62      agc      1017:
1.31      pooka    1018:        if (rn->flags & RN_OPEN) {
                   1019:                if (pn->pn_va.va_type == VDIR) {
                   1020:                        if (fuse->op.releasedir)
                   1021:                                ret = fuse->op.releasedir(path, fi);
                   1022:                } else {
                   1023:                        if (fuse->op.release)
                   1024:                                ret = fuse->op.release(path, fi);
                   1025:                }
                   1026:        }
                   1027:        rn->flags &= ~RN_OPEN;
                   1028:        rn->opencount--;
                   1029:
                   1030:        return ret;
                   1031: }
                   1032:
1.1       agc      1033: /* read some more from the file */
                   1034: /* ARGSUSED5 */
                   1035: static int
1.85      pooka    1036: puffs_fuse_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf,
1.1       agc      1037:        off_t offset, size_t *resid, const struct puffs_cred *pcr,
                   1038:        int ioflag)
                   1039: {
                   1040:        struct puffs_node       *pn = opc;
1.5       pooka    1041:        struct refusenode       *rn = pn->pn_data;
1.1       agc      1042:        struct fuse             *fuse;
                   1043:        const char              *path = PNPATH(pn);
1.25      pooka    1044:        size_t                  maxread;
1.1       agc      1045:        int                     ret;
                   1046:
1.46      pooka    1047:        fuse = puffs_getspecific(pu);
1.1       agc      1048:        if (fuse->op.read == NULL) {
                   1049:                return ENOSYS;
                   1050:        }
                   1051:
1.66      agc      1052:        set_fuse_context_uid_gid(pcr);
1.62      agc      1053:
1.25      pooka    1054:        maxread = *resid;
1.26      pooka    1055:        if (maxread > pn->pn_va.va_size - offset) {
                   1056:                /*LINTED*/
1.25      pooka    1057:                maxread = pn->pn_va.va_size - offset;
1.26      pooka    1058:        }
1.25      pooka    1059:        if (maxread == 0)
                   1060:                return 0;
                   1061:
                   1062:        ret = (*fuse->op.read)(path, (char *)buf, maxread, offset,
1.7       pooka    1063:            &rn->file_info);
1.1       agc      1064:
                   1065:        if (ret > 0) {
                   1066:                *resid -= ret;
1.16      pooka    1067:                ret = 0;
1.1       agc      1068:        }
                   1069:
1.16      pooka    1070:        return -ret;
1.1       agc      1071: }
                   1072:
                   1073: /* write to the file */
                   1074: /* ARGSUSED0 */
                   1075: static int
1.85      pooka    1076: puffs_fuse_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
1.1       agc      1077:        off_t offset, size_t *resid, const struct puffs_cred *pcr,
                   1078:        int ioflag)
                   1079: {
                   1080:        struct puffs_node       *pn = opc;
1.8       pooka    1081:        struct refusenode       *rn = pn->pn_data;
1.1       agc      1082:        struct fuse             *fuse;
                   1083:        const char              *path = PNPATH(pn);
                   1084:        int                     ret;
                   1085:
1.46      pooka    1086:        fuse = puffs_getspecific(pu);
1.1       agc      1087:        if (fuse->op.write == NULL) {
                   1088:                return ENOSYS;
                   1089:        }
                   1090:
1.66      agc      1091:        set_fuse_context_uid_gid(pcr);
1.62      agc      1092:
1.17      pooka    1093:        if (ioflag & PUFFS_IO_APPEND)
                   1094:                offset = pn->pn_va.va_size;
                   1095:
1.8       pooka    1096:        ret = (*fuse->op.write)(path, (char *)buf, *resid, offset,
                   1097:            &rn->file_info);
1.1       agc      1098:
1.96      tron     1099:        if (ret >= 0) {
1.90      lukem    1100:                if ((uint64_t)(offset + ret) > pn->pn_va.va_size)
1.23      pooka    1101:                        pn->pn_va.va_size = offset + ret;
1.26      pooka    1102:                *resid -= ret;
1.96      tron     1103:                ret = (*resid == 0) ? 0 : ENOSPC;
                   1104:        } else {
                   1105:                ret = -ret;
1.1       agc      1106:        }
                   1107:
1.96      tron     1108:        return ret;
1.1       agc      1109: }
                   1110:
                   1111:
                   1112: /* ARGSUSED3 */
                   1113: static int
1.85      pooka    1114: puffs_fuse_node_readdir(struct puffs_usermount *pu, void *opc,
                   1115:        struct dirent *dent, off_t *readoff, size_t *reslen,
                   1116:        const struct puffs_cred *pcr, int *eofflag,
                   1117:        off_t *cookies, size_t *ncookies)
1.1       agc      1118: {
                   1119:        struct puffs_node       *pn = opc;
1.8       pooka    1120:        struct refusenode       *rn = pn->pn_data;
1.43      agc      1121:        struct puffs_fuse_dirh  *dirh;
                   1122:        struct fuse             *fuse;
1.41      agc      1123:        struct dirent           *fromdent;
1.1       agc      1124:        const char              *path = PNPATH(pn);
                   1125:        int                     ret;
                   1126:
1.46      pooka    1127:        fuse = puffs_getspecific(pu);
1.4       pooka    1128:        if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
1.1       agc      1129:                return ENOSYS;
                   1130:        }
                   1131:
1.66      agc      1132:        set_fuse_context_uid_gid(pcr);
1.62      agc      1133:
1.36      pooka    1134:        if (pn->pn_va.va_type != VDIR)
                   1135:                return ENOTDIR;
                   1136:
                   1137:        dirh = &rn->dirh;
                   1138:
                   1139:        /*
                   1140:         * if we are starting from the beginning, slurp entire directory
                   1141:         * into our buffers
                   1142:         */
                   1143:        if (*readoff == 0) {
                   1144:                /* free old buffers */
                   1145:                free(dirh->dbuf);
                   1146:                memset(dirh, 0, sizeof(struct puffs_fuse_dirh));
                   1147:
                   1148:                if (fuse->op.readdir)
                   1149:                        ret = fuse->op.readdir(path, dirh, puffs_fuse_fill_dir,
                   1150:                            0, &rn->file_info);
                   1151:                else
                   1152:                        ret = fuse->op.getdir(path, dirh, puffs_fuse_dirfil);
                   1153:                if (ret)
                   1154:                        return -ret;
1.35      pooka    1155:        }
                   1156:
1.95      manu     1157:         /* Both op.readdir and op.getdir read full directory */
                   1158:         *eofflag = 1;
                   1159:
1.36      pooka    1160:        /* now, stuff results into the kernel buffers */
1.91      lukem    1161:        while (*readoff < (off_t)(dirh->bufsize - dirh->reslen)) {
1.36      pooka    1162:                /*LINTED*/
                   1163:                fromdent = (struct dirent *)((uint8_t *)dirh->dbuf + *readoff);
                   1164:
                   1165:                if (*reslen < _DIRENT_SIZE(fromdent))
                   1166:                        break;
                   1167:
                   1168:                memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
                   1169:                *readoff += _DIRENT_SIZE(fromdent);
                   1170:                *reslen -= _DIRENT_SIZE(fromdent);
1.1       agc      1171:
1.36      pooka    1172:                dent = _DIRENT_NEXT(dent);
1.1       agc      1173:        }
                   1174:
1.36      pooka    1175:        return 0;
1.1       agc      1176: }
                   1177:
1.26      pooka    1178: /* ARGSUSED */
                   1179: static int
1.85      pooka    1180: puffs_fuse_node_reclaim(struct puffs_usermount *pu, void *opc)
1.26      pooka    1181: {
                   1182:        struct puffs_node       *pn = opc;
1.3       pooka    1183:
1.5       pooka    1184:        nukern(pn);
1.26      pooka    1185:        return 0;
1.3       pooka    1186: }
                   1187:
1.1       agc      1188: /* ARGSUSED1 */
                   1189: static int
1.85      pooka    1190: puffs_fuse_fs_unmount(struct puffs_usermount *pu, int flags)
1.1       agc      1191: {
                   1192:        struct fuse             *fuse;
                   1193:
1.46      pooka    1194:        fuse = puffs_getspecific(pu);
1.1       agc      1195:        if (fuse->op.destroy == NULL) {
1.2       pooka    1196:                return 0;
1.1       agc      1197:        }
                   1198:        (*fuse->op.destroy)(fuse);
                   1199:         return 0;
                   1200: }
                   1201:
                   1202: /* ARGSUSED0 */
                   1203: static int
1.85      pooka    1204: puffs_fuse_fs_sync(struct puffs_usermount *pu, int flags,
1.84      pooka    1205:             const struct puffs_cred *cr)
1.1       agc      1206: {
1.66      agc      1207:        set_fuse_context_uid_gid(cr);
1.1       agc      1208:         return 0;
                   1209: }
                   1210:
                   1211: /* ARGSUSED2 */
                   1212: static int
1.85      pooka    1213: puffs_fuse_fs_statvfs(struct puffs_usermount *pu, struct statvfs *svfsb)
1.1       agc      1214: {
                   1215:        struct fuse             *fuse;
                   1216:        int                     ret;
                   1217:
1.46      pooka    1218:        fuse = puffs_getspecific(pu);
1.1       agc      1219:        if (fuse->op.statfs == NULL) {
1.46      pooka    1220:                if ((ret = statvfs(PNPATH(puffs_getroot(pu)), svfsb)) == -1) {
1.1       agc      1221:                        return errno;
                   1222:                }
                   1223:        } else {
1.46      pooka    1224:                ret = fuse->op.statfs(PNPATH(puffs_getroot(pu)), svfsb);
1.1       agc      1225:        }
                   1226:
1.88      pooka    1227:         return -ret;
1.1       agc      1228: }
                   1229:
                   1230:
                   1231: /* End of puffs_fuse operations */
                   1232: /* ARGSUSED3 */
                   1233: int
                   1234: fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
                   1235:        size_t size, void *userdata)
                   1236: {
1.51      agc      1237:        struct fuse     *fuse;
                   1238:        char            *mountpoint;
                   1239:        int              multithreaded;
                   1240:        int              fd;
1.38      pooka    1241:
1.93      tron     1242:        fuse = fuse_setup_real(argc, argv, ops, size, &mountpoint,
                   1243:            &multithreaded, &fd, userdata);
1.38      pooka    1244:
1.51      agc      1245:        return fuse_loop(fuse);
1.38      pooka    1246: }
                   1247:
                   1248: /*
                   1249:  * XXX: just defer the operation until fuse_new() when we have more
                   1250:  * info on our hands.  The real beef is why's this separate in fuse in
                   1251:  * the first place?
                   1252:  */
                   1253: /* ARGSUSED1 */
                   1254: struct fuse_chan *
                   1255: fuse_mount(const char *dir, struct fuse_args *args)
                   1256: {
1.48      agc      1257:        struct fuse_chan        *fc;
1.53      agc      1258:        char                     name[64];
1.38      pooka    1259:
1.65      agc      1260:        if ((fc = calloc(1, sizeof(*fc))) == NULL) {
                   1261:                err(EXIT_FAILURE, "fuse_mount");
                   1262:        }
1.60      pooka    1263:        fc->dead = 0;
1.38      pooka    1264:
1.65      agc      1265:        if ((fc->dir = strdup(dir)) == NULL) {
                   1266:                err(EXIT_FAILURE, "fuse_mount");
                   1267:        }
1.48      agc      1268:
                   1269:        /*
                   1270:         * we need to deep copy the args struct - some fuse file
                   1271:         * systems "clean up" the argument vector for "security
                   1272:         * reasons"
                   1273:         */
1.56      christos 1274:        fc->args = fuse_opt_deep_copy_args(args->argc, args->argv);
1.53      agc      1275:
                   1276:        if (args->argc > 0) {
                   1277:                set_refuse_mount_name(args->argv, name, sizeof(name));
1.55      christos 1278:                if ((args->argv[0] = strdup(name)) == NULL)
                   1279:                        err(1, "fuse_mount");
1.53      agc      1280:        }
                   1281:
1.38      pooka    1282:        return fc;
                   1283: }
                   1284:
                   1285: /* ARGSUSED1 */
                   1286: struct fuse *
                   1287: fuse_new(struct fuse_chan *fc, struct fuse_args *args,
                   1288:        const struct fuse_operations *ops, size_t size, void *userdata)
                   1289: {
1.1       agc      1290:        struct puffs_usermount  *pu;
1.66      agc      1291:        struct fuse_context     *fusectx;
1.1       agc      1292:        struct puffs_pathobj    *po_root;
1.46      pooka    1293:        struct puffs_node       *pn_root;
1.43      agc      1294:        struct puffs_ops        *pops;
1.41      agc      1295:        struct refusenode       *rn_root;
1.62      agc      1296:        struct statvfs           svfsb;
                   1297:        struct stat              st;
1.1       agc      1298:        struct fuse             *fuse;
1.62      agc      1299:        extern int               puffs_fakecc;
1.53      agc      1300:        char                     name[64];
                   1301:        char                    *argv0;
1.38      pooka    1302:
1.65      agc      1303:        if ((fuse = calloc(1, sizeof(*fuse))) == NULL) {
                   1304:                err(EXIT_FAILURE, "fuse_new");
                   1305:        }
1.38      pooka    1306:
1.92      msaitoh  1307:        /* copy fuse ops to their own structure */
1.38      pooka    1308:        (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
                   1309:
1.66      agc      1310:        fusectx = fuse_get_context();
                   1311:        fusectx->fuse = fuse;
                   1312:        fusectx->uid = 0;
                   1313:        fusectx->gid = 0;
                   1314:        fusectx->pid = 0;
                   1315:        fusectx->private_data = userdata;
1.38      pooka    1316:
                   1317:        fuse->fc = fc;
1.1       agc      1318:
1.94      tron     1319:        if (fuse->op.init != NULL)
                   1320:                fusectx->private_data = fuse->op.init(NULL); /* XXX */
                   1321:
1.1       agc      1322:        /* initialise the puffs operations structure */
                   1323:         PUFFSOP_INIT(pops);
                   1324:
                   1325:         PUFFSOP_SET(pops, puffs_fuse, fs, sync);
                   1326:         PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
                   1327:         PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
                   1328:
1.2       pooka    1329:        /*
                   1330:         * XXX: all of these don't possibly need to be
                   1331:         * unconditionally set
                   1332:         */
1.1       agc      1333:         PUFFSOP_SET(pops, puffs_fuse, node, lookup);
                   1334:         PUFFSOP_SET(pops, puffs_fuse, node, getattr);
1.15      pooka    1335:         PUFFSOP_SET(pops, puffs_fuse, node, setattr);
1.1       agc      1336:         PUFFSOP_SET(pops, puffs_fuse, node, readdir);
                   1337:         PUFFSOP_SET(pops, puffs_fuse, node, readlink);
                   1338:         PUFFSOP_SET(pops, puffs_fuse, node, mknod);
1.16      pooka    1339:         PUFFSOP_SET(pops, puffs_fuse, node, create);
1.15      pooka    1340:         PUFFSOP_SET(pops, puffs_fuse, node, remove);
1.1       agc      1341:         PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
                   1342:         PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
                   1343:         PUFFSOP_SET(pops, puffs_fuse, node, symlink);
                   1344:         PUFFSOP_SET(pops, puffs_fuse, node, rename);
                   1345:         PUFFSOP_SET(pops, puffs_fuse, node, link);
                   1346:         PUFFSOP_SET(pops, puffs_fuse, node, open);
1.31      pooka    1347:         PUFFSOP_SET(pops, puffs_fuse, node, close);
1.1       agc      1348:         PUFFSOP_SET(pops, puffs_fuse, node, read);
                   1349:         PUFFSOP_SET(pops, puffs_fuse, node, write);
1.3       pooka    1350:         PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
1.1       agc      1351:
1.53      agc      1352:        argv0 = (*args->argv[0] == 0x0) ? fc->args->argv[0] : args->argv[0];
                   1353:        set_refuse_mount_name(&argv0, name, sizeof(name));
                   1354:
1.54      pooka    1355:        puffs_fakecc = 1; /* XXX */
1.72      pooka    1356:        pu = puffs_init(pops, _PATH_PUFFS, name, fuse,
1.38      pooka    1357:                         PUFFS_FLAG_BUILDPATH
1.49      pooka    1358:                           | PUFFS_FLAG_HASHPATH
1.68      pooka    1359:                           | PUFFS_KFLAG_NOCACHE);
1.1       agc      1360:        if (pu == NULL) {
1.57      pooka    1361:                err(EXIT_FAILURE, "puffs_init");
1.1       agc      1362:        }
1.38      pooka    1363:        fc->pu = pu;
1.1       agc      1364:
1.46      pooka    1365:        pn_root = newrn(pu);
                   1366:        puffs_setroot(pu, pn_root);
                   1367:        rn_root = pn_root->pn_data;
1.30      pooka    1368:        rn_root->flags |= RN_ROOT;
                   1369:
1.1       agc      1370:        po_root = puffs_getrootpathobj(pu);
1.55      christos 1371:        if ((po_root->po_path = strdup("/")) == NULL)
                   1372:                err(1, "fuse_new");
1.1       agc      1373:        po_root->po_len = 1;
1.59      pooka    1374:        puffs_path_buildhash(pu, po_root);
1.1       agc      1375:
1.25      pooka    1376:        /* sane defaults */
1.46      pooka    1377:        puffs_vattr_null(&pn_root->pn_va);
                   1378:        pn_root->pn_va.va_type = VDIR;
                   1379:        pn_root->pn_va.va_mode = 0755;
1.25      pooka    1380:        if (fuse->op.getattr)
                   1381:                if (fuse->op.getattr(po_root->po_path, &st) == 0)
1.46      pooka    1382:                        puffs_stat2vattr(&pn_root->pn_va, &st);
                   1383:        assert(pn_root->pn_va.va_type == VDIR);
1.25      pooka    1384:
1.79      pooka    1385:        puffs_set_prepost(pu, set_fuse_context_pid, NULL);
                   1386:
1.38      pooka    1387:        puffs_zerostatvfs(&svfsb);
1.57      pooka    1388:        if (puffs_mount(pu, fc->dir, MNT_NODEV | MNT_NOSUID, pn_root) == -1) {
                   1389:                err(EXIT_FAILURE, "puffs_mount: directory \"%s\"", fc->dir);
1.1       agc      1390:        }
                   1391:
1.38      pooka    1392:        return fuse;
                   1393: }
                   1394:
                   1395: int
                   1396: fuse_loop(struct fuse *fuse)
                   1397: {
                   1398:
1.82      pooka    1399:        return puffs_mainloop(fuse->fc->pu);
1.38      pooka    1400: }
                   1401:
                   1402: void
                   1403: fuse_destroy(struct fuse *fuse)
                   1404: {
                   1405:
1.80      pooka    1406:        /*
                   1407:         * TODO: needs to assert the fs is quiescent, i.e. no other
                   1408:         * threads exist
                   1409:         */
                   1410:
1.66      agc      1411:        delete_context_key();
1.38      pooka    1412:        /* XXXXXX: missing stuff */
1.55      christos 1413:        free(fuse);
1.1       agc      1414: }
                   1415:
1.20      agc      1416: void
1.38      pooka    1417: fuse_exit(struct fuse *fuse)
1.20      agc      1418: {
                   1419:
1.60      pooka    1420:        /* XXX: puffs_exit() is WRONG */
                   1421:        if (fuse->fc->dead == 0)
                   1422:                puffs_exit(fuse->fc->pu, 1);
                   1423:        fuse->fc->dead = 1;
1.20      agc      1424: }
1.29      pooka    1425:
                   1426: /*
                   1427:  * XXX: obviously not the most perfect of functions, but needs some
                   1428:  * puffs tweaking for a better tomorrow
                   1429:  */
1.31      pooka    1430: /*ARGSUSED*/
1.29      pooka    1431: void
1.38      pooka    1432: fuse_unmount(const char *mp, struct fuse_chan *fc)
                   1433: {
                   1434:
1.60      pooka    1435:        /* XXX: puffs_exit() is WRONG */
                   1436:        if (fc->dead == 0)
                   1437:                puffs_exit(fc->pu, 1);
                   1438:        fc->dead = 1;
1.38      pooka    1439: }
                   1440:
                   1441: /*ARGSUSED*/
                   1442: void
                   1443: fuse_unmount_compat22(const char *mp)
1.29      pooka    1444: {
                   1445:
                   1446:        return;
                   1447: }
1.51      agc      1448:
                   1449: /* The next function "exposes" struct fuse to userland.  Not much
                   1450: * that we can do about this, as we're conforming to a defined
                   1451: * interface.  */
                   1452:
                   1453: void
                   1454: fuse_teardown(struct fuse *fuse, char *mountpoint)
                   1455: {
                   1456:        fuse_unmount(mountpoint, fuse->fc);
                   1457:        fuse_destroy(fuse);
                   1458: }

CVSweb <webmaster@jp.NetBSD.org>