refuse.c revision 1.41 1 1.41 agc /* $NetBSD: refuse.c,v 1.41 2007/03/13 20:50:47 agc Exp $ */
2 1.7 pooka
3 1.1 agc /*
4 1.1 agc * Copyright 2007 Alistair Crooks. All rights reserved.
5 1.1 agc *
6 1.1 agc * Redistribution and use in source and binary forms, with or without
7 1.1 agc * modification, are permitted provided that the following conditions
8 1.1 agc * are met:
9 1.1 agc * 1. Redistributions of source code must retain the above copyright
10 1.1 agc * notice, this list of conditions and the following disclaimer.
11 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 agc * notice, this list of conditions and the following disclaimer in the
13 1.1 agc * documentation and/or other materials provided with the distribution.
14 1.1 agc * 3. The name of the author may not be used to endorse or promote
15 1.1 agc * products derived from this software without specific prior written
16 1.1 agc * permission.
17 1.1 agc *
18 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 1.1 agc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 1.1 agc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 1.1 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 1.1 agc * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 1.1 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 1.1 agc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 1.1 agc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 1.1 agc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 1.1 agc * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 1.1 agc */
30 1.7 pooka
31 1.7 pooka #include <sys/cdefs.h>
32 1.7 pooka #if !defined(lint)
33 1.41 agc __RCSID("$NetBSD: refuse.c,v 1.41 2007/03/13 20:50:47 agc Exp $");
34 1.7 pooka #endif /* !lint */
35 1.7 pooka
36 1.25 pooka #include <assert.h>
37 1.1 agc #include <err.h>
38 1.1 agc #include <errno.h>
39 1.1 agc #include <fuse.h>
40 1.1 agc #include <unistd.h>
41 1.1 agc
42 1.1 agc #include "defs.h"
43 1.1 agc
44 1.41 agc /*
45 1.41 agc This module implements refuse, a re-implementation of the FUSE model,
46 1.41 agc using puffs and libpuffs. It is intended to be source code compatible
47 1.41 agc with FUSE. Specifically, it implements FUSE versions 2.5 and 2.6,
48 1.41 agc although some effort was put in to make it backwards compatible (by
49 1.41 agc Antti, not me).
50 1.41 agc
51 1.41 agc The error codes returned from refuse require some explanation. Linux
52 1.41 agc error codes in the kernel are negative, whereas traditional NetBSD
53 1.41 agc error codes are positive. For this reason, negative error codes are
54 1.41 agc returned from refuse, so that they are reported correctly to the
55 1.41 agc invoking application.
56 1.41 agc */
57 1.41 agc
58 1.1 agc typedef uint64_t fuse_ino_t;
59 1.1 agc
60 1.1 agc struct fuse_config {
61 1.1 agc uid_t uid;
62 1.1 agc gid_t gid;
63 1.1 agc mode_t umask;
64 1.1 agc double entry_timeout;
65 1.1 agc double negative_timeout;
66 1.1 agc double attr_timeout;
67 1.1 agc double ac_attr_timeout;
68 1.1 agc int ac_attr_timeout_set;
69 1.1 agc int debug;
70 1.1 agc int hard_remove;
71 1.1 agc int use_ino;
72 1.1 agc int readdir_ino;
73 1.1 agc int set_mode;
74 1.1 agc int set_uid;
75 1.1 agc int set_gid;
76 1.1 agc int direct_io;
77 1.1 agc int kernel_cache;
78 1.1 agc int auto_cache;
79 1.1 agc int intr;
80 1.1 agc int intr_signal;
81 1.1 agc };
82 1.1 agc
83 1.41 agc /* the fuse channel describes the physical attributes of the FUSE instance */
84 1.38 pooka struct fuse_chan {
85 1.41 agc const char *dir; /* directory */
86 1.41 agc struct fuse_args *args; /* arguments to FUSE/puffs */
87 1.41 agc struct puffs_usermount *pu; /* puffs information */
88 1.38 pooka };
89 1.38 pooka
90 1.1 agc /* this is the private fuse structure */
91 1.1 agc struct fuse {
92 1.38 pooka struct fuse_chan *fc; /* fuse channel pointer */
93 1.1 agc struct fuse_operations op; /* switch table of operations */
94 1.7 pooka int compat; /* compat level -
95 1.7 pooka * not used in puffs_fuse */
96 1.1 agc struct node **name_table;
97 1.1 agc size_t name_table_size;
98 1.1 agc struct node **id_table;
99 1.1 agc size_t id_table_size;
100 1.1 agc fuse_ino_t ctr;
101 1.1 agc unsigned int generation;
102 1.1 agc unsigned int hidectr;
103 1.1 agc pthread_mutex_t lock;
104 1.1 agc pthread_rwlock_t tree_lock;
105 1.1 agc void *user_data;
106 1.1 agc struct fuse_config conf;
107 1.1 agc int intr_installed;
108 1.1 agc };
109 1.1 agc
110 1.41 agc /* this struct describes a directory handle */
111 1.36 pooka struct puffs_fuse_dirh {
112 1.41 agc void *dbuf; /* directory buffer */
113 1.41 agc struct dirent *d; /* pointer to its dirent */
114 1.41 agc size_t reslen; /* result length */
115 1.41 agc size_t bufsize; /* buffer size */
116 1.36 pooka };
117 1.36 pooka
118 1.41 agc /* this struct describes a node in refuse land */
119 1.41 agc typedef struct refusenode {
120 1.41 agc struct fuse_file_info file_info; /* file information */
121 1.41 agc struct puffs_fuse_dirh dirh; /* directory handle */
122 1.41 agc int opencount; /* # of times opened */
123 1.41 agc int flags; /* associated flags */
124 1.41 agc } refusenode_t;
125 1.30 pooka #define RN_ROOT 0x01
126 1.31 pooka #define RN_OPEN 0x02 /* XXX: could just use opencount */
127 1.5 pooka
128 1.41 agc /* debugging functions */
129 1.41 agc
130 1.41 agc /* change the debug level by increment */
131 1.41 agc int
132 1.41 agc __fuse_debug(int incr)
133 1.41 agc {
134 1.41 agc static int __fuse_debug_level;
135 1.41 agc
136 1.41 agc return __fuse_debug_level += incr;
137 1.41 agc }
138 1.41 agc
139 1.41 agc /* print argv vector */
140 1.41 agc void
141 1.41 agc __fuse_pargs(const char *s, int argc, char **argv)
142 1.41 agc {
143 1.41 agc int i;
144 1.41 agc
145 1.41 agc for (i = 0 ; i < argc ; i++) {
146 1.41 agc printf("%s: argv[%d] = `%s'\n", s, i, argv[i]);
147 1.41 agc }
148 1.41 agc }
149 1.26 pooka
150 1.41 agc
151 1.41 agc /* create a new struct puffs_node and return it */
152 1.5 pooka static struct puffs_node *
153 1.5 pooka newrn(struct puffs_usermount *pu)
154 1.5 pooka {
155 1.5 pooka struct puffs_node *pn;
156 1.5 pooka struct refusenode *rn;
157 1.5 pooka
158 1.38 pooka NEW(struct refusenode, rn, "newrn", exit(EXIT_FAILURE));
159 1.5 pooka pn = puffs_pn_new(pu, rn);
160 1.5 pooka
161 1.5 pooka return pn;
162 1.5 pooka }
163 1.5 pooka
164 1.41 agc /* destroy a struct puffs_node */
165 1.5 pooka static void
166 1.5 pooka nukern(struct puffs_node *pn)
167 1.5 pooka {
168 1.36 pooka struct refusenode *rn = pn->pn_data;
169 1.5 pooka
170 1.36 pooka free(rn->dirh.dbuf);
171 1.36 pooka free(rn);
172 1.5 pooka puffs_pn_put(pn);
173 1.5 pooka }
174 1.5 pooka
175 1.1 agc static ino_t fakeino = 3;
176 1.1 agc
177 1.21 pooka /*
178 1.41 agc * XXX: do this differently if/when we grow thread support
179 1.21 pooka *
180 1.21 pooka * XXX2: does not consistently supply uid, gid or pid currently
181 1.21 pooka */
182 1.21 pooka static struct fuse_context fcon;
183 1.21 pooka
184 1.36 pooka #define DIR_CHUNKSIZE 4096
185 1.36 pooka static int
186 1.36 pooka fill_dirbuf(struct puffs_fuse_dirh *dh, const char *name, ino_t dino,
187 1.36 pooka uint8_t dtype)
188 1.36 pooka {
189 1.36 pooka
190 1.36 pooka /* initial? */
191 1.36 pooka if (dh->bufsize == 0) {
192 1.36 pooka dh->dbuf = malloc(DIR_CHUNKSIZE);
193 1.41 agc if (dh->dbuf == NULL) {
194 1.41 agc err(EXIT_FAILURE, "fill_dirbuf");
195 1.41 agc }
196 1.36 pooka dh->d = dh->dbuf;
197 1.36 pooka dh->reslen = dh->bufsize = DIR_CHUNKSIZE;
198 1.36 pooka }
199 1.21 pooka
200 1.41 agc if (puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen)) {
201 1.36 pooka return 0;
202 1.41 agc }
203 1.36 pooka
204 1.36 pooka /* try to increase buffer space */
205 1.36 pooka dh->dbuf = realloc(dh->dbuf, dh->bufsize + DIR_CHUNKSIZE);
206 1.41 agc if (dh->dbuf == NULL) {
207 1.41 agc err(EXIT_FAILURE, "fill_dirbuf realloc");
208 1.41 agc }
209 1.36 pooka dh->d = (void *)((uint8_t *)dh->dbuf + (dh->bufsize - dh->reslen));
210 1.36 pooka dh->reslen += DIR_CHUNKSIZE;
211 1.36 pooka dh->bufsize += DIR_CHUNKSIZE;
212 1.36 pooka
213 1.36 pooka return !puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen);
214 1.36 pooka }
215 1.1 agc
216 1.36 pooka /* ARGSUSED3 */
217 1.36 pooka /* XXX: I have no idea how "off" is supposed to be used */
218 1.1 agc static int
219 1.4 pooka puffs_fuse_fill_dir(void *buf, const char *name,
220 1.1 agc const struct stat *stbuf, off_t off)
221 1.1 agc {
222 1.36 pooka struct puffs_fuse_dirh *deh = buf;
223 1.13 pooka ino_t dino;
224 1.1 agc uint8_t dtype;
225 1.1 agc
226 1.13 pooka if (stbuf == NULL) {
227 1.13 pooka dtype = DT_UNKNOWN;
228 1.13 pooka dino = fakeino++;
229 1.13 pooka } else {
230 1.13 pooka dtype = puffs_vtype2dt(puffs_mode2vt(stbuf->st_mode));
231 1.13 pooka dino = stbuf->st_ino;
232 1.13 pooka }
233 1.1 agc
234 1.36 pooka return fill_dirbuf(deh, name, dino, dtype);
235 1.4 pooka }
236 1.4 pooka
237 1.4 pooka static int
238 1.4 pooka puffs_fuse_dirfil(fuse_dirh_t h, const char *name, int type, ino_t ino)
239 1.4 pooka {
240 1.41 agc ino_t dino;
241 1.41 agc int dtype;
242 1.4 pooka
243 1.41 agc if ((dtype = type) == 0) {
244 1.13 pooka dtype = DT_UNKNOWN;
245 1.41 agc }
246 1.41 agc if ((dino = ino) == 0) {
247 1.4 pooka dino = fakeino++;
248 1.41 agc }
249 1.4 pooka
250 1.36 pooka return fill_dirbuf(h, name, dino, dtype);
251 1.1 agc }
252 1.1 agc
253 1.18 pooka #define FUSE_ERR_UNLINK(fuse, file) if (fuse->op.unlink) fuse->op.unlink(file)
254 1.18 pooka #define FUSE_ERR_RMDIR(fuse, dir) if (fuse->op.rmdir) fuse->op.rmdir(dir)
255 1.18 pooka
256 1.26 pooka /* ARGSUSED1 */
257 1.26 pooka static int
258 1.26 pooka fuse_getattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
259 1.26 pooka struct vattr *va)
260 1.26 pooka {
261 1.26 pooka struct stat st;
262 1.26 pooka int ret;
263 1.26 pooka
264 1.26 pooka if (fuse->op.getattr == NULL) {
265 1.26 pooka return ENOSYS;
266 1.26 pooka }
267 1.26 pooka
268 1.26 pooka /* wrap up return code */
269 1.26 pooka ret = (*fuse->op.getattr)(path, &st);
270 1.26 pooka
271 1.26 pooka if (ret == 0) {
272 1.26 pooka puffs_stat2vattr(va, &st);
273 1.26 pooka }
274 1.26 pooka
275 1.26 pooka return -ret;
276 1.26 pooka }
277 1.26 pooka
278 1.26 pooka static int
279 1.26 pooka fuse_setattr(struct fuse *fuse, struct puffs_node *pn, const char *path,
280 1.26 pooka const struct vattr *va)
281 1.26 pooka {
282 1.26 pooka struct refusenode *rn = pn->pn_data;
283 1.26 pooka mode_t mode;
284 1.26 pooka uid_t uid;
285 1.26 pooka gid_t gid;
286 1.26 pooka int error, ret;
287 1.26 pooka
288 1.26 pooka error = 0;
289 1.26 pooka
290 1.26 pooka mode = va->va_mode;
291 1.26 pooka uid = va->va_uid;
292 1.26 pooka gid = va->va_gid;
293 1.26 pooka
294 1.26 pooka if (mode != (mode_t)PUFFS_VNOVAL) {
295 1.26 pooka ret = 0;
296 1.26 pooka
297 1.26 pooka if (fuse->op.chmod == NULL) {
298 1.26 pooka error = -ENOSYS;
299 1.26 pooka } else {
300 1.26 pooka ret = fuse->op.chmod(path, mode);
301 1.26 pooka if (ret)
302 1.26 pooka error = ret;
303 1.26 pooka }
304 1.26 pooka }
305 1.26 pooka if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) {
306 1.26 pooka ret = 0;
307 1.26 pooka
308 1.26 pooka if (fuse->op.chown == NULL) {
309 1.26 pooka error = -ENOSYS;
310 1.26 pooka } else {
311 1.26 pooka ret = fuse->op.chown(path, uid, gid);
312 1.26 pooka if (ret)
313 1.26 pooka error = ret;
314 1.26 pooka }
315 1.26 pooka }
316 1.26 pooka if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
317 1.26 pooka || va->va_mtime.tv_sec != (long)PUFFS_VNOVAL) {
318 1.26 pooka ret = 0;
319 1.26 pooka
320 1.26 pooka if (fuse->op.utimens) {
321 1.26 pooka struct timespec tv[2];
322 1.26 pooka
323 1.26 pooka tv[0].tv_sec = va->va_atime.tv_sec;
324 1.26 pooka tv[0].tv_nsec = va->va_atime.tv_nsec;
325 1.26 pooka tv[1].tv_sec = va->va_mtime.tv_sec;
326 1.26 pooka tv[1].tv_nsec = va->va_mtime.tv_nsec;
327 1.26 pooka
328 1.26 pooka ret = fuse->op.utimens(path, tv);
329 1.26 pooka } else if (fuse->op.utime) {
330 1.26 pooka struct utimbuf timbuf;
331 1.26 pooka
332 1.26 pooka timbuf.actime = va->va_atime.tv_sec;
333 1.26 pooka timbuf.modtime = va->va_mtime.tv_sec;
334 1.26 pooka
335 1.26 pooka ret = fuse->op.utime(path, &timbuf);
336 1.26 pooka } else {
337 1.26 pooka error = -ENOSYS;
338 1.26 pooka }
339 1.26 pooka
340 1.26 pooka if (ret)
341 1.26 pooka error = ret;
342 1.26 pooka }
343 1.26 pooka if (va->va_size != (u_quad_t)PUFFS_VNOVAL) {
344 1.26 pooka ret = 0;
345 1.26 pooka
346 1.26 pooka if (fuse->op.truncate) {
347 1.26 pooka ret = fuse->op.truncate(path, (off_t)va->va_size);
348 1.26 pooka } else if (fuse->op.ftruncate) {
349 1.26 pooka ret = fuse->op.ftruncate(path, (off_t)va->va_size,
350 1.26 pooka &rn->file_info);
351 1.26 pooka } else {
352 1.26 pooka error = -ENOSYS;
353 1.26 pooka }
354 1.26 pooka
355 1.26 pooka if (ret)
356 1.26 pooka error = ret;
357 1.26 pooka }
358 1.26 pooka /* XXX: no reflection with reality */
359 1.26 pooka puffs_setvattr(&pn->pn_va, va);
360 1.26 pooka
361 1.26 pooka return -error;
362 1.26 pooka
363 1.26 pooka }
364 1.26 pooka
365 1.26 pooka static int
366 1.26 pooka fuse_newnode(struct puffs_usermount *pu, const char *path,
367 1.26 pooka const struct vattr *va, struct fuse_file_info *fi, void **newnode)
368 1.26 pooka {
369 1.26 pooka struct vattr newva;
370 1.26 pooka struct fuse *fuse;
371 1.26 pooka struct puffs_node *pn;
372 1.26 pooka struct refusenode *rn;
373 1.26 pooka
374 1.26 pooka fuse = (struct fuse *)pu->pu_privdata;
375 1.26 pooka
376 1.26 pooka /* fix up nodes */
377 1.26 pooka pn = newrn(pu);
378 1.26 pooka if (pn == NULL) {
379 1.26 pooka if (va->va_type == VDIR) {
380 1.26 pooka FUSE_ERR_RMDIR(fuse, path);
381 1.26 pooka } else {
382 1.26 pooka FUSE_ERR_UNLINK(fuse, path);
383 1.26 pooka }
384 1.26 pooka return ENOMEM;
385 1.26 pooka }
386 1.26 pooka fuse_setattr(fuse, pn, path, va);
387 1.26 pooka if (fuse_getattr(fuse, pn, path, &newva) == 0)
388 1.26 pooka puffs_setvattr(&pn->pn_va, &newva);
389 1.26 pooka
390 1.26 pooka rn = pn->pn_data;
391 1.26 pooka if (fi)
392 1.26 pooka memcpy(&rn->file_info, fi, sizeof(struct fuse_file_info));
393 1.26 pooka
394 1.26 pooka *newnode = pn;
395 1.26 pooka
396 1.26 pooka return 0;
397 1.26 pooka }
398 1.26 pooka
399 1.26 pooka
400 1.1 agc /* operation wrappers start here */
401 1.1 agc
402 1.1 agc /* lookup the path */
403 1.1 agc /* ARGSUSED1 */
404 1.1 agc static int
405 1.1 agc puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
406 1.1 agc enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
407 1.1 agc const struct puffs_cn *pcn)
408 1.1 agc {
409 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
410 1.12 pooka struct puffs_node *pn_res;
411 1.1 agc struct stat st;
412 1.1 agc struct fuse *fuse;
413 1.1 agc const char *path = PCNPATH(pcn);
414 1.1 agc int ret;
415 1.1 agc
416 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
417 1.1 agc ret = fuse->op.getattr(path, &st);
418 1.12 pooka
419 1.1 agc if (ret != 0) {
420 1.18 pooka return -ret;
421 1.12 pooka }
422 1.12 pooka
423 1.12 pooka /* XXX: fiXXXme unconst */
424 1.12 pooka pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
425 1.12 pooka __UNCONST(&pcn->pcn_po_full));
426 1.12 pooka if (pn_res == NULL) {
427 1.12 pooka pn_res = newrn(pu);
428 1.12 pooka if (pn_res == NULL)
429 1.12 pooka return errno;
430 1.26 pooka puffs_stat2vattr(&pn_res->pn_va, &st);
431 1.1 agc }
432 1.12 pooka
433 1.12 pooka *newnode = pn_res;
434 1.12 pooka *newtype = pn_res->pn_va.va_type;
435 1.12 pooka *newsize = pn_res->pn_va.va_size;
436 1.12 pooka *newrdev = pn_res->pn_va.va_rdev;
437 1.12 pooka
438 1.12 pooka return 0;
439 1.1 agc }
440 1.1 agc
441 1.1 agc /* get attributes for the path name */
442 1.1 agc /* ARGSUSED3 */
443 1.1 agc static int
444 1.1 agc puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
445 1.1 agc const struct puffs_cred *pcr, pid_t pid)
446 1.1 agc {
447 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
448 1.1 agc struct puffs_node *pn = opc;
449 1.1 agc struct fuse *fuse;
450 1.1 agc const char *path = PNPATH(pn);
451 1.1 agc
452 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
453 1.26 pooka return fuse_getattr(fuse, pn, path, va);
454 1.1 agc }
455 1.1 agc
456 1.1 agc /* read the contents of the symbolic link */
457 1.1 agc /* ARGSUSED2 */
458 1.1 agc static int
459 1.1 agc puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
460 1.1 agc const struct puffs_cred *cred, char *linkname, size_t *linklen)
461 1.1 agc {
462 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
463 1.1 agc struct puffs_node *pn = opc;
464 1.1 agc struct fuse *fuse;
465 1.13 pooka const char *path = PNPATH(pn), *p;
466 1.1 agc int ret;
467 1.1 agc
468 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
469 1.1 agc if (fuse->op.readlink == NULL) {
470 1.1 agc return ENOSYS;
471 1.1 agc }
472 1.1 agc
473 1.1 agc /* wrap up return code */
474 1.1 agc ret = (*fuse->op.readlink)(path, linkname, *linklen);
475 1.1 agc
476 1.1 agc if (ret == 0) {
477 1.41 agc p = memchr(linkname, 0x0, *linklen);
478 1.13 pooka if (!p)
479 1.13 pooka return EINVAL;
480 1.13 pooka
481 1.14 pooka *linklen = p - linkname;
482 1.1 agc }
483 1.1 agc
484 1.13 pooka return -ret;
485 1.1 agc }
486 1.1 agc
487 1.1 agc /* make the special node */
488 1.1 agc /* ARGSUSED1 */
489 1.1 agc static int
490 1.1 agc puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
491 1.1 agc const struct puffs_cn *pcn, const struct vattr *va)
492 1.1 agc {
493 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
494 1.1 agc struct fuse *fuse;
495 1.1 agc mode_t mode = va->va_mode;
496 1.1 agc const char *path = PCNPATH(pcn);
497 1.1 agc int ret;
498 1.1 agc
499 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
500 1.1 agc if (fuse->op.mknod == NULL) {
501 1.1 agc return ENOSYS;
502 1.1 agc }
503 1.1 agc
504 1.1 agc /* wrap up return code */
505 1.1 agc ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
506 1.1 agc
507 1.1 agc if (ret == 0) {
508 1.26 pooka ret = fuse_newnode(pu, path, va, NULL, newnode);
509 1.1 agc }
510 1.1 agc
511 1.18 pooka return -ret;
512 1.1 agc }
513 1.1 agc
514 1.1 agc /* make a directory */
515 1.1 agc /* ARGSUSED1 */
516 1.1 agc static int
517 1.1 agc puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
518 1.1 agc const struct puffs_cn *pcn, const struct vattr *va)
519 1.1 agc {
520 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
521 1.1 agc struct fuse *fuse;
522 1.1 agc mode_t mode = va->va_mode;
523 1.1 agc const char *path = PCNPATH(pcn);
524 1.1 agc int ret;
525 1.1 agc
526 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
527 1.1 agc if (fuse->op.mkdir == NULL) {
528 1.1 agc return ENOSYS;
529 1.1 agc }
530 1.1 agc
531 1.1 agc /* wrap up return code */
532 1.1 agc ret = (*fuse->op.mkdir)(path, mode);
533 1.1 agc
534 1.1 agc if (ret == 0) {
535 1.26 pooka ret = fuse_newnode(pu, path, va, NULL, newnode);
536 1.1 agc }
537 1.1 agc
538 1.18 pooka return -ret;
539 1.1 agc }
540 1.1 agc
541 1.21 pooka /*
542 1.21 pooka * create a regular file
543 1.21 pooka *
544 1.21 pooka * since linux/fuse sports using mknod for creating regular files
545 1.21 pooka * instead of having a separate call for it in some versions, if
546 1.21 pooka * we don't have create, just jump to op->mknod.
547 1.21 pooka */
548 1.16 pooka /*ARGSUSED1*/
549 1.16 pooka static int
550 1.16 pooka puffs_fuse_node_create(struct puffs_cc *pcc, void *opc, void **newnode,
551 1.16 pooka const struct puffs_cn *pcn, const struct vattr *va)
552 1.16 pooka {
553 1.16 pooka struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
554 1.16 pooka struct fuse *fuse;
555 1.16 pooka struct fuse_file_info fi;
556 1.16 pooka mode_t mode = va->va_mode;
557 1.16 pooka const char *path = PCNPATH(pcn);
558 1.31 pooka int ret, created;
559 1.16 pooka
560 1.16 pooka fuse = (struct fuse *)pu->pu_privdata;
561 1.21 pooka
562 1.31 pooka created = 0;
563 1.21 pooka if (fuse->op.create) {
564 1.21 pooka ret = fuse->op.create(path, mode, &fi);
565 1.31 pooka if (ret == 0)
566 1.31 pooka created = 1;
567 1.21 pooka
568 1.21 pooka } else if (fuse->op.mknod) {
569 1.21 pooka fcon.uid = va->va_uid; /*XXX*/
570 1.21 pooka fcon.gid = va->va_gid; /*XXX*/
571 1.21 pooka
572 1.21 pooka ret = fuse->op.mknod(path, mode | S_IFREG, 0);
573 1.21 pooka
574 1.21 pooka } else {
575 1.21 pooka ret = -ENOSYS;
576 1.16 pooka }
577 1.16 pooka
578 1.16 pooka if (ret == 0) {
579 1.26 pooka ret = fuse_newnode(pu, path, va, &fi, newnode);
580 1.31 pooka
581 1.31 pooka /* sweet.. create also open the file */
582 1.31 pooka if (created) {
583 1.31 pooka struct puffs_node *pn;
584 1.31 pooka struct refusenode *rn;
585 1.31 pooka
586 1.31 pooka pn = *newnode;
587 1.31 pooka rn = pn->pn_data;
588 1.31 pooka rn->flags |= RN_OPEN;
589 1.31 pooka rn->opencount++;
590 1.31 pooka }
591 1.16 pooka }
592 1.16 pooka
593 1.18 pooka return -ret;
594 1.16 pooka }
595 1.16 pooka
596 1.1 agc /* remove the directory entry */
597 1.23 pooka /* ARGSUSED1 */
598 1.1 agc static int
599 1.1 agc puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
600 1.1 agc const struct puffs_cn *pcn)
601 1.1 agc {
602 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
603 1.23 pooka struct puffs_node *pn_targ = targ;
604 1.1 agc struct fuse *fuse;
605 1.23 pooka const char *path = PNPATH(pn_targ);
606 1.1 agc int ret;
607 1.1 agc
608 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
609 1.1 agc if (fuse->op.unlink == NULL) {
610 1.1 agc return ENOSYS;
611 1.1 agc }
612 1.1 agc
613 1.1 agc /* wrap up return code */
614 1.1 agc ret = (*fuse->op.unlink)(path);
615 1.1 agc
616 1.18 pooka return -ret;
617 1.1 agc }
618 1.1 agc
619 1.1 agc /* remove the directory */
620 1.1 agc /* ARGSUSED1 */
621 1.1 agc static int
622 1.1 agc puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
623 1.1 agc const struct puffs_cn *pcn)
624 1.1 agc {
625 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
626 1.23 pooka struct puffs_node *pn_targ = targ;
627 1.1 agc struct fuse *fuse;
628 1.23 pooka const char *path = PNPATH(pn_targ);
629 1.1 agc int ret;
630 1.1 agc
631 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
632 1.1 agc if (fuse->op.rmdir == NULL) {
633 1.1 agc return ENOSYS;
634 1.1 agc }
635 1.1 agc
636 1.1 agc /* wrap up return code */
637 1.1 agc ret = (*fuse->op.rmdir)(path);
638 1.1 agc
639 1.18 pooka return -ret;
640 1.1 agc }
641 1.1 agc
642 1.1 agc /* create a symbolic link */
643 1.1 agc /* ARGSUSED1 */
644 1.1 agc static int
645 1.1 agc puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
646 1.1 agc const struct puffs_cn *pcn_src, const struct vattr *va,
647 1.1 agc const char *link_target)
648 1.1 agc {
649 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
650 1.1 agc struct fuse *fuse;
651 1.1 agc const char *path = PCNPATH(pcn_src);
652 1.1 agc int ret;
653 1.1 agc
654 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
655 1.1 agc if (fuse->op.symlink == NULL) {
656 1.1 agc return ENOSYS;
657 1.1 agc }
658 1.1 agc
659 1.1 agc /* wrap up return code */
660 1.32 pooka ret = fuse->op.symlink(link_target, path);
661 1.1 agc
662 1.1 agc if (ret == 0) {
663 1.26 pooka ret = fuse_newnode(pu, path, va, NULL, newnode);
664 1.1 agc }
665 1.1 agc
666 1.18 pooka return -ret;
667 1.1 agc }
668 1.1 agc
669 1.1 agc /* rename a directory entry */
670 1.1 agc /* ARGSUSED1 */
671 1.1 agc static int
672 1.1 agc puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
673 1.1 agc const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
674 1.1 agc const struct puffs_cn *pcn_targ)
675 1.1 agc {
676 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
677 1.1 agc struct fuse *fuse;
678 1.24 pooka const char *path_src = PCNPATH(pcn_src);
679 1.24 pooka const char *path_dest = PCNPATH(pcn_targ);
680 1.1 agc int ret;
681 1.1 agc
682 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
683 1.1 agc if (fuse->op.rename == NULL) {
684 1.1 agc return ENOSYS;
685 1.1 agc }
686 1.1 agc
687 1.24 pooka ret = fuse->op.rename(path_src, path_dest);
688 1.1 agc
689 1.1 agc if (ret == 0) {
690 1.1 agc }
691 1.1 agc
692 1.18 pooka return -ret;
693 1.1 agc }
694 1.1 agc
695 1.1 agc /* create a link in the file system */
696 1.1 agc /* ARGSUSED1 */
697 1.1 agc static int
698 1.1 agc puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
699 1.1 agc const struct puffs_cn *pcn)
700 1.1 agc {
701 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
702 1.1 agc struct puffs_node *pn = targ;
703 1.1 agc struct fuse *fuse;
704 1.1 agc int ret;
705 1.1 agc
706 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
707 1.1 agc if (fuse->op.link == NULL) {
708 1.1 agc return ENOSYS;
709 1.1 agc }
710 1.1 agc
711 1.1 agc /* wrap up return code */
712 1.1 agc ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
713 1.1 agc
714 1.18 pooka return -ret;
715 1.1 agc }
716 1.1 agc
717 1.1 agc /*
718 1.19 pooka * fuse's regular interface provides chmod(), chown(), utimes()
719 1.19 pooka * and truncate() + some variations, so try to fit the square block
720 1.19 pooka * in the circle hole and the circle block .... something like that
721 1.7 pooka */
722 1.1 agc /* ARGSUSED3 */
723 1.1 agc static int
724 1.1 agc puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
725 1.1 agc const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
726 1.1 agc {
727 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
728 1.1 agc struct puffs_node *pn = opc;
729 1.1 agc struct fuse *fuse;
730 1.1 agc const char *path = PNPATH(pn);
731 1.1 agc
732 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
733 1.1 agc
734 1.26 pooka return fuse_setattr(fuse, pn, path, va);
735 1.1 agc }
736 1.1 agc
737 1.1 agc /* ARGSUSED2 */
738 1.1 agc static int
739 1.31 pooka puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int mode,
740 1.1 agc const struct puffs_cred *cred, pid_t pid)
741 1.1 agc {
742 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
743 1.1 agc struct puffs_node *pn = opc;
744 1.5 pooka struct refusenode *rn = pn->pn_data;
745 1.31 pooka struct fuse_file_info *fi = &rn->file_info;
746 1.1 agc struct fuse *fuse;
747 1.1 agc const char *path = PNPATH(pn);
748 1.1 agc
749 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
750 1.1 agc
751 1.30 pooka /* if open, don't open again, lest risk nuking file private info */
752 1.31 pooka if (rn->flags & RN_OPEN) {
753 1.31 pooka rn->opencount++;
754 1.1 agc return 0;
755 1.31 pooka }
756 1.1 agc
757 1.37 pooka /* OFLAGS(), need to convert FREAD/FWRITE to O_RD/WR */
758 1.37 pooka fi->flags = (mode & ~(O_CREAT | O_EXCL | O_TRUNC)) - 1;
759 1.37 pooka
760 1.30 pooka if (pn->pn_va.va_type == VDIR) {
761 1.30 pooka if (fuse->op.opendir)
762 1.33 pooka fuse->op.opendir(path, fi);
763 1.30 pooka } else {
764 1.30 pooka if (fuse->op.open)
765 1.33 pooka fuse->op.open(path, fi);
766 1.30 pooka }
767 1.1 agc
768 1.33 pooka rn->flags |= RN_OPEN;
769 1.33 pooka rn->opencount++;
770 1.1 agc
771 1.33 pooka return 0;
772 1.1 agc }
773 1.1 agc
774 1.31 pooka /* ARGSUSED2 */
775 1.31 pooka static int
776 1.31 pooka puffs_fuse_node_close(struct puffs_cc *pcc, void *opc, int fflag,
777 1.31 pooka const struct puffs_cred *pcr, pid_t pid)
778 1.31 pooka {
779 1.31 pooka struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
780 1.31 pooka struct puffs_node *pn = opc;
781 1.31 pooka struct refusenode *rn = pn->pn_data;
782 1.31 pooka struct fuse *fuse;
783 1.31 pooka struct fuse_file_info *fi;
784 1.31 pooka const char *path = PNPATH(pn);
785 1.31 pooka int ret;
786 1.31 pooka
787 1.31 pooka fuse = (struct fuse *)pu->pu_privdata;
788 1.31 pooka fi = &rn->file_info;
789 1.31 pooka ret = 0;
790 1.31 pooka
791 1.31 pooka if (rn->flags & RN_OPEN) {
792 1.31 pooka if (pn->pn_va.va_type == VDIR) {
793 1.31 pooka if (fuse->op.releasedir)
794 1.31 pooka ret = fuse->op.releasedir(path, fi);
795 1.31 pooka } else {
796 1.31 pooka if (fuse->op.release)
797 1.31 pooka ret = fuse->op.release(path, fi);
798 1.31 pooka }
799 1.31 pooka }
800 1.31 pooka rn->flags &= ~RN_OPEN;
801 1.31 pooka rn->opencount--;
802 1.31 pooka
803 1.31 pooka return ret;
804 1.31 pooka }
805 1.31 pooka
806 1.1 agc /* read some more from the file */
807 1.1 agc /* ARGSUSED5 */
808 1.1 agc static int
809 1.1 agc puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
810 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr,
811 1.1 agc int ioflag)
812 1.1 agc {
813 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
814 1.1 agc struct puffs_node *pn = opc;
815 1.5 pooka struct refusenode *rn = pn->pn_data;
816 1.1 agc struct fuse *fuse;
817 1.1 agc const char *path = PNPATH(pn);
818 1.25 pooka size_t maxread;
819 1.1 agc int ret;
820 1.1 agc
821 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
822 1.1 agc if (fuse->op.read == NULL) {
823 1.1 agc return ENOSYS;
824 1.1 agc }
825 1.1 agc
826 1.25 pooka maxread = *resid;
827 1.26 pooka if (maxread > pn->pn_va.va_size - offset) {
828 1.26 pooka /*LINTED*/
829 1.25 pooka maxread = pn->pn_va.va_size - offset;
830 1.26 pooka }
831 1.25 pooka if (maxread == 0)
832 1.25 pooka return 0;
833 1.25 pooka
834 1.25 pooka ret = (*fuse->op.read)(path, (char *)buf, maxread, offset,
835 1.7 pooka &rn->file_info);
836 1.1 agc
837 1.1 agc if (ret > 0) {
838 1.1 agc *resid -= ret;
839 1.16 pooka ret = 0;
840 1.1 agc }
841 1.1 agc
842 1.16 pooka return -ret;
843 1.1 agc }
844 1.1 agc
845 1.1 agc /* write to the file */
846 1.1 agc /* ARGSUSED0 */
847 1.1 agc static int
848 1.1 agc puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
849 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr,
850 1.1 agc int ioflag)
851 1.1 agc {
852 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
853 1.1 agc struct puffs_node *pn = opc;
854 1.8 pooka struct refusenode *rn = pn->pn_data;
855 1.1 agc struct fuse *fuse;
856 1.1 agc const char *path = PNPATH(pn);
857 1.1 agc int ret;
858 1.1 agc
859 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
860 1.1 agc if (fuse->op.write == NULL) {
861 1.1 agc return ENOSYS;
862 1.1 agc }
863 1.1 agc
864 1.17 pooka if (ioflag & PUFFS_IO_APPEND)
865 1.17 pooka offset = pn->pn_va.va_size;
866 1.17 pooka
867 1.8 pooka ret = (*fuse->op.write)(path, (char *)buf, *resid, offset,
868 1.8 pooka &rn->file_info);
869 1.1 agc
870 1.1 agc if (ret > 0) {
871 1.23 pooka if (offset + ret > pn->pn_va.va_size)
872 1.23 pooka pn->pn_va.va_size = offset + ret;
873 1.26 pooka *resid -= ret;
874 1.16 pooka ret = 0;
875 1.1 agc }
876 1.1 agc
877 1.16 pooka return -ret;
878 1.1 agc }
879 1.1 agc
880 1.1 agc
881 1.1 agc /* ARGSUSED3 */
882 1.1 agc static int
883 1.1 agc puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
884 1.1 agc struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
885 1.1 agc size_t *reslen)
886 1.1 agc {
887 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
888 1.41 agc struct puffs_fuse_dirh *dirh;
889 1.1 agc struct puffs_node *pn = opc;
890 1.8 pooka struct refusenode *rn = pn->pn_data;
891 1.41 agc struct dirent *fromdent;
892 1.1 agc struct fuse *fuse;
893 1.1 agc const char *path = PNPATH(pn);
894 1.1 agc int ret;
895 1.1 agc
896 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
897 1.4 pooka if (fuse->op.readdir == NULL && fuse->op.getdir == NULL) {
898 1.1 agc return ENOSYS;
899 1.1 agc }
900 1.1 agc
901 1.36 pooka if (pn->pn_va.va_type != VDIR)
902 1.36 pooka return ENOTDIR;
903 1.36 pooka
904 1.36 pooka dirh = &rn->dirh;
905 1.36 pooka
906 1.36 pooka /*
907 1.36 pooka * if we are starting from the beginning, slurp entire directory
908 1.36 pooka * into our buffers
909 1.36 pooka */
910 1.36 pooka if (*readoff == 0) {
911 1.36 pooka /* free old buffers */
912 1.36 pooka free(dirh->dbuf);
913 1.36 pooka memset(dirh, 0, sizeof(struct puffs_fuse_dirh));
914 1.36 pooka
915 1.36 pooka if (fuse->op.readdir)
916 1.36 pooka ret = fuse->op.readdir(path, dirh, puffs_fuse_fill_dir,
917 1.36 pooka 0, &rn->file_info);
918 1.36 pooka else
919 1.36 pooka ret = fuse->op.getdir(path, dirh, puffs_fuse_dirfil);
920 1.36 pooka if (ret)
921 1.36 pooka return -ret;
922 1.35 pooka }
923 1.35 pooka
924 1.36 pooka /* now, stuff results into the kernel buffers */
925 1.36 pooka while (*readoff < dirh->bufsize - dirh->reslen) {
926 1.36 pooka /*LINTED*/
927 1.36 pooka fromdent = (struct dirent *)((uint8_t *)dirh->dbuf + *readoff);
928 1.36 pooka
929 1.36 pooka if (*reslen < _DIRENT_SIZE(fromdent))
930 1.36 pooka break;
931 1.36 pooka
932 1.36 pooka memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
933 1.36 pooka *readoff += _DIRENT_SIZE(fromdent);
934 1.36 pooka *reslen -= _DIRENT_SIZE(fromdent);
935 1.1 agc
936 1.36 pooka dent = _DIRENT_NEXT(dent);
937 1.1 agc }
938 1.1 agc
939 1.36 pooka return 0;
940 1.1 agc }
941 1.1 agc
942 1.26 pooka /* ARGSUSED */
943 1.26 pooka static int
944 1.26 pooka puffs_fuse_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
945 1.26 pooka {
946 1.26 pooka struct puffs_node *pn = opc;
947 1.3 pooka
948 1.5 pooka nukern(pn);
949 1.3 pooka
950 1.26 pooka return 0;
951 1.3 pooka }
952 1.3 pooka
953 1.1 agc /* ARGSUSED1 */
954 1.1 agc static int
955 1.1 agc puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
956 1.1 agc {
957 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
958 1.1 agc struct fuse *fuse;
959 1.1 agc
960 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
961 1.1 agc if (fuse->op.destroy == NULL) {
962 1.2 pooka return 0;
963 1.1 agc }
964 1.1 agc (*fuse->op.destroy)(fuse);
965 1.1 agc return 0;
966 1.1 agc }
967 1.1 agc
968 1.1 agc /* ARGSUSED0 */
969 1.1 agc static int
970 1.1 agc puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
971 1.1 agc const struct puffs_cred *cr, pid_t pid)
972 1.1 agc {
973 1.1 agc return 0;
974 1.1 agc }
975 1.1 agc
976 1.1 agc /* ARGSUSED2 */
977 1.1 agc static int
978 1.1 agc puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
979 1.1 agc {
980 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
981 1.1 agc struct fuse *fuse;
982 1.1 agc int ret;
983 1.1 agc
984 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
985 1.1 agc if (fuse->op.statfs == NULL) {
986 1.41 agc #ifdef REFUSE_INHERIT_FS_CHARACTERISTICS
987 1.1 agc if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
988 1.1 agc return errno;
989 1.1 agc }
990 1.41 agc #else
991 1.41 agc (void) memset(svfsb, 0x0, sizeof(*svfsb));
992 1.41 agc ret = 0;
993 1.41 agc #endif
994 1.1 agc } else {
995 1.1 agc ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
996 1.1 agc }
997 1.1 agc
998 1.1 agc return ret;
999 1.1 agc }
1000 1.1 agc
1001 1.1 agc
1002 1.1 agc /* End of puffs_fuse operations */
1003 1.1 agc
1004 1.41 agc
1005 1.1 agc /* ARGSUSED3 */
1006 1.1 agc int
1007 1.1 agc fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
1008 1.1 agc size_t size, void *userdata)
1009 1.1 agc {
1010 1.41 agc struct fuse_chan *fc;
1011 1.41 agc struct fuse_args args;
1012 1.38 pooka struct fuse *fuse;
1013 1.38 pooka int ret;
1014 1.38 pooka
1015 1.41 agc (void) memset(&args, 0x0, sizeof(args));
1016 1.41 agc args.argc = argc;
1017 1.41 agc args.argv = argv;
1018 1.41 agc
1019 1.41 agc if (__fuse_debug(0)) {
1020 1.41 agc __fuse_pargs("fuse_main_real", argc, argv);
1021 1.38 pooka }
1022 1.41 agc fc = fuse_mount(argv[argc - 1], &args);
1023 1.38 pooka /* XXX: stuff name into fuse_args */
1024 1.41 agc fuse = fuse_new(fc, fc->args, ops, size, userdata);
1025 1.38 pooka
1026 1.38 pooka ret = fuse_loop(fuse);
1027 1.38 pooka
1028 1.38 pooka return ret;
1029 1.38 pooka }
1030 1.38 pooka
1031 1.38 pooka /*
1032 1.38 pooka * XXX: just defer the operation until fuse_new() when we have more
1033 1.38 pooka * info on our hands. The real beef is why's this separate in fuse in
1034 1.38 pooka * the first place?
1035 1.38 pooka */
1036 1.38 pooka /* ARGSUSED1 */
1037 1.38 pooka struct fuse_chan *
1038 1.38 pooka fuse_mount(const char *dir, struct fuse_args *args)
1039 1.38 pooka {
1040 1.41 agc struct fuse_chan *fc;
1041 1.41 agc int i;
1042 1.38 pooka
1043 1.41 agc NEW(struct fuse_chan, fc, "fuse_mount", return NULL);
1044 1.38 pooka
1045 1.38 pooka fc->dir = strdup(dir);
1046 1.41 agc
1047 1.41 agc if (args && args->argc > 0) {
1048 1.41 agc NEW(struct fuse_args, fc->args, "fuse_mount2", return NULL);
1049 1.41 agc
1050 1.41 agc /* yes, we do need to deep copy */
1051 1.41 agc fc->args->allocated = ((args->argc / 32) + 1) * 32;
1052 1.41 agc NEWARRAY(char *, fc->args->argv, fc->args->allocated, "fuse_mount3", return NULL);
1053 1.41 agc
1054 1.41 agc for (i = 0 ; i < args->argc ; i++) {
1055 1.41 agc fc->args->argv[i] = strdup(args->argv[i]);
1056 1.41 agc }
1057 1.41 agc }
1058 1.38 pooka
1059 1.38 pooka return fc;
1060 1.38 pooka }
1061 1.38 pooka
1062 1.38 pooka /* ARGSUSED1 */
1063 1.38 pooka struct fuse *
1064 1.38 pooka fuse_new(struct fuse_chan *fc, struct fuse_args *args,
1065 1.38 pooka const struct fuse_operations *ops, size_t size, void *userdata)
1066 1.38 pooka {
1067 1.1 agc struct puffs_usermount *pu;
1068 1.1 agc struct puffs_pathobj *po_root;
1069 1.41 agc struct refusenode *rn_root;
1070 1.1 agc struct puffs_ops *pops;
1071 1.1 agc struct statvfs svfsb;
1072 1.25 pooka struct stat st;
1073 1.1 agc struct fuse *fuse;
1074 1.41 agc char name[64];
1075 1.41 agc char *slash;
1076 1.38 pooka
1077 1.38 pooka NEW(struct fuse, fuse, "fuse_new", exit(EXIT_FAILURE));
1078 1.38 pooka
1079 1.38 pooka /* copy fuse ops to their own stucture */
1080 1.38 pooka (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
1081 1.38 pooka
1082 1.38 pooka fcon.fuse = fuse;
1083 1.38 pooka fcon.private_data = userdata;
1084 1.38 pooka
1085 1.38 pooka fuse->fc = fc;
1086 1.1 agc
1087 1.1 agc /* initialise the puffs operations structure */
1088 1.1 agc PUFFSOP_INIT(pops);
1089 1.1 agc
1090 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, sync);
1091 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
1092 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
1093 1.1 agc
1094 1.2 pooka /*
1095 1.2 pooka * XXX: all of these don't possibly need to be
1096 1.2 pooka * unconditionally set
1097 1.2 pooka */
1098 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, lookup);
1099 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, getattr);
1100 1.15 pooka PUFFSOP_SET(pops, puffs_fuse, node, setattr);
1101 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readdir);
1102 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readlink);
1103 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mknod);
1104 1.16 pooka PUFFSOP_SET(pops, puffs_fuse, node, create);
1105 1.15 pooka PUFFSOP_SET(pops, puffs_fuse, node, remove);
1106 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
1107 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
1108 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, symlink);
1109 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rename);
1110 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, link);
1111 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, open);
1112 1.31 pooka PUFFSOP_SET(pops, puffs_fuse, node, close);
1113 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, read);
1114 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, write);
1115 1.3 pooka PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
1116 1.1 agc
1117 1.41 agc /* work out what we'll call ourselves in df output */
1118 1.41 agc if (args == NULL) {
1119 1.41 agc args = fc->args;
1120 1.41 agc }
1121 1.41 agc if (args == NULL || args->argv == NULL || args->argv[0] == NULL) {
1122 1.41 agc (void) strlcpy(name, "refuse", sizeof(name));
1123 1.41 agc } else {
1124 1.41 agc if ((slash = strrchr(*args->argv, '/')) == NULL) {
1125 1.41 agc slash = *args->argv;
1126 1.41 agc } else {
1127 1.41 agc slash += 1;
1128 1.41 agc }
1129 1.41 agc (void) snprintf(name, sizeof(name), "refuse:%s", slash);
1130 1.41 agc }
1131 1.41 agc
1132 1.38 pooka pu = puffs_mount(pops, fc->dir, MNT_NODEV | MNT_NOSUID,
1133 1.41 agc name, NULL,
1134 1.38 pooka PUFFS_FLAG_BUILDPATH
1135 1.38 pooka | PUFFS_FLAG_OPDUMP
1136 1.38 pooka | PUFFS_KFLAG_NOCACHE,
1137 1.38 pooka 0);
1138 1.1 agc if (pu == NULL) {
1139 1.1 agc err(EXIT_FAILURE, "puffs_mount");
1140 1.1 agc }
1141 1.38 pooka fc->pu = pu;
1142 1.41 agc /* whilst this (assigning the pu_privdata in the puffs
1143 1.41 agc * usermount struct to be the fuse struct) might seem like
1144 1.41 agc * we are chasing our tail here, the logic is as follows:
1145 1.41 agc + the operation wrapper gets called with the puffs
1146 1.41 agc calling conventions
1147 1.41 agc + we need to fix up args first
1148 1.41 agc + then call the fuse user-supplied operation
1149 1.41 agc + then we fix up any values on return that we need to
1150 1.41 agc + and fix up any nodes, etc
1151 1.41 agc * so we need to be able to get at the fuse ops from within the
1152 1.41 agc * puffs_usermount struct
1153 1.41 agc */
1154 1.38 pooka pu->pu_privdata = fuse;
1155 1.1 agc
1156 1.30 pooka pu->pu_pn_root = newrn(pu);
1157 1.30 pooka rn_root = pu->pu_pn_root->pn_data;
1158 1.30 pooka rn_root->flags |= RN_ROOT;
1159 1.30 pooka
1160 1.1 agc po_root = puffs_getrootpathobj(pu);
1161 1.1 agc po_root->po_path = strdup("/");
1162 1.1 agc po_root->po_len = 1;
1163 1.1 agc
1164 1.25 pooka /* sane defaults */
1165 1.25 pooka puffs_vattr_null(&pu->pu_pn_root->pn_va);
1166 1.25 pooka pu->pu_pn_root->pn_va.va_type = VDIR;
1167 1.25 pooka pu->pu_pn_root->pn_va.va_mode = 0755;
1168 1.25 pooka if (fuse->op.getattr)
1169 1.25 pooka if (fuse->op.getattr(po_root->po_path, &st) == 0)
1170 1.25 pooka puffs_stat2vattr(&pu->pu_pn_root->pn_va, &st);
1171 1.25 pooka assert(pu->pu_pn_root->pn_va.va_type == VDIR);
1172 1.25 pooka
1173 1.11 pooka if (fuse->op.init)
1174 1.11 pooka fcon.private_data = fuse->op.init(NULL); /* XXX */
1175 1.11 pooka
1176 1.38 pooka puffs_zerostatvfs(&svfsb);
1177 1.1 agc if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
1178 1.1 agc err(EXIT_FAILURE, "puffs_start");
1179 1.1 agc }
1180 1.1 agc
1181 1.38 pooka return fuse;
1182 1.38 pooka }
1183 1.38 pooka
1184 1.38 pooka int
1185 1.38 pooka fuse_loop(struct fuse *fuse)
1186 1.38 pooka {
1187 1.38 pooka
1188 1.38 pooka return puffs_mainloop(fuse->fc->pu, PUFFSLOOP_NODAEMON);
1189 1.38 pooka }
1190 1.38 pooka
1191 1.38 pooka void
1192 1.38 pooka fuse_destroy(struct fuse *fuse)
1193 1.38 pooka {
1194 1.38 pooka
1195 1.1 agc
1196 1.38 pooka /* XXXXXX: missing stuff */
1197 1.1 agc FREE(fuse);
1198 1.1 agc }
1199 1.1 agc
1200 1.11 pooka /* XXX: threads */
1201 1.11 pooka struct fuse_context *
1202 1.11 pooka fuse_get_context()
1203 1.11 pooka {
1204 1.11 pooka
1205 1.11 pooka return &fcon;
1206 1.11 pooka }
1207 1.20 agc
1208 1.20 agc void
1209 1.38 pooka fuse_exit(struct fuse *fuse)
1210 1.20 agc {
1211 1.20 agc
1212 1.38 pooka puffs_exit(fuse->fc->pu, 1);
1213 1.20 agc }
1214 1.29 pooka
1215 1.29 pooka /*
1216 1.29 pooka * XXX: obviously not the most perfect of functions, but needs some
1217 1.29 pooka * puffs tweaking for a better tomorrow
1218 1.29 pooka */
1219 1.31 pooka /*ARGSUSED*/
1220 1.29 pooka void
1221 1.38 pooka fuse_unmount(const char *mp, struct fuse_chan *fc)
1222 1.38 pooka {
1223 1.38 pooka
1224 1.38 pooka puffs_exit(fc->pu, 1);
1225 1.38 pooka }
1226 1.38 pooka
1227 1.38 pooka /*ARGSUSED*/
1228 1.38 pooka void
1229 1.38 pooka fuse_unmount_compat22(const char *mp)
1230 1.29 pooka {
1231 1.29 pooka
1232 1.29 pooka return;
1233 1.29 pooka }
1234