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