xref: /minix3/lib/librefuse/refuse.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: refuse.c,v 1.96 2012/12/30 10:04:22 tron Exp $	*/
2490e0de5SThomas Veerman 
3490e0de5SThomas Veerman /*
4490e0de5SThomas Veerman  * Copyright � 2007 Alistair Crooks.  All rights reserved.
5490e0de5SThomas Veerman  * Copyright � 2007 Antti Kantee.  All rights reserved.
6490e0de5SThomas Veerman  *
7490e0de5SThomas Veerman  * Redistribution and use in source and binary forms, with or without
8490e0de5SThomas Veerman  * modification, are permitted provided that the following conditions
9490e0de5SThomas Veerman  * are met:
10490e0de5SThomas Veerman  * 1. Redistributions of source code must retain the above copyright
11490e0de5SThomas Veerman  *    notice, this list of conditions and the following disclaimer.
12490e0de5SThomas Veerman  * 2. Redistributions in binary form must reproduce the above copyright
13490e0de5SThomas Veerman  *    notice, this list of conditions and the following disclaimer in the
14490e0de5SThomas Veerman  *    documentation and/or other materials provided with the distribution.
15490e0de5SThomas Veerman  * 3. The name of the author may not be used to endorse or promote
16490e0de5SThomas Veerman  *    products derived from this software without specific prior written
17490e0de5SThomas Veerman  *    permission.
18490e0de5SThomas Veerman  *
19490e0de5SThomas Veerman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20490e0de5SThomas Veerman  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21490e0de5SThomas Veerman  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22490e0de5SThomas Veerman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23490e0de5SThomas Veerman  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24490e0de5SThomas Veerman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25490e0de5SThomas Veerman  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26490e0de5SThomas Veerman  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27490e0de5SThomas Veerman  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28490e0de5SThomas Veerman  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29490e0de5SThomas Veerman  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30490e0de5SThomas Veerman  */
31490e0de5SThomas Veerman 
32490e0de5SThomas Veerman #include <sys/cdefs.h>
33490e0de5SThomas Veerman #if !defined(lint)
34*84d9c625SLionel Sambuc __RCSID("$NetBSD: refuse.c,v 1.96 2012/12/30 10:04:22 tron Exp $");
35490e0de5SThomas Veerman #endif /* !lint */
36490e0de5SThomas Veerman 
37490e0de5SThomas Veerman #include <sys/types.h>
38490e0de5SThomas Veerman 
39490e0de5SThomas Veerman #include <assert.h>
40490e0de5SThomas Veerman #include <err.h>
41490e0de5SThomas Veerman #include <errno.h>
42490e0de5SThomas Veerman #include <fuse.h>
43490e0de5SThomas Veerman #include <paths.h>
44490e0de5SThomas Veerman #include <stdio.h>
45490e0de5SThomas Veerman #include <stdlib.h>
46490e0de5SThomas Veerman #include <string.h>
47490e0de5SThomas Veerman #include <unistd.h>
48490e0de5SThomas Veerman #ifdef MULTITHREADED_REFUSE
49490e0de5SThomas Veerman #include <pthread.h>
50490e0de5SThomas Veerman #endif
51490e0de5SThomas Veerman 
52490e0de5SThomas Veerman typedef uint64_t	 fuse_ino_t;
53490e0de5SThomas Veerman 
54490e0de5SThomas Veerman struct fuse_config {
55490e0de5SThomas Veerman 	uid_t		uid;
56490e0de5SThomas Veerman 	gid_t		gid;
57490e0de5SThomas Veerman 	mode_t		umask;
58490e0de5SThomas Veerman 	double		entry_timeout;
59490e0de5SThomas Veerman 	double		negative_timeout;
60490e0de5SThomas Veerman 	double		attr_timeout;
61490e0de5SThomas Veerman 	double		ac_attr_timeout;
62490e0de5SThomas Veerman 	int		ac_attr_timeout_set;
63490e0de5SThomas Veerman 	int		debug;
64490e0de5SThomas Veerman 	int		hard_remove;
65490e0de5SThomas Veerman 	int		use_ino;
66490e0de5SThomas Veerman 	int		readdir_ino;
67490e0de5SThomas Veerman 	int		set_mode;
68490e0de5SThomas Veerman 	int		set_uid;
69490e0de5SThomas Veerman 	int		set_gid;
70490e0de5SThomas Veerman 	int		direct_io;
71490e0de5SThomas Veerman 	int		kernel_cache;
72490e0de5SThomas Veerman 	int		auto_cache;
73490e0de5SThomas Veerman 	int		intr;
74490e0de5SThomas Veerman 	int		intr_signal;
75490e0de5SThomas Veerman };
76490e0de5SThomas Veerman 
77490e0de5SThomas Veerman struct fuse_chan {
78490e0de5SThomas Veerman 	const char		*dir;
79490e0de5SThomas Veerman 	struct fuse_args	*args;
80490e0de5SThomas Veerman 	struct puffs_usermount	*pu;
81490e0de5SThomas Veerman 	int 			dead;
82490e0de5SThomas Veerman };
83490e0de5SThomas Veerman 
84490e0de5SThomas Veerman /* this is the private fuse structure */
85490e0de5SThomas Veerman struct fuse {
86490e0de5SThomas Veerman 	struct fuse_chan	*fc;		/* fuse channel pointer */
87490e0de5SThomas Veerman 	struct fuse_operations	op;		/* switch table of operations */
88490e0de5SThomas Veerman 	int			compat;		/* compat level -
89490e0de5SThomas Veerman 						 * not used in puffs_fuse */
90490e0de5SThomas Veerman 	struct node		**name_table;
91490e0de5SThomas Veerman 	size_t			name_table_size;
92490e0de5SThomas Veerman 	struct node		**id_table;
93490e0de5SThomas Veerman 	size_t			id_table_size;
94490e0de5SThomas Veerman 	fuse_ino_t		ctr;
95490e0de5SThomas Veerman 	unsigned int		generation;
96490e0de5SThomas Veerman 	unsigned int		hidectr;
97*84d9c625SLionel Sambuc #if !defined(__minix)
98490e0de5SThomas Veerman 	pthread_mutex_t		lock;
99490e0de5SThomas Veerman 	pthread_rwlock_t	tree_lock;
100*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
101490e0de5SThomas Veerman 	void			*user_data;
102490e0de5SThomas Veerman 	struct fuse_config	conf;
103490e0de5SThomas Veerman 	int			intr_installed;
104490e0de5SThomas Veerman };
105490e0de5SThomas Veerman 
106490e0de5SThomas Veerman struct puffs_fuse_dirh {
107490e0de5SThomas Veerman 	void *dbuf;
108490e0de5SThomas Veerman 	struct dirent *d;
109490e0de5SThomas Veerman 
110490e0de5SThomas Veerman 	size_t reslen;
111490e0de5SThomas Veerman 	size_t bufsize;
112490e0de5SThomas Veerman };
113490e0de5SThomas Veerman 
114490e0de5SThomas Veerman struct refusenode {
115490e0de5SThomas Veerman 	struct fuse_file_info	file_info;
116490e0de5SThomas Veerman 	struct puffs_fuse_dirh	dirh;
117490e0de5SThomas Veerman 	int opencount;
118490e0de5SThomas Veerman 	int flags;
119490e0de5SThomas Veerman };
120490e0de5SThomas Veerman #define RN_ROOT		0x01
121490e0de5SThomas Veerman #define RN_OPEN		0x02	/* XXX: could just use opencount */
122490e0de5SThomas Veerman 
123490e0de5SThomas Veerman static int fuse_setattr(struct fuse *, struct puffs_node *,
124490e0de5SThomas Veerman 			const char *, const struct vattr *);
125490e0de5SThomas Veerman 
126490e0de5SThomas Veerman static struct puffs_node *
newrn(struct puffs_usermount * pu)127490e0de5SThomas Veerman newrn(struct puffs_usermount *pu)
128490e0de5SThomas Veerman {
129490e0de5SThomas Veerman 	struct puffs_node *pn;
130490e0de5SThomas Veerman 	struct refusenode *rn;
131490e0de5SThomas Veerman 
132490e0de5SThomas Veerman 	if ((rn = calloc(1, sizeof(*rn))) == NULL) {
133490e0de5SThomas Veerman 		err(EXIT_FAILURE, "newrn");
134490e0de5SThomas Veerman 	}
135490e0de5SThomas Veerman 	pn = puffs_pn_new(pu, rn);
136490e0de5SThomas Veerman 
137490e0de5SThomas Veerman 	return pn;
138490e0de5SThomas Veerman }
139490e0de5SThomas Veerman 
140490e0de5SThomas Veerman static void
nukern(struct puffs_node * pn)141490e0de5SThomas Veerman nukern(struct puffs_node *pn)
142490e0de5SThomas Veerman {
143490e0de5SThomas Veerman 	struct refusenode *rn = pn->pn_data;
144490e0de5SThomas Veerman 
145490e0de5SThomas Veerman 	free(rn->dirh.dbuf);
146490e0de5SThomas Veerman 	free(rn);
147490e0de5SThomas Veerman 	puffs_pn_put(pn);
148490e0de5SThomas Veerman }
149490e0de5SThomas Veerman 
150490e0de5SThomas Veerman /* XXX - not threadsafe */
151490e0de5SThomas Veerman static ino_t fakeino = 3;
152490e0de5SThomas Veerman 
153490e0de5SThomas Veerman /***************** start of pthread context routines ************************/
154490e0de5SThomas Veerman 
155490e0de5SThomas Veerman /*
156490e0de5SThomas Veerman  * Notes on fuse_context:
157490e0de5SThomas Veerman  * we follow fuse's lead and use the pthread specific information to hold
158490e0de5SThomas Veerman  * a reference to the fuse_context structure for this thread.
159490e0de5SThomas Veerman  */
160490e0de5SThomas Veerman #ifdef MULTITHREADED_REFUSE
161490e0de5SThomas Veerman static pthread_mutex_t		context_mutex = PTHREAD_MUTEX_INITIALIZER;
162490e0de5SThomas Veerman static pthread_key_t		context_key;
163490e0de5SThomas Veerman static unsigned long		context_refc;
164490e0de5SThomas Veerman #endif
165490e0de5SThomas Veerman 
166490e0de5SThomas Veerman /* return the fuse_context struct related to this thread */
167490e0de5SThomas Veerman struct fuse_context *
fuse_get_context(void)168490e0de5SThomas Veerman fuse_get_context(void)
169490e0de5SThomas Veerman {
170490e0de5SThomas Veerman #ifdef MULTITHREADED_REFUSE
171490e0de5SThomas Veerman 	struct fuse_context	*ctxt;
172490e0de5SThomas Veerman 
173490e0de5SThomas Veerman 	if ((ctxt = pthread_getspecific(context_key)) == NULL) {
174490e0de5SThomas Veerman 		if ((ctxt = calloc(1, sizeof(struct fuse_context))) == NULL) {
175490e0de5SThomas Veerman 			abort();
176490e0de5SThomas Veerman 		}
177490e0de5SThomas Veerman 		pthread_setspecific(context_key, ctxt);
178490e0de5SThomas Veerman 	}
179490e0de5SThomas Veerman 	return ctxt;
180490e0de5SThomas Veerman #else
181490e0de5SThomas Veerman 	static struct fuse_context	fcon;
182490e0de5SThomas Veerman 
183490e0de5SThomas Veerman 	return &fcon;
184490e0de5SThomas Veerman #endif
185490e0de5SThomas Veerman }
186490e0de5SThomas Veerman 
187490e0de5SThomas Veerman /* used as a callback function */
188490e0de5SThomas Veerman #ifdef MULTITHREADED_REFUSE
189490e0de5SThomas Veerman static void
free_context(void * ctxt)190490e0de5SThomas Veerman free_context(void *ctxt)
191490e0de5SThomas Veerman {
192490e0de5SThomas Veerman 	free(ctxt);
193490e0de5SThomas Veerman }
194490e0de5SThomas Veerman #endif
195490e0de5SThomas Veerman 
196490e0de5SThomas Veerman /*
197490e0de5SThomas Veerman  * Create the pthread key.  The reason for the complexity is to
198490e0de5SThomas Veerman  * enable use of multiple fuse instances within a single process.
199490e0de5SThomas Veerman  */
200490e0de5SThomas Veerman static int
create_context_key(void)201490e0de5SThomas Veerman create_context_key(void)
202490e0de5SThomas Veerman {
203490e0de5SThomas Veerman #ifdef MULTITHREADED_REFUSE
204490e0de5SThomas Veerman 	int rv;
205490e0de5SThomas Veerman 
206490e0de5SThomas Veerman 	rv = pthread_mutex_lock(&context_mutex);
207490e0de5SThomas Veerman 	assert(rv == 0);
208490e0de5SThomas Veerman 
209490e0de5SThomas Veerman 	if (context_refc == 0) {
210490e0de5SThomas Veerman 		if (pthread_key_create(&context_key, free_context) != 0) {
211490e0de5SThomas Veerman 			warnx("create_context_key: pthread_key_create failed");
212490e0de5SThomas Veerman 			pthread_mutex_unlock(&context_mutex);
213490e0de5SThomas Veerman 			return 0;
214490e0de5SThomas Veerman 		}
215490e0de5SThomas Veerman 	}
216490e0de5SThomas Veerman 	context_refc += 1;
217490e0de5SThomas Veerman 	pthread_mutex_unlock(&context_mutex);
218490e0de5SThomas Veerman 	return 1;
219490e0de5SThomas Veerman #else
220490e0de5SThomas Veerman 	return 1;
221490e0de5SThomas Veerman #endif
222490e0de5SThomas Veerman }
223490e0de5SThomas Veerman 
224490e0de5SThomas Veerman static void
delete_context_key(void)225490e0de5SThomas Veerman delete_context_key(void)
226490e0de5SThomas Veerman {
227490e0de5SThomas Veerman #ifdef MULTITHREADED_REFUSE
228490e0de5SThomas Veerman 	pthread_mutex_lock(&context_mutex);
229490e0de5SThomas Veerman 	/* If we are the last fuse instances using the key, delete it */
230490e0de5SThomas Veerman 	if (--context_refc == 0) {
231490e0de5SThomas Veerman 		free(pthread_getspecific(context_key));
232490e0de5SThomas Veerman 		pthread_key_delete(context_key);
233490e0de5SThomas Veerman 	}
234490e0de5SThomas Veerman 	pthread_mutex_unlock(&context_mutex);
235490e0de5SThomas Veerman #endif
236490e0de5SThomas Veerman }
237490e0de5SThomas Veerman 
238490e0de5SThomas Veerman /* set the uid and gid of the calling process in the current fuse context */
239490e0de5SThomas Veerman static void
set_fuse_context_uid_gid(const struct puffs_cred * cred)240490e0de5SThomas Veerman set_fuse_context_uid_gid(const struct puffs_cred *cred)
241490e0de5SThomas Veerman {
242490e0de5SThomas Veerman 	struct fuse_context	*fusectx;
243490e0de5SThomas Veerman 	uid_t			 uid;
244490e0de5SThomas Veerman 	gid_t			 gid;
245490e0de5SThomas Veerman 
246490e0de5SThomas Veerman 	fusectx = fuse_get_context();
247490e0de5SThomas Veerman 	if (puffs_cred_getuid(cred, &uid) == 0) {
248490e0de5SThomas Veerman 		fusectx->uid = uid;
249490e0de5SThomas Veerman 	}
250490e0de5SThomas Veerman 	if (puffs_cred_getgid(cred, &gid) == 0) {
251490e0de5SThomas Veerman 		fusectx->gid = gid;
252490e0de5SThomas Veerman 	}
253490e0de5SThomas Veerman }
254490e0de5SThomas Veerman 
255490e0de5SThomas Veerman /* set the pid of the calling process in the current fuse context */
256490e0de5SThomas Veerman static void
set_fuse_context_pid(struct puffs_usermount * pu)257490e0de5SThomas Veerman set_fuse_context_pid(struct puffs_usermount *pu)
258490e0de5SThomas Veerman {
259490e0de5SThomas Veerman 	struct puffs_cc		*pcc = puffs_cc_getcc(pu);
260490e0de5SThomas Veerman 	struct fuse_context	*fusectx;
261490e0de5SThomas Veerman 
262490e0de5SThomas Veerman 	fusectx = fuse_get_context();
263490e0de5SThomas Veerman 	puffs_cc_getcaller(pcc, &fusectx->pid, NULL);
264490e0de5SThomas Veerman }
265490e0de5SThomas Veerman 
266490e0de5SThomas Veerman /***************** end of pthread context routines ************************/
267490e0de5SThomas Veerman 
268490e0de5SThomas Veerman #define DIR_CHUNKSIZE 4096
269490e0de5SThomas Veerman static int
fill_dirbuf(struct puffs_fuse_dirh * dh,const char * name,ino_t dino,uint8_t dtype)270490e0de5SThomas Veerman fill_dirbuf(struct puffs_fuse_dirh *dh, const char *name, ino_t dino,
271490e0de5SThomas Veerman 	uint8_t dtype)
272490e0de5SThomas Veerman {
273490e0de5SThomas Veerman 
274490e0de5SThomas Veerman 	/* initial? */
275490e0de5SThomas Veerman 	if (dh->bufsize == 0) {
276490e0de5SThomas Veerman 		if ((dh->dbuf = calloc(1, DIR_CHUNKSIZE)) == NULL) {
277490e0de5SThomas Veerman 			abort();
278490e0de5SThomas Veerman 		}
279490e0de5SThomas Veerman 		dh->d = dh->dbuf;
280490e0de5SThomas Veerman 		dh->reslen = dh->bufsize = DIR_CHUNKSIZE;
281490e0de5SThomas Veerman 	}
282490e0de5SThomas Veerman 
283490e0de5SThomas Veerman 	if (puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen)) {
284490e0de5SThomas Veerman 		return 0;
285490e0de5SThomas Veerman 	}
286490e0de5SThomas Veerman 
287490e0de5SThomas Veerman 	/* try to increase buffer space */
288490e0de5SThomas Veerman 	dh->dbuf = realloc(dh->dbuf, dh->bufsize + DIR_CHUNKSIZE);
289490e0de5SThomas Veerman 	if (dh->dbuf == NULL) {
290490e0de5SThomas Veerman 		abort();
291490e0de5SThomas Veerman 	}
292490e0de5SThomas Veerman 	dh->d = (void *)((uint8_t *)dh->dbuf + (dh->bufsize - dh->reslen));
293490e0de5SThomas Veerman 	dh->reslen += DIR_CHUNKSIZE;
294490e0de5SThomas Veerman 	dh->bufsize += DIR_CHUNKSIZE;
295490e0de5SThomas Veerman 
296490e0de5SThomas Veerman 	return !puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen);
297490e0de5SThomas Veerman }
298490e0de5SThomas Veerman 
299490e0de5SThomas Veerman /* ARGSUSED3 */
300490e0de5SThomas Veerman /* XXX: I have no idea how "off" is supposed to be used */
301490e0de5SThomas Veerman static int
puffs_fuse_fill_dir(void * buf,const char * name,const struct stat * stbuf,off_t off)302490e0de5SThomas Veerman puffs_fuse_fill_dir(void *buf, const char *name,
303490e0de5SThomas Veerman 	const struct stat *stbuf, off_t off)
304490e0de5SThomas Veerman {
305490e0de5SThomas Veerman 	struct puffs_fuse_dirh *deh = buf;
306490e0de5SThomas Veerman 	ino_t dino;
307490e0de5SThomas Veerman 	uint8_t dtype;
308490e0de5SThomas Veerman 
309490e0de5SThomas Veerman 	if (stbuf == NULL) {
310490e0de5SThomas Veerman 		dtype = DT_UNKNOWN;
311490e0de5SThomas Veerman 		dino = fakeino++;
312490e0de5SThomas Veerman 	} else {
313490e0de5SThomas Veerman 		dtype = puffs_vtype2dt(puffs_mode2vt(stbuf->st_mode));
314490e0de5SThomas Veerman 		dino = stbuf->st_ino;
315490e0de5SThomas Veerman 
316490e0de5SThomas Veerman 		/*
317490e0de5SThomas Veerman 		 * Some FUSE file systems like to always use 0 as the
318490e0de5SThomas Veerman 		 * inode number.   Our readdir() doesn't like to show
319490e0de5SThomas Veerman 		 * directory entries with inode number 0 ==> workaround.
320490e0de5SThomas Veerman 		 */
321490e0de5SThomas Veerman 		if (dino == 0) {
322490e0de5SThomas Veerman 			dino = fakeino++;
323490e0de5SThomas Veerman 		}
324490e0de5SThomas Veerman 	}
325490e0de5SThomas Veerman 
326490e0de5SThomas Veerman 	return fill_dirbuf(deh, name, dino, dtype);
327490e0de5SThomas Veerman }
328490e0de5SThomas Veerman 
329490e0de5SThomas Veerman static int
puffs_fuse_dirfil(fuse_dirh_t h,const char * name,int type,ino_t ino)330490e0de5SThomas Veerman puffs_fuse_dirfil(fuse_dirh_t h, const char *name, int type, ino_t ino)
331490e0de5SThomas Veerman {
332490e0de5SThomas Veerman 	ino_t dino;
333490e0de5SThomas Veerman 	int dtype;
334490e0de5SThomas Veerman 
335490e0de5SThomas Veerman 	if ((dtype = type) == 0) {
336490e0de5SThomas Veerman 		dtype = DT_UNKNOWN;
337490e0de5SThomas Veerman 	}
338490e0de5SThomas Veerman 
339490e0de5SThomas Veerman 	dino = (ino) ? ino : fakeino++;
340490e0de5SThomas Veerman 
341490e0de5SThomas Veerman 	return fill_dirbuf(h, name, dino, dtype);
342490e0de5SThomas Veerman }
343490e0de5SThomas Veerman 
344490e0de5SThomas Veerman /* place the refuse file system name into `name' */
345490e0de5SThomas Veerman static void
set_refuse_mount_name(char ** argv,char * name,size_t size)346490e0de5SThomas Veerman set_refuse_mount_name(char **argv, char *name, size_t size)
347490e0de5SThomas Veerman {
348490e0de5SThomas Veerman 	char	*slash;
349490e0de5SThomas Veerman 
350490e0de5SThomas Veerman 	if (argv == NULL || *argv == NULL) {
351490e0de5SThomas Veerman 		(void) strlcpy(name, "refuse", size);
352490e0de5SThomas Veerman 	} else {
353490e0de5SThomas Veerman 		if ((slash = strrchr(*argv, '/')) == NULL) {
354490e0de5SThomas Veerman 			slash = *argv;
355490e0de5SThomas Veerman 		} else {
356490e0de5SThomas Veerman 			slash += 1;
357490e0de5SThomas Veerman 		}
358490e0de5SThomas Veerman 		if (strncmp(*argv, "refuse:", 7) == 0) {
359490e0de5SThomas Veerman 			/* we've already done this */
360490e0de5SThomas Veerman 			(void) strlcpy(name, *argv, size);
361490e0de5SThomas Veerman 		} else {
362490e0de5SThomas Veerman 			(void) snprintf(name, size, "refuse:%s", slash);
363490e0de5SThomas Veerman 		}
364490e0de5SThomas Veerman 	}
365490e0de5SThomas Veerman }
366490e0de5SThomas Veerman 
367490e0de5SThomas Veerman 
368490e0de5SThomas Veerman /* this function exposes struct fuse to userland */
369490e0de5SThomas Veerman static struct fuse *
fuse_setup_real(int argc,char ** argv,const struct fuse_operations * ops,size_t size,char ** mountpoint,int * multithreaded,int * fd,void * user_data)370490e0de5SThomas Veerman fuse_setup_real(int argc, char **argv, const struct fuse_operations *ops,
371490e0de5SThomas Veerman 	size_t size, char **mountpoint, int *multithreaded, int *fd,
372490e0de5SThomas Veerman         void *user_data)
373490e0de5SThomas Veerman {
374490e0de5SThomas Veerman 	struct fuse_chan	*fc;
375490e0de5SThomas Veerman 	struct fuse_args	*args;
376490e0de5SThomas Veerman 	struct fuse		*fuse;
377490e0de5SThomas Veerman 	char			 name[64];
378490e0de5SThomas Veerman 	int			 i;
379490e0de5SThomas Veerman 
380490e0de5SThomas Veerman 	/* set up the proper name */
381490e0de5SThomas Veerman 	set_refuse_mount_name(argv, name, sizeof(name));
382490e0de5SThomas Veerman 
383490e0de5SThomas Veerman 	/* grab the pthread context key */
384490e0de5SThomas Veerman 	if (!create_context_key()) {
385490e0de5SThomas Veerman 		return NULL;
386490e0de5SThomas Veerman 	}
387490e0de5SThomas Veerman 
388490e0de5SThomas Veerman 	/* stuff name into fuse_args */
389490e0de5SThomas Veerman 	args = fuse_opt_deep_copy_args(argc, argv);
390490e0de5SThomas Veerman 	if (args->argc > 0) {
391490e0de5SThomas Veerman 		free(args->argv[0]);
392490e0de5SThomas Veerman 	}
393490e0de5SThomas Veerman 	if ((args->argv[0] = strdup(name)) == NULL) {
394490e0de5SThomas Veerman 		fuse_opt_free_args(args);
395490e0de5SThomas Veerman 		return NULL;
396490e0de5SThomas Veerman 	}
397490e0de5SThomas Veerman 
398490e0de5SThomas Veerman 	/* count back from the end over arguments starting with '-' */
399490e0de5SThomas Veerman 	for (i = argc - 1 ; i > 0 && *argv[i] == '-' ; --i) {
400490e0de5SThomas Veerman 	}
401490e0de5SThomas Veerman 
402490e0de5SThomas Veerman 	fc = fuse_mount(*mountpoint = argv[i], args);
403490e0de5SThomas Veerman 	fuse = fuse_new(fc, args, ops, size, user_data);
404490e0de5SThomas Veerman 
405490e0de5SThomas Veerman 	fuse_opt_free_args(args);
406490e0de5SThomas Veerman 	free(args);
407490e0de5SThomas Veerman 
408490e0de5SThomas Veerman 	/* XXX - wait for puffs to become multi-threaded */
409490e0de5SThomas Veerman 	if (multithreaded) {
410490e0de5SThomas Veerman 		*multithreaded = 0;
411490e0de5SThomas Veerman 	}
412490e0de5SThomas Veerman 
413490e0de5SThomas Veerman 	/* XXX - this is unused */
414490e0de5SThomas Veerman 	if (fd) {
415490e0de5SThomas Veerman 		*fd = 0;
416490e0de5SThomas Veerman 	}
417490e0de5SThomas Veerman 
418490e0de5SThomas Veerman 	return fuse;
419490e0de5SThomas Veerman }
420490e0de5SThomas Veerman 
421490e0de5SThomas Veerman #ifdef fuse_setup
422490e0de5SThomas Veerman #undef fuse_setup
423490e0de5SThomas Veerman #endif
424490e0de5SThomas Veerman 
425490e0de5SThomas Veerman struct fuse *
fuse_setup(int argc,char ** argv,const struct fuse_operations * ops,size_t size,char ** mountpoint,int * multithreaded,int * fd)426490e0de5SThomas Veerman fuse_setup(int argc, char **argv, const struct fuse_operations *ops,
427490e0de5SThomas Veerman 	size_t size, char **mountpoint, int *multithreaded, int *fd)
428490e0de5SThomas Veerman {
429490e0de5SThomas Veerman     return fuse_setup_real(argc, argv, ops, size, mountpoint,
430490e0de5SThomas Veerman 	multithreaded, fd, NULL);
431490e0de5SThomas Veerman }
432490e0de5SThomas Veerman 
433490e0de5SThomas Veerman struct fuse *
fuse_setup26(int argc,char ** argv,const struct fuse_operations * ops,size_t size,char ** mountpoint,int * multithreaded,void * user_data)434490e0de5SThomas Veerman fuse_setup26(int argc, char **argv, const struct fuse_operations *ops,
435490e0de5SThomas Veerman 	size_t size, char **mountpoint, int *multithreaded, void *user_data)
436490e0de5SThomas Veerman {
437490e0de5SThomas Veerman     return fuse_setup_real(argc, argv, ops, size, mountpoint,
438490e0de5SThomas Veerman 	multithreaded, NULL, user_data);
439490e0de5SThomas Veerman }
440490e0de5SThomas Veerman 
441490e0de5SThomas Veerman #define FUSE_ERR_UNLINK(fuse, file) if (fuse->op.unlink) fuse->op.unlink(file)
442490e0de5SThomas Veerman #define FUSE_ERR_RMDIR(fuse, dir) if (fuse->op.rmdir) fuse->op.rmdir(dir)
443490e0de5SThomas Veerman 
444490e0de5SThomas Veerman /* ARGSUSED1 */
445490e0de5SThomas Veerman static int
fuse_getattr(struct fuse * fuse,struct puffs_node * pn,const char * path,struct vattr * va)446490e0de5SThomas Veerman fuse_getattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
447490e0de5SThomas Veerman 	struct vattr *va)
448490e0de5SThomas Veerman {
449490e0de5SThomas Veerman 	struct stat		 st;
450490e0de5SThomas Veerman 	int			ret;
451490e0de5SThomas Veerman 
452490e0de5SThomas Veerman 	if (fuse->op.getattr == NULL) {
453490e0de5SThomas Veerman 		return ENOSYS;
454490e0de5SThomas Veerman 	}
455490e0de5SThomas Veerman 
456490e0de5SThomas Veerman 	/* wrap up return code */
457490e0de5SThomas Veerman 	memset(&st, 0, sizeof(st));
458490e0de5SThomas Veerman 	ret = (*fuse->op.getattr)(path, &st);
459490e0de5SThomas Veerman 
460490e0de5SThomas Veerman 	if (ret == 0) {
461490e0de5SThomas Veerman 		if (st.st_blksize == 0)
462490e0de5SThomas Veerman 			st.st_blksize = DEV_BSIZE;
463490e0de5SThomas Veerman 		puffs_stat2vattr(va, &st);
464490e0de5SThomas Veerman 	}
465490e0de5SThomas Veerman 
466490e0de5SThomas Veerman 	return -ret;
467490e0de5SThomas Veerman }
468490e0de5SThomas Veerman 
469490e0de5SThomas Veerman /* utility function to set various elements of the attribute */
470490e0de5SThomas Veerman static int
fuse_setattr(struct fuse * fuse,struct puffs_node * pn,const char * path,const struct vattr * va)471490e0de5SThomas Veerman fuse_setattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
472490e0de5SThomas Veerman 	const struct vattr *va)
473490e0de5SThomas Veerman {
474490e0de5SThomas Veerman 	struct refusenode	*rn = pn->pn_data;
475490e0de5SThomas Veerman 	mode_t			mode;
476490e0de5SThomas Veerman 	uid_t			uid;
477490e0de5SThomas Veerman 	gid_t			gid;
478490e0de5SThomas Veerman 	int			error, ret;
479490e0de5SThomas Veerman 
480490e0de5SThomas Veerman 	error = 0;
481490e0de5SThomas Veerman 
482490e0de5SThomas Veerman 	mode = va->va_mode;
483490e0de5SThomas Veerman 	uid = va->va_uid;
484490e0de5SThomas Veerman 	gid = va->va_gid;
485490e0de5SThomas Veerman 
486490e0de5SThomas Veerman 	if (mode != (mode_t)PUFFS_VNOVAL) {
487490e0de5SThomas Veerman 		ret = 0;
488490e0de5SThomas Veerman 
489490e0de5SThomas Veerman 		if (fuse->op.chmod == NULL) {
490490e0de5SThomas Veerman 			error = -ENOSYS;
491490e0de5SThomas Veerman 		} else {
492490e0de5SThomas Veerman 			ret = fuse->op.chmod(path, mode);
493490e0de5SThomas Veerman 			if (ret)
494490e0de5SThomas Veerman 				error = ret;
495490e0de5SThomas Veerman 		}
496490e0de5SThomas Veerman 	}
497490e0de5SThomas Veerman 	if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
498490e0de5SThomas Veerman 		ret = 0;
499490e0de5SThomas Veerman 
500490e0de5SThomas Veerman 		if (fuse->op.chown == NULL) {
501490e0de5SThomas Veerman 			error = -ENOSYS;
502490e0de5SThomas Veerman 		} else {
503490e0de5SThomas Veerman 			ret = fuse->op.chown(path, uid, gid);
504490e0de5SThomas Veerman 			if (ret)
505490e0de5SThomas Veerman 				error = ret;
506490e0de5SThomas Veerman 		}
507490e0de5SThomas Veerman 	}
508490e0de5SThomas Veerman 	if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
509490e0de5SThomas Veerman 	    || va->va_mtime.tv_sec != (long)PUFFS_VNOVAL) {
510490e0de5SThomas Veerman 		ret = 0;
511490e0de5SThomas Veerman 
512490e0de5SThomas Veerman 		if (fuse->op.utimens) {
513490e0de5SThomas Veerman 			struct timespec tv[2];
514490e0de5SThomas Veerman 
515490e0de5SThomas Veerman 			tv[0].tv_sec = va->va_atime.tv_sec;
516490e0de5SThomas Veerman 			tv[0].tv_nsec = va->va_atime.tv_nsec;
517490e0de5SThomas Veerman 			tv[1].tv_sec = va->va_mtime.tv_sec;
518490e0de5SThomas Veerman 			tv[1].tv_nsec = va->va_mtime.tv_nsec;
519490e0de5SThomas Veerman 
520490e0de5SThomas Veerman 			ret = fuse->op.utimens(path, tv);
521490e0de5SThomas Veerman 		} else if (fuse->op.utime) {
522490e0de5SThomas Veerman 			struct utimbuf timbuf;
523490e0de5SThomas Veerman 
524490e0de5SThomas Veerman 			timbuf.actime = va->va_atime.tv_sec;
525490e0de5SThomas Veerman 			timbuf.modtime = va->va_mtime.tv_sec;
526490e0de5SThomas Veerman 
527490e0de5SThomas Veerman 			ret = fuse->op.utime(path, &timbuf);
528490e0de5SThomas Veerman 		} else {
529490e0de5SThomas Veerman 			error = -ENOSYS;
530490e0de5SThomas Veerman 		}
531490e0de5SThomas Veerman 
532490e0de5SThomas Veerman 		if (ret)
533490e0de5SThomas Veerman 			error = ret;
534490e0de5SThomas Veerman 	}
535490e0de5SThomas Veerman 	if (va->va_size != (u_quad_t)PUFFS_VNOVAL) {
536490e0de5SThomas Veerman 		ret = 0;
537490e0de5SThomas Veerman 
538490e0de5SThomas Veerman 		if (fuse->op.truncate) {
539490e0de5SThomas Veerman 			ret = fuse->op.truncate(path, (off_t)va->va_size);
540490e0de5SThomas Veerman 		} else if (fuse->op.ftruncate) {
541490e0de5SThomas Veerman 			ret = fuse->op.ftruncate(path, (off_t)va->va_size,
542490e0de5SThomas Veerman 			    &rn->file_info);
543490e0de5SThomas Veerman 		} else {
544490e0de5SThomas Veerman 			error = -ENOSYS;
545490e0de5SThomas Veerman 		}
546490e0de5SThomas Veerman 
547490e0de5SThomas Veerman 		if (ret)
548490e0de5SThomas Veerman 			error = ret;
549490e0de5SThomas Veerman 	}
550490e0de5SThomas Veerman 	/* XXX: no reflection with reality */
551490e0de5SThomas Veerman 	puffs_setvattr(&pn->pn_va, va);
552490e0de5SThomas Veerman 
553490e0de5SThomas Veerman 	return -error;
554490e0de5SThomas Veerman 
555490e0de5SThomas Veerman }
556490e0de5SThomas Veerman 
557490e0de5SThomas Veerman static int
fuse_newnode(struct puffs_usermount * pu,const char * path,const struct vattr * va,struct fuse_file_info * fi,struct puffs_newinfo * pni,struct puffs_node ** pn_new)558490e0de5SThomas Veerman fuse_newnode(struct puffs_usermount *pu, const char *path,
559490e0de5SThomas Veerman 	const struct vattr *va, struct fuse_file_info *fi,
560490e0de5SThomas Veerman 	struct puffs_newinfo *pni, struct puffs_node **pn_new)
561490e0de5SThomas Veerman {
562490e0de5SThomas Veerman 	struct puffs_node	*pn;
563490e0de5SThomas Veerman 	struct refusenode	*rn;
564490e0de5SThomas Veerman 	struct vattr		 newva;
565490e0de5SThomas Veerman 	struct fuse		*fuse;
566490e0de5SThomas Veerman 
567490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
568490e0de5SThomas Veerman 
569490e0de5SThomas Veerman 	/* fix up nodes */
570490e0de5SThomas Veerman 	pn = newrn(pu);
571490e0de5SThomas Veerman 	if (pn == NULL) {
572490e0de5SThomas Veerman 		if (va->va_type == VDIR) {
573490e0de5SThomas Veerman 			FUSE_ERR_RMDIR(fuse, path);
574490e0de5SThomas Veerman 		} else {
575490e0de5SThomas Veerman 			FUSE_ERR_UNLINK(fuse, path);
576490e0de5SThomas Veerman 		}
577490e0de5SThomas Veerman 		return ENOMEM;
578490e0de5SThomas Veerman 	}
579490e0de5SThomas Veerman 	fuse_setattr(fuse, pn, path, va);
580490e0de5SThomas Veerman 	if (fuse_getattr(fuse, pn, path, &newva) == 0)
581490e0de5SThomas Veerman 		puffs_setvattr(&pn->pn_va, &newva);
582490e0de5SThomas Veerman 
583490e0de5SThomas Veerman 	rn = pn->pn_data;
584490e0de5SThomas Veerman 	if (fi)
585490e0de5SThomas Veerman 		memcpy(&rn->file_info, fi, sizeof(struct fuse_file_info));
586490e0de5SThomas Veerman 
587490e0de5SThomas Veerman 	puffs_newinfo_setcookie(pni, pn);
588490e0de5SThomas Veerman 	if (pn_new)
589490e0de5SThomas Veerman 		*pn_new = pn;
590490e0de5SThomas Veerman 
591490e0de5SThomas Veerman 	return 0;
592490e0de5SThomas Veerman }
593490e0de5SThomas Veerman 
594490e0de5SThomas Veerman 
595490e0de5SThomas Veerman /* operation wrappers start here */
596490e0de5SThomas Veerman 
597490e0de5SThomas Veerman /* lookup the path */
598490e0de5SThomas Veerman /* ARGSUSED1 */
599490e0de5SThomas Veerman static int
puffs_fuse_node_lookup(struct puffs_usermount * pu,void * opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn)600490e0de5SThomas Veerman puffs_fuse_node_lookup(struct puffs_usermount *pu, void *opc,
601490e0de5SThomas Veerman 	struct puffs_newinfo *pni, const struct puffs_cn *pcn)
602490e0de5SThomas Veerman {
603490e0de5SThomas Veerman 	struct puffs_node	*pn_res;
604490e0de5SThomas Veerman 	struct stat		 st;
605490e0de5SThomas Veerman 	struct fuse		*fuse;
606490e0de5SThomas Veerman 	const char		*path = PCNPATH(pcn);
607490e0de5SThomas Veerman 	int			 ret;
608490e0de5SThomas Veerman 
609490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
610490e0de5SThomas Veerman 
611490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn->pcn_cred);
612490e0de5SThomas Veerman 
613490e0de5SThomas Veerman 	ret = fuse->op.getattr(path, &st);
614490e0de5SThomas Veerman 
615490e0de5SThomas Veerman 	if (ret != 0) {
616490e0de5SThomas Veerman 		return -ret;
617490e0de5SThomas Veerman 	}
618490e0de5SThomas Veerman 
619490e0de5SThomas Veerman 	/* XXX: fiXXXme unconst */
620490e0de5SThomas Veerman 	pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
621490e0de5SThomas Veerman 	    __UNCONST(&pcn->pcn_po_full));
622490e0de5SThomas Veerman 	if (pn_res == NULL) {
623490e0de5SThomas Veerman 		pn_res = newrn(pu);
624490e0de5SThomas Veerman 		if (pn_res == NULL)
625490e0de5SThomas Veerman 			return errno;
626490e0de5SThomas Veerman 		puffs_stat2vattr(&pn_res->pn_va, &st);
627490e0de5SThomas Veerman 	}
628490e0de5SThomas Veerman 
629490e0de5SThomas Veerman 	puffs_newinfo_setcookie(pni, pn_res);
630490e0de5SThomas Veerman 	puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
631490e0de5SThomas Veerman 	puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
632490e0de5SThomas Veerman 	puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
633490e0de5SThomas Veerman 
634490e0de5SThomas Veerman 	return 0;
635490e0de5SThomas Veerman }
636490e0de5SThomas Veerman 
637490e0de5SThomas Veerman /* get attributes for the path name */
638490e0de5SThomas Veerman /* ARGSUSED3 */
639490e0de5SThomas Veerman static int
puffs_fuse_node_getattr(struct puffs_usermount * pu,void * opc,struct vattr * va,const struct puffs_cred * pcr)640490e0de5SThomas Veerman puffs_fuse_node_getattr(struct puffs_usermount *pu, void *opc, struct vattr *va,
641490e0de5SThomas Veerman 	const struct puffs_cred *pcr)
642490e0de5SThomas Veerman {
643490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
644490e0de5SThomas Veerman 	struct fuse		*fuse;
645490e0de5SThomas Veerman 	const char		*path = PNPATH(pn);
646490e0de5SThomas Veerman 
647490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
648490e0de5SThomas Veerman 
649490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcr);
650490e0de5SThomas Veerman 
651490e0de5SThomas Veerman 	return fuse_getattr(fuse, pn, path, va);
652490e0de5SThomas Veerman }
653490e0de5SThomas Veerman 
654490e0de5SThomas Veerman /* read the contents of the symbolic link */
655490e0de5SThomas Veerman /* ARGSUSED2 */
656490e0de5SThomas Veerman static int
puffs_fuse_node_readlink(struct puffs_usermount * pu,void * opc,const struct puffs_cred * cred,char * linkname,size_t * linklen)657490e0de5SThomas Veerman puffs_fuse_node_readlink(struct puffs_usermount *pu, void *opc,
658490e0de5SThomas Veerman 	const struct puffs_cred *cred, char *linkname, size_t *linklen)
659490e0de5SThomas Veerman {
660490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
661490e0de5SThomas Veerman 	struct fuse		*fuse;
662490e0de5SThomas Veerman 	const char		*path = PNPATH(pn), *p;
663490e0de5SThomas Veerman 	int			ret;
664490e0de5SThomas Veerman 
665490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
666490e0de5SThomas Veerman 	if (fuse->op.readlink == NULL) {
667490e0de5SThomas Veerman 		return ENOSYS;
668490e0de5SThomas Veerman 	}
669490e0de5SThomas Veerman 
670490e0de5SThomas Veerman 	set_fuse_context_uid_gid(cred);
671490e0de5SThomas Veerman 
672490e0de5SThomas Veerman 	/* wrap up return code */
673490e0de5SThomas Veerman 	ret = (*fuse->op.readlink)(path, linkname, *linklen);
674490e0de5SThomas Veerman 
675490e0de5SThomas Veerman 	if (ret == 0) {
676490e0de5SThomas Veerman 		p = memchr(linkname, '\0', *linklen);
677490e0de5SThomas Veerman 		if (!p)
678490e0de5SThomas Veerman 			return EINVAL;
679490e0de5SThomas Veerman 
680490e0de5SThomas Veerman 		*linklen = p - linkname;
681490e0de5SThomas Veerman 	}
682490e0de5SThomas Veerman 
683490e0de5SThomas Veerman 	return -ret;
684490e0de5SThomas Veerman }
685490e0de5SThomas Veerman 
686490e0de5SThomas Veerman /* make the special node */
687490e0de5SThomas Veerman /* ARGSUSED1 */
688490e0de5SThomas Veerman static int
puffs_fuse_node_mknod(struct puffs_usermount * pu,void * opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * va)689490e0de5SThomas Veerman puffs_fuse_node_mknod(struct puffs_usermount *pu, void *opc,
690490e0de5SThomas Veerman 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
691490e0de5SThomas Veerman 	const struct vattr *va)
692490e0de5SThomas Veerman {
693490e0de5SThomas Veerman 	struct fuse		*fuse;
694490e0de5SThomas Veerman 	mode_t			 mode;
695490e0de5SThomas Veerman 	const char		*path = PCNPATH(pcn);
696490e0de5SThomas Veerman 	int			ret;
697490e0de5SThomas Veerman 
698490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
699490e0de5SThomas Veerman 	if (fuse->op.mknod == NULL) {
700490e0de5SThomas Veerman 		return ENOSYS;
701490e0de5SThomas Veerman 	}
702490e0de5SThomas Veerman 
703490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn->pcn_cred);
704490e0de5SThomas Veerman 
705490e0de5SThomas Veerman 	/* wrap up return code */
706490e0de5SThomas Veerman 	mode = puffs_addvtype2mode(va->va_mode, va->va_type);
707490e0de5SThomas Veerman 	ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
708490e0de5SThomas Veerman 
709490e0de5SThomas Veerman 	if (ret == 0) {
710490e0de5SThomas Veerman 		ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
711490e0de5SThomas Veerman 	}
712490e0de5SThomas Veerman 
713490e0de5SThomas Veerman 	return -ret;
714490e0de5SThomas Veerman }
715490e0de5SThomas Veerman 
716490e0de5SThomas Veerman /* make a directory */
717490e0de5SThomas Veerman /* ARGSUSED1 */
718490e0de5SThomas Veerman static int
puffs_fuse_node_mkdir(struct puffs_usermount * pu,void * opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * va)719490e0de5SThomas Veerman puffs_fuse_node_mkdir(struct puffs_usermount *pu, void *opc,
720490e0de5SThomas Veerman 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
721490e0de5SThomas Veerman 	const struct vattr *va)
722490e0de5SThomas Veerman {
723490e0de5SThomas Veerman 	struct fuse		*fuse;
724490e0de5SThomas Veerman 	mode_t			 mode = va->va_mode;
725490e0de5SThomas Veerman 	const char		*path = PCNPATH(pcn);
726490e0de5SThomas Veerman 	int			ret;
727490e0de5SThomas Veerman 
728490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
729490e0de5SThomas Veerman 
730490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn->pcn_cred);
731490e0de5SThomas Veerman 
732490e0de5SThomas Veerman 	if (fuse->op.mkdir == NULL) {
733490e0de5SThomas Veerman 		return ENOSYS;
734490e0de5SThomas Veerman 	}
735490e0de5SThomas Veerman 
736490e0de5SThomas Veerman 	/* wrap up return code */
737490e0de5SThomas Veerman 	ret = (*fuse->op.mkdir)(path, mode);
738490e0de5SThomas Veerman 
739490e0de5SThomas Veerman 	if (ret == 0) {
740490e0de5SThomas Veerman 		ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
741490e0de5SThomas Veerman 	}
742490e0de5SThomas Veerman 
743490e0de5SThomas Veerman 	return -ret;
744490e0de5SThomas Veerman }
745490e0de5SThomas Veerman 
746490e0de5SThomas Veerman /*
747490e0de5SThomas Veerman  * create a regular file
748490e0de5SThomas Veerman  *
749490e0de5SThomas Veerman  * since linux/fuse sports using mknod for creating regular files
750490e0de5SThomas Veerman  * instead of having a separate call for it in some versions, if
751490e0de5SThomas Veerman  * we don't have create, just jump to op->mknod.
752490e0de5SThomas Veerman  */
753490e0de5SThomas Veerman /*ARGSUSED1*/
754490e0de5SThomas Veerman static int
puffs_fuse_node_create(struct puffs_usermount * pu,void * opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * va)755490e0de5SThomas Veerman puffs_fuse_node_create(struct puffs_usermount *pu, void *opc,
756490e0de5SThomas Veerman 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
757490e0de5SThomas Veerman 	const struct vattr *va)
758490e0de5SThomas Veerman {
759490e0de5SThomas Veerman 	struct fuse		*fuse;
760490e0de5SThomas Veerman 	struct fuse_file_info	fi;
761490e0de5SThomas Veerman 	struct puffs_node	*pn;
762490e0de5SThomas Veerman 	mode_t			mode = va->va_mode;
763490e0de5SThomas Veerman 	const char		*path = PCNPATH(pcn);
764490e0de5SThomas Veerman 	int			ret, created;
765490e0de5SThomas Veerman 
766490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
767490e0de5SThomas Veerman 
768490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn->pcn_cred);
769490e0de5SThomas Veerman 
770490e0de5SThomas Veerman 	created = 0;
771490e0de5SThomas Veerman 	if (fuse->op.create) {
772490e0de5SThomas Veerman 		ret = fuse->op.create(path, mode | S_IFREG, &fi);
773490e0de5SThomas Veerman 		if (ret == 0)
774490e0de5SThomas Veerman 			created = 1;
775490e0de5SThomas Veerman 
776490e0de5SThomas Veerman 	} else if (fuse->op.mknod) {
777490e0de5SThomas Veerman 		ret = fuse->op.mknod(path, mode | S_IFREG, 0);
778490e0de5SThomas Veerman 
779490e0de5SThomas Veerman 	} else {
780490e0de5SThomas Veerman 		ret = -ENOSYS;
781490e0de5SThomas Veerman 	}
782490e0de5SThomas Veerman 
783490e0de5SThomas Veerman 	if (ret == 0) {
784490e0de5SThomas Veerman 		ret = fuse_newnode(pu, path, va, &fi, pni, &pn);
785490e0de5SThomas Veerman 
786490e0de5SThomas Veerman 		/* sweet..  create also open the file */
787490e0de5SThomas Veerman 		if (created) {
788490e0de5SThomas Veerman 			struct refusenode *rn;
789490e0de5SThomas Veerman 
790490e0de5SThomas Veerman 			rn = pn->pn_data;
791490e0de5SThomas Veerman 			rn->flags |= RN_OPEN;
792490e0de5SThomas Veerman 			rn->opencount++;
793490e0de5SThomas Veerman 		}
794490e0de5SThomas Veerman 	}
795490e0de5SThomas Veerman 
796490e0de5SThomas Veerman 	return -ret;
797490e0de5SThomas Veerman }
798490e0de5SThomas Veerman 
799490e0de5SThomas Veerman /* remove the directory entry */
800490e0de5SThomas Veerman /* ARGSUSED1 */
801490e0de5SThomas Veerman static int
puffs_fuse_node_remove(struct puffs_usermount * pu,void * opc,void * targ,const struct puffs_cn * pcn)802490e0de5SThomas Veerman puffs_fuse_node_remove(struct puffs_usermount *pu, void *opc, void *targ,
803490e0de5SThomas Veerman 	const struct puffs_cn *pcn)
804490e0de5SThomas Veerman {
805490e0de5SThomas Veerman 	struct puffs_node	*pn_targ = targ;
806490e0de5SThomas Veerman 	struct fuse		*fuse;
807490e0de5SThomas Veerman 	const char		*path = PNPATH(pn_targ);
808490e0de5SThomas Veerman 	int			ret;
809490e0de5SThomas Veerman 
810490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
811490e0de5SThomas Veerman 
812490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn->pcn_cred);
813490e0de5SThomas Veerman 
814490e0de5SThomas Veerman 	if (fuse->op.unlink == NULL) {
815490e0de5SThomas Veerman 		return ENOSYS;
816490e0de5SThomas Veerman 	}
817490e0de5SThomas Veerman 
818490e0de5SThomas Veerman 	/* wrap up return code */
819490e0de5SThomas Veerman 	ret = (*fuse->op.unlink)(path);
820490e0de5SThomas Veerman 
821490e0de5SThomas Veerman 	return -ret;
822490e0de5SThomas Veerman }
823490e0de5SThomas Veerman 
824490e0de5SThomas Veerman /* remove the directory */
825490e0de5SThomas Veerman /* ARGSUSED1 */
826490e0de5SThomas Veerman static int
puffs_fuse_node_rmdir(struct puffs_usermount * pu,void * opc,void * targ,const struct puffs_cn * pcn)827490e0de5SThomas Veerman puffs_fuse_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ,
828490e0de5SThomas Veerman 	const struct puffs_cn *pcn)
829490e0de5SThomas Veerman {
830490e0de5SThomas Veerman 	struct puffs_node	*pn_targ = targ;
831490e0de5SThomas Veerman 	struct fuse		*fuse;
832490e0de5SThomas Veerman 	const char		*path = PNPATH(pn_targ);
833490e0de5SThomas Veerman 	int			ret;
834490e0de5SThomas Veerman 
835490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
836490e0de5SThomas Veerman 
837490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn->pcn_cred);
838490e0de5SThomas Veerman 
839490e0de5SThomas Veerman 	if (fuse->op.rmdir == NULL) {
840490e0de5SThomas Veerman 		return ENOSYS;
841490e0de5SThomas Veerman 	}
842490e0de5SThomas Veerman 
843490e0de5SThomas Veerman 	/* wrap up return code */
844490e0de5SThomas Veerman 	ret = (*fuse->op.rmdir)(path);
845490e0de5SThomas Veerman 
846490e0de5SThomas Veerman 	return -ret;
847490e0de5SThomas Veerman }
848490e0de5SThomas Veerman 
849490e0de5SThomas Veerman /* create a symbolic link */
850490e0de5SThomas Veerman /* ARGSUSED1 */
851490e0de5SThomas Veerman static int
puffs_fuse_node_symlink(struct puffs_usermount * pu,void * opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn_src,const struct vattr * va,const char * link_target)852490e0de5SThomas Veerman puffs_fuse_node_symlink(struct puffs_usermount *pu, void *opc,
853490e0de5SThomas Veerman 	struct puffs_newinfo *pni, const struct puffs_cn *pcn_src,
854490e0de5SThomas Veerman 	const struct vattr *va, const char *link_target)
855490e0de5SThomas Veerman {
856490e0de5SThomas Veerman 	struct fuse		*fuse;
857490e0de5SThomas Veerman 	const char		*path = PCNPATH(pcn_src);
858490e0de5SThomas Veerman 	int			ret;
859490e0de5SThomas Veerman 
860490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
861490e0de5SThomas Veerman 
862490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn_src->pcn_cred);
863490e0de5SThomas Veerman 
864490e0de5SThomas Veerman 	if (fuse->op.symlink == NULL) {
865490e0de5SThomas Veerman 		return ENOSYS;
866490e0de5SThomas Veerman 	}
867490e0de5SThomas Veerman 
868490e0de5SThomas Veerman 	/* wrap up return code */
869490e0de5SThomas Veerman 	ret = fuse->op.symlink(link_target, path);
870490e0de5SThomas Veerman 
871490e0de5SThomas Veerman 	if (ret == 0) {
872490e0de5SThomas Veerman 		ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
873490e0de5SThomas Veerman 	}
874490e0de5SThomas Veerman 
875490e0de5SThomas Veerman 	return -ret;
876490e0de5SThomas Veerman }
877490e0de5SThomas Veerman 
878490e0de5SThomas Veerman /* rename a directory entry */
879490e0de5SThomas Veerman /* ARGSUSED1 */
880490e0de5SThomas Veerman static int
puffs_fuse_node_rename(struct puffs_usermount * pu,void * opc,void * src,const struct puffs_cn * pcn_src,void * targ_dir,void * targ,const struct puffs_cn * pcn_targ)881490e0de5SThomas Veerman puffs_fuse_node_rename(struct puffs_usermount *pu, void *opc, void *src,
882490e0de5SThomas Veerman 	const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
883490e0de5SThomas Veerman 	const struct puffs_cn *pcn_targ)
884490e0de5SThomas Veerman {
885490e0de5SThomas Veerman 	struct fuse		*fuse;
886490e0de5SThomas Veerman 	const char		*path_src = PCNPATH(pcn_src);
887490e0de5SThomas Veerman 	const char		*path_dest = PCNPATH(pcn_targ);
888490e0de5SThomas Veerman 	int			ret;
889490e0de5SThomas Veerman 
890490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
891490e0de5SThomas Veerman 
892490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn_targ->pcn_cred);
893490e0de5SThomas Veerman 
894490e0de5SThomas Veerman 	if (fuse->op.rename == NULL) {
895490e0de5SThomas Veerman 		return ENOSYS;
896490e0de5SThomas Veerman 	}
897490e0de5SThomas Veerman 
898490e0de5SThomas Veerman 	ret = fuse->op.rename(path_src, path_dest);
899490e0de5SThomas Veerman 
900490e0de5SThomas Veerman 	if (ret == 0) {
901490e0de5SThomas Veerman 	}
902490e0de5SThomas Veerman 
903490e0de5SThomas Veerman 	return -ret;
904490e0de5SThomas Veerman }
905490e0de5SThomas Veerman 
906490e0de5SThomas Veerman /* create a link in the file system */
907490e0de5SThomas Veerman /* ARGSUSED1 */
908490e0de5SThomas Veerman static int
puffs_fuse_node_link(struct puffs_usermount * pu,void * opc,void * targ,const struct puffs_cn * pcn)909490e0de5SThomas Veerman puffs_fuse_node_link(struct puffs_usermount *pu, void *opc, void *targ,
910490e0de5SThomas Veerman 	const struct puffs_cn *pcn)
911490e0de5SThomas Veerman {
912490e0de5SThomas Veerman 	struct puffs_node	*pn = targ;
913490e0de5SThomas Veerman 	struct fuse		*fuse;
914490e0de5SThomas Veerman 	int			ret;
915490e0de5SThomas Veerman 
916490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
917490e0de5SThomas Veerman 
918490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcn->pcn_cred);
919490e0de5SThomas Veerman 
920490e0de5SThomas Veerman 	if (fuse->op.link == NULL) {
921490e0de5SThomas Veerman 		return ENOSYS;
922490e0de5SThomas Veerman 	}
923490e0de5SThomas Veerman 
924490e0de5SThomas Veerman 	/* wrap up return code */
925490e0de5SThomas Veerman 	ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
926490e0de5SThomas Veerman 
927490e0de5SThomas Veerman 	return -ret;
928490e0de5SThomas Veerman }
929490e0de5SThomas Veerman 
930490e0de5SThomas Veerman /*
931490e0de5SThomas Veerman  * fuse's regular interface provides chmod(), chown(), utimes()
932490e0de5SThomas Veerman  * and truncate() + some variations, so try to fit the square block
933490e0de5SThomas Veerman  * in the circle hole and the circle block .... something like that
934490e0de5SThomas Veerman  */
935490e0de5SThomas Veerman /* ARGSUSED3 */
936490e0de5SThomas Veerman static int
puffs_fuse_node_setattr(struct puffs_usermount * pu,void * opc,const struct vattr * va,const struct puffs_cred * pcr)937490e0de5SThomas Veerman puffs_fuse_node_setattr(struct puffs_usermount *pu, void *opc,
938490e0de5SThomas Veerman 	const struct vattr *va, const struct puffs_cred *pcr)
939490e0de5SThomas Veerman {
940490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
941490e0de5SThomas Veerman 	struct fuse		*fuse;
942490e0de5SThomas Veerman 	const char		*path = PNPATH(pn);
943490e0de5SThomas Veerman 
944490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
945490e0de5SThomas Veerman 
946490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcr);
947490e0de5SThomas Veerman 
948490e0de5SThomas Veerman 	return fuse_setattr(fuse, pn, path, va);
949490e0de5SThomas Veerman }
950490e0de5SThomas Veerman 
951490e0de5SThomas Veerman /* ARGSUSED2 */
952490e0de5SThomas Veerman static int
puffs_fuse_node_open(struct puffs_usermount * pu,void * opc,int mode,const struct puffs_cred * cred)953490e0de5SThomas Veerman puffs_fuse_node_open(struct puffs_usermount *pu, void *opc, int mode,
954490e0de5SThomas Veerman 	const struct puffs_cred *cred)
955490e0de5SThomas Veerman {
956490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
957490e0de5SThomas Veerman 	struct refusenode	*rn = pn->pn_data;
958490e0de5SThomas Veerman 	struct fuse_file_info	*fi = &rn->file_info;
959490e0de5SThomas Veerman 	struct fuse		*fuse;
960490e0de5SThomas Veerman 	const char		*path = PNPATH(pn);
961490e0de5SThomas Veerman 
962490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
963490e0de5SThomas Veerman 
964490e0de5SThomas Veerman 	set_fuse_context_uid_gid(cred);
965490e0de5SThomas Veerman 
966490e0de5SThomas Veerman 	/* if open, don't open again, lest risk nuking file private info */
967490e0de5SThomas Veerman 	if (rn->flags & RN_OPEN) {
968490e0de5SThomas Veerman 		rn->opencount++;
969490e0de5SThomas Veerman 		return 0;
970490e0de5SThomas Veerman 	}
971490e0de5SThomas Veerman 
972490e0de5SThomas Veerman 	/* OFLAGS(), need to convert FREAD/FWRITE to O_RD/WR */
973490e0de5SThomas Veerman 	fi->flags = (mode & ~(O_CREAT | O_EXCL | O_TRUNC)) - 1;
974490e0de5SThomas Veerman 
975490e0de5SThomas Veerman 	if (pn->pn_va.va_type == VDIR) {
976490e0de5SThomas Veerman 		if (fuse->op.opendir)
977490e0de5SThomas Veerman 			fuse->op.opendir(path, fi);
978490e0de5SThomas Veerman 	} else {
979490e0de5SThomas Veerman 		if (fuse->op.open)
980490e0de5SThomas Veerman 			fuse->op.open(path, fi);
981490e0de5SThomas Veerman 	}
982490e0de5SThomas Veerman 
983490e0de5SThomas Veerman 	rn->flags |= RN_OPEN;
984490e0de5SThomas Veerman 	rn->opencount++;
985490e0de5SThomas Veerman 
986490e0de5SThomas Veerman 	return 0;
987490e0de5SThomas Veerman }
988490e0de5SThomas Veerman 
989490e0de5SThomas Veerman /* ARGSUSED2 */
990490e0de5SThomas Veerman static int
puffs_fuse_node_close(struct puffs_usermount * pu,void * opc,int fflag,const struct puffs_cred * pcr)991490e0de5SThomas Veerman puffs_fuse_node_close(struct puffs_usermount *pu, void *opc, int fflag,
992490e0de5SThomas Veerman 	const struct puffs_cred *pcr)
993490e0de5SThomas Veerman {
994490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
995490e0de5SThomas Veerman 	struct refusenode	*rn = pn->pn_data;
996490e0de5SThomas Veerman 	struct fuse		*fuse;
997490e0de5SThomas Veerman 	struct fuse_file_info	*fi;
998490e0de5SThomas Veerman 	const char		*path = PNPATH(pn);
999490e0de5SThomas Veerman 	int			ret;
1000490e0de5SThomas Veerman 
1001490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
1002490e0de5SThomas Veerman 	fi = &rn->file_info;
1003490e0de5SThomas Veerman 	ret = 0;
1004490e0de5SThomas Veerman 
1005490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcr);
1006490e0de5SThomas Veerman 
1007490e0de5SThomas Veerman 	if (rn->flags & RN_OPEN) {
1008490e0de5SThomas Veerman 		if (pn->pn_va.va_type == VDIR) {
1009490e0de5SThomas Veerman 			if (fuse->op.releasedir)
1010490e0de5SThomas Veerman 				ret = fuse->op.releasedir(path, fi);
1011490e0de5SThomas Veerman 		} else {
1012490e0de5SThomas Veerman 			if (fuse->op.release)
1013490e0de5SThomas Veerman 				ret = fuse->op.release(path, fi);
1014490e0de5SThomas Veerman 		}
1015490e0de5SThomas Veerman 	}
1016490e0de5SThomas Veerman 	rn->flags &= ~RN_OPEN;
1017490e0de5SThomas Veerman 	rn->opencount--;
1018490e0de5SThomas Veerman 
1019490e0de5SThomas Veerman 	return ret;
1020490e0de5SThomas Veerman }
1021490e0de5SThomas Veerman 
1022490e0de5SThomas Veerman /* read some more from the file */
1023490e0de5SThomas Veerman /* ARGSUSED5 */
1024490e0de5SThomas Veerman static int
puffs_fuse_node_read(struct puffs_usermount * pu,void * opc,uint8_t * buf,off_t offset,size_t * resid,const struct puffs_cred * pcr,int ioflag)1025490e0de5SThomas Veerman puffs_fuse_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf,
1026490e0de5SThomas Veerman 	off_t offset, size_t *resid, const struct puffs_cred *pcr,
1027490e0de5SThomas Veerman 	int ioflag)
1028490e0de5SThomas Veerman {
1029490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
1030490e0de5SThomas Veerman 	struct refusenode	*rn = pn->pn_data;
1031490e0de5SThomas Veerman 	struct fuse		*fuse;
1032490e0de5SThomas Veerman 	const char		*path = PNPATH(pn);
1033490e0de5SThomas Veerman 	size_t			maxread;
1034490e0de5SThomas Veerman 	int			ret;
1035490e0de5SThomas Veerman 
1036490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
1037490e0de5SThomas Veerman 	if (fuse->op.read == NULL) {
1038490e0de5SThomas Veerman 		return ENOSYS;
1039490e0de5SThomas Veerman 	}
1040490e0de5SThomas Veerman 
1041490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcr);
1042490e0de5SThomas Veerman 
1043490e0de5SThomas Veerman 	maxread = *resid;
1044490e0de5SThomas Veerman 	if (maxread > pn->pn_va.va_size - offset) {
1045490e0de5SThomas Veerman 		/*LINTED*/
1046490e0de5SThomas Veerman 		maxread = pn->pn_va.va_size - offset;
1047490e0de5SThomas Veerman 	}
1048490e0de5SThomas Veerman 	if (maxread == 0)
1049490e0de5SThomas Veerman 		return 0;
1050490e0de5SThomas Veerman 
1051490e0de5SThomas Veerman 	ret = (*fuse->op.read)(path, (char *)buf, maxread, offset,
1052490e0de5SThomas Veerman 	    &rn->file_info);
1053490e0de5SThomas Veerman 
1054490e0de5SThomas Veerman 	if (ret > 0) {
1055490e0de5SThomas Veerman 		*resid -= ret;
1056490e0de5SThomas Veerman 		ret = 0;
1057490e0de5SThomas Veerman 	}
1058490e0de5SThomas Veerman 
1059490e0de5SThomas Veerman 	return -ret;
1060490e0de5SThomas Veerman }
1061490e0de5SThomas Veerman 
1062490e0de5SThomas Veerman /* write to the file */
1063490e0de5SThomas Veerman /* ARGSUSED0 */
1064490e0de5SThomas Veerman static int
puffs_fuse_node_write(struct puffs_usermount * pu,void * opc,uint8_t * buf,off_t offset,size_t * resid,const struct puffs_cred * pcr,int ioflag)1065490e0de5SThomas Veerman puffs_fuse_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
1066490e0de5SThomas Veerman 	off_t offset, size_t *resid, const struct puffs_cred *pcr,
1067490e0de5SThomas Veerman 	int ioflag)
1068490e0de5SThomas Veerman {
1069490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
1070490e0de5SThomas Veerman 	struct refusenode	*rn = pn->pn_data;
1071490e0de5SThomas Veerman 	struct fuse		*fuse;
1072490e0de5SThomas Veerman 	const char		*path = PNPATH(pn);
1073490e0de5SThomas Veerman 	int			ret;
1074490e0de5SThomas Veerman 
1075490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
1076490e0de5SThomas Veerman 	if (fuse->op.write == NULL) {
1077490e0de5SThomas Veerman 		return ENOSYS;
1078490e0de5SThomas Veerman 	}
1079490e0de5SThomas Veerman 
1080490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcr);
1081490e0de5SThomas Veerman 
1082490e0de5SThomas Veerman 	if (ioflag & PUFFS_IO_APPEND)
1083490e0de5SThomas Veerman 		offset = pn->pn_va.va_size;
1084490e0de5SThomas Veerman 
1085490e0de5SThomas Veerman 	ret = (*fuse->op.write)(path, (char *)buf, *resid, offset,
1086490e0de5SThomas Veerman 	    &rn->file_info);
1087490e0de5SThomas Veerman 
1088*84d9c625SLionel Sambuc 	if (ret >= 0) {
1089490e0de5SThomas Veerman 		if ((uint64_t)(offset + ret) > pn->pn_va.va_size)
1090490e0de5SThomas Veerman 			pn->pn_va.va_size = offset + ret;
1091490e0de5SThomas Veerman 		*resid -= ret;
1092*84d9c625SLionel Sambuc 		ret = (*resid == 0) ? 0 : ENOSPC;
1093*84d9c625SLionel Sambuc 	} else {
1094*84d9c625SLionel Sambuc 		ret = -ret;
1095490e0de5SThomas Veerman 	}
1096490e0de5SThomas Veerman 
1097*84d9c625SLionel Sambuc 	return ret;
1098490e0de5SThomas Veerman }
1099490e0de5SThomas Veerman 
1100490e0de5SThomas Veerman 
1101490e0de5SThomas Veerman /* ARGSUSED3 */
1102490e0de5SThomas Veerman static int
puffs_fuse_node_readdir(struct puffs_usermount * pu,void * opc,struct dirent * dent,off_t * readoff,size_t * reslen,const struct puffs_cred * pcr,int * eofflag,off_t * cookies,size_t * ncookies)1103490e0de5SThomas Veerman puffs_fuse_node_readdir(struct puffs_usermount *pu, void *opc,
1104490e0de5SThomas Veerman 	struct dirent *dent, off_t *readoff, size_t *reslen,
1105490e0de5SThomas Veerman 	const struct puffs_cred *pcr, int *eofflag,
1106490e0de5SThomas Veerman 	off_t *cookies, size_t *ncookies)
1107490e0de5SThomas Veerman {
1108490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
1109490e0de5SThomas Veerman 	struct refusenode	*rn = pn->pn_data;
1110490e0de5SThomas Veerman 	struct puffs_fuse_dirh	*dirh;
1111490e0de5SThomas Veerman 	struct fuse		*fuse;
1112490e0de5SThomas Veerman 	struct dirent		*fromdent;
1113490e0de5SThomas Veerman 	const char		*path = PNPATH(pn);
1114490e0de5SThomas Veerman 	int			ret;
1115490e0de5SThomas Veerman 
1116490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
1117490e0de5SThomas Veerman 	if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
1118490e0de5SThomas Veerman 		return ENOSYS;
1119490e0de5SThomas Veerman 	}
1120490e0de5SThomas Veerman 
1121490e0de5SThomas Veerman 	set_fuse_context_uid_gid(pcr);
1122490e0de5SThomas Veerman 
1123490e0de5SThomas Veerman 	if (pn->pn_va.va_type != VDIR)
1124490e0de5SThomas Veerman 		return ENOTDIR;
1125490e0de5SThomas Veerman 
1126490e0de5SThomas Veerman 	dirh = &rn->dirh;
1127490e0de5SThomas Veerman 
1128490e0de5SThomas Veerman 	/*
1129490e0de5SThomas Veerman 	 * if we are starting from the beginning, slurp entire directory
1130490e0de5SThomas Veerman 	 * into our buffers
1131490e0de5SThomas Veerman 	 */
1132490e0de5SThomas Veerman 	if (*readoff == 0) {
1133490e0de5SThomas Veerman 		/* free old buffers */
1134490e0de5SThomas Veerman 		free(dirh->dbuf);
1135490e0de5SThomas Veerman 		memset(dirh, 0, sizeof(struct puffs_fuse_dirh));
1136490e0de5SThomas Veerman 
1137490e0de5SThomas Veerman 		if (fuse->op.readdir)
1138490e0de5SThomas Veerman 			ret = fuse->op.readdir(path, dirh, puffs_fuse_fill_dir,
1139490e0de5SThomas Veerman 			    0, &rn->file_info);
1140490e0de5SThomas Veerman 		else
1141490e0de5SThomas Veerman 			ret = fuse->op.getdir(path, dirh, puffs_fuse_dirfil);
1142490e0de5SThomas Veerman 		if (ret)
1143490e0de5SThomas Veerman 			return -ret;
1144490e0de5SThomas Veerman 	}
1145490e0de5SThomas Veerman 
1146490e0de5SThomas Veerman         /* Both op.readdir and op.getdir read full directory */
1147490e0de5SThomas Veerman         *eofflag = 1;
1148490e0de5SThomas Veerman 
1149490e0de5SThomas Veerman 	/* now, stuff results into the kernel buffers */
1150490e0de5SThomas Veerman 	while (*readoff < (off_t)(dirh->bufsize - dirh->reslen)) {
1151490e0de5SThomas Veerman 		/*LINTED*/
1152490e0de5SThomas Veerman 		fromdent = (struct dirent *)((uint8_t *)dirh->dbuf + *readoff);
1153490e0de5SThomas Veerman 
1154490e0de5SThomas Veerman 		if (*reslen < _DIRENT_SIZE(fromdent))
1155490e0de5SThomas Veerman 			break;
1156490e0de5SThomas Veerman 
1157490e0de5SThomas Veerman 		memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
1158490e0de5SThomas Veerman 		*readoff += _DIRENT_SIZE(fromdent);
1159490e0de5SThomas Veerman 		*reslen -= _DIRENT_SIZE(fromdent);
1160490e0de5SThomas Veerman 
1161490e0de5SThomas Veerman 		dent = _DIRENT_NEXT(dent);
1162490e0de5SThomas Veerman 	}
1163490e0de5SThomas Veerman 
1164490e0de5SThomas Veerman 	return 0;
1165490e0de5SThomas Veerman }
1166490e0de5SThomas Veerman 
1167490e0de5SThomas Veerman /* ARGSUSED */
1168490e0de5SThomas Veerman static int
puffs_fuse_node_reclaim(struct puffs_usermount * pu,void * opc)1169490e0de5SThomas Veerman puffs_fuse_node_reclaim(struct puffs_usermount *pu, void *opc)
1170490e0de5SThomas Veerman {
1171490e0de5SThomas Veerman 	struct puffs_node	*pn = opc;
1172490e0de5SThomas Veerman 
1173490e0de5SThomas Veerman 	nukern(pn);
1174490e0de5SThomas Veerman 	return 0;
1175490e0de5SThomas Veerman }
1176490e0de5SThomas Veerman 
1177490e0de5SThomas Veerman /* ARGSUSED1 */
1178490e0de5SThomas Veerman static int
puffs_fuse_fs_unmount(struct puffs_usermount * pu,int flags)1179490e0de5SThomas Veerman puffs_fuse_fs_unmount(struct puffs_usermount *pu, int flags)
1180490e0de5SThomas Veerman {
1181490e0de5SThomas Veerman 	struct fuse		*fuse;
1182490e0de5SThomas Veerman 
1183490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
1184490e0de5SThomas Veerman 	if (fuse->op.destroy == NULL) {
1185490e0de5SThomas Veerman 		return 0;
1186490e0de5SThomas Veerman 	}
1187490e0de5SThomas Veerman 	(*fuse->op.destroy)(fuse);
1188490e0de5SThomas Veerman         return 0;
1189490e0de5SThomas Veerman }
1190490e0de5SThomas Veerman 
1191490e0de5SThomas Veerman /* ARGSUSED0 */
1192490e0de5SThomas Veerman static int
puffs_fuse_fs_sync(struct puffs_usermount * pu,int flags,const struct puffs_cred * cr)1193490e0de5SThomas Veerman puffs_fuse_fs_sync(struct puffs_usermount *pu, int flags,
1194490e0de5SThomas Veerman             const struct puffs_cred *cr)
1195490e0de5SThomas Veerman {
1196490e0de5SThomas Veerman 	set_fuse_context_uid_gid(cr);
1197490e0de5SThomas Veerman         return 0;
1198490e0de5SThomas Veerman }
1199490e0de5SThomas Veerman 
1200490e0de5SThomas Veerman /* ARGSUSED2 */
1201490e0de5SThomas Veerman static int
puffs_fuse_fs_statvfs(struct puffs_usermount * pu,struct statvfs * svfsb)1202490e0de5SThomas Veerman puffs_fuse_fs_statvfs(struct puffs_usermount *pu, struct statvfs *svfsb)
1203490e0de5SThomas Veerman {
1204490e0de5SThomas Veerman 	struct fuse		*fuse;
1205490e0de5SThomas Veerman 	int			ret;
1206490e0de5SThomas Veerman 
1207490e0de5SThomas Veerman 	fuse = puffs_getspecific(pu);
1208490e0de5SThomas Veerman 	if (fuse->op.statfs == NULL) {
1209490e0de5SThomas Veerman 		if ((ret = statvfs(PNPATH(puffs_getroot(pu)), svfsb)) == -1) {
1210490e0de5SThomas Veerman 			return errno;
1211490e0de5SThomas Veerman 		}
1212490e0de5SThomas Veerman 	} else {
1213490e0de5SThomas Veerman 		ret = fuse->op.statfs(PNPATH(puffs_getroot(pu)), svfsb);
1214490e0de5SThomas Veerman 	}
1215490e0de5SThomas Veerman 
1216490e0de5SThomas Veerman         return -ret;
1217490e0de5SThomas Veerman }
1218490e0de5SThomas Veerman 
1219490e0de5SThomas Veerman 
1220490e0de5SThomas Veerman /* End of puffs_fuse operations */
1221490e0de5SThomas Veerman /* ARGSUSED3 */
1222490e0de5SThomas Veerman int
fuse_main_real(int argc,char ** argv,const struct fuse_operations * ops,size_t size,void * userdata)1223490e0de5SThomas Veerman fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
1224490e0de5SThomas Veerman 	size_t size, void *userdata)
1225490e0de5SThomas Veerman {
1226490e0de5SThomas Veerman 	struct fuse	*fuse;
1227490e0de5SThomas Veerman 	char		*mountpoint;
1228490e0de5SThomas Veerman 	int		 multithreaded;
1229490e0de5SThomas Veerman 	int		 fd;
1230490e0de5SThomas Veerman 
1231*84d9c625SLionel Sambuc 	fuse = fuse_setup_real(argc, argv, ops, size, &mountpoint,
1232*84d9c625SLionel Sambuc 	    &multithreaded, &fd, userdata);
1233490e0de5SThomas Veerman 
1234490e0de5SThomas Veerman 	return fuse_loop(fuse);
1235490e0de5SThomas Veerman }
1236490e0de5SThomas Veerman 
1237490e0de5SThomas Veerman /*
1238490e0de5SThomas Veerman  * XXX: just defer the operation until fuse_new() when we have more
1239490e0de5SThomas Veerman  * info on our hands.  The real beef is why's this separate in fuse in
1240490e0de5SThomas Veerman  * the first place?
1241490e0de5SThomas Veerman  */
1242490e0de5SThomas Veerman /* ARGSUSED1 */
1243490e0de5SThomas Veerman struct fuse_chan *
fuse_mount(const char * dir,struct fuse_args * args)1244490e0de5SThomas Veerman fuse_mount(const char *dir, struct fuse_args *args)
1245490e0de5SThomas Veerman {
1246490e0de5SThomas Veerman  	struct fuse_chan	*fc;
1247490e0de5SThomas Veerman 	char			 name[64];
1248490e0de5SThomas Veerman 
1249490e0de5SThomas Veerman 	if ((fc = calloc(1, sizeof(*fc))) == NULL) {
1250490e0de5SThomas Veerman 		err(EXIT_FAILURE, "fuse_mount");
1251490e0de5SThomas Veerman 	}
1252490e0de5SThomas Veerman 	fc->dead = 0;
1253490e0de5SThomas Veerman 
1254490e0de5SThomas Veerman 	if ((fc->dir = strdup(dir)) == NULL) {
1255490e0de5SThomas Veerman 		err(EXIT_FAILURE, "fuse_mount");
1256490e0de5SThomas Veerman 	}
1257490e0de5SThomas Veerman 
1258490e0de5SThomas Veerman 	/*
1259490e0de5SThomas Veerman 	 * we need to deep copy the args struct - some fuse file
1260490e0de5SThomas Veerman 	 * systems "clean up" the argument vector for "security
1261490e0de5SThomas Veerman 	 * reasons"
1262490e0de5SThomas Veerman 	 */
1263490e0de5SThomas Veerman 	fc->args = fuse_opt_deep_copy_args(args->argc, args->argv);
1264490e0de5SThomas Veerman 
1265490e0de5SThomas Veerman 	if (args->argc > 0) {
1266490e0de5SThomas Veerman 		set_refuse_mount_name(args->argv, name, sizeof(name));
1267490e0de5SThomas Veerman 		if ((args->argv[0] = strdup(name)) == NULL)
1268490e0de5SThomas Veerman 			err(1, "fuse_mount");
1269490e0de5SThomas Veerman 	}
1270490e0de5SThomas Veerman 
1271490e0de5SThomas Veerman 	return fc;
1272490e0de5SThomas Veerman }
1273490e0de5SThomas Veerman 
1274490e0de5SThomas Veerman /* ARGSUSED1 */
1275490e0de5SThomas Veerman struct fuse *
fuse_new(struct fuse_chan * fc,struct fuse_args * args,const struct fuse_operations * ops,size_t size,void * userdata)1276490e0de5SThomas Veerman fuse_new(struct fuse_chan *fc, struct fuse_args *args,
1277490e0de5SThomas Veerman 	const struct fuse_operations *ops, size_t size, void *userdata)
1278490e0de5SThomas Veerman {
1279490e0de5SThomas Veerman 	struct puffs_usermount	*pu;
1280490e0de5SThomas Veerman 	struct fuse_context	*fusectx;
1281490e0de5SThomas Veerman 	struct puffs_pathobj	*po_root;
1282490e0de5SThomas Veerman 	struct puffs_node	*pn_root;
1283490e0de5SThomas Veerman 	struct puffs_ops	*pops;
1284490e0de5SThomas Veerman 	struct refusenode	*rn_root;
1285490e0de5SThomas Veerman 	struct statvfs		 svfsb;
1286490e0de5SThomas Veerman 	struct stat		 st;
1287490e0de5SThomas Veerman 	struct fuse		*fuse;
1288490e0de5SThomas Veerman 	extern int		 puffs_fakecc;
1289490e0de5SThomas Veerman 	char			 name[64];
1290490e0de5SThomas Veerman 	char			*argv0;
1291490e0de5SThomas Veerman 
1292490e0de5SThomas Veerman 	if ((fuse = calloc(1, sizeof(*fuse))) == NULL) {
1293490e0de5SThomas Veerman 		err(EXIT_FAILURE, "fuse_new");
1294490e0de5SThomas Veerman 	}
1295490e0de5SThomas Veerman 
1296490e0de5SThomas Veerman 	/* copy fuse ops to their own structure */
1297490e0de5SThomas Veerman 	(void) memcpy(&fuse->op, ops, sizeof(fuse->op));
1298490e0de5SThomas Veerman 
1299490e0de5SThomas Veerman 	fusectx = fuse_get_context();
1300490e0de5SThomas Veerman 	fusectx->fuse = fuse;
1301490e0de5SThomas Veerman 	fusectx->uid = 0;
1302490e0de5SThomas Veerman 	fusectx->gid = 0;
1303490e0de5SThomas Veerman 	fusectx->pid = 0;
1304490e0de5SThomas Veerman 	fusectx->private_data = userdata;
1305490e0de5SThomas Veerman 
1306490e0de5SThomas Veerman 	fuse->fc = fc;
1307490e0de5SThomas Veerman 
1308*84d9c625SLionel Sambuc 	if (fuse->op.init != NULL)
1309*84d9c625SLionel Sambuc 		fusectx->private_data = fuse->op.init(NULL); /* XXX */
1310*84d9c625SLionel Sambuc 
1311490e0de5SThomas Veerman 	/* initialise the puffs operations structure */
1312490e0de5SThomas Veerman         PUFFSOP_INIT(pops);
1313490e0de5SThomas Veerman 
1314490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, fs, sync);
1315490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
1316490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
1317490e0de5SThomas Veerman 
1318490e0de5SThomas Veerman 	/*
1319490e0de5SThomas Veerman 	 * XXX: all of these don't possibly need to be
1320490e0de5SThomas Veerman 	 * unconditionally set
1321490e0de5SThomas Veerman 	 */
1322490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, lookup);
1323490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, getattr);
1324490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, setattr);
1325490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, readdir);
1326490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, readlink);
1327490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, mknod);
1328490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, create);
1329490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, remove);
1330490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
1331490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
1332490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, symlink);
1333490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, rename);
1334490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, link);
1335490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, open);
1336490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, close);
1337490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, read);
1338490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, write);
1339490e0de5SThomas Veerman         PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
1340490e0de5SThomas Veerman 
1341490e0de5SThomas Veerman 	argv0 = (*args->argv[0] == 0x0) ? fc->args->argv[0] : args->argv[0];
1342490e0de5SThomas Veerman 	set_refuse_mount_name(&argv0, name, sizeof(name));
1343490e0de5SThomas Veerman 
1344490e0de5SThomas Veerman 	puffs_fakecc = 1; /* XXX */
1345490e0de5SThomas Veerman 	pu = puffs_init(pops, _PATH_PUFFS, name, fuse,
1346490e0de5SThomas Veerman 			 PUFFS_FLAG_BUILDPATH
1347490e0de5SThomas Veerman 			   | PUFFS_FLAG_HASHPATH
1348490e0de5SThomas Veerman 			   | PUFFS_KFLAG_NOCACHE);
1349490e0de5SThomas Veerman 	if (pu == NULL) {
1350490e0de5SThomas Veerman 		err(EXIT_FAILURE, "puffs_init");
1351490e0de5SThomas Veerman 	}
1352490e0de5SThomas Veerman 	fc->pu = pu;
1353490e0de5SThomas Veerman 
1354490e0de5SThomas Veerman 	pn_root = newrn(pu);
1355490e0de5SThomas Veerman 	puffs_setroot(pu, pn_root);
1356490e0de5SThomas Veerman 	rn_root = pn_root->pn_data;
1357490e0de5SThomas Veerman 	rn_root->flags |= RN_ROOT;
1358490e0de5SThomas Veerman 
1359490e0de5SThomas Veerman 	po_root = puffs_getrootpathobj(pu);
1360490e0de5SThomas Veerman 	if ((po_root->po_path = strdup("/")) == NULL)
1361490e0de5SThomas Veerman 		err(1, "fuse_new");
1362490e0de5SThomas Veerman 	po_root->po_len = 1;
1363490e0de5SThomas Veerman 	puffs_path_buildhash(pu, po_root);
1364490e0de5SThomas Veerman 
1365490e0de5SThomas Veerman 	/* sane defaults */
1366490e0de5SThomas Veerman 	puffs_vattr_null(&pn_root->pn_va);
1367490e0de5SThomas Veerman 	pn_root->pn_va.va_type = VDIR;
1368490e0de5SThomas Veerman 	pn_root->pn_va.va_mode = 0755;
1369490e0de5SThomas Veerman 	if (fuse->op.getattr)
1370490e0de5SThomas Veerman 		if (fuse->op.getattr(po_root->po_path, &st) == 0)
1371490e0de5SThomas Veerman 			puffs_stat2vattr(&pn_root->pn_va, &st);
1372490e0de5SThomas Veerman 	assert(pn_root->pn_va.va_type == VDIR);
1373490e0de5SThomas Veerman 
1374490e0de5SThomas Veerman 	puffs_set_prepost(pu, set_fuse_context_pid, NULL);
1375490e0de5SThomas Veerman 
1376490e0de5SThomas Veerman 	puffs_zerostatvfs(&svfsb);
1377490e0de5SThomas Veerman 	if (puffs_mount(pu, fc->dir, MNT_NODEV | MNT_NOSUID, pn_root) == -1) {
1378490e0de5SThomas Veerman 		err(EXIT_FAILURE, "puffs_mount: directory \"%s\"", fc->dir);
1379490e0de5SThomas Veerman 	}
1380490e0de5SThomas Veerman 
1381490e0de5SThomas Veerman 	return fuse;
1382490e0de5SThomas Veerman }
1383490e0de5SThomas Veerman 
1384490e0de5SThomas Veerman int
fuse_loop(struct fuse * fuse)1385490e0de5SThomas Veerman fuse_loop(struct fuse *fuse)
1386490e0de5SThomas Veerman {
1387490e0de5SThomas Veerman 
1388490e0de5SThomas Veerman 	return puffs_mainloop(fuse->fc->pu);
1389490e0de5SThomas Veerman }
1390490e0de5SThomas Veerman 
1391490e0de5SThomas Veerman void
fuse_destroy(struct fuse * fuse)1392490e0de5SThomas Veerman fuse_destroy(struct fuse *fuse)
1393490e0de5SThomas Veerman {
1394490e0de5SThomas Veerman 
1395490e0de5SThomas Veerman 	/*
1396490e0de5SThomas Veerman 	 * TODO: needs to assert the fs is quiescent, i.e. no other
1397490e0de5SThomas Veerman 	 * threads exist
1398490e0de5SThomas Veerman 	 */
1399490e0de5SThomas Veerman 
1400490e0de5SThomas Veerman 	delete_context_key();
1401490e0de5SThomas Veerman 	/* XXXXXX: missing stuff */
1402490e0de5SThomas Veerman 	free(fuse);
1403490e0de5SThomas Veerman }
1404490e0de5SThomas Veerman 
1405490e0de5SThomas Veerman void
fuse_exit(struct fuse * fuse)1406490e0de5SThomas Veerman fuse_exit(struct fuse *fuse)
1407490e0de5SThomas Veerman {
1408490e0de5SThomas Veerman 
1409490e0de5SThomas Veerman 	/* XXX: puffs_exit() is WRONG */
1410490e0de5SThomas Veerman 	if (fuse->fc->dead == 0)
1411490e0de5SThomas Veerman 		puffs_exit(fuse->fc->pu, 1);
1412490e0de5SThomas Veerman 	fuse->fc->dead = 1;
1413490e0de5SThomas Veerman }
1414490e0de5SThomas Veerman 
1415490e0de5SThomas Veerman /*
1416490e0de5SThomas Veerman  * XXX: obviously not the most perfect of functions, but needs some
1417490e0de5SThomas Veerman  * puffs tweaking for a better tomorrow
1418490e0de5SThomas Veerman  */
1419490e0de5SThomas Veerman /*ARGSUSED*/
1420490e0de5SThomas Veerman void
fuse_unmount(const char * mp,struct fuse_chan * fc)1421490e0de5SThomas Veerman fuse_unmount(const char *mp, struct fuse_chan *fc)
1422490e0de5SThomas Veerman {
1423490e0de5SThomas Veerman 
1424490e0de5SThomas Veerman 	/* XXX: puffs_exit() is WRONG */
1425490e0de5SThomas Veerman 	if (fc->dead == 0)
1426490e0de5SThomas Veerman 		puffs_exit(fc->pu, 1);
1427490e0de5SThomas Veerman 	fc->dead = 1;
1428490e0de5SThomas Veerman }
1429490e0de5SThomas Veerman 
1430490e0de5SThomas Veerman /*ARGSUSED*/
1431490e0de5SThomas Veerman void
fuse_unmount_compat22(const char * mp)1432490e0de5SThomas Veerman fuse_unmount_compat22(const char *mp)
1433490e0de5SThomas Veerman {
1434490e0de5SThomas Veerman 
1435490e0de5SThomas Veerman 	return;
1436490e0de5SThomas Veerman }
1437490e0de5SThomas Veerman 
1438490e0de5SThomas Veerman /* The next function "exposes" struct fuse to userland.  Not much
1439490e0de5SThomas Veerman * that we can do about this, as we're conforming to a defined
1440490e0de5SThomas Veerman * interface.  */
1441490e0de5SThomas Veerman 
1442490e0de5SThomas Veerman void
fuse_teardown(struct fuse * fuse,char * mountpoint)1443490e0de5SThomas Veerman fuse_teardown(struct fuse *fuse, char *mountpoint)
1444490e0de5SThomas Veerman {
1445490e0de5SThomas Veerman 	fuse_unmount(mountpoint, fuse->fc);
1446490e0de5SThomas Veerman 	fuse_destroy(fuse);
1447490e0de5SThomas Veerman }
1448