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