Home | History | Annotate | Line # | Download | only in librefuse
refuse.c revision 1.6
      1  1.1    agc /*
      2  1.1    agc  * Copyright  2007 Alistair Crooks.  All rights reserved.
      3  1.1    agc  *
      4  1.1    agc  * Redistribution and use in source and binary forms, with or without
      5  1.1    agc  * modification, are permitted provided that the following conditions
      6  1.1    agc  * are met:
      7  1.1    agc  * 1. Redistributions of source code must retain the above copyright
      8  1.1    agc  *    notice, this list of conditions and the following disclaimer.
      9  1.1    agc  * 2. Redistributions in binary form must reproduce the above copyright
     10  1.1    agc  *    notice, this list of conditions and the following disclaimer in the
     11  1.1    agc  *    documentation and/or other materials provided with the distribution.
     12  1.1    agc  * 3. The name of the author may not be used to endorse or promote
     13  1.1    agc  *    products derived from this software without specific prior written
     14  1.1    agc  *    permission.
     15  1.1    agc  *
     16  1.1    agc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     17  1.1    agc  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  1.1    agc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1    agc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     20  1.1    agc  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  1.1    agc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     22  1.1    agc  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1    agc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  1.1    agc  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     25  1.1    agc  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     26  1.1    agc  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  1.1    agc  */
     28  1.1    agc #include <err.h>
     29  1.1    agc #include <errno.h>
     30  1.1    agc #include <fuse.h>
     31  1.1    agc #include <ucontext.h>
     32  1.1    agc #include <unistd.h>
     33  1.1    agc 
     34  1.1    agc #include "defs.h"
     35  1.1    agc 
     36  1.1    agc typedef uint64_t	 fuse_ino_t;
     37  1.1    agc 
     38  1.1    agc struct fuse_config {
     39  1.1    agc 	uid_t		uid;
     40  1.1    agc 	gid_t		gid;
     41  1.1    agc 	mode_t		umask;
     42  1.1    agc 	double		entry_timeout;
     43  1.1    agc 	double		negative_timeout;
     44  1.1    agc 	double		attr_timeout;
     45  1.1    agc 	double		ac_attr_timeout;
     46  1.1    agc 	int		ac_attr_timeout_set;
     47  1.1    agc 	int		debug;
     48  1.1    agc 	int		hard_remove;
     49  1.1    agc 	int		use_ino;
     50  1.1    agc 	int		readdir_ino;
     51  1.1    agc 	int		set_mode;
     52  1.1    agc 	int		set_uid;
     53  1.1    agc 	int		set_gid;
     54  1.1    agc 	int		direct_io;
     55  1.1    agc 	int		kernel_cache;
     56  1.1    agc 	int		auto_cache;
     57  1.1    agc 	int		intr;
     58  1.1    agc 	int		intr_signal;
     59  1.1    agc };
     60  1.1    agc 
     61  1.1    agc /* this is the private fuse structure */
     62  1.1    agc struct fuse {
     63  1.1    agc 	struct fuse_session	*se;		/* fuse session pointer */
     64  1.1    agc 	struct fuse_operations	op;		/* switch table of operations */
     65  1.1    agc 	int			compat;		/* compat level - not used in puffs_fuse */
     66  1.1    agc 	struct node		**name_table;
     67  1.1    agc 	size_t			name_table_size;
     68  1.1    agc 	struct node		**id_table;
     69  1.1    agc 	size_t			id_table_size;
     70  1.1    agc 	fuse_ino_t		ctr;
     71  1.1    agc 	unsigned int		generation;
     72  1.1    agc 	unsigned int		hidectr;
     73  1.1    agc 	pthread_mutex_t		lock;
     74  1.1    agc 	pthread_rwlock_t	tree_lock;
     75  1.1    agc 	void			*user_data;
     76  1.1    agc 	struct fuse_config	conf;
     77  1.1    agc 	int			intr_installed;
     78  1.1    agc 	struct puffs_usermount	*pu;
     79  1.1    agc };
     80  1.1    agc 
     81  1.5  pooka struct refusenode {
     82  1.5  pooka 	struct fuse_file_info	 file_info;
     83  1.5  pooka };
     84  1.5  pooka 
     85  1.5  pooka static struct puffs_node *
     86  1.5  pooka newrn(struct puffs_usermount *pu)
     87  1.5  pooka {
     88  1.5  pooka 	struct puffs_node *pn;
     89  1.5  pooka 	struct refusenode *rn;
     90  1.5  pooka 
     91  1.5  pooka 	rn = malloc(sizeof(struct refusenode));
     92  1.5  pooka 	if (!rn)
     93  1.5  pooka 		abort(); /*XXX*/
     94  1.5  pooka 
     95  1.5  pooka 	memset(rn, 0, sizeof(struct refusenode));
     96  1.5  pooka 	pn = puffs_pn_new(pu, rn);
     97  1.5  pooka 
     98  1.5  pooka 	return pn;
     99  1.5  pooka }
    100  1.5  pooka 
    101  1.5  pooka static void
    102  1.5  pooka nukern(struct puffs_node *pn)
    103  1.5  pooka {
    104  1.5  pooka 
    105  1.5  pooka 	free(pn->pn_data);
    106  1.5  pooka 	puffs_pn_put(pn);
    107  1.5  pooka }
    108  1.5  pooka 
    109  1.1    agc static ino_t fakeino = 3;
    110  1.1    agc 
    111  1.4  pooka /* XXX: rethinkme */
    112  1.4  pooka struct fuse_dirh {
    113  1.1    agc 	struct dirent *dent;
    114  1.1    agc 	size_t reslen;
    115  1.4  pooka 	off_t readoff;
    116  1.1    agc };
    117  1.1    agc 
    118  1.1    agc /* ARGSUSED2 */
    119  1.1    agc static int
    120  1.4  pooka puffs_fuse_fill_dir(void *buf, const char *name,
    121  1.1    agc 	const struct stat *stbuf, off_t off)
    122  1.1    agc {
    123  1.4  pooka 	struct fuse_dirh *deh = buf;
    124  1.1    agc 	uint8_t dtype;
    125  1.1    agc 
    126  1.2  pooka 	/* XXX: this is hacked *purely* for hellofs, so fiXXXme */
    127  1.1    agc 	if (*name == '.')
    128  1.1    agc 		dtype = DT_DIR;
    129  1.1    agc 	else
    130  1.1    agc 		dtype = DT_REG;
    131  1.1    agc 
    132  1.6  pooka 	return !puffs_nextdent(&deh->dent, name, fakeino++, dtype,&deh->reslen);
    133  1.4  pooka }
    134  1.4  pooka 
    135  1.4  pooka static int
    136  1.4  pooka puffs_fuse_dirfil(fuse_dirh_t h, const char *name, int type, ino_t ino)
    137  1.4  pooka {
    138  1.4  pooka 	ino_t dino;
    139  1.4  pooka 	int dtype;
    140  1.4  pooka 
    141  1.4  pooka 	/* XXX: this is hacked *purely* for cddafs, so fiXXXme */
    142  1.4  pooka 	if (type == 0) {
    143  1.4  pooka 		if (*name == '.')
    144  1.4  pooka 			dtype = DT_DIR;
    145  1.4  pooka 		else
    146  1.4  pooka 			dtype = DT_REG;
    147  1.4  pooka 	} else
    148  1.4  pooka 		dtype = type;
    149  1.4  pooka 
    150  1.4  pooka 	if (ino)
    151  1.4  pooka 		dino = ino;
    152  1.4  pooka 	else
    153  1.4  pooka 		dino = fakeino++;
    154  1.4  pooka 
    155  1.6  pooka 	return !puffs_nextdent(&h->dent, name, dino, dtype, &h->reslen);
    156  1.1    agc }
    157  1.1    agc 
    158  1.1    agc int
    159  1.1    agc fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    160  1.1    agc {
    161  1.1    agc 	char	**oldargv;
    162  1.1    agc 	int	oldargc;
    163  1.1    agc 
    164  1.1    agc 	if (args->allocated) {
    165  1.1    agc 		RENEW(char *, args->argv, args->argc + 1, "fuse_opt_add_arg1", return 0);
    166  1.1    agc 	} else {
    167  1.1    agc 		oldargv = args->argv;
    168  1.1    agc 		oldargc = args->argc;
    169  1.1    agc 		NEWARRAY(char *, args->argv, oldargc + 1, "fuse_opt_add_arg2", return 0);
    170  1.1    agc 		(void) memcpy(args->argv, oldargv, oldargc * sizeof(char *));
    171  1.1    agc 		args->allocated = 1;
    172  1.1    agc 	}
    173  1.1    agc 	args->argv[args->argc++] = strdup(arg);
    174  1.1    agc 	return 1;
    175  1.1    agc }
    176  1.1    agc 
    177  1.1    agc /* operation wrappers start here */
    178  1.1    agc 
    179  1.1    agc /* lookup the path */
    180  1.1    agc /* ARGSUSED1 */
    181  1.1    agc static int
    182  1.1    agc puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
    183  1.1    agc 	enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
    184  1.1    agc 	const struct puffs_cn *pcn)
    185  1.1    agc {
    186  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    187  1.1    agc 	struct stat		st;
    188  1.1    agc 	struct fuse		*fuse;
    189  1.1    agc 	const char		*path = PCNPATH(pcn);
    190  1.1    agc 	int			ret;
    191  1.1    agc 
    192  1.1    agc 	/* XXX: THIS IS VERY WRONG */
    193  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    194  1.1    agc 	ret = fuse->op.getattr(path, &st);
    195  1.1    agc 	ret = -ret; /* linux foo */
    196  1.1    agc 	if (ret != 0) {
    197  1.1    agc 		return ret;
    198  1.1    agc 	}
    199  1.5  pooka 	*newnode = newrn(pu);
    200  1.1    agc 	*newtype = (S_ISDIR(st.st_mode)) ? VDIR : VREG;
    201  1.1    agc 	*newsize = st.st_size;
    202  1.1    agc 	return ret;
    203  1.1    agc }
    204  1.1    agc 
    205  1.1    agc /* get attributes for the path name */
    206  1.1    agc /* ARGSUSED3 */
    207  1.1    agc static int
    208  1.1    agc puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
    209  1.1    agc 	const struct puffs_cred *pcr, pid_t pid)
    210  1.1    agc {
    211  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    212  1.1    agc 	struct puffs_node	*pn = opc;
    213  1.1    agc 	struct stat		 st;
    214  1.1    agc 	struct fuse		*fuse;
    215  1.1    agc 	const char		*path = PNPATH(pn);
    216  1.1    agc 	int			ret;
    217  1.1    agc 
    218  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    219  1.1    agc 	if (fuse->op.getattr == NULL) {
    220  1.1    agc 		return ENOSYS;
    221  1.1    agc 	}
    222  1.1    agc 
    223  1.1    agc 	/* wrap up return code */
    224  1.1    agc 	ret = (*fuse->op.getattr)(path, &st);
    225  1.1    agc 
    226  1.1    agc 	if (ret == 0) {
    227  1.1    agc 		/* fill in va from st */
    228  1.1    agc 		va->va_mode = st.st_mode;
    229  1.1    agc 		va->va_nlink = st.st_nlink;
    230  1.1    agc 		va->va_uid = st.st_uid;
    231  1.1    agc 		va->va_gid = st.st_gid;
    232  1.1    agc 		va->va_fsid = st.st_rdev;
    233  1.1    agc 		va->va_fileid = st.st_ino;
    234  1.1    agc 		va->va_size = st.st_size;
    235  1.1    agc 		va->va_blocksize = st.st_blksize;
    236  1.1    agc 		va->va_atime = st.st_atimespec;
    237  1.1    agc 		va->va_mtime = st.st_mtimespec;
    238  1.1    agc 		va->va_ctime = st.st_ctimespec;
    239  1.1    agc 		va->va_birthtime = st.st_birthtimespec;
    240  1.1    agc 		va->va_gen = st.st_gen;
    241  1.1    agc 		va->va_flags = st.st_flags;
    242  1.1    agc 		va->va_rdev = st.st_rdev;
    243  1.1    agc 		va->va_bytes = st.st_size;
    244  1.1    agc 		va->va_filerev = st.st_gen;
    245  1.1    agc 		va->va_vaflags = st.st_flags;
    246  1.1    agc 
    247  1.1    agc 	}
    248  1.1    agc 
    249  1.1    agc 	return ret;
    250  1.1    agc }
    251  1.1    agc 
    252  1.1    agc /* read the contents of the symbolic link */
    253  1.1    agc /* ARGSUSED2 */
    254  1.1    agc static int
    255  1.1    agc puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
    256  1.1    agc 	const struct puffs_cred *cred, char *linkname, size_t *linklen)
    257  1.1    agc {
    258  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    259  1.1    agc 	struct puffs_node	*pn = opc;
    260  1.1    agc 	struct fuse		*fuse;
    261  1.1    agc 	const char		*path = PNPATH(pn);
    262  1.1    agc 	int			ret;
    263  1.1    agc 
    264  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    265  1.1    agc 	if (fuse->op.readlink == NULL) {
    266  1.1    agc 		return ENOSYS;
    267  1.1    agc 	}
    268  1.1    agc 
    269  1.1    agc 	/* wrap up return code */
    270  1.1    agc 	ret = (*fuse->op.readlink)(path, linkname, *linklen);
    271  1.1    agc 
    272  1.1    agc 	if (ret == 0) {
    273  1.1    agc 	}
    274  1.1    agc 
    275  1.1    agc 	return ret;
    276  1.1    agc }
    277  1.1    agc 
    278  1.1    agc /* make the special node */
    279  1.1    agc /* ARGSUSED1 */
    280  1.1    agc static int
    281  1.1    agc puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
    282  1.1    agc 	const struct puffs_cn *pcn, const struct vattr *va)
    283  1.1    agc {
    284  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    285  1.1    agc 	struct puffs_node	*pn;
    286  1.1    agc 	struct fuse		*fuse;
    287  1.1    agc 	mode_t			 mode = va->va_mode;
    288  1.1    agc 	const char		*path = PCNPATH(pcn);
    289  1.1    agc 	int			ret;
    290  1.1    agc 
    291  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    292  1.1    agc 	if (fuse->op.mknod == NULL) {
    293  1.1    agc 		return ENOSYS;
    294  1.1    agc 	}
    295  1.1    agc 
    296  1.1    agc 	/* wrap up return code */
    297  1.1    agc 	ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
    298  1.1    agc 
    299  1.1    agc 	if (ret == 0) {
    300  1.1    agc 		/* fix up nodes */
    301  1.5  pooka 		pn = newrn(pu);
    302  1.1    agc 		if (pn == NULL) {
    303  1.1    agc 			unlink(PCNPATH(pcn));
    304  1.1    agc 			return ENOMEM;
    305  1.1    agc 		}
    306  1.1    agc 		puffs_setvattr(&pn->pn_va, va);
    307  1.1    agc 
    308  1.1    agc 		*newnode = pn;
    309  1.1    agc 	}
    310  1.1    agc 
    311  1.1    agc 	return ret;
    312  1.1    agc }
    313  1.1    agc 
    314  1.1    agc /* make a directory */
    315  1.1    agc /* ARGSUSED1 */
    316  1.1    agc static int
    317  1.1    agc puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
    318  1.1    agc 	const struct puffs_cn *pcn, const struct vattr *va)
    319  1.1    agc {
    320  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    321  1.1    agc 	struct puffs_node	*pn;
    322  1.1    agc 	struct fuse		*fuse;
    323  1.1    agc 	mode_t			 mode = va->va_mode;
    324  1.1    agc 	const char		*path = PCNPATH(pcn);
    325  1.1    agc 	int			ret;
    326  1.1    agc 
    327  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    328  1.1    agc 	if (fuse->op.mkdir == NULL) {
    329  1.1    agc 		return ENOSYS;
    330  1.1    agc 	}
    331  1.1    agc 
    332  1.1    agc 	/* wrap up return code */
    333  1.1    agc 	ret = (*fuse->op.mkdir)(path, mode);
    334  1.1    agc 
    335  1.1    agc 	if (ret == 0) {
    336  1.1    agc 		/* fix up nodes */
    337  1.5  pooka 		pn = newrn(pu);
    338  1.1    agc 		if (pn == NULL) {
    339  1.1    agc 			rmdir(PCNPATH(pcn));
    340  1.1    agc 			return ENOMEM;
    341  1.1    agc 		}
    342  1.1    agc 		puffs_setvattr(&pn->pn_va, va);
    343  1.1    agc 
    344  1.1    agc 		*newnode = pn;
    345  1.1    agc 	}
    346  1.1    agc 
    347  1.1    agc 	return ret;
    348  1.1    agc }
    349  1.1    agc 
    350  1.1    agc /* remove the directory entry */
    351  1.1    agc /* ARGSUSED1 */
    352  1.1    agc static int
    353  1.1    agc puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
    354  1.1    agc 	const struct puffs_cn *pcn)
    355  1.1    agc {
    356  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    357  1.1    agc 	struct fuse		*fuse;
    358  1.1    agc 	const char		*path = PCNPATH(pcn);
    359  1.1    agc 	int			ret;
    360  1.1    agc 
    361  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    362  1.1    agc 	if (fuse->op.unlink == NULL) {
    363  1.1    agc 		return ENOSYS;
    364  1.1    agc 	}
    365  1.1    agc 
    366  1.1    agc 	/* wrap up return code */
    367  1.1    agc 	ret = (*fuse->op.unlink)(path);
    368  1.1    agc 
    369  1.1    agc 	return ret;
    370  1.1    agc }
    371  1.1    agc 
    372  1.1    agc /* remove the directory */
    373  1.1    agc /* ARGSUSED1 */
    374  1.1    agc static int
    375  1.1    agc puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
    376  1.1    agc 	const struct puffs_cn *pcn)
    377  1.1    agc {
    378  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    379  1.1    agc 	struct fuse		*fuse;
    380  1.1    agc 	const char		*path = PCNPATH(pcn);
    381  1.1    agc 	int			ret;
    382  1.1    agc 
    383  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    384  1.1    agc 	if (fuse->op.rmdir == NULL) {
    385  1.1    agc 		return ENOSYS;
    386  1.1    agc 	}
    387  1.1    agc 
    388  1.1    agc 	/* wrap up return code */
    389  1.1    agc 	ret = (*fuse->op.rmdir)(path);
    390  1.1    agc 
    391  1.1    agc 	return ret;
    392  1.1    agc }
    393  1.1    agc 
    394  1.1    agc /* create a symbolic link */
    395  1.1    agc /* ARGSUSED1 */
    396  1.1    agc static int
    397  1.1    agc puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
    398  1.1    agc 	const struct puffs_cn *pcn_src, const struct vattr *va,
    399  1.1    agc 	const char *link_target)
    400  1.1    agc {
    401  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    402  1.1    agc 	struct puffs_node	*pn;
    403  1.1    agc 	struct fuse		*fuse;
    404  1.1    agc 	const char		*path = PCNPATH(pcn_src);
    405  1.1    agc 	int			ret;
    406  1.1    agc 
    407  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    408  1.1    agc 	if (fuse->op.symlink == NULL) {
    409  1.1    agc 		return ENOSYS;
    410  1.1    agc 	}
    411  1.1    agc 
    412  1.1    agc 	/* wrap up return code */
    413  1.1    agc 	ret = (*fuse->op.symlink)(path, link_target);
    414  1.1    agc 	/* XXX - check I haven't transposed these args */
    415  1.1    agc 
    416  1.1    agc 	if (ret == 0) {
    417  1.1    agc 		/* fix up nodes */
    418  1.5  pooka 		pn = newrn(pu);
    419  1.1    agc 		if (pn == NULL) {
    420  1.1    agc 			unlink(link_target);
    421  1.1    agc 			return ENOMEM;
    422  1.1    agc 		}
    423  1.1    agc 		puffs_setvattr(&pn->pn_va, va);
    424  1.1    agc 
    425  1.1    agc 		*newnode = pn;
    426  1.1    agc 	}
    427  1.1    agc 
    428  1.1    agc 	return ret;
    429  1.1    agc }
    430  1.1    agc 
    431  1.1    agc /* rename a directory entry */
    432  1.1    agc /* ARGSUSED1 */
    433  1.1    agc static int
    434  1.1    agc puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
    435  1.1    agc 	const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
    436  1.1    agc 	const struct puffs_cn *pcn_targ)
    437  1.1    agc {
    438  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    439  1.1    agc 	struct puffs_node	*pn = opc;
    440  1.1    agc 	struct vattr		va;
    441  1.1    agc 	struct fuse		*fuse;
    442  1.1    agc 	const char		*path = PCNPATH(pcn_src);
    443  1.1    agc 	int			ret;
    444  1.1    agc 
    445  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    446  1.1    agc 	if (fuse->op.rename == NULL) {
    447  1.1    agc 		return ENOSYS;
    448  1.1    agc 	}
    449  1.1    agc 
    450  1.1    agc 	/* wrap up return code */
    451  1.1    agc 	ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
    452  1.1    agc 
    453  1.5  pooka 	/* XXX: what's this guy doing??? */
    454  1.1    agc 	if (ret == 0) {
    455  1.1    agc 		(void) memcpy(&va, &pn->pn_va, sizeof(va));
    456  1.1    agc 
    457  1.1    agc 		puffs_pn_put(pn);
    458  1.1    agc 
    459  1.1    agc 		pn = puffs_pn_new(pu, NULL);
    460  1.1    agc 		if (pn == NULL) {
    461  1.1    agc 			return ENOMEM;
    462  1.1    agc 		}
    463  1.1    agc 		puffs_setvattr(&pn->pn_va, &va);
    464  1.1    agc 
    465  1.1    agc 	}
    466  1.1    agc 
    467  1.1    agc 	return ret;
    468  1.1    agc }
    469  1.1    agc 
    470  1.1    agc /* create a link in the file system */
    471  1.1    agc /* ARGSUSED1 */
    472  1.1    agc static int
    473  1.1    agc puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
    474  1.1    agc 	const struct puffs_cn *pcn)
    475  1.1    agc {
    476  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    477  1.1    agc 	struct puffs_node	*pn = targ;
    478  1.1    agc 	struct fuse		*fuse;
    479  1.1    agc 	int			ret;
    480  1.1    agc 
    481  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    482  1.1    agc 	if (fuse->op.link == NULL) {
    483  1.1    agc 		return ENOSYS;
    484  1.1    agc 	}
    485  1.1    agc 
    486  1.1    agc 	/* wrap up return code */
    487  1.1    agc 	ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
    488  1.1    agc 
    489  1.1    agc 	if (ret == 0) {
    490  1.1    agc 		/* fix up nodes */
    491  1.5  pooka 		pn = newrn(pu);
    492  1.1    agc 		if (pn == NULL) {
    493  1.1    agc 			unlink(PCNPATH(pcn));
    494  1.1    agc 			return ENOMEM;
    495  1.1    agc 		}
    496  1.1    agc 	}
    497  1.1    agc 
    498  1.1    agc 	return ret;
    499  1.1    agc }
    500  1.1    agc 
    501  1.1    agc /*
    502  1.1    agc We run into a slight problemette here - puffs provides
    503  1.1    agc setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
    504  1.1    agc functionality.  So that we don't miss out on anything when calling a
    505  1.1    agc fuse operation, we have to get the vattr from the existing file,
    506  1.1    agc find out what's changed, and then switch on that to call the fuse
    507  1.1    agc function accordingly.
    508  1.1    agc */
    509  1.1    agc /* ARGSUSED3 */
    510  1.1    agc static int
    511  1.1    agc puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
    512  1.1    agc 	const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
    513  1.1    agc {
    514  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    515  1.1    agc 	struct puffs_node	*pn = opc;
    516  1.1    agc 	struct fuse		*fuse;
    517  1.1    agc 	const char		*path = PNPATH(pn);
    518  1.1    agc 	mode_t			mode;
    519  1.1    agc 	uid_t			uid;
    520  1.1    agc 	gid_t			gid;
    521  1.1    agc 	int			ret;
    522  1.1    agc 
    523  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    524  1.1    agc 
    525  1.1    agc 	ret = -1;
    526  1.1    agc 
    527  1.1    agc 	mode = va->va_mode;
    528  1.1    agc 	uid = va->va_uid;
    529  1.1    agc 	gid = va->va_gid;
    530  1.1    agc 
    531  1.1    agc 	if (mode != 0) {
    532  1.1    agc 		if (fuse->op.chmod == NULL) {
    533  1.1    agc 			return ENOSYS;
    534  1.1    agc 		}
    535  1.1    agc 		ret = (*fuse->op.chmod)(path, mode);
    536  1.1    agc 	}
    537  1.1    agc 	if (uid != 0 || gid != 0) {
    538  1.1    agc 		if (fuse->op.chown == NULL) {
    539  1.1    agc 			return ENOSYS;
    540  1.1    agc 		}
    541  1.1    agc 		ret = (*fuse->op.chown)(path, uid, gid);
    542  1.1    agc 	}
    543  1.1    agc 
    544  1.1    agc 	if (ret == 0) {
    545  1.1    agc 	}
    546  1.1    agc 
    547  1.1    agc 	return ret;
    548  1.1    agc }
    549  1.1    agc 
    550  1.1    agc /* ARGSUSED2 */
    551  1.1    agc static int
    552  1.1    agc puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
    553  1.1    agc 	const struct puffs_cred *cred, pid_t pid)
    554  1.1    agc {
    555  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    556  1.1    agc 	struct puffs_node	*pn = opc;
    557  1.5  pooka 	struct refusenode	*rn = pn->pn_data;
    558  1.1    agc 	struct fuse		*fuse;
    559  1.1    agc 	struct stat		 st;
    560  1.1    agc 	const char		*path = PNPATH(pn);
    561  1.1    agc 	int			 ret;
    562  1.1    agc 
    563  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    564  1.1    agc 	if (fuse->op.open == NULL) {
    565  1.1    agc 		return ENOSYS;
    566  1.1    agc 	}
    567  1.1    agc 
    568  1.1    agc 	/* examine type - if directory, return 0 rather than open */
    569  1.1    agc 	ret = (fuse->op.getattr == NULL) ?
    570  1.1    agc 		stat(path, &st) :
    571  1.1    agc 		(*fuse->op.getattr)(path, &st);
    572  1.1    agc 	if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
    573  1.1    agc 		return 0;
    574  1.1    agc 	}
    575  1.1    agc 
    576  1.1    agc 	if (strcmp(path, "/") == 0) {
    577  1.1    agc 		return 0;
    578  1.1    agc 	}
    579  1.1    agc 
    580  1.5  pooka 	ret = (*fuse->op.open)(path, &rn->file_info);
    581  1.1    agc 
    582  1.1    agc 	if (ret == 0) {
    583  1.1    agc 	}
    584  1.1    agc 
    585  1.1    agc 	return ret;
    586  1.1    agc }
    587  1.1    agc 
    588  1.1    agc /* read some more from the file */
    589  1.1    agc /* ARGSUSED5 */
    590  1.1    agc static int
    591  1.1    agc puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
    592  1.1    agc 	off_t offset, size_t *resid, const struct puffs_cred *pcr,
    593  1.1    agc 	int ioflag)
    594  1.1    agc {
    595  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    596  1.1    agc 	struct puffs_node	*pn = opc;
    597  1.5  pooka 	struct refusenode	*rn = pn->pn_data;
    598  1.1    agc 	struct fuse		*fuse;
    599  1.1    agc 	const char		*path = PNPATH(pn);
    600  1.1    agc 	int			ret;
    601  1.1    agc 
    602  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    603  1.1    agc 	if (fuse->op.read == NULL) {
    604  1.1    agc 		return ENOSYS;
    605  1.1    agc 	}
    606  1.1    agc 
    607  1.5  pooka 	ret = (*fuse->op.read)(path, (char *)buf, *resid, offset, &rn->file_info);
    608  1.1    agc 
    609  1.1    agc 	if (ret > 0) {
    610  1.1    agc 		*resid -= ret;
    611  1.1    agc 	}
    612  1.1    agc 
    613  1.1    agc 	return 0;
    614  1.1    agc }
    615  1.1    agc 
    616  1.1    agc /* write to the file */
    617  1.1    agc /* ARGSUSED0 */
    618  1.1    agc static int
    619  1.1    agc puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
    620  1.1    agc 	off_t offset, size_t *resid, const struct puffs_cred *pcr,
    621  1.1    agc 	int ioflag)
    622  1.1    agc {
    623  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    624  1.1    agc 	struct fuse_file_info	file_info;
    625  1.1    agc 	struct puffs_node	*pn = opc;
    626  1.1    agc 	struct fuse		*fuse;
    627  1.1    agc 	const char		*path = PNPATH(pn);
    628  1.1    agc 	int			ret;
    629  1.1    agc 
    630  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    631  1.1    agc 	if (fuse->op.write == NULL) {
    632  1.1    agc 		return ENOSYS;
    633  1.1    agc 	}
    634  1.1    agc 
    635  1.1    agc 	(void) memset(&file_info, 0x0, sizeof(file_info));
    636  1.1    agc 
    637  1.1    agc 	/* XXX fill in file_info here */
    638  1.1    agc 
    639  1.1    agc 	ret = (*fuse->op.write)(path, (char *)buf, *resid, offset, &file_info);
    640  1.1    agc 
    641  1.1    agc 	if (ret > 0) {
    642  1.1    agc 		*resid -= ret;
    643  1.1    agc 	}
    644  1.1    agc 
    645  1.1    agc 	return ret;
    646  1.1    agc }
    647  1.1    agc 
    648  1.1    agc 
    649  1.1    agc /* ARGSUSED3 */
    650  1.1    agc static int
    651  1.1    agc puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
    652  1.1    agc 	struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
    653  1.1    agc 	size_t *reslen)
    654  1.1    agc {
    655  1.1    agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    656  1.1    agc 	struct fuse_file_info	file_info;
    657  1.1    agc 	struct puffs_node	*pn = opc;
    658  1.1    agc 	struct fuse		*fuse;
    659  1.1    agc 	const char		*path = PNPATH(pn);
    660  1.4  pooka 	struct fuse_dirh	deh;
    661  1.1    agc 	int			ret;
    662  1.1    agc 
    663  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    664  1.4  pooka 	if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
    665  1.1    agc 		return ENOSYS;
    666  1.1    agc 	}
    667  1.1    agc 
    668  1.1    agc 	/* XXX: how to handle this??? */
    669  1.1    agc 	if (*readoff != 0) {
    670  1.1    agc 		return 0;
    671  1.1    agc 	}
    672  1.1    agc 
    673  1.1    agc 	(void) memset(&file_info, 0x0, sizeof(file_info));
    674  1.1    agc 	/* XXX - fill in file_info here */
    675  1.1    agc 
    676  1.4  pooka 	deh.dent = dent;
    677  1.4  pooka 	deh.reslen = *reslen;
    678  1.4  pooka 	deh.readoff = *readoff;
    679  1.4  pooka 
    680  1.4  pooka 	if (fuse->op.readdir)
    681  1.4  pooka 		ret = fuse->op.readdir(path, &deh, puffs_fuse_fill_dir, *readoff, &file_info);
    682  1.4  pooka 	else
    683  1.4  pooka 		ret = fuse->op.getdir(path, &deh, puffs_fuse_dirfil);
    684  1.4  pooka 	*reslen = deh.reslen;
    685  1.1    agc 	*readoff = 1;
    686  1.1    agc 
    687  1.1    agc 	if (ret == 0) {
    688  1.1    agc 	}
    689  1.1    agc 
    690  1.1    agc 	return ret;
    691  1.1    agc }
    692  1.1    agc 
    693  1.3  pooka /* ARGSUSED */
    694  1.3  pooka static int
    695  1.3  pooka puffs_fuse_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
    696  1.3  pooka {
    697  1.3  pooka 	struct puffs_node	*pn = opc;
    698  1.3  pooka 
    699  1.5  pooka 	nukern(pn);
    700  1.3  pooka 
    701  1.3  pooka 	return 0;
    702  1.3  pooka }
    703  1.3  pooka 
    704  1.1    agc /* ARGSUSED1 */
    705  1.1    agc static int
    706  1.1    agc puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
    707  1.1    agc {
    708  1.1    agc         struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    709  1.1    agc 	struct fuse		*fuse;
    710  1.1    agc 
    711  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    712  1.1    agc 	if (fuse->op.destroy == NULL) {
    713  1.2  pooka 		return 0;
    714  1.1    agc 	}
    715  1.1    agc 	(*fuse->op.destroy)(fuse);
    716  1.1    agc         return 0;
    717  1.1    agc }
    718  1.1    agc 
    719  1.1    agc /* ARGSUSED0 */
    720  1.1    agc static int
    721  1.1    agc puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
    722  1.1    agc             const struct puffs_cred *cr, pid_t pid)
    723  1.1    agc {
    724  1.1    agc         return 0;
    725  1.1    agc }
    726  1.1    agc 
    727  1.1    agc /* ARGSUSED2 */
    728  1.1    agc static int
    729  1.1    agc puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
    730  1.1    agc {
    731  1.1    agc         struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    732  1.1    agc 	struct fuse		*fuse;
    733  1.1    agc 	int			ret;
    734  1.1    agc 
    735  1.1    agc 	fuse = (struct fuse *)pu->pu_privdata;
    736  1.1    agc 	if (fuse->op.statfs == NULL) {
    737  1.1    agc 		if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
    738  1.1    agc 			return errno;
    739  1.1    agc 		}
    740  1.1    agc 	} else {
    741  1.1    agc 		ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
    742  1.1    agc 	}
    743  1.1    agc 
    744  1.1    agc         return ret;
    745  1.1    agc }
    746  1.1    agc 
    747  1.1    agc 
    748  1.1    agc 
    749  1.1    agc 
    750  1.1    agc /* End of puffs_fuse operations */
    751  1.1    agc 
    752  1.1    agc /* ARGSUSED3 */
    753  1.1    agc int
    754  1.1    agc fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
    755  1.1    agc 	size_t size, void *userdata)
    756  1.1    agc {
    757  1.1    agc 	struct puffs_usermount	*pu;
    758  1.1    agc 	struct puffs_pathobj	*po_root;
    759  1.1    agc 	struct puffs_ops	*pops;
    760  1.1    agc 	struct statvfs		svfsb;
    761  1.1    agc 	struct fuse		*fuse;
    762  1.1    agc 	char			 name[64];
    763  1.1    agc 	char			*slash;
    764  1.1    agc 	int			 ret;
    765  1.1    agc 
    766  1.1    agc 	/* initialise the puffs operations structure */
    767  1.1    agc         PUFFSOP_INIT(pops);
    768  1.1    agc 
    769  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, fs, sync);
    770  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
    771  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
    772  1.1    agc 
    773  1.2  pooka 	/*
    774  1.2  pooka 	 * XXX: all of these don't possibly need to be
    775  1.2  pooka 	 * unconditionally set
    776  1.2  pooka 	 */
    777  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, lookup);
    778  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, getattr);
    779  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, readdir);
    780  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, readlink);
    781  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, mknod);
    782  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
    783  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, remove);
    784  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
    785  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, symlink);
    786  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, rename);
    787  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, link);
    788  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, setattr);
    789  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, open);
    790  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, read);
    791  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, write);
    792  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, readdir);
    793  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, read);
    794  1.1    agc         PUFFSOP_SET(pops, puffs_fuse, node, write);
    795  1.3  pooka         PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
    796  1.1    agc 
    797  1.1    agc 	NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
    798  1.1    agc 
    799  1.1    agc 	/* copy fuse ops to their own stucture */
    800  1.1    agc 	(void) memcpy(&fuse->op, ops, sizeof(fuse->op));
    801  1.1    agc 
    802  1.1    agc 	/* whilst this (assigning the pu_privdata in the puffs
    803  1.1    agc 	 * usermount struct to be the fuse struct) might seem like
    804  1.1    agc 	 * we are chasing our tail here, the logic is as follows:
    805  1.1    agc 		+ the operation wrapper gets called with the puffs
    806  1.1    agc 		  calling conventions
    807  1.1    agc 		+ we need to fix up args first
    808  1.1    agc 		+ then call the fuse user-supplied operation
    809  1.1    agc 		+ then we fix up any values on return that we need to
    810  1.1    agc 		+ and fix up any nodes, etc
    811  1.1    agc 	* so we need to be able to get at the fuse ops from within the
    812  1.1    agc 	* puffs_usermount struct
    813  1.1    agc 	*/
    814  1.1    agc 	if ((slash = strrchr(*argv, '/')) == NULL) {
    815  1.1    agc 		slash = *argv;
    816  1.1    agc 	} else {
    817  1.1    agc 		slash += 1;
    818  1.1    agc 	}
    819  1.1    agc 	(void) snprintf(name, sizeof(name), "refuse:%s", slash);
    820  1.1    agc 	pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
    821  1.1    agc 			name, fuse,
    822  1.1    agc 			PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
    823  1.1    agc 	if (pu == NULL) {
    824  1.1    agc 		err(EXIT_FAILURE, "puffs_mount");
    825  1.1    agc 	}
    826  1.1    agc 
    827  1.1    agc 	fuse->pu = pu;
    828  1.1    agc 	pu->pu_pn_root = puffs_pn_new(pu, NULL);
    829  1.1    agc 	po_root = puffs_getrootpathobj(pu);
    830  1.1    agc 	po_root->po_path = strdup("/");
    831  1.1    agc 	po_root->po_len = 1;
    832  1.1    agc 
    833  1.1    agc 	statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
    834  1.1    agc 	if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
    835  1.1    agc 		err(EXIT_FAILURE, "puffs_start");
    836  1.1    agc 	}
    837  1.1    agc 
    838  1.1    agc 	ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
    839  1.1    agc 
    840  1.1    agc 	(void) free(po_root->po_path);
    841  1.1    agc 	FREE(fuse);
    842  1.1    agc 	return ret;
    843  1.1    agc }
    844  1.1    agc 
    845  1.1    agc /* ARGSUSED0 */
    846  1.1    agc int
    847  1.1    agc fuse_opt_parse(struct fuse_args *args, void *data,
    848  1.1    agc 	const struct fuse_opt *opts, fuse_opt_proc_t proc)
    849  1.1    agc {
    850  1.1    agc 	return 0;
    851  1.1    agc }
    852