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