Home | History | Annotate | Line # | Download | only in librefuse
refuse.c revision 1.1
      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.1  agc /* call context */
     82  1.1  agc 
     83  1.1  agc struct puffs_cc {
     84  1.1  agc 	struct puffs_usermount	*pcc_pu;
     85  1.1  agc 	struct puffs_req	*pcc_preq;
     86  1.1  agc 
     87  1.1  agc 	ucontext_t		pcc_uc;		/* "continue" 		*/
     88  1.1  agc 	ucontext_t		pcc_uc_ret;	/* "yield" 		*/
     89  1.1  agc 	void			*pcc_stack;
     90  1.1  agc 
     91  1.1  agc 	int			pcc_flags;
     92  1.1  agc 
     93  1.1  agc 	/* these are for threading information to the implementation	*/
     94  1.1  agc 	void			*pcc_priv;
     95  1.1  agc 	int			pcc_rv;
     96  1.1  agc 
     97  1.1  agc 	TAILQ_ENTRY(puffs_cc)	entries;
     98  1.1  agc };
     99  1.1  agc 
    100  1.1  agc static ino_t fakeino = 3;
    101  1.1  agc 
    102  1.1  agc struct feh {
    103  1.1  agc 	struct dirent *dent;
    104  1.1  agc 	size_t reslen;
    105  1.1  agc };
    106  1.1  agc 
    107  1.1  agc /* ARGSUSED2 */
    108  1.1  agc static int
    109  1.1  agc puffs_fuse_dirfiller(void *buf, const char *name,
    110  1.1  agc 	const struct stat *stbuf, off_t off)
    111  1.1  agc {
    112  1.1  agc 	struct feh *feh = buf;
    113  1.1  agc 	uint8_t dtype;
    114  1.1  agc 
    115  1.1  agc 	/* gazeesus & other similar dudes */
    116  1.1  agc 	if (*name == '.')
    117  1.1  agc 		dtype = DT_DIR;
    118  1.1  agc 	else
    119  1.1  agc 		dtype = DT_REG;
    120  1.1  agc 
    121  1.1  agc 	return puffs_nextdent(&feh->dent, name, fakeino++, dtype, &feh->reslen);
    122  1.1  agc }
    123  1.1  agc 
    124  1.1  agc int
    125  1.1  agc fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    126  1.1  agc {
    127  1.1  agc 	char	**oldargv;
    128  1.1  agc 	int	oldargc;
    129  1.1  agc 
    130  1.1  agc 	if (args->allocated) {
    131  1.1  agc 		RENEW(char *, args->argv, args->argc + 1, "fuse_opt_add_arg1", return 0);
    132  1.1  agc 	} else {
    133  1.1  agc 		oldargv = args->argv;
    134  1.1  agc 		oldargc = args->argc;
    135  1.1  agc 		NEWARRAY(char *, args->argv, oldargc + 1, "fuse_opt_add_arg2", return 0);
    136  1.1  agc 		(void) memcpy(args->argv, oldargv, oldargc * sizeof(char *));
    137  1.1  agc 		args->allocated = 1;
    138  1.1  agc 	}
    139  1.1  agc 	args->argv[args->argc++] = strdup(arg);
    140  1.1  agc 	return 1;
    141  1.1  agc }
    142  1.1  agc 
    143  1.1  agc /* operation wrappers start here */
    144  1.1  agc 
    145  1.1  agc /* lookup the path */
    146  1.1  agc /* ARGSUSED1 */
    147  1.1  agc static int
    148  1.1  agc puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
    149  1.1  agc 	enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
    150  1.1  agc 	const struct puffs_cn *pcn)
    151  1.1  agc {
    152  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    153  1.1  agc 	struct stat		st;
    154  1.1  agc 	struct fuse		*fuse;
    155  1.1  agc 	const char		*path = PCNPATH(pcn);
    156  1.1  agc 	int			ret;
    157  1.1  agc 
    158  1.1  agc 	/* XXX: THIS IS VERY WRONG */
    159  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    160  1.1  agc 	ret = fuse->op.getattr(path, &st);
    161  1.1  agc 	ret = -ret; /* linux foo */
    162  1.1  agc 	if (ret != 0) {
    163  1.1  agc 		return ret;
    164  1.1  agc 	}
    165  1.1  agc 	*newnode = puffs_pn_new(pu, NULL);
    166  1.1  agc 	*newtype = (S_ISDIR(st.st_mode)) ? VDIR : VREG;
    167  1.1  agc 	*newsize = st.st_size;
    168  1.1  agc 	return ret;
    169  1.1  agc }
    170  1.1  agc 
    171  1.1  agc /* get attributes for the path name */
    172  1.1  agc /* ARGSUSED3 */
    173  1.1  agc static int
    174  1.1  agc puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
    175  1.1  agc 	const struct puffs_cred *pcr, pid_t pid)
    176  1.1  agc {
    177  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    178  1.1  agc 	struct puffs_node	*pn = opc;
    179  1.1  agc 	struct stat		 st;
    180  1.1  agc 	struct fuse		*fuse;
    181  1.1  agc 	const char		*path = PNPATH(pn);
    182  1.1  agc 	int			ret;
    183  1.1  agc 
    184  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    185  1.1  agc 	if (fuse->op.getattr == NULL) {
    186  1.1  agc 		return ENOSYS;
    187  1.1  agc 	}
    188  1.1  agc 
    189  1.1  agc 	/* wrap up return code */
    190  1.1  agc 	ret = (*fuse->op.getattr)(path, &st);
    191  1.1  agc 
    192  1.1  agc 	if (ret == 0) {
    193  1.1  agc 		/* fill in va from st */
    194  1.1  agc 		va->va_mode = st.st_mode;
    195  1.1  agc 		va->va_nlink = st.st_nlink;
    196  1.1  agc 		va->va_uid = st.st_uid;
    197  1.1  agc 		va->va_gid = st.st_gid;
    198  1.1  agc 		va->va_fsid = st.st_rdev;
    199  1.1  agc 		va->va_fileid = st.st_ino;
    200  1.1  agc 		va->va_size = st.st_size;
    201  1.1  agc 		va->va_blocksize = st.st_blksize;
    202  1.1  agc 		va->va_atime = st.st_atimespec;
    203  1.1  agc 		va->va_mtime = st.st_mtimespec;
    204  1.1  agc 		va->va_ctime = st.st_ctimespec;
    205  1.1  agc 		va->va_birthtime = st.st_birthtimespec;
    206  1.1  agc 		va->va_gen = st.st_gen;
    207  1.1  agc 		va->va_flags = st.st_flags;
    208  1.1  agc 		va->va_rdev = st.st_rdev;
    209  1.1  agc 		va->va_bytes = st.st_size;
    210  1.1  agc 		va->va_filerev = st.st_gen;
    211  1.1  agc 		va->va_vaflags = st.st_flags;
    212  1.1  agc 
    213  1.1  agc 	}
    214  1.1  agc 
    215  1.1  agc 	return ret;
    216  1.1  agc }
    217  1.1  agc 
    218  1.1  agc /* read the contents of the symbolic link */
    219  1.1  agc /* ARGSUSED2 */
    220  1.1  agc static int
    221  1.1  agc puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
    222  1.1  agc 	const struct puffs_cred *cred, char *linkname, size_t *linklen)
    223  1.1  agc {
    224  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    225  1.1  agc 	struct puffs_node	*pn = opc;
    226  1.1  agc 	struct fuse		*fuse;
    227  1.1  agc 	const char		*path = PNPATH(pn);
    228  1.1  agc 	int			ret;
    229  1.1  agc 
    230  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    231  1.1  agc 	if (fuse->op.readlink == NULL) {
    232  1.1  agc 		return ENOSYS;
    233  1.1  agc 	}
    234  1.1  agc 
    235  1.1  agc 	/* wrap up return code */
    236  1.1  agc 	ret = (*fuse->op.readlink)(path, linkname, *linklen);
    237  1.1  agc 
    238  1.1  agc 	if (ret == 0) {
    239  1.1  agc 	}
    240  1.1  agc 
    241  1.1  agc 	return ret;
    242  1.1  agc }
    243  1.1  agc 
    244  1.1  agc /* make the special node */
    245  1.1  agc /* ARGSUSED1 */
    246  1.1  agc static int
    247  1.1  agc puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
    248  1.1  agc 	const struct puffs_cn *pcn, const struct vattr *va)
    249  1.1  agc {
    250  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    251  1.1  agc 	struct puffs_node	*pn;
    252  1.1  agc 	struct fuse		*fuse;
    253  1.1  agc 	mode_t			 mode = va->va_mode;
    254  1.1  agc 	const char		*path = PCNPATH(pcn);
    255  1.1  agc 	int			ret;
    256  1.1  agc 
    257  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    258  1.1  agc 	if (fuse->op.mknod == NULL) {
    259  1.1  agc 		return ENOSYS;
    260  1.1  agc 	}
    261  1.1  agc 
    262  1.1  agc 	/* wrap up return code */
    263  1.1  agc 	ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
    264  1.1  agc 
    265  1.1  agc 	if (ret == 0) {
    266  1.1  agc 		/* fix up nodes */
    267  1.1  agc 		pn = puffs_pn_new(pu, NULL);
    268  1.1  agc 		if (pn == NULL) {
    269  1.1  agc 			unlink(PCNPATH(pcn));
    270  1.1  agc 			return ENOMEM;
    271  1.1  agc 		}
    272  1.1  agc 		puffs_setvattr(&pn->pn_va, va);
    273  1.1  agc 
    274  1.1  agc 		*newnode = pn;
    275  1.1  agc 	}
    276  1.1  agc 
    277  1.1  agc 	return ret;
    278  1.1  agc }
    279  1.1  agc 
    280  1.1  agc /* make a directory */
    281  1.1  agc /* ARGSUSED1 */
    282  1.1  agc static int
    283  1.1  agc puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
    284  1.1  agc 	const struct puffs_cn *pcn, const struct vattr *va)
    285  1.1  agc {
    286  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    287  1.1  agc 	struct puffs_node	*pn;
    288  1.1  agc 	struct fuse		*fuse;
    289  1.1  agc 	mode_t			 mode = va->va_mode;
    290  1.1  agc 	const char		*path = PCNPATH(pcn);
    291  1.1  agc 	int			ret;
    292  1.1  agc 
    293  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    294  1.1  agc 	if (fuse->op.mkdir == NULL) {
    295  1.1  agc 		return ENOSYS;
    296  1.1  agc 	}
    297  1.1  agc 
    298  1.1  agc 	/* wrap up return code */
    299  1.1  agc 	ret = (*fuse->op.mkdir)(path, mode);
    300  1.1  agc 
    301  1.1  agc 	if (ret == 0) {
    302  1.1  agc 		/* fix up nodes */
    303  1.1  agc 		pn = puffs_pn_new(pu, NULL);
    304  1.1  agc 		if (pn == NULL) {
    305  1.1  agc 			rmdir(PCNPATH(pcn));
    306  1.1  agc 			return ENOMEM;
    307  1.1  agc 		}
    308  1.1  agc 		puffs_setvattr(&pn->pn_va, va);
    309  1.1  agc 
    310  1.1  agc 		*newnode = pn;
    311  1.1  agc 	}
    312  1.1  agc 
    313  1.1  agc 	return ret;
    314  1.1  agc }
    315  1.1  agc 
    316  1.1  agc /* remove the directory entry */
    317  1.1  agc /* ARGSUSED1 */
    318  1.1  agc static int
    319  1.1  agc puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
    320  1.1  agc 	const struct puffs_cn *pcn)
    321  1.1  agc {
    322  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    323  1.1  agc 	struct puffs_node	*pn = opc;
    324  1.1  agc 	struct fuse		*fuse;
    325  1.1  agc 	const char		*path = PCNPATH(pcn);
    326  1.1  agc 	int			ret;
    327  1.1  agc 
    328  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    329  1.1  agc 	if (fuse->op.unlink == NULL) {
    330  1.1  agc 		return ENOSYS;
    331  1.1  agc 	}
    332  1.1  agc 
    333  1.1  agc 	/* wrap up return code */
    334  1.1  agc 	ret = (*fuse->op.unlink)(path);
    335  1.1  agc 
    336  1.1  agc 	if (ret == 0) {
    337  1.1  agc 		puffs_pn_put(pn);
    338  1.1  agc 	}
    339  1.1  agc 
    340  1.1  agc 	return ret;
    341  1.1  agc }
    342  1.1  agc 
    343  1.1  agc /* remove the directory */
    344  1.1  agc /* ARGSUSED1 */
    345  1.1  agc static int
    346  1.1  agc puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
    347  1.1  agc 	const struct puffs_cn *pcn)
    348  1.1  agc {
    349  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    350  1.1  agc 	struct puffs_node	*pn = opc;
    351  1.1  agc 	struct fuse		*fuse;
    352  1.1  agc 	const char		*path = PCNPATH(pcn);
    353  1.1  agc 	int			ret;
    354  1.1  agc 
    355  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    356  1.1  agc 	if (fuse->op.rmdir == NULL) {
    357  1.1  agc 		return ENOSYS;
    358  1.1  agc 	}
    359  1.1  agc 
    360  1.1  agc 	/* wrap up return code */
    361  1.1  agc 	ret = (*fuse->op.rmdir)(path);
    362  1.1  agc 
    363  1.1  agc 	if (ret == 0) {
    364  1.1  agc 		puffs_pn_put(pn);
    365  1.1  agc 	}
    366  1.1  agc 
    367  1.1  agc 	return ret;
    368  1.1  agc }
    369  1.1  agc 
    370  1.1  agc /* create a symbolic link */
    371  1.1  agc /* ARGSUSED1 */
    372  1.1  agc static int
    373  1.1  agc puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
    374  1.1  agc 	const struct puffs_cn *pcn_src, const struct vattr *va,
    375  1.1  agc 	const char *link_target)
    376  1.1  agc {
    377  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    378  1.1  agc 	struct puffs_node	*pn;
    379  1.1  agc 	struct fuse		*fuse;
    380  1.1  agc 	const char		*path = PCNPATH(pcn_src);
    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.symlink == 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.symlink)(path, link_target);
    390  1.1  agc 	/* XXX - check I haven't transposed these args */
    391  1.1  agc 
    392  1.1  agc 	if (ret == 0) {
    393  1.1  agc 		/* fix up nodes */
    394  1.1  agc 		pn = puffs_pn_new(pu, NULL);
    395  1.1  agc 		if (pn == NULL) {
    396  1.1  agc 			unlink(link_target);
    397  1.1  agc 			return ENOMEM;
    398  1.1  agc 		}
    399  1.1  agc 		puffs_setvattr(&pn->pn_va, va);
    400  1.1  agc 
    401  1.1  agc 		*newnode = pn;
    402  1.1  agc 	}
    403  1.1  agc 
    404  1.1  agc 	return ret;
    405  1.1  agc }
    406  1.1  agc 
    407  1.1  agc /* rename a directory entry */
    408  1.1  agc /* ARGSUSED1 */
    409  1.1  agc static int
    410  1.1  agc puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
    411  1.1  agc 	const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
    412  1.1  agc 	const struct puffs_cn *pcn_targ)
    413  1.1  agc {
    414  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    415  1.1  agc 	struct puffs_node	*pn = opc;
    416  1.1  agc 	struct vattr		va;
    417  1.1  agc 	struct fuse		*fuse;
    418  1.1  agc 	const char		*path = PCNPATH(pcn_src);
    419  1.1  agc 	int			ret;
    420  1.1  agc 
    421  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    422  1.1  agc 	if (fuse->op.rename == NULL) {
    423  1.1  agc 		return ENOSYS;
    424  1.1  agc 	}
    425  1.1  agc 
    426  1.1  agc 	/* wrap up return code */
    427  1.1  agc 	ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
    428  1.1  agc 
    429  1.1  agc 	if (ret == 0) {
    430  1.1  agc 		(void) memcpy(&va, &pn->pn_va, sizeof(va));
    431  1.1  agc 
    432  1.1  agc 		puffs_pn_put(pn);
    433  1.1  agc 
    434  1.1  agc 		pn = puffs_pn_new(pu, NULL);
    435  1.1  agc 		if (pn == NULL) {
    436  1.1  agc 			return ENOMEM;
    437  1.1  agc 		}
    438  1.1  agc 		puffs_setvattr(&pn->pn_va, &va);
    439  1.1  agc 
    440  1.1  agc 	}
    441  1.1  agc 
    442  1.1  agc 	return ret;
    443  1.1  agc }
    444  1.1  agc 
    445  1.1  agc /* create a link in the file system */
    446  1.1  agc /* ARGSUSED1 */
    447  1.1  agc static int
    448  1.1  agc puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
    449  1.1  agc 	const struct puffs_cn *pcn)
    450  1.1  agc {
    451  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    452  1.1  agc 	struct puffs_node	*pn = targ;
    453  1.1  agc 	struct fuse		*fuse;
    454  1.1  agc 	int			ret;
    455  1.1  agc 
    456  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    457  1.1  agc 	if (fuse->op.link == NULL) {
    458  1.1  agc 		return ENOSYS;
    459  1.1  agc 	}
    460  1.1  agc 
    461  1.1  agc 	/* wrap up return code */
    462  1.1  agc 	ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
    463  1.1  agc 
    464  1.1  agc 	if (ret == 0) {
    465  1.1  agc 		/* fix up nodes */
    466  1.1  agc 		pn = puffs_pn_new(pu, NULL);
    467  1.1  agc 		if (pn == NULL) {
    468  1.1  agc 			unlink(PCNPATH(pcn));
    469  1.1  agc 			return ENOMEM;
    470  1.1  agc 		}
    471  1.1  agc 	}
    472  1.1  agc 
    473  1.1  agc 	return ret;
    474  1.1  agc }
    475  1.1  agc 
    476  1.1  agc /*
    477  1.1  agc We run into a slight problemette here - puffs provides
    478  1.1  agc setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
    479  1.1  agc functionality.  So that we don't miss out on anything when calling a
    480  1.1  agc fuse operation, we have to get the vattr from the existing file,
    481  1.1  agc find out what's changed, and then switch on that to call the fuse
    482  1.1  agc function accordingly.
    483  1.1  agc */
    484  1.1  agc /* ARGSUSED3 */
    485  1.1  agc static int
    486  1.1  agc puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
    487  1.1  agc 	const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
    488  1.1  agc {
    489  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    490  1.1  agc 	struct puffs_node	*pn = opc;
    491  1.1  agc 	struct fuse		*fuse;
    492  1.1  agc 	const char		*path = PNPATH(pn);
    493  1.1  agc 	mode_t			mode;
    494  1.1  agc 	uid_t			uid;
    495  1.1  agc 	gid_t			gid;
    496  1.1  agc 	int			ret;
    497  1.1  agc 
    498  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    499  1.1  agc 
    500  1.1  agc 	ret = -1;
    501  1.1  agc 
    502  1.1  agc 	mode = va->va_mode;
    503  1.1  agc 	uid = va->va_uid;
    504  1.1  agc 	gid = va->va_gid;
    505  1.1  agc 
    506  1.1  agc 	if (mode != 0) {
    507  1.1  agc 		if (fuse->op.chmod == NULL) {
    508  1.1  agc 			return ENOSYS;
    509  1.1  agc 		}
    510  1.1  agc 		ret = (*fuse->op.chmod)(path, mode);
    511  1.1  agc 	}
    512  1.1  agc 	if (uid != 0 || gid != 0) {
    513  1.1  agc 		if (fuse->op.chown == NULL) {
    514  1.1  agc 			return ENOSYS;
    515  1.1  agc 		}
    516  1.1  agc 		ret = (*fuse->op.chown)(path, uid, gid);
    517  1.1  agc 	}
    518  1.1  agc 
    519  1.1  agc 	if (ret == 0) {
    520  1.1  agc 	}
    521  1.1  agc 
    522  1.1  agc 	return ret;
    523  1.1  agc }
    524  1.1  agc 
    525  1.1  agc /* ARGSUSED2 */
    526  1.1  agc static int
    527  1.1  agc puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
    528  1.1  agc 	const struct puffs_cred *cred, pid_t pid)
    529  1.1  agc {
    530  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    531  1.1  agc 	struct fuse_file_info	 file_info;
    532  1.1  agc 	struct puffs_node	*pn = opc;
    533  1.1  agc 	struct fuse		*fuse;
    534  1.1  agc 	struct stat		 st;
    535  1.1  agc 	const char		*path = PNPATH(pn);
    536  1.1  agc 	int			 ret;
    537  1.1  agc 
    538  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    539  1.1  agc 	if (fuse->op.open == NULL) {
    540  1.1  agc 		return ENOSYS;
    541  1.1  agc 	}
    542  1.1  agc 
    543  1.1  agc 	(void) memset(&file_info, 0x0, sizeof(file_info));
    544  1.1  agc 
    545  1.1  agc 	/* examine type - if directory, return 0 rather than open */
    546  1.1  agc 	ret = (fuse->op.getattr == NULL) ?
    547  1.1  agc 		stat(path, &st) :
    548  1.1  agc 		(*fuse->op.getattr)(path, &st);
    549  1.1  agc 	if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
    550  1.1  agc 		return 0;
    551  1.1  agc 	}
    552  1.1  agc 
    553  1.1  agc 	if (strcmp(path, "/") == 0) {
    554  1.1  agc 		return 0;
    555  1.1  agc 	}
    556  1.1  agc 
    557  1.1  agc 	ret = (*fuse->op.open)(path, &file_info);
    558  1.1  agc 
    559  1.1  agc 	if (ret == 0) {
    560  1.1  agc 	}
    561  1.1  agc 
    562  1.1  agc 	return ret;
    563  1.1  agc }
    564  1.1  agc 
    565  1.1  agc /* read some more from the file */
    566  1.1  agc /* ARGSUSED5 */
    567  1.1  agc static int
    568  1.1  agc puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
    569  1.1  agc 	off_t offset, size_t *resid, const struct puffs_cred *pcr,
    570  1.1  agc 	int ioflag)
    571  1.1  agc {
    572  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    573  1.1  agc 	struct fuse_file_info	file_info;
    574  1.1  agc 	struct puffs_node	*pn = opc;
    575  1.1  agc 	struct fuse		*fuse;
    576  1.1  agc 	const char		*path = PNPATH(pn);
    577  1.1  agc 	int			ret;
    578  1.1  agc 
    579  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    580  1.1  agc 	if (fuse->op.read == NULL) {
    581  1.1  agc 		return ENOSYS;
    582  1.1  agc 	}
    583  1.1  agc 
    584  1.1  agc 	(void) memset(&file_info, 0x0, sizeof(file_info));
    585  1.1  agc 	/* XXX fill in file_info here */
    586  1.1  agc 
    587  1.1  agc 	ret = (*fuse->op.read)(path, (char *)buf, *resid, offset, &file_info);
    588  1.1  agc 
    589  1.1  agc 	if (ret > 0) {
    590  1.1  agc 		*resid -= ret;
    591  1.1  agc 	}
    592  1.1  agc 
    593  1.1  agc 	return 0;
    594  1.1  agc }
    595  1.1  agc 
    596  1.1  agc /* write to the file */
    597  1.1  agc /* ARGSUSED0 */
    598  1.1  agc static int
    599  1.1  agc puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
    600  1.1  agc 	off_t offset, size_t *resid, const struct puffs_cred *pcr,
    601  1.1  agc 	int ioflag)
    602  1.1  agc {
    603  1.1  agc #if 0
    604  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    605  1.1  agc 	struct fuse_file_info	file_info;
    606  1.1  agc 	struct puffs_node	*pn = opc;
    607  1.1  agc 	struct fuse		*fuse;
    608  1.1  agc 	const char		*path = PNPATH(pn);
    609  1.1  agc 	int			ret;
    610  1.1  agc 
    611  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    612  1.1  agc 	if (fuse->op.write == NULL) {
    613  1.1  agc 		return ENOSYS;
    614  1.1  agc 	}
    615  1.1  agc 
    616  1.1  agc 	(void) memset(&file_info, 0x0, sizeof(file_info));
    617  1.1  agc 
    618  1.1  agc 	/* XXX fill in file_info here */
    619  1.1  agc 
    620  1.1  agc 	ret = (*fuse->op.write)(path, (char *)buf, *resid, offset, &file_info);
    621  1.1  agc 
    622  1.1  agc 	if (ret > 0) {
    623  1.1  agc 		*resid -= ret;
    624  1.1  agc 	}
    625  1.1  agc 
    626  1.1  agc 	return ret;
    627  1.1  agc #else
    628  1.1  agc 	/*
    629  1.1  agc 	 * XXX: currently puffs vfs will suck if you have read but
    630  1.1  agc 	 * no write, so just dummyfy this
    631  1.1  agc 	 */
    632  1.1  agc 	return 0;
    633  1.1  agc #endif
    634  1.1  agc }
    635  1.1  agc 
    636  1.1  agc 
    637  1.1  agc /* ARGSUSED3 */
    638  1.1  agc static int
    639  1.1  agc puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
    640  1.1  agc 	struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
    641  1.1  agc 	size_t *reslen)
    642  1.1  agc {
    643  1.1  agc 	struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    644  1.1  agc 	struct fuse_file_info	file_info;
    645  1.1  agc 	struct puffs_node	*pn = opc;
    646  1.1  agc 	struct fuse		*fuse;
    647  1.1  agc 	const char		*path = PNPATH(pn);
    648  1.1  agc 	struct feh		feh; /* XXX */
    649  1.1  agc 	int			ret;
    650  1.1  agc 
    651  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    652  1.1  agc 	if (fuse->op.readdir == NULL) {
    653  1.1  agc 		return ENOSYS;
    654  1.1  agc 	}
    655  1.1  agc 
    656  1.1  agc 	/* XXX: how to handle this??? */
    657  1.1  agc 	if (*readoff != 0) {
    658  1.1  agc 		return 0;
    659  1.1  agc 	}
    660  1.1  agc 
    661  1.1  agc 	(void) memset(&file_info, 0x0, sizeof(file_info));
    662  1.1  agc 	/* XXX - fill in file_info here */
    663  1.1  agc 
    664  1.1  agc 	feh.dent = dent;
    665  1.1  agc 	feh.reslen = *reslen;
    666  1.1  agc 	ret = (*fuse->op.readdir)(path, &feh, puffs_fuse_dirfiller, *readoff, &file_info);
    667  1.1  agc 	*reslen = feh.reslen;
    668  1.1  agc 	*readoff = 1;
    669  1.1  agc 
    670  1.1  agc 	if (ret == 0) {
    671  1.1  agc 	}
    672  1.1  agc 
    673  1.1  agc 	return ret;
    674  1.1  agc }
    675  1.1  agc 
    676  1.1  agc /* ARGSUSED1 */
    677  1.1  agc static int
    678  1.1  agc puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
    679  1.1  agc {
    680  1.1  agc         struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    681  1.1  agc 	struct fuse		*fuse;
    682  1.1  agc 
    683  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    684  1.1  agc 	if (fuse->op.destroy == NULL) {
    685  1.1  agc 		return ENOSYS;
    686  1.1  agc 	}
    687  1.1  agc 	(*fuse->op.destroy)(fuse);
    688  1.1  agc         return 0;
    689  1.1  agc }
    690  1.1  agc 
    691  1.1  agc /* ARGSUSED0 */
    692  1.1  agc static int
    693  1.1  agc puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
    694  1.1  agc             const struct puffs_cred *cr, pid_t pid)
    695  1.1  agc {
    696  1.1  agc         return 0;
    697  1.1  agc }
    698  1.1  agc 
    699  1.1  agc /* ARGSUSED2 */
    700  1.1  agc static int
    701  1.1  agc puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
    702  1.1  agc {
    703  1.1  agc         struct puffs_usermount	*pu = puffs_cc_getusermount(pcc);
    704  1.1  agc 	struct fuse		*fuse;
    705  1.1  agc 	int			ret;
    706  1.1  agc 
    707  1.1  agc 	fuse = (struct fuse *)pu->pu_privdata;
    708  1.1  agc 	if (fuse->op.statfs == NULL) {
    709  1.1  agc 		if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
    710  1.1  agc 			return errno;
    711  1.1  agc 		}
    712  1.1  agc 	} else {
    713  1.1  agc 		ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
    714  1.1  agc 	}
    715  1.1  agc 
    716  1.1  agc         return ret;
    717  1.1  agc }
    718  1.1  agc 
    719  1.1  agc 
    720  1.1  agc 
    721  1.1  agc 
    722  1.1  agc /* End of puffs_fuse operations */
    723  1.1  agc 
    724  1.1  agc /* ARGSUSED3 */
    725  1.1  agc int
    726  1.1  agc fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
    727  1.1  agc 	size_t size, void *userdata)
    728  1.1  agc {
    729  1.1  agc 	struct puffs_usermount	*pu;
    730  1.1  agc 	struct puffs_pathobj	*po_root;
    731  1.1  agc 	struct puffs_ops	*pops;
    732  1.1  agc 	struct statvfs		svfsb;
    733  1.1  agc 	struct fuse		*fuse;
    734  1.1  agc 	char			 name[64];
    735  1.1  agc 	char			*slash;
    736  1.1  agc 	int			 ret;
    737  1.1  agc 
    738  1.1  agc 	/* initialise the puffs operations structure */
    739  1.1  agc         PUFFSOP_INIT(pops);
    740  1.1  agc 
    741  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, fs, sync);
    742  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
    743  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
    744  1.1  agc 
    745  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, lookup);
    746  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, getattr);
    747  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, readdir);
    748  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, readlink);
    749  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, mknod);
    750  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
    751  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, remove);
    752  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
    753  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, symlink);
    754  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, rename);
    755  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, link);
    756  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, setattr);
    757  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, open);
    758  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, read);
    759  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, write);
    760  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, readdir);
    761  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, read);
    762  1.1  agc         PUFFSOP_SET(pops, puffs_fuse, node, write);
    763  1.1  agc 
    764  1.1  agc 	NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
    765  1.1  agc 
    766  1.1  agc 	/* copy fuse ops to their own stucture */
    767  1.1  agc 	(void) memcpy(&fuse->op, ops, sizeof(fuse->op));
    768  1.1  agc 
    769  1.1  agc 	/* whilst this (assigning the pu_privdata in the puffs
    770  1.1  agc 	 * usermount struct to be the fuse struct) might seem like
    771  1.1  agc 	 * we are chasing our tail here, the logic is as follows:
    772  1.1  agc 		+ the operation wrapper gets called with the puffs
    773  1.1  agc 		  calling conventions
    774  1.1  agc 		+ we need to fix up args first
    775  1.1  agc 		+ then call the fuse user-supplied operation
    776  1.1  agc 		+ then we fix up any values on return that we need to
    777  1.1  agc 		+ and fix up any nodes, etc
    778  1.1  agc 	* so we need to be able to get at the fuse ops from within the
    779  1.1  agc 	* puffs_usermount struct
    780  1.1  agc 	*/
    781  1.1  agc 	if ((slash = strrchr(*argv, '/')) == NULL) {
    782  1.1  agc 		slash = *argv;
    783  1.1  agc 	} else {
    784  1.1  agc 		slash += 1;
    785  1.1  agc 	}
    786  1.1  agc 	(void) snprintf(name, sizeof(name), "refuse:%s", slash);
    787  1.1  agc 	pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
    788  1.1  agc 			name, fuse,
    789  1.1  agc 			PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
    790  1.1  agc 	if (pu == NULL) {
    791  1.1  agc 		err(EXIT_FAILURE, "puffs_mount");
    792  1.1  agc 	}
    793  1.1  agc 
    794  1.1  agc 	fuse->pu = pu;
    795  1.1  agc 	pu->pu_pn_root = puffs_pn_new(pu, NULL);
    796  1.1  agc 	po_root = puffs_getrootpathobj(pu);
    797  1.1  agc 	po_root->po_path = strdup("/");
    798  1.1  agc 	po_root->po_len = 1;
    799  1.1  agc 
    800  1.1  agc 	statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
    801  1.1  agc 	if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
    802  1.1  agc 		err(EXIT_FAILURE, "puffs_start");
    803  1.1  agc 	}
    804  1.1  agc 
    805  1.1  agc 	ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
    806  1.1  agc 
    807  1.1  agc 	(void) free(po_root->po_path);
    808  1.1  agc 	FREE(fuse);
    809  1.1  agc 	return ret;
    810  1.1  agc }
    811  1.1  agc 
    812  1.1  agc /* ARGSUSED0 */
    813  1.1  agc int
    814  1.1  agc fuse_opt_parse(struct fuse_args *args, void *data,
    815  1.1  agc 	const struct fuse_opt *opts, fuse_opt_proc_t proc)
    816  1.1  agc {
    817  1.1  agc 	return 0;
    818  1.1  agc }
    819