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