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