refuse.c revision 1.114 1 1.114 pho /* $NetBSD: refuse.c,v 1.114 2022/01/22 08:09:39 pho Exp $ */
2 1.7 pooka
3 1.1 agc /*
4 1.1 agc * Copyright 2007 Alistair Crooks. All rights reserved.
5 1.83 pooka * Copyright 2007 Antti Kantee. All rights reserved.
6 1.1 agc *
7 1.1 agc * Redistribution and use in source and binary forms, with or without
8 1.1 agc * modification, are permitted provided that the following conditions
9 1.1 agc * are met:
10 1.1 agc * 1. Redistributions of source code must retain the above copyright
11 1.1 agc * notice, this list of conditions and the following disclaimer.
12 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 agc * notice, this list of conditions and the following disclaimer in the
14 1.1 agc * documentation and/or other materials provided with the distribution.
15 1.1 agc * 3. The name of the author may not be used to endorse or promote
16 1.1 agc * products derived from this software without specific prior written
17 1.1 agc * permission.
18 1.1 agc *
19 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 1.1 agc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 1.1 agc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 1.1 agc * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 1.1 agc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 1.1 agc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 1.1 agc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 1.1 agc * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 1.1 agc */
31 1.7 pooka
32 1.7 pooka #include <sys/cdefs.h>
33 1.7 pooka #if !defined(lint)
34 1.114 pho __RCSID("$NetBSD: refuse.c,v 1.114 2022/01/22 08:09:39 pho Exp $");
35 1.7 pooka #endif /* !lint */
36 1.7 pooka
37 1.81 pooka #include <sys/types.h>
38 1.81 pooka
39 1.25 pooka #include <assert.h>
40 1.1 agc #include <err.h>
41 1.1 agc #include <errno.h>
42 1.103 pho #include <fuse_internal.h>
43 1.98 pho #include <fuse_opt.h>
44 1.72 pooka #include <paths.h>
45 1.104 pho #include <puffs.h>
46 1.104 pho #include <stdbool.h>
47 1.98 pho #include <stddef.h>
48 1.81 pooka #include <stdio.h>
49 1.81 pooka #include <stdlib.h>
50 1.81 pooka #include <string.h>
51 1.78 pooka #include <unistd.h>
52 1.78 pooka #ifdef MULTITHREADED_REFUSE
53 1.77 pooka #include <pthread.h>
54 1.78 pooka #endif
55 1.1 agc
56 1.1 agc typedef uint64_t fuse_ino_t;
57 1.1 agc
58 1.98 pho struct refuse_config {
59 1.98 pho int debug;
60 1.98 pho char *fsname;
61 1.1 agc };
62 1.1 agc
63 1.98 pho #define REFUSE_OPT(t, p, v) \
64 1.98 pho { t, offsetof(struct refuse_config, p), v }
65 1.98 pho
66 1.98 pho static struct fuse_opt refuse_opts[] = {
67 1.98 pho REFUSE_OPT("debug" , debug , 1),
68 1.98 pho REFUSE_OPT("fsname=%s", fsname, 0),
69 1.98 pho FUSE_OPT_END
70 1.38 pooka };
71 1.38 pooka
72 1.36 pooka struct puffs_fuse_dirh {
73 1.43 agc void *dbuf;
74 1.43 agc struct dirent *d;
75 1.43 agc
76 1.43 agc size_t reslen;
77 1.43 agc size_t bufsize;
78 1.36 pooka };
79 1.36 pooka
80 1.43 agc struct refusenode {
81 1.43 agc struct fuse_file_info file_info;
82 1.43 agc struct puffs_fuse_dirh dirh;
83 1.43 agc int opencount;
84 1.43 agc int flags;
85 1.43 agc };
86 1.30 pooka #define RN_ROOT 0x01
87 1.31 pooka #define RN_OPEN 0x02 /* XXX: could just use opencount */
88 1.5 pooka
89 1.43 agc static int fuse_setattr(struct fuse *, struct puffs_node *,
90 1.43 agc const char *, const struct vattr *);
91 1.26 pooka
92 1.5 pooka static struct puffs_node *
93 1.5 pooka newrn(struct puffs_usermount *pu)
94 1.5 pooka {
95 1.5 pooka struct puffs_node *pn;
96 1.5 pooka struct refusenode *rn;
97 1.5 pooka
98 1.62 agc if ((rn = calloc(1, sizeof(*rn))) == NULL) {
99 1.62 agc err(EXIT_FAILURE, "newrn");
100 1.62 agc }
101 1.5 pooka pn = puffs_pn_new(pu, rn);
102 1.5 pooka
103 1.5 pooka return pn;
104 1.5 pooka }
105 1.5 pooka
106 1.5 pooka static void
107 1.5 pooka nukern(struct puffs_node *pn)
108 1.5 pooka {
109 1.36 pooka struct refusenode *rn = pn->pn_data;
110 1.5 pooka
111 1.36 pooka free(rn->dirh.dbuf);
112 1.36 pooka free(rn);
113 1.5 pooka puffs_pn_put(pn);
114 1.5 pooka }
115 1.5 pooka
116 1.66 agc /* XXX - not threadsafe */
117 1.1 agc static ino_t fakeino = 3;
118 1.1 agc
119 1.66 agc /***************** start of pthread context routines ************************/
120 1.66 agc
121 1.21 pooka /*
122 1.66 agc * Notes on fuse_context:
123 1.66 agc * we follow fuse's lead and use the pthread specific information to hold
124 1.66 agc * a reference to the fuse_context structure for this thread.
125 1.21 pooka */
126 1.78 pooka #ifdef MULTITHREADED_REFUSE
127 1.66 agc static pthread_mutex_t context_mutex = PTHREAD_MUTEX_INITIALIZER;
128 1.66 agc static pthread_key_t context_key;
129 1.80 pooka static unsigned long context_refc;
130 1.78 pooka #endif
131 1.66 agc
132 1.66 agc /* return the fuse_context struct related to this thread */
133 1.66 agc struct fuse_context *
134 1.66 agc fuse_get_context(void)
135 1.66 agc {
136 1.78 pooka #ifdef MULTITHREADED_REFUSE
137 1.66 agc struct fuse_context *ctxt;
138 1.66 agc
139 1.66 agc if ((ctxt = pthread_getspecific(context_key)) == NULL) {
140 1.66 agc if ((ctxt = calloc(1, sizeof(struct fuse_context))) == NULL) {
141 1.80 pooka abort();
142 1.66 agc }
143 1.66 agc pthread_setspecific(context_key, ctxt);
144 1.66 agc }
145 1.66 agc return ctxt;
146 1.78 pooka #else
147 1.78 pooka static struct fuse_context fcon;
148 1.78 pooka
149 1.78 pooka return &fcon;
150 1.78 pooka #endif
151 1.66 agc }
152 1.66 agc
153 1.66 agc /* used as a callback function */
154 1.78 pooka #ifdef MULTITHREADED_REFUSE
155 1.66 agc static void
156 1.66 agc free_context(void *ctxt)
157 1.66 agc {
158 1.66 agc free(ctxt);
159 1.66 agc }
160 1.78 pooka #endif
161 1.66 agc
162 1.80 pooka /*
163 1.80 pooka * Create the pthread key. The reason for the complexity is to
164 1.80 pooka * enable use of multiple fuse instances within a single process.
165 1.80 pooka */
166 1.66 agc static int
167 1.66 agc create_context_key(void)
168 1.66 agc {
169 1.78 pooka #ifdef MULTITHREADED_REFUSE
170 1.80 pooka int rv;
171 1.80 pooka
172 1.80 pooka rv = pthread_mutex_lock(&context_mutex);
173 1.80 pooka assert(rv == 0);
174 1.80 pooka
175 1.80 pooka if (context_refc == 0) {
176 1.66 agc if (pthread_key_create(&context_key, free_context) != 0) {
177 1.66 agc warnx("create_context_key: pthread_key_create failed");
178 1.66 agc pthread_mutex_unlock(&context_mutex);
179 1.66 agc return 0;
180 1.66 agc }
181 1.66 agc }
182 1.66 agc context_refc += 1;
183 1.66 agc pthread_mutex_unlock(&context_mutex);
184 1.66 agc return 1;
185 1.78 pooka #else
186 1.78 pooka return 1;
187 1.78 pooka #endif
188 1.66 agc }
189 1.66 agc
190 1.113 pho /* struct fuse_context is potentially reused among different
191 1.113 pho * invocations of fuse_new() / fuse_destroy() pair. Clear its content
192 1.113 pho * on fuse_destroy() so that no dangling pointers remain in the
193 1.113 pho * context. */
194 1.113 pho static void
195 1.113 pho clear_context(void)
196 1.113 pho {
197 1.113 pho struct fuse_context *ctx;
198 1.113 pho
199 1.113 pho ctx = fuse_get_context();
200 1.113 pho memset(ctx, 0, sizeof(*ctx));
201 1.113 pho }
202 1.113 pho
203 1.66 agc static void
204 1.66 agc delete_context_key(void)
205 1.66 agc {
206 1.78 pooka #ifdef MULTITHREADED_REFUSE
207 1.66 agc pthread_mutex_lock(&context_mutex);
208 1.80 pooka /* If we are the last fuse instances using the key, delete it */
209 1.66 agc if (--context_refc == 0) {
210 1.66 agc free(pthread_getspecific(context_key));
211 1.66 agc pthread_key_delete(context_key);
212 1.66 agc }
213 1.66 agc pthread_mutex_unlock(&context_mutex);
214 1.78 pooka #endif
215 1.66 agc }
216 1.66 agc
217 1.66 agc /* set the uid and gid of the calling process in the current fuse context */
218 1.66 agc static void
219 1.66 agc set_fuse_context_uid_gid(const struct puffs_cred *cred)
220 1.66 agc {
221 1.66 agc struct fuse_context *fusectx;
222 1.66 agc uid_t uid;
223 1.66 agc gid_t gid;
224 1.66 agc
225 1.66 agc fusectx = fuse_get_context();
226 1.66 agc if (puffs_cred_getuid(cred, &uid) == 0) {
227 1.66 agc fusectx->uid = uid;
228 1.66 agc }
229 1.66 agc if (puffs_cred_getgid(cred, &gid) == 0) {
230 1.66 agc fusectx->gid = gid;
231 1.66 agc }
232 1.66 agc }
233 1.66 agc
234 1.66 agc /* set the pid of the calling process in the current fuse context */
235 1.66 agc static void
236 1.85 pooka set_fuse_context_pid(struct puffs_usermount *pu)
237 1.66 agc {
238 1.85 pooka struct puffs_cc *pcc = puffs_cc_getcc(pu);
239 1.66 agc struct fuse_context *fusectx;
240 1.21 pooka
241 1.66 agc fusectx = fuse_get_context();
242 1.76 pooka puffs_cc_getcaller(pcc, &fusectx->pid, NULL);
243 1.66 agc }
244 1.66 agc
245 1.66 agc /***************** end of pthread context routines ************************/
246 1.62 agc
247 1.36 pooka #define DIR_CHUNKSIZE 4096
248 1.36 pooka static int
249 1.36 pooka fill_dirbuf(struct puffs_fuse_dirh *dh, const char *name, ino_t dino,
250 1.36 pooka uint8_t dtype)
251 1.36 pooka {
252 1.36 pooka
253 1.36 pooka /* initial? */
254 1.36 pooka if (dh->bufsize == 0) {
255 1.65 agc if ((dh->dbuf = calloc(1, DIR_CHUNKSIZE)) == NULL) {
256 1.80 pooka abort();
257 1.62 agc }
258 1.36 pooka dh->d = dh->dbuf;
259 1.36 pooka dh->reslen = dh->bufsize = DIR_CHUNKSIZE;
260 1.36 pooka }
261 1.21 pooka
262 1.62 agc if (puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen)) {
263 1.36 pooka return 0;
264 1.62 agc }
265 1.36 pooka
266 1.36 pooka /* try to increase buffer space */
267 1.36 pooka dh->dbuf = realloc(dh->dbuf, dh->bufsize + DIR_CHUNKSIZE);
268 1.62 agc if (dh->dbuf == NULL) {
269 1.80 pooka abort();
270 1.62 agc }
271 1.36 pooka dh->d = (void *)((uint8_t *)dh->dbuf + (dh->bufsize - dh->reslen));
272 1.36 pooka dh->reslen += DIR_CHUNKSIZE;
273 1.36 pooka dh->bufsize += DIR_CHUNKSIZE;
274 1.36 pooka
275 1.36 pooka return !puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen);
276 1.36 pooka }
277 1.1 agc
278 1.36 pooka /* ARGSUSED3 */
279 1.36 pooka /* XXX: I have no idea how "off" is supposed to be used */
280 1.1 agc static int
281 1.4 pooka puffs_fuse_fill_dir(void *buf, const char *name,
282 1.114 pho const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
283 1.1 agc {
284 1.36 pooka struct puffs_fuse_dirh *deh = buf;
285 1.13 pooka ino_t dino;
286 1.1 agc uint8_t dtype;
287 1.1 agc
288 1.13 pooka if (stbuf == NULL) {
289 1.13 pooka dtype = DT_UNKNOWN;
290 1.13 pooka dino = fakeino++;
291 1.13 pooka } else {
292 1.106 pho dtype = (uint8_t)puffs_vtype2dt(puffs_mode2vt(stbuf->st_mode));
293 1.13 pooka dino = stbuf->st_ino;
294 1.50 pooka
295 1.50 pooka /*
296 1.50 pooka * Some FUSE file systems like to always use 0 as the
297 1.50 pooka * inode number. Our readdir() doesn't like to show
298 1.50 pooka * directory entries with inode number 0 ==> workaround.
299 1.50 pooka */
300 1.62 agc if (dino == 0) {
301 1.50 pooka dino = fakeino++;
302 1.62 agc }
303 1.13 pooka }
304 1.1 agc
305 1.36 pooka return fill_dirbuf(deh, name, dino, dtype);
306 1.4 pooka }
307 1.4 pooka
308 1.26 pooka /* ARGSUSED1 */
309 1.26 pooka static int
310 1.26 pooka fuse_getattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
311 1.26 pooka struct vattr *va)
312 1.26 pooka {
313 1.114 pho struct refusenode *rn = pn->pn_data;
314 1.114 pho struct fuse_file_info *fi = rn->opencount > 0 ? &rn->file_info : NULL;
315 1.26 pooka struct stat st;
316 1.26 pooka int ret;
317 1.26 pooka
318 1.26 pooka /* wrap up return code */
319 1.74 pooka memset(&st, 0, sizeof(st));
320 1.114 pho ret = fuse_fs_getattr_v30(fuse->fs, path, &st, fi);
321 1.26 pooka
322 1.26 pooka if (ret == 0) {
323 1.74 pooka if (st.st_blksize == 0)
324 1.74 pooka st.st_blksize = DEV_BSIZE;
325 1.26 pooka puffs_stat2vattr(va, &st);
326 1.26 pooka }
327 1.26 pooka
328 1.26 pooka return -ret;
329 1.26 pooka }
330 1.26 pooka
331 1.66 agc /* utility function to set various elements of the attribute */
332 1.26 pooka static int
333 1.26 pooka fuse_setattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
334 1.26 pooka const struct vattr *va)
335 1.26 pooka {
336 1.26 pooka struct refusenode *rn = pn->pn_data;
337 1.114 pho struct fuse_file_info *fi = rn->opencount > 0 ? &rn->file_info : NULL;
338 1.26 pooka mode_t mode;
339 1.26 pooka uid_t uid;
340 1.26 pooka gid_t gid;
341 1.26 pooka int error, ret;
342 1.26 pooka
343 1.26 pooka error = 0;
344 1.26 pooka
345 1.26 pooka mode = va->va_mode;
346 1.26 pooka uid = va->va_uid;
347 1.26 pooka gid = va->va_gid;
348 1.26 pooka
349 1.26 pooka if (mode != (mode_t)PUFFS_VNOVAL) {
350 1.114 pho ret = fuse_fs_chmod_v30(fuse->fs, path, mode, fi);
351 1.114 pho if (ret)
352 1.114 pho error = ret;
353 1.26 pooka }
354 1.26 pooka if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
355 1.114 pho ret = fuse_fs_chown_v30(fuse->fs, path, uid, gid, fi);
356 1.114 pho if (ret)
357 1.114 pho error = ret;
358 1.26 pooka }
359 1.26 pooka if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
360 1.114 pho || va->va_mtime.tv_sec != (long)PUFFS_VNOVAL) {
361 1.26 pooka
362 1.114 pho struct timespec tv[2];
363 1.26 pooka
364 1.114 pho tv[0].tv_sec = va->va_atime.tv_sec;
365 1.114 pho tv[0].tv_nsec = va->va_atime.tv_nsec;
366 1.114 pho tv[1].tv_sec = va->va_mtime.tv_sec;
367 1.114 pho tv[1].tv_nsec = va->va_mtime.tv_nsec;
368 1.26 pooka
369 1.114 pho ret = fuse_fs_utimens_v30(fuse->fs, path, tv, fi);
370 1.26 pooka if (ret)
371 1.26 pooka error = ret;
372 1.26 pooka }
373 1.26 pooka if (va->va_size != (u_quad_t)PUFFS_VNOVAL) {
374 1.114 pho ret = fuse_fs_truncate_v30(fuse->fs, path, (off_t)va->va_size, fi);
375 1.26 pooka if (ret)
376 1.26 pooka error = ret;
377 1.26 pooka }
378 1.26 pooka /* XXX: no reflection with reality */
379 1.26 pooka puffs_setvattr(&pn->pn_va, va);
380 1.26 pooka
381 1.26 pooka return -error;
382 1.26 pooka
383 1.26 pooka }
384 1.26 pooka
385 1.26 pooka static int
386 1.26 pooka fuse_newnode(struct puffs_usermount *pu, const char *path,
387 1.71 pooka const struct vattr *va, struct fuse_file_info *fi,
388 1.71 pooka struct puffs_newinfo *pni, struct puffs_node **pn_new)
389 1.26 pooka {
390 1.26 pooka struct puffs_node *pn;
391 1.26 pooka struct refusenode *rn;
392 1.66 agc struct vattr newva;
393 1.66 agc struct fuse *fuse;
394 1.26 pooka
395 1.46 pooka fuse = puffs_getspecific(pu);
396 1.26 pooka
397 1.26 pooka /* fix up nodes */
398 1.26 pooka pn = newrn(pu);
399 1.26 pooka if (pn == NULL) {
400 1.26 pooka if (va->va_type == VDIR) {
401 1.114 pho fuse_fs_rmdir(fuse->fs, path);
402 1.26 pooka } else {
403 1.114 pho fuse_fs_unlink(fuse->fs, path);
404 1.26 pooka }
405 1.26 pooka return ENOMEM;
406 1.26 pooka }
407 1.26 pooka fuse_setattr(fuse, pn, path, va);
408 1.26 pooka if (fuse_getattr(fuse, pn, path, &newva) == 0)
409 1.26 pooka puffs_setvattr(&pn->pn_va, &newva);
410 1.26 pooka
411 1.26 pooka rn = pn->pn_data;
412 1.26 pooka if (fi)
413 1.26 pooka memcpy(&rn->file_info, fi, sizeof(struct fuse_file_info));
414 1.26 pooka
415 1.71 pooka puffs_newinfo_setcookie(pni, pn);
416 1.71 pooka if (pn_new)
417 1.71 pooka *pn_new = pn;
418 1.26 pooka
419 1.26 pooka return 0;
420 1.26 pooka }
421 1.26 pooka
422 1.26 pooka
423 1.1 agc /* operation wrappers start here */
424 1.1 agc
425 1.1 agc /* lookup the path */
426 1.1 agc /* ARGSUSED1 */
427 1.1 agc static int
428 1.85 pooka puffs_fuse_node_lookup(struct puffs_usermount *pu, void *opc,
429 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn)
430 1.1 agc {
431 1.12 pooka struct puffs_node *pn_res;
432 1.66 agc struct stat st;
433 1.1 agc struct fuse *fuse;
434 1.1 agc const char *path = PCNPATH(pcn);
435 1.66 agc int ret;
436 1.1 agc
437 1.46 pooka fuse = puffs_getspecific(pu);
438 1.62 agc
439 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred);
440 1.62 agc
441 1.114 pho ret = fuse_fs_getattr_v30(fuse->fs, path, &st, NULL);
442 1.1 agc if (ret != 0) {
443 1.18 pooka return -ret;
444 1.12 pooka }
445 1.12 pooka
446 1.12 pooka /* XXX: fiXXXme unconst */
447 1.12 pooka pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
448 1.12 pooka __UNCONST(&pcn->pcn_po_full));
449 1.12 pooka if (pn_res == NULL) {
450 1.12 pooka pn_res = newrn(pu);
451 1.12 pooka if (pn_res == NULL)
452 1.12 pooka return errno;
453 1.26 pooka puffs_stat2vattr(&pn_res->pn_va, &st);
454 1.1 agc }
455 1.12 pooka
456 1.71 pooka puffs_newinfo_setcookie(pni, pn_res);
457 1.71 pooka puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
458 1.71 pooka puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
459 1.71 pooka puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
460 1.12 pooka
461 1.12 pooka return 0;
462 1.1 agc }
463 1.1 agc
464 1.1 agc /* get attributes for the path name */
465 1.1 agc /* ARGSUSED3 */
466 1.1 agc static int
467 1.85 pooka puffs_fuse_node_getattr(struct puffs_usermount *pu, void *opc, struct vattr *va,
468 1.84 pooka const struct puffs_cred *pcr)
469 1.1 agc {
470 1.1 agc struct puffs_node *pn = opc;
471 1.1 agc struct fuse *fuse;
472 1.1 agc const char *path = PNPATH(pn);
473 1.1 agc
474 1.46 pooka fuse = puffs_getspecific(pu);
475 1.62 agc
476 1.66 agc set_fuse_context_uid_gid(pcr);
477 1.62 agc
478 1.26 pooka return fuse_getattr(fuse, pn, path, va);
479 1.1 agc }
480 1.1 agc
481 1.1 agc /* read the contents of the symbolic link */
482 1.1 agc /* ARGSUSED2 */
483 1.1 agc static int
484 1.85 pooka puffs_fuse_node_readlink(struct puffs_usermount *pu, void *opc,
485 1.1 agc const struct puffs_cred *cred, char *linkname, size_t *linklen)
486 1.1 agc {
487 1.1 agc struct puffs_node *pn = opc;
488 1.1 agc struct fuse *fuse;
489 1.13 pooka const char *path = PNPATH(pn), *p;
490 1.1 agc int ret;
491 1.1 agc
492 1.46 pooka fuse = puffs_getspecific(pu);
493 1.1 agc
494 1.66 agc set_fuse_context_uid_gid(cred);
495 1.62 agc
496 1.1 agc /* wrap up return code */
497 1.114 pho ret = fuse_fs_readlink(fuse->fs, path, linkname, *linklen);
498 1.1 agc
499 1.1 agc if (ret == 0) {
500 1.43 agc p = memchr(linkname, '\0', *linklen);
501 1.13 pooka if (!p)
502 1.13 pooka return EINVAL;
503 1.13 pooka
504 1.106 pho *linklen = (size_t)(p - linkname);
505 1.1 agc }
506 1.1 agc
507 1.13 pooka return -ret;
508 1.1 agc }
509 1.1 agc
510 1.1 agc /* make the special node */
511 1.1 agc /* ARGSUSED1 */
512 1.1 agc static int
513 1.85 pooka puffs_fuse_node_mknod(struct puffs_usermount *pu, void *opc,
514 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn,
515 1.71 pooka const struct vattr *va)
516 1.1 agc {
517 1.1 agc struct fuse *fuse;
518 1.44 pooka mode_t mode;
519 1.1 agc const char *path = PCNPATH(pcn);
520 1.1 agc int ret;
521 1.1 agc
522 1.46 pooka fuse = puffs_getspecific(pu);
523 1.1 agc
524 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred);
525 1.62 agc
526 1.1 agc /* wrap up return code */
527 1.44 pooka mode = puffs_addvtype2mode(va->va_mode, va->va_type);
528 1.114 pho ret = fuse_fs_mknod(fuse->fs, path, mode, va->va_rdev);
529 1.1 agc
530 1.1 agc if (ret == 0) {
531 1.71 pooka ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
532 1.1 agc }
533 1.1 agc
534 1.18 pooka return -ret;
535 1.1 agc }
536 1.1 agc
537 1.1 agc /* make a directory */
538 1.1 agc /* ARGSUSED1 */
539 1.1 agc static int
540 1.85 pooka puffs_fuse_node_mkdir(struct puffs_usermount *pu, void *opc,
541 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn,
542 1.71 pooka const struct vattr *va)
543 1.1 agc {
544 1.1 agc struct fuse *fuse;
545 1.1 agc mode_t mode = va->va_mode;
546 1.1 agc const char *path = PCNPATH(pcn);
547 1.1 agc int ret;
548 1.1 agc
549 1.46 pooka fuse = puffs_getspecific(pu);
550 1.62 agc
551 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred);
552 1.62 agc
553 1.1 agc /* wrap up return code */
554 1.114 pho ret = fuse_fs_mkdir(fuse->fs, path, mode);
555 1.1 agc
556 1.1 agc if (ret == 0) {
557 1.71 pooka ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
558 1.1 agc }
559 1.1 agc
560 1.18 pooka return -ret;
561 1.1 agc }
562 1.1 agc
563 1.21 pooka /*
564 1.21 pooka * create a regular file
565 1.21 pooka *
566 1.21 pooka * since linux/fuse sports using mknod for creating regular files
567 1.21 pooka * instead of having a separate call for it in some versions, if
568 1.21 pooka * we don't have create, just jump to op->mknod.
569 1.21 pooka */
570 1.16 pooka /*ARGSUSED1*/
571 1.16 pooka static int
572 1.85 pooka puffs_fuse_node_create(struct puffs_usermount *pu, void *opc,
573 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn,
574 1.71 pooka const struct vattr *va)
575 1.16 pooka {
576 1.16 pooka struct fuse *fuse;
577 1.16 pooka struct fuse_file_info fi;
578 1.71 pooka struct puffs_node *pn;
579 1.16 pooka mode_t mode = va->va_mode;
580 1.16 pooka const char *path = PCNPATH(pcn);
581 1.31 pooka int ret, created;
582 1.16 pooka
583 1.46 pooka fuse = puffs_getspecific(pu);
584 1.21 pooka
585 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred);
586 1.62 agc
587 1.97 pho memset(&fi, 0, sizeof(fi));
588 1.114 pho /* In puffs "create" and "open" are two separate operations
589 1.114 pho * with atomicity achieved by locking the parent vnode. In
590 1.114 pho * fuse, on the other hand, "create" is actually a
591 1.114 pho * create-and-open-atomically and the open flags (O_RDWR,
592 1.114 pho * O_APPEND, ...) are passed via fi.flags. So the only way to
593 1.114 pho * emulate the fuse semantics is to open the file with dummy
594 1.114 pho * flags and then immediately close it.
595 1.114 pho *
596 1.114 pho * You might think that we could simply use fuse->op.mknod all
597 1.114 pho * the time but no, that's not possible because most file
598 1.114 pho * systems nowadays expect op.mknod to be called only for
599 1.114 pho * non-regular files and many don't even support it. */
600 1.31 pooka created = 0;
601 1.114 pho fi.flags = O_WRONLY | O_CREAT | O_EXCL;
602 1.114 pho ret = fuse_fs_create(fuse->fs, path, mode | S_IFREG, &fi);
603 1.114 pho if (ret == 0) {
604 1.114 pho created = 1;
605 1.114 pho }
606 1.114 pho else if (ret == -ENOSYS) {
607 1.114 pho ret = fuse_fs_mknod(fuse->fs, path, mode | S_IFREG, 0);
608 1.16 pooka }
609 1.16 pooka
610 1.16 pooka if (ret == 0) {
611 1.71 pooka ret = fuse_newnode(pu, path, va, &fi, pni, &pn);
612 1.31 pooka
613 1.31 pooka /* sweet.. create also open the file */
614 1.114 pho if (created) {
615 1.97 pho struct refusenode *rn = pn->pn_data;
616 1.97 pho /* The return value of op.release is expected to be
617 1.97 pho * discarded. */
618 1.114 pho (void)fuse_fs_release(fuse->fs, path, &rn->file_info);
619 1.31 pooka }
620 1.16 pooka }
621 1.16 pooka
622 1.18 pooka return -ret;
623 1.16 pooka }
624 1.16 pooka
625 1.1 agc /* remove the directory entry */
626 1.23 pooka /* ARGSUSED1 */
627 1.1 agc static int
628 1.85 pooka puffs_fuse_node_remove(struct puffs_usermount *pu, void *opc, void *targ,
629 1.1 agc const struct puffs_cn *pcn)
630 1.1 agc {
631 1.23 pooka struct puffs_node *pn_targ = targ;
632 1.1 agc struct fuse *fuse;
633 1.23 pooka const char *path = PNPATH(pn_targ);
634 1.1 agc int ret;
635 1.1 agc
636 1.46 pooka fuse = puffs_getspecific(pu);
637 1.62 agc
638 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred);
639 1.62 agc
640 1.1 agc /* wrap up return code */
641 1.114 pho ret = fuse_fs_unlink(fuse->fs, path);
642 1.1 agc
643 1.18 pooka return -ret;
644 1.1 agc }
645 1.1 agc
646 1.1 agc /* remove the directory */
647 1.1 agc /* ARGSUSED1 */
648 1.1 agc static int
649 1.85 pooka puffs_fuse_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ,
650 1.1 agc const struct puffs_cn *pcn)
651 1.1 agc {
652 1.23 pooka struct puffs_node *pn_targ = targ;
653 1.1 agc struct fuse *fuse;
654 1.23 pooka const char *path = PNPATH(pn_targ);
655 1.1 agc int ret;
656 1.1 agc
657 1.46 pooka fuse = puffs_getspecific(pu);
658 1.62 agc
659 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred);
660 1.62 agc
661 1.1 agc /* wrap up return code */
662 1.114 pho ret = fuse_fs_rmdir(fuse->fs, path);
663 1.1 agc
664 1.18 pooka return -ret;
665 1.1 agc }
666 1.1 agc
667 1.1 agc /* create a symbolic link */
668 1.1 agc /* ARGSUSED1 */
669 1.1 agc static int
670 1.85 pooka puffs_fuse_node_symlink(struct puffs_usermount *pu, void *opc,
671 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn_src,
672 1.71 pooka const struct vattr *va, const char *link_target)
673 1.1 agc {
674 1.1 agc struct fuse *fuse;
675 1.1 agc const char *path = PCNPATH(pcn_src);
676 1.1 agc int ret;
677 1.1 agc
678 1.46 pooka fuse = puffs_getspecific(pu);
679 1.62 agc
680 1.69 pooka set_fuse_context_uid_gid(pcn_src->pcn_cred);
681 1.62 agc
682 1.1 agc /* wrap up return code */
683 1.114 pho ret = fuse_fs_symlink(fuse->fs, link_target, path);
684 1.1 agc
685 1.1 agc if (ret == 0) {
686 1.71 pooka ret = fuse_newnode(pu, path, va, NULL, pni, NULL);
687 1.1 agc }
688 1.1 agc
689 1.18 pooka return -ret;
690 1.1 agc }
691 1.1 agc
692 1.1 agc /* rename a directory entry */
693 1.1 agc /* ARGSUSED1 */
694 1.1 agc static int
695 1.85 pooka puffs_fuse_node_rename(struct puffs_usermount *pu, void *opc, void *src,
696 1.1 agc const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
697 1.1 agc const struct puffs_cn *pcn_targ)
698 1.1 agc {
699 1.1 agc struct fuse *fuse;
700 1.24 pooka const char *path_src = PCNPATH(pcn_src);
701 1.24 pooka const char *path_dest = PCNPATH(pcn_targ);
702 1.1 agc int ret;
703 1.1 agc
704 1.46 pooka fuse = puffs_getspecific(pu);
705 1.62 agc
706 1.69 pooka set_fuse_context_uid_gid(pcn_targ->pcn_cred);
707 1.62 agc
708 1.114 pho ret = fuse_fs_rename_v30(fuse->fs, path_src, path_dest, 0);
709 1.1 agc
710 1.18 pooka return -ret;
711 1.1 agc }
712 1.1 agc
713 1.1 agc /* create a link in the file system */
714 1.1 agc /* ARGSUSED1 */
715 1.1 agc static int
716 1.85 pooka puffs_fuse_node_link(struct puffs_usermount *pu, void *opc, void *targ,
717 1.1 agc const struct puffs_cn *pcn)
718 1.1 agc {
719 1.1 agc struct puffs_node *pn = targ;
720 1.1 agc struct fuse *fuse;
721 1.1 agc int ret;
722 1.1 agc
723 1.46 pooka fuse = puffs_getspecific(pu);
724 1.62 agc
725 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred);
726 1.62 agc
727 1.1 agc /* wrap up return code */
728 1.114 pho ret = fuse_fs_link(fuse->fs, PNPATH(pn), PCNPATH(pcn));
729 1.1 agc
730 1.18 pooka return -ret;
731 1.1 agc }
732 1.1 agc
733 1.1 agc /*
734 1.19 pooka * fuse's regular interface provides chmod(), chown(), utimes()
735 1.19 pooka * and truncate() + some variations, so try to fit the square block
736 1.19 pooka * in the circle hole and the circle block .... something like that
737 1.7 pooka */
738 1.1 agc /* ARGSUSED3 */
739 1.1 agc static int
740 1.85 pooka puffs_fuse_node_setattr(struct puffs_usermount *pu, void *opc,
741 1.84 pooka const struct vattr *va, const struct puffs_cred *pcr)
742 1.1 agc {
743 1.1 agc struct puffs_node *pn = opc;
744 1.1 agc struct fuse *fuse;
745 1.1 agc const char *path = PNPATH(pn);
746 1.1 agc
747 1.46 pooka fuse = puffs_getspecific(pu);
748 1.1 agc
749 1.66 agc set_fuse_context_uid_gid(pcr);
750 1.62 agc
751 1.26 pooka return fuse_setattr(fuse, pn, path, va);
752 1.1 agc }
753 1.1 agc
754 1.108 pho static int
755 1.108 pho puffs_fuse_node_pathconf(struct puffs_usermount *pu, void *opc,
756 1.108 pho int name, __register_t *retval)
757 1.108 pho {
758 1.108 pho /* Returning EINVAL for pathconf(2) means that this filesystem
759 1.108 pho * does not support an association of the given name with the
760 1.108 pho * file. This is necessary because the default error code
761 1.108 pho * returned by the puffs kernel module (ENOTSUPP) is not
762 1.108 pho * suitable for an errno from pathconf(2), and "ls -l"
763 1.108 pho * complains about it. */
764 1.108 pho return EINVAL;
765 1.108 pho }
766 1.108 pho
767 1.1 agc /* ARGSUSED2 */
768 1.1 agc static int
769 1.85 pooka puffs_fuse_node_open(struct puffs_usermount *pu, void *opc, int mode,
770 1.84 pooka const struct puffs_cred *cred)
771 1.1 agc {
772 1.1 agc struct puffs_node *pn = opc;
773 1.5 pooka struct refusenode *rn = pn->pn_data;
774 1.31 pooka struct fuse_file_info *fi = &rn->file_info;
775 1.1 agc struct fuse *fuse;
776 1.1 agc const char *path = PNPATH(pn);
777 1.114 pho int ret;
778 1.1 agc
779 1.46 pooka fuse = puffs_getspecific(pu);
780 1.1 agc
781 1.66 agc set_fuse_context_uid_gid(cred);
782 1.62 agc
783 1.30 pooka /* if open, don't open again, lest risk nuking file private info */
784 1.31 pooka if (rn->flags & RN_OPEN) {
785 1.31 pooka rn->opencount++;
786 1.1 agc return 0;
787 1.31 pooka }
788 1.1 agc
789 1.37 pooka /* OFLAGS(), need to convert FREAD/FWRITE to O_RD/WR */
790 1.37 pooka fi->flags = (mode & ~(O_CREAT | O_EXCL | O_TRUNC)) - 1;
791 1.37 pooka
792 1.30 pooka if (pn->pn_va.va_type == VDIR) {
793 1.114 pho ret = fuse_fs_opendir(fuse->fs, path, fi);
794 1.30 pooka } else {
795 1.114 pho ret = fuse_fs_open(fuse->fs, path, fi);
796 1.30 pooka }
797 1.1 agc
798 1.114 pho if (ret == 0) {
799 1.114 pho rn->flags |= RN_OPEN;
800 1.114 pho rn->opencount++;
801 1.114 pho }
802 1.1 agc
803 1.114 pho return -ret;
804 1.1 agc }
805 1.1 agc
806 1.31 pooka /* ARGSUSED2 */
807 1.31 pooka static int
808 1.85 pooka puffs_fuse_node_close(struct puffs_usermount *pu, void *opc, int fflag,
809 1.84 pooka const struct puffs_cred *pcr)
810 1.31 pooka {
811 1.31 pooka struct puffs_node *pn = opc;
812 1.31 pooka struct refusenode *rn = pn->pn_data;
813 1.31 pooka struct fuse *fuse;
814 1.31 pooka struct fuse_file_info *fi;
815 1.31 pooka const char *path = PNPATH(pn);
816 1.31 pooka int ret;
817 1.31 pooka
818 1.46 pooka fuse = puffs_getspecific(pu);
819 1.31 pooka fi = &rn->file_info;
820 1.31 pooka ret = 0;
821 1.31 pooka
822 1.66 agc set_fuse_context_uid_gid(pcr);
823 1.62 agc
824 1.31 pooka if (rn->flags & RN_OPEN) {
825 1.31 pooka if (pn->pn_va.va_type == VDIR) {
826 1.114 pho ret = fuse_fs_releasedir(fuse->fs, path, fi);
827 1.31 pooka } else {
828 1.114 pho ret = fuse_fs_release(fuse->fs, path, fi);
829 1.31 pooka }
830 1.31 pooka }
831 1.31 pooka rn->flags &= ~RN_OPEN;
832 1.31 pooka rn->opencount--;
833 1.31 pooka
834 1.31 pooka return ret;
835 1.31 pooka }
836 1.31 pooka
837 1.1 agc /* read some more from the file */
838 1.1 agc /* ARGSUSED5 */
839 1.1 agc static int
840 1.85 pooka puffs_fuse_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf,
841 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr,
842 1.1 agc int ioflag)
843 1.1 agc {
844 1.1 agc struct puffs_node *pn = opc;
845 1.5 pooka struct refusenode *rn = pn->pn_data;
846 1.1 agc struct fuse *fuse;
847 1.1 agc const char *path = PNPATH(pn);
848 1.25 pooka size_t maxread;
849 1.1 agc int ret;
850 1.1 agc
851 1.46 pooka fuse = puffs_getspecific(pu);
852 1.1 agc
853 1.66 agc set_fuse_context_uid_gid(pcr);
854 1.62 agc
855 1.25 pooka maxread = *resid;
856 1.106 pho if (maxread > (size_t)((off_t)pn->pn_va.va_size - offset)) {
857 1.26 pooka /*LINTED*/
858 1.106 pho maxread = (size_t)((off_t)pn->pn_va.va_size - offset);
859 1.26 pooka }
860 1.25 pooka if (maxread == 0)
861 1.25 pooka return 0;
862 1.25 pooka
863 1.114 pho ret = fuse_fs_read(fuse->fs, path, (char *)buf, maxread, offset,
864 1.114 pho &rn->file_info);
865 1.1 agc
866 1.1 agc if (ret > 0) {
867 1.106 pho *resid -= (size_t)ret;
868 1.16 pooka ret = 0;
869 1.1 agc }
870 1.1 agc
871 1.16 pooka return -ret;
872 1.1 agc }
873 1.1 agc
874 1.1 agc /* write to the file */
875 1.1 agc /* ARGSUSED0 */
876 1.1 agc static int
877 1.85 pooka puffs_fuse_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
878 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr,
879 1.1 agc int ioflag)
880 1.1 agc {
881 1.1 agc struct puffs_node *pn = opc;
882 1.8 pooka struct refusenode *rn = pn->pn_data;
883 1.1 agc struct fuse *fuse;
884 1.1 agc const char *path = PNPATH(pn);
885 1.1 agc int ret;
886 1.1 agc
887 1.46 pooka fuse = puffs_getspecific(pu);
888 1.1 agc
889 1.66 agc set_fuse_context_uid_gid(pcr);
890 1.62 agc
891 1.17 pooka if (ioflag & PUFFS_IO_APPEND)
892 1.106 pho offset = (off_t)pn->pn_va.va_size;
893 1.17 pooka
894 1.114 pho ret = fuse_fs_write(fuse->fs, path, (char *)buf, *resid, offset,
895 1.114 pho &rn->file_info);
896 1.1 agc
897 1.96 tron if (ret >= 0) {
898 1.90 lukem if ((uint64_t)(offset + ret) > pn->pn_va.va_size)
899 1.106 pho pn->pn_va.va_size = (u_quad_t)(offset + ret);
900 1.106 pho *resid -= (size_t)ret;
901 1.96 tron ret = (*resid == 0) ? 0 : ENOSPC;
902 1.96 tron } else {
903 1.96 tron ret = -ret;
904 1.1 agc }
905 1.1 agc
906 1.96 tron return ret;
907 1.1 agc }
908 1.1 agc
909 1.1 agc
910 1.1 agc /* ARGSUSED3 */
911 1.1 agc static int
912 1.85 pooka puffs_fuse_node_readdir(struct puffs_usermount *pu, void *opc,
913 1.85 pooka struct dirent *dent, off_t *readoff, size_t *reslen,
914 1.85 pooka const struct puffs_cred *pcr, int *eofflag,
915 1.85 pooka off_t *cookies, size_t *ncookies)
916 1.1 agc {
917 1.1 agc struct puffs_node *pn = opc;
918 1.8 pooka struct refusenode *rn = pn->pn_data;
919 1.43 agc struct puffs_fuse_dirh *dirh;
920 1.43 agc struct fuse *fuse;
921 1.41 agc struct dirent *fromdent;
922 1.1 agc const char *path = PNPATH(pn);
923 1.1 agc int ret;
924 1.1 agc
925 1.46 pooka fuse = puffs_getspecific(pu);
926 1.1 agc
927 1.66 agc set_fuse_context_uid_gid(pcr);
928 1.62 agc
929 1.36 pooka if (pn->pn_va.va_type != VDIR)
930 1.36 pooka return ENOTDIR;
931 1.36 pooka
932 1.36 pooka dirh = &rn->dirh;
933 1.36 pooka
934 1.36 pooka /*
935 1.36 pooka * if we are starting from the beginning, slurp entire directory
936 1.36 pooka * into our buffers
937 1.36 pooka */
938 1.36 pooka if (*readoff == 0) {
939 1.36 pooka /* free old buffers */
940 1.36 pooka free(dirh->dbuf);
941 1.36 pooka memset(dirh, 0, sizeof(struct puffs_fuse_dirh));
942 1.36 pooka
943 1.114 pho ret = fuse_fs_readdir_v30(
944 1.114 pho fuse->fs, path, dirh, puffs_fuse_fill_dir,
945 1.114 pho 0, &rn->file_info, (enum fuse_readdir_flags)0);
946 1.114 pho
947 1.36 pooka if (ret)
948 1.36 pooka return -ret;
949 1.35 pooka }
950 1.35 pooka
951 1.95 manu /* Both op.readdir and op.getdir read full directory */
952 1.95 manu *eofflag = 1;
953 1.95 manu
954 1.36 pooka /* now, stuff results into the kernel buffers */
955 1.91 lukem while (*readoff < (off_t)(dirh->bufsize - dirh->reslen)) {
956 1.36 pooka /*LINTED*/
957 1.36 pooka fromdent = (struct dirent *)((uint8_t *)dirh->dbuf + *readoff);
958 1.36 pooka
959 1.36 pooka if (*reslen < _DIRENT_SIZE(fromdent))
960 1.36 pooka break;
961 1.36 pooka
962 1.36 pooka memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
963 1.106 pho *readoff += (off_t)_DIRENT_SIZE(fromdent);
964 1.36 pooka *reslen -= _DIRENT_SIZE(fromdent);
965 1.1 agc
966 1.36 pooka dent = _DIRENT_NEXT(dent);
967 1.1 agc }
968 1.1 agc
969 1.36 pooka return 0;
970 1.1 agc }
971 1.1 agc
972 1.26 pooka /* ARGSUSED */
973 1.26 pooka static int
974 1.85 pooka puffs_fuse_node_reclaim(struct puffs_usermount *pu, void *opc)
975 1.26 pooka {
976 1.26 pooka struct puffs_node *pn = opc;
977 1.3 pooka
978 1.5 pooka nukern(pn);
979 1.26 pooka return 0;
980 1.3 pooka }
981 1.3 pooka
982 1.1 agc /* ARGSUSED1 */
983 1.1 agc static int
984 1.85 pooka puffs_fuse_fs_unmount(struct puffs_usermount *pu, int flags)
985 1.1 agc {
986 1.1 agc struct fuse *fuse;
987 1.1 agc
988 1.46 pooka fuse = puffs_getspecific(pu);
989 1.114 pho fuse_fs_destroy(fuse->fs);
990 1.1 agc return 0;
991 1.1 agc }
992 1.1 agc
993 1.1 agc /* ARGSUSED0 */
994 1.1 agc static int
995 1.85 pooka puffs_fuse_fs_sync(struct puffs_usermount *pu, int flags,
996 1.84 pooka const struct puffs_cred *cr)
997 1.1 agc {
998 1.66 agc set_fuse_context_uid_gid(cr);
999 1.1 agc return 0;
1000 1.1 agc }
1001 1.1 agc
1002 1.1 agc /* ARGSUSED2 */
1003 1.1 agc static int
1004 1.101 christos puffs_fuse_fs_statvfs(struct puffs_usermount *pu, struct puffs_statvfs *svfsb)
1005 1.1 agc {
1006 1.1 agc struct fuse *fuse;
1007 1.1 agc int ret;
1008 1.101 christos struct statvfs sb;
1009 1.1 agc
1010 1.114 pho /* fuse_fs_statfs() is special: it returns 0 even if the
1011 1.114 pho * filesystem doesn't support statfs. So clear the struct
1012 1.114 pho * before calling it. */
1013 1.114 pho memset(&sb, 0, sizeof(sb));
1014 1.114 pho
1015 1.46 pooka fuse = puffs_getspecific(pu);
1016 1.114 pho ret = fuse_fs_statfs(fuse->fs, PNPATH(puffs_getroot(pu)), &sb);
1017 1.114 pho
1018 1.114 pho if (ret == 0)
1019 1.114 pho statvfs_to_puffs_statvfs(&sb, svfsb);
1020 1.1 agc
1021 1.88 pooka return -ret;
1022 1.1 agc }
1023 1.1 agc
1024 1.114 pho /* End of puffs_fuse operations */
1025 1.1 agc
1026 1.114 pho struct fuse *
1027 1.114 pho __fuse_setup(int argc, char* argv[],
1028 1.114 pho const void* op, int op_version, void* user_data,
1029 1.114 pho struct fuse_cmdline_opts* opts)
1030 1.1 agc {
1031 1.98 pho struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1032 1.114 pho struct fuse *fuse = NULL;
1033 1.98 pho
1034 1.98 pho /* parse low-level options */
1035 1.114 pho if (fuse_parse_cmdline_v30(&args, opts) != 0)
1036 1.114 pho return NULL;
1037 1.98 pho
1038 1.114 pho if (opts->show_version) {
1039 1.98 pho fuse_lowlevel_version();
1040 1.98 pho goto free_args;
1041 1.98 pho }
1042 1.98 pho
1043 1.114 pho if (opts->show_help) {
1044 1.114 pho switch (opts->show_help) {
1045 1.112 pho case REFUSE_SHOW_HELP_FULL:
1046 1.112 pho if (args.argv[0] != NULL && args.argv[0][0] != '\0') {
1047 1.112 pho /* argv[0] being empty means that the application doesn't
1048 1.112 pho * want us to print the usage string.
1049 1.112 pho */
1050 1.112 pho printf("Usage: %s [options] mountpoint\n\n", args.argv[0]);
1051 1.112 pho }
1052 1.112 pho break;
1053 1.112 pho case REFUSE_SHOW_HELP_NO_HEADER:
1054 1.112 pho break;
1055 1.98 pho }
1056 1.98 pho fuse_cmdline_help();
1057 1.98 pho goto free_args;
1058 1.98 pho }
1059 1.98 pho
1060 1.114 pho if (opts->mountpoint == NULL) {
1061 1.98 pho fprintf(stderr, "fuse: no mountpoint specified\n");
1062 1.98 pho goto free_args;
1063 1.98 pho }
1064 1.38 pooka
1065 1.114 pho if (opts->debug) {
1066 1.114 pho if (fuse_opt_add_arg(&args, "-odebug") != 0)
1067 1.98 pho goto free_args;
1068 1.98 pho }
1069 1.38 pooka
1070 1.114 pho fuse = __fuse_new(&args, op, op_version, user_data);
1071 1.114 pho if (fuse == NULL)
1072 1.98 pho goto free_args;
1073 1.98 pho
1074 1.114 pho if (fuse_daemonize(opts->foreground) != 0)
1075 1.114 pho goto destroy;
1076 1.114 pho
1077 1.114 pho if (fuse_mount_v30(fuse, opts->mountpoint) != 0)
1078 1.114 pho goto destroy;
1079 1.98 pho
1080 1.114 pho if (__fuse_set_signal_handlers(fuse) != 0) {
1081 1.114 pho warn("%s: Failed to set signal handlers", __func__);
1082 1.98 pho goto destroy;
1083 1.98 pho }
1084 1.98 pho
1085 1.114 pho goto done;
1086 1.98 pho
1087 1.98 pho destroy:
1088 1.114 pho fuse_destroy_v30(fuse);
1089 1.114 pho fuse = NULL;
1090 1.98 pho free_args:
1091 1.114 pho free(opts->mountpoint);
1092 1.114 pho done:
1093 1.114 pho fuse_opt_free_args(&args);
1094 1.114 pho return fuse;
1095 1.114 pho }
1096 1.114 pho
1097 1.114 pho void
1098 1.114 pho __fuse_teardown(struct fuse* fuse)
1099 1.114 pho {
1100 1.114 pho if (__fuse_remove_signal_handlers(fuse) != 0)
1101 1.114 pho warn("%s: Failed to restore signal handlers", __func__);
1102 1.114 pho
1103 1.114 pho fuse_unmount_v30(fuse);
1104 1.114 pho }
1105 1.114 pho
1106 1.114 pho /* ARGSUSED3 */
1107 1.114 pho int
1108 1.114 pho __fuse_main(int argc, char **argv, const void *op,
1109 1.114 pho int op_version, void *user_data)
1110 1.114 pho {
1111 1.114 pho struct fuse_cmdline_opts opts;
1112 1.114 pho struct fuse *fuse;
1113 1.114 pho int rv;
1114 1.114 pho
1115 1.114 pho fuse = __fuse_setup(argc, argv, op, op_version, user_data, &opts);
1116 1.114 pho if (fuse == NULL)
1117 1.114 pho return -1;
1118 1.114 pho
1119 1.114 pho rv = fuse_loop(fuse);
1120 1.114 pho
1121 1.114 pho __fuse_teardown(fuse);
1122 1.114 pho
1123 1.98 pho free(opts.mountpoint);
1124 1.98 pho return rv;
1125 1.38 pooka }
1126 1.38 pooka
1127 1.114 pho int __fuse_mount(struct fuse *fuse, const char *mountpoint)
1128 1.38 pooka {
1129 1.98 pho struct puffs_pathobj *po_root;
1130 1.98 pho struct puffs_node *pn_root;
1131 1.98 pho struct refusenode *rn_root;
1132 1.101 christos struct puffs_statvfs svfsb;
1133 1.98 pho
1134 1.98 pho pn_root = newrn(fuse->pu);
1135 1.98 pho puffs_setroot(fuse->pu, pn_root);
1136 1.98 pho rn_root = pn_root->pn_data;
1137 1.98 pho rn_root->flags |= RN_ROOT;
1138 1.98 pho
1139 1.98 pho po_root = puffs_getrootpathobj(fuse->pu);
1140 1.98 pho if ((po_root->po_path = strdup("/")) == NULL)
1141 1.98 pho err(1, "fuse_mount");
1142 1.98 pho po_root->po_len = 1;
1143 1.98 pho puffs_path_buildhash(fuse->pu, po_root);
1144 1.98 pho
1145 1.98 pho /* sane defaults */
1146 1.98 pho puffs_vattr_null(&pn_root->pn_va);
1147 1.98 pho pn_root->pn_va.va_type = VDIR;
1148 1.98 pho pn_root->pn_va.va_mode = 0755;
1149 1.107 pho /* It might be tempting to call op.getattr("/") here to
1150 1.107 pho * populate pn_root->pa_va, but that would mean invoking an
1151 1.107 pho * operation callback without initializing the filesystem. We
1152 1.107 pho * cannot call op.init() either, because that is supposed to
1153 1.107 pho * be called right before entering the main loop. */
1154 1.38 pooka
1155 1.98 pho puffs_set_prepost(fuse->pu, set_fuse_context_pid, NULL);
1156 1.38 pooka
1157 1.98 pho puffs_zerostatvfs(&svfsb);
1158 1.98 pho if (puffs_mount(fuse->pu, mountpoint, MNT_NODEV | MNT_NOSUID, pn_root) == -1) {
1159 1.98 pho err(EXIT_FAILURE, "puffs_mount: directory \"%s\"", mountpoint);
1160 1.65 agc }
1161 1.48 agc
1162 1.98 pho return 0;
1163 1.98 pho }
1164 1.53 agc
1165 1.110 pho int fuse_daemonize(int foreground)
1166 1.98 pho {
1167 1.110 pho /* There is an impedance mismatch here: FUSE wants to
1168 1.110 pho * daemonize the process without any contexts but puffs wants
1169 1.110 pho * one. */
1170 1.110 pho struct fuse *fuse = fuse_get_context()->fuse;
1171 1.110 pho
1172 1.110 pho if (!fuse)
1173 1.110 pho /* FUSE would probably allow this, but we cannot. */
1174 1.110 pho errx(EXIT_FAILURE,
1175 1.110 pho "%s: librefuse doesn't allow calling"
1176 1.110 pho " this function before fuse_new().", __func__);
1177 1.110 pho
1178 1.110 pho if (!foreground)
1179 1.110 pho return puffs_daemon(fuse->pu, 0, 0);
1180 1.110 pho
1181 1.110 pho return 0;
1182 1.38 pooka }
1183 1.38 pooka
1184 1.38 pooka struct fuse *
1185 1.114 pho __fuse_new(struct fuse_args *args, const void *op, int op_version, void* user_data)
1186 1.38 pooka {
1187 1.98 pho struct refuse_config config;
1188 1.1 agc struct puffs_usermount *pu;
1189 1.66 agc struct fuse_context *fusectx;
1190 1.43 agc struct puffs_ops *pops;
1191 1.1 agc struct fuse *fuse;
1192 1.106 pho uint32_t puffs_flags;
1193 1.98 pho
1194 1.98 pho /* parse refuse options */
1195 1.114 pho memset(&config, 0, sizeof(config));
1196 1.98 pho if (fuse_opt_parse(args, &config, refuse_opts, NULL) == -1)
1197 1.98 pho return NULL;
1198 1.38 pooka
1199 1.65 agc if ((fuse = calloc(1, sizeof(*fuse))) == NULL) {
1200 1.65 agc err(EXIT_FAILURE, "fuse_new");
1201 1.65 agc }
1202 1.38 pooka
1203 1.98 pho /* grab the pthread context key */
1204 1.98 pho if (!create_context_key()) {
1205 1.98 pho free(config.fsname);
1206 1.98 pho free(fuse);
1207 1.98 pho return NULL;
1208 1.98 pho }
1209 1.98 pho
1210 1.114 pho /* Create the base filesystem layer. */
1211 1.114 pho fuse->fs = __fuse_fs_new(op, op_version, user_data);
1212 1.114 pho
1213 1.66 agc fusectx = fuse_get_context();
1214 1.66 agc fusectx->fuse = fuse;
1215 1.66 agc fusectx->uid = 0;
1216 1.66 agc fusectx->gid = 0;
1217 1.66 agc fusectx->pid = 0;
1218 1.114 pho fusectx->private_data = user_data;
1219 1.38 pooka
1220 1.1 agc /* initialise the puffs operations structure */
1221 1.1 agc PUFFSOP_INIT(pops);
1222 1.1 agc
1223 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, sync);
1224 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
1225 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
1226 1.1 agc
1227 1.2 pooka /*
1228 1.2 pooka * XXX: all of these don't possibly need to be
1229 1.2 pooka * unconditionally set
1230 1.2 pooka */
1231 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, lookup);
1232 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, getattr);
1233 1.15 pooka PUFFSOP_SET(pops, puffs_fuse, node, setattr);
1234 1.108 pho PUFFSOP_SET(pops, puffs_fuse, node, pathconf);
1235 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readdir);
1236 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readlink);
1237 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mknod);
1238 1.16 pooka PUFFSOP_SET(pops, puffs_fuse, node, create);
1239 1.15 pooka PUFFSOP_SET(pops, puffs_fuse, node, remove);
1240 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
1241 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
1242 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, symlink);
1243 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rename);
1244 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, link);
1245 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, open);
1246 1.31 pooka PUFFSOP_SET(pops, puffs_fuse, node, close);
1247 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, read);
1248 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, write);
1249 1.3 pooka PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
1250 1.1 agc
1251 1.98 pho puffs_flags = PUFFS_FLAG_BUILDPATH
1252 1.98 pho | PUFFS_FLAG_HASHPATH
1253 1.98 pho | PUFFS_KFLAG_NOCACHE;
1254 1.98 pho if (config.debug)
1255 1.98 pho puffs_flags |= PUFFS_FLAG_OPDUMP;
1256 1.53 agc
1257 1.98 pho pu = puffs_init(pops, _PATH_PUFFS, config.fsname, fuse, puffs_flags);
1258 1.1 agc if (pu == NULL) {
1259 1.57 pooka err(EXIT_FAILURE, "puffs_init");
1260 1.1 agc }
1261 1.98 pho fuse->pu = pu;
1262 1.1 agc
1263 1.98 pho free(config.fsname);
1264 1.38 pooka return fuse;
1265 1.38 pooka }
1266 1.38 pooka
1267 1.38 pooka int
1268 1.38 pooka fuse_loop(struct fuse *fuse)
1269 1.38 pooka {
1270 1.114 pho struct fuse_conn_info conn;
1271 1.114 pho struct fuse_config cfg;
1272 1.102 pho
1273 1.114 pho /* struct fuse_conn_info is a part of the FUSE API so we must
1274 1.114 pho * expose it to users, but we currently don't use them at
1275 1.114 pho * all. The same goes for struct fuse_config. */
1276 1.114 pho memset(&conn, 0, sizeof(conn));
1277 1.114 pho memset(&cfg, 0, sizeof(cfg));
1278 1.114 pho
1279 1.114 pho fuse_fs_init_v30(fuse->fs, &conn, &cfg);
1280 1.102 pho
1281 1.98 pho return puffs_mainloop(fuse->pu);
1282 1.38 pooka }
1283 1.38 pooka
1284 1.114 pho int
1285 1.114 pho __fuse_loop_mt(struct fuse *fuse,
1286 1.114 pho struct fuse_loop_config *config __attribute__((__unused__)))
1287 1.114 pho {
1288 1.114 pho /* TODO: Implement a proper multi-threaded loop. */
1289 1.114 pho return fuse_loop(fuse);
1290 1.114 pho }
1291 1.114 pho
1292 1.38 pooka void
1293 1.114 pho __fuse_destroy(struct fuse *fuse)
1294 1.38 pooka {
1295 1.38 pooka
1296 1.80 pooka /*
1297 1.80 pooka * TODO: needs to assert the fs is quiescent, i.e. no other
1298 1.80 pooka * threads exist
1299 1.80 pooka */
1300 1.80 pooka
1301 1.113 pho clear_context();
1302 1.66 agc delete_context_key();
1303 1.38 pooka /* XXXXXX: missing stuff */
1304 1.55 christos free(fuse);
1305 1.1 agc }
1306 1.1 agc
1307 1.20 agc void
1308 1.38 pooka fuse_exit(struct fuse *fuse)
1309 1.20 agc {
1310 1.60 pooka /* XXX: puffs_exit() is WRONG */
1311 1.98 pho if (fuse->dead == 0)
1312 1.98 pho puffs_exit(fuse->pu, 1);
1313 1.98 pho fuse->dead = 1;
1314 1.20 agc }
1315 1.29 pooka
1316 1.29 pooka /*
1317 1.29 pooka * XXX: obviously not the most perfect of functions, but needs some
1318 1.29 pooka * puffs tweaking for a better tomorrow
1319 1.29 pooka */
1320 1.29 pooka void
1321 1.114 pho __fuse_unmount(struct fuse *fuse)
1322 1.38 pooka {
1323 1.60 pooka /* XXX: puffs_exit() is WRONG */
1324 1.98 pho if (fuse->dead == 0)
1325 1.98 pho puffs_exit(fuse->pu, 1);
1326 1.98 pho fuse->dead = 1;
1327 1.38 pooka }
1328 1.38 pooka
1329 1.111 pho void
1330 1.111 pho fuse_lib_help(struct fuse_args *args __attribute__((__unused__)))
1331 1.111 pho {
1332 1.111 pho fuse_cmdline_help();
1333 1.111 pho }
1334 1.111 pho
1335 1.111 pho int
1336 1.111 pho fuse_interrupted(void)
1337 1.111 pho {
1338 1.111 pho /* ReFUSE doesn't support request interruption at the
1339 1.111 pho * moment. */
1340 1.111 pho return 0;
1341 1.111 pho }
1342 1.111 pho
1343 1.99 maya int
1344 1.105 pho fuse_invalidate_path(struct fuse *fuse __attribute__((__unused__)),
1345 1.105 pho const char *path __attribute__((__unused__)))
1346 1.105 pho {
1347 1.105 pho /* ReFUSE doesn't cache anything at the moment. No need to do
1348 1.105 pho * anything. */
1349 1.105 pho return -ENOENT;
1350 1.105 pho }
1351 1.105 pho
1352 1.105 pho int
1353 1.99 maya fuse_version(void)
1354 1.99 maya {
1355 1.109 pho return _REFUSE_VERSION_;
1356 1.99 maya }
1357 1.105 pho
1358 1.111 pho const char *
1359 1.111 pho fuse_pkgversion(void)
1360 1.111 pho {
1361 1.111 pho return "ReFUSE " ___STRING(_REFUSE_MAJOR_VERSION_)
1362 1.111 pho "." ___STRING(_REFUSE_MINOR_VERSION_);
1363 1.111 pho }
1364 1.111 pho
1365 1.111 pho int
1366 1.111 pho fuse_getgroups(int size, gid_t list[])
1367 1.111 pho {
1368 1.111 pho /* XXX: In order to implement this, we need to save a pointer
1369 1.111 pho * to struct puffs_cred in struct fuse upon entering a puffs
1370 1.111 pho * callback, and set it back to NULL upon leaving it. Then we
1371 1.111 pho * can use puffs_cred_getgroups(3) here. */
1372 1.111 pho return -ENOSYS;
1373 1.111 pho }
1374 1.111 pho
1375 1.111 pho int
1376 1.111 pho fuse_start_cleanup_thread(struct fuse *fuse)
1377 1.111 pho {
1378 1.111 pho /* XXX: ReFUSE doesn't support -oremember at the moment. */
1379 1.111 pho return 0;
1380 1.111 pho }
1381 1.111 pho
1382 1.111 pho void
1383 1.111 pho fuse_stop_cleanup_thread(struct fuse *fuse) {
1384 1.111 pho /* XXX: ReFUSE doesn't support -oremember at the moment. */
1385 1.111 pho }
1386 1.111 pho
1387 1.111 pho int
1388 1.111 pho fuse_clean_cache(struct fuse *fuse) {
1389 1.111 pho /* XXX: ReFUSE doesn't support -oremember at the moment. */
1390 1.111 pho return 3600;
1391 1.111 pho }
1392 1.111 pho
1393 1.105 pho /* This is a legacy function that has been removed from the FUSE API,
1394 1.105 pho * but is defined here because it needs to access refuse_opts. */
1395 1.105 pho int
1396 1.105 pho fuse_is_lib_option(const char *opt)
1397 1.105 pho {
1398 1.105 pho return fuse_opt_match(refuse_opts, opt);
1399 1.105 pho }
1400