refuse.c revision 1.2 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 puffs_node *pn = opc;
306 1.1 agc struct fuse *fuse;
307 1.1 agc const char *path = PCNPATH(pcn);
308 1.1 agc int ret;
309 1.1 agc
310 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
311 1.1 agc if (fuse->op.unlink == NULL) {
312 1.1 agc return ENOSYS;
313 1.1 agc }
314 1.1 agc
315 1.1 agc /* wrap up return code */
316 1.1 agc ret = (*fuse->op.unlink)(path);
317 1.1 agc
318 1.1 agc if (ret == 0) {
319 1.1 agc puffs_pn_put(pn);
320 1.1 agc }
321 1.1 agc
322 1.1 agc return ret;
323 1.1 agc }
324 1.1 agc
325 1.1 agc /* remove the directory */
326 1.1 agc /* ARGSUSED1 */
327 1.1 agc static int
328 1.1 agc puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
329 1.1 agc const struct puffs_cn *pcn)
330 1.1 agc {
331 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
332 1.1 agc struct puffs_node *pn = opc;
333 1.1 agc struct fuse *fuse;
334 1.1 agc const char *path = PCNPATH(pcn);
335 1.1 agc int ret;
336 1.1 agc
337 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
338 1.1 agc if (fuse->op.rmdir == NULL) {
339 1.1 agc return ENOSYS;
340 1.1 agc }
341 1.1 agc
342 1.1 agc /* wrap up return code */
343 1.1 agc ret = (*fuse->op.rmdir)(path);
344 1.1 agc
345 1.1 agc if (ret == 0) {
346 1.1 agc puffs_pn_put(pn);
347 1.1 agc }
348 1.1 agc
349 1.1 agc return ret;
350 1.1 agc }
351 1.1 agc
352 1.1 agc /* create a symbolic link */
353 1.1 agc /* ARGSUSED1 */
354 1.1 agc static int
355 1.1 agc puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
356 1.1 agc const struct puffs_cn *pcn_src, const struct vattr *va,
357 1.1 agc const char *link_target)
358 1.1 agc {
359 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
360 1.1 agc struct puffs_node *pn;
361 1.1 agc struct fuse *fuse;
362 1.1 agc const char *path = PCNPATH(pcn_src);
363 1.1 agc int ret;
364 1.1 agc
365 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
366 1.1 agc if (fuse->op.symlink == NULL) {
367 1.1 agc return ENOSYS;
368 1.1 agc }
369 1.1 agc
370 1.1 agc /* wrap up return code */
371 1.1 agc ret = (*fuse->op.symlink)(path, link_target);
372 1.1 agc /* XXX - check I haven't transposed these args */
373 1.1 agc
374 1.1 agc if (ret == 0) {
375 1.1 agc /* fix up nodes */
376 1.1 agc pn = puffs_pn_new(pu, NULL);
377 1.1 agc if (pn == NULL) {
378 1.1 agc unlink(link_target);
379 1.1 agc return ENOMEM;
380 1.1 agc }
381 1.1 agc puffs_setvattr(&pn->pn_va, va);
382 1.1 agc
383 1.1 agc *newnode = pn;
384 1.1 agc }
385 1.1 agc
386 1.1 agc return ret;
387 1.1 agc }
388 1.1 agc
389 1.1 agc /* rename a directory entry */
390 1.1 agc /* ARGSUSED1 */
391 1.1 agc static int
392 1.1 agc puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
393 1.1 agc const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
394 1.1 agc const struct puffs_cn *pcn_targ)
395 1.1 agc {
396 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
397 1.1 agc struct puffs_node *pn = opc;
398 1.1 agc struct vattr va;
399 1.1 agc struct fuse *fuse;
400 1.1 agc const char *path = PCNPATH(pcn_src);
401 1.1 agc int ret;
402 1.1 agc
403 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
404 1.1 agc if (fuse->op.rename == NULL) {
405 1.1 agc return ENOSYS;
406 1.1 agc }
407 1.1 agc
408 1.1 agc /* wrap up return code */
409 1.1 agc ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
410 1.1 agc
411 1.1 agc if (ret == 0) {
412 1.1 agc (void) memcpy(&va, &pn->pn_va, sizeof(va));
413 1.1 agc
414 1.1 agc puffs_pn_put(pn);
415 1.1 agc
416 1.1 agc pn = puffs_pn_new(pu, NULL);
417 1.1 agc if (pn == NULL) {
418 1.1 agc return ENOMEM;
419 1.1 agc }
420 1.1 agc puffs_setvattr(&pn->pn_va, &va);
421 1.1 agc
422 1.1 agc }
423 1.1 agc
424 1.1 agc return ret;
425 1.1 agc }
426 1.1 agc
427 1.1 agc /* create a link in the file system */
428 1.1 agc /* ARGSUSED1 */
429 1.1 agc static int
430 1.1 agc puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
431 1.1 agc const struct puffs_cn *pcn)
432 1.1 agc {
433 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
434 1.1 agc struct puffs_node *pn = targ;
435 1.1 agc struct fuse *fuse;
436 1.1 agc int ret;
437 1.1 agc
438 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
439 1.1 agc if (fuse->op.link == NULL) {
440 1.1 agc return ENOSYS;
441 1.1 agc }
442 1.1 agc
443 1.1 agc /* wrap up return code */
444 1.1 agc ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
445 1.1 agc
446 1.1 agc if (ret == 0) {
447 1.1 agc /* fix up nodes */
448 1.1 agc pn = puffs_pn_new(pu, NULL);
449 1.1 agc if (pn == NULL) {
450 1.1 agc unlink(PCNPATH(pcn));
451 1.1 agc return ENOMEM;
452 1.1 agc }
453 1.1 agc }
454 1.1 agc
455 1.1 agc return ret;
456 1.1 agc }
457 1.1 agc
458 1.1 agc /*
459 1.1 agc We run into a slight problemette here - puffs provides
460 1.1 agc setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
461 1.1 agc functionality. So that we don't miss out on anything when calling a
462 1.1 agc fuse operation, we have to get the vattr from the existing file,
463 1.1 agc find out what's changed, and then switch on that to call the fuse
464 1.1 agc function accordingly.
465 1.1 agc */
466 1.1 agc /* ARGSUSED3 */
467 1.1 agc static int
468 1.1 agc puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
469 1.1 agc const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
470 1.1 agc {
471 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
472 1.1 agc struct puffs_node *pn = opc;
473 1.1 agc struct fuse *fuse;
474 1.1 agc const char *path = PNPATH(pn);
475 1.1 agc mode_t mode;
476 1.1 agc uid_t uid;
477 1.1 agc gid_t gid;
478 1.1 agc int ret;
479 1.1 agc
480 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
481 1.1 agc
482 1.1 agc ret = -1;
483 1.1 agc
484 1.1 agc mode = va->va_mode;
485 1.1 agc uid = va->va_uid;
486 1.1 agc gid = va->va_gid;
487 1.1 agc
488 1.1 agc if (mode != 0) {
489 1.1 agc if (fuse->op.chmod == NULL) {
490 1.1 agc return ENOSYS;
491 1.1 agc }
492 1.1 agc ret = (*fuse->op.chmod)(path, mode);
493 1.1 agc }
494 1.1 agc if (uid != 0 || gid != 0) {
495 1.1 agc if (fuse->op.chown == NULL) {
496 1.1 agc return ENOSYS;
497 1.1 agc }
498 1.1 agc ret = (*fuse->op.chown)(path, uid, gid);
499 1.1 agc }
500 1.1 agc
501 1.1 agc if (ret == 0) {
502 1.1 agc }
503 1.1 agc
504 1.1 agc return ret;
505 1.1 agc }
506 1.1 agc
507 1.1 agc /* ARGSUSED2 */
508 1.1 agc static int
509 1.1 agc puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
510 1.1 agc const struct puffs_cred *cred, pid_t pid)
511 1.1 agc {
512 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
513 1.1 agc struct fuse_file_info file_info;
514 1.1 agc struct puffs_node *pn = opc;
515 1.1 agc struct fuse *fuse;
516 1.1 agc struct stat st;
517 1.1 agc const char *path = PNPATH(pn);
518 1.1 agc int ret;
519 1.1 agc
520 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
521 1.1 agc if (fuse->op.open == NULL) {
522 1.1 agc return ENOSYS;
523 1.1 agc }
524 1.1 agc
525 1.1 agc (void) memset(&file_info, 0x0, sizeof(file_info));
526 1.1 agc
527 1.1 agc /* examine type - if directory, return 0 rather than open */
528 1.1 agc ret = (fuse->op.getattr == NULL) ?
529 1.1 agc stat(path, &st) :
530 1.1 agc (*fuse->op.getattr)(path, &st);
531 1.1 agc if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
532 1.1 agc return 0;
533 1.1 agc }
534 1.1 agc
535 1.1 agc if (strcmp(path, "/") == 0) {
536 1.1 agc return 0;
537 1.1 agc }
538 1.1 agc
539 1.1 agc ret = (*fuse->op.open)(path, &file_info);
540 1.1 agc
541 1.1 agc if (ret == 0) {
542 1.1 agc }
543 1.1 agc
544 1.1 agc return ret;
545 1.1 agc }
546 1.1 agc
547 1.1 agc /* read some more from the file */
548 1.1 agc /* ARGSUSED5 */
549 1.1 agc static int
550 1.1 agc puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
551 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr,
552 1.1 agc int ioflag)
553 1.1 agc {
554 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
555 1.1 agc struct fuse_file_info file_info;
556 1.1 agc struct puffs_node *pn = opc;
557 1.1 agc struct fuse *fuse;
558 1.1 agc const char *path = PNPATH(pn);
559 1.1 agc int ret;
560 1.1 agc
561 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
562 1.1 agc if (fuse->op.read == NULL) {
563 1.1 agc return ENOSYS;
564 1.1 agc }
565 1.1 agc
566 1.1 agc (void) memset(&file_info, 0x0, sizeof(file_info));
567 1.1 agc /* XXX fill in file_info here */
568 1.1 agc
569 1.1 agc ret = (*fuse->op.read)(path, (char *)buf, *resid, offset, &file_info);
570 1.1 agc
571 1.1 agc if (ret > 0) {
572 1.1 agc *resid -= ret;
573 1.1 agc }
574 1.1 agc
575 1.1 agc return 0;
576 1.1 agc }
577 1.1 agc
578 1.1 agc /* write to the file */
579 1.1 agc /* ARGSUSED0 */
580 1.1 agc static int
581 1.1 agc puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
582 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr,
583 1.1 agc int ioflag)
584 1.1 agc {
585 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
586 1.1 agc struct fuse_file_info file_info;
587 1.1 agc struct puffs_node *pn = opc;
588 1.1 agc struct fuse *fuse;
589 1.1 agc const char *path = PNPATH(pn);
590 1.1 agc int ret;
591 1.1 agc
592 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
593 1.1 agc if (fuse->op.write == NULL) {
594 1.1 agc return ENOSYS;
595 1.1 agc }
596 1.1 agc
597 1.1 agc (void) memset(&file_info, 0x0, sizeof(file_info));
598 1.1 agc
599 1.1 agc /* XXX fill in file_info here */
600 1.1 agc
601 1.1 agc ret = (*fuse->op.write)(path, (char *)buf, *resid, offset, &file_info);
602 1.1 agc
603 1.1 agc if (ret > 0) {
604 1.1 agc *resid -= ret;
605 1.1 agc }
606 1.1 agc
607 1.1 agc return ret;
608 1.1 agc }
609 1.1 agc
610 1.1 agc
611 1.1 agc /* ARGSUSED3 */
612 1.1 agc static int
613 1.1 agc puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
614 1.1 agc struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
615 1.1 agc size_t *reslen)
616 1.1 agc {
617 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
618 1.1 agc struct fuse_file_info file_info;
619 1.1 agc struct puffs_node *pn = opc;
620 1.1 agc struct fuse *fuse;
621 1.1 agc const char *path = PNPATH(pn);
622 1.1 agc struct feh feh; /* XXX */
623 1.1 agc int ret;
624 1.1 agc
625 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
626 1.1 agc if (fuse->op.readdir == NULL) {
627 1.1 agc return ENOSYS;
628 1.1 agc }
629 1.1 agc
630 1.1 agc /* XXX: how to handle this??? */
631 1.1 agc if (*readoff != 0) {
632 1.1 agc return 0;
633 1.1 agc }
634 1.1 agc
635 1.1 agc (void) memset(&file_info, 0x0, sizeof(file_info));
636 1.1 agc /* XXX - fill in file_info here */
637 1.1 agc
638 1.1 agc feh.dent = dent;
639 1.1 agc feh.reslen = *reslen;
640 1.1 agc ret = (*fuse->op.readdir)(path, &feh, puffs_fuse_dirfiller, *readoff, &file_info);
641 1.1 agc *reslen = feh.reslen;
642 1.1 agc *readoff = 1;
643 1.1 agc
644 1.1 agc if (ret == 0) {
645 1.1 agc }
646 1.1 agc
647 1.1 agc return ret;
648 1.1 agc }
649 1.1 agc
650 1.1 agc /* ARGSUSED1 */
651 1.1 agc static int
652 1.1 agc puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
653 1.1 agc {
654 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
655 1.1 agc struct fuse *fuse;
656 1.1 agc
657 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
658 1.1 agc if (fuse->op.destroy == NULL) {
659 1.2 pooka return 0;
660 1.1 agc }
661 1.1 agc (*fuse->op.destroy)(fuse);
662 1.1 agc return 0;
663 1.1 agc }
664 1.1 agc
665 1.1 agc /* ARGSUSED0 */
666 1.1 agc static int
667 1.1 agc puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
668 1.1 agc const struct puffs_cred *cr, pid_t pid)
669 1.1 agc {
670 1.1 agc return 0;
671 1.1 agc }
672 1.1 agc
673 1.1 agc /* ARGSUSED2 */
674 1.1 agc static int
675 1.1 agc puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
676 1.1 agc {
677 1.1 agc struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
678 1.1 agc struct fuse *fuse;
679 1.1 agc int ret;
680 1.1 agc
681 1.1 agc fuse = (struct fuse *)pu->pu_privdata;
682 1.1 agc if (fuse->op.statfs == NULL) {
683 1.1 agc if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
684 1.1 agc return errno;
685 1.1 agc }
686 1.1 agc } else {
687 1.1 agc ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
688 1.1 agc }
689 1.1 agc
690 1.1 agc return ret;
691 1.1 agc }
692 1.1 agc
693 1.1 agc
694 1.1 agc
695 1.1 agc
696 1.1 agc /* End of puffs_fuse operations */
697 1.1 agc
698 1.1 agc /* ARGSUSED3 */
699 1.1 agc int
700 1.1 agc fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
701 1.1 agc size_t size, void *userdata)
702 1.1 agc {
703 1.1 agc struct puffs_usermount *pu;
704 1.1 agc struct puffs_pathobj *po_root;
705 1.1 agc struct puffs_ops *pops;
706 1.1 agc struct statvfs svfsb;
707 1.1 agc struct fuse *fuse;
708 1.1 agc char name[64];
709 1.1 agc char *slash;
710 1.1 agc int ret;
711 1.1 agc
712 1.1 agc /* initialise the puffs operations structure */
713 1.1 agc PUFFSOP_INIT(pops);
714 1.1 agc
715 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, sync);
716 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
717 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
718 1.1 agc
719 1.2 pooka /*
720 1.2 pooka * XXX: all of these don't possibly need to be
721 1.2 pooka * unconditionally set
722 1.2 pooka */
723 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, lookup);
724 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, getattr);
725 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readdir);
726 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readlink);
727 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mknod);
728 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
729 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, remove);
730 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
731 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, symlink);
732 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rename);
733 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, link);
734 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, setattr);
735 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, open);
736 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, read);
737 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, write);
738 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readdir);
739 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, read);
740 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, write);
741 1.2 pooka /* XXX: reclaim is missing */
742 1.1 agc
743 1.1 agc NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
744 1.1 agc
745 1.1 agc /* copy fuse ops to their own stucture */
746 1.1 agc (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
747 1.1 agc
748 1.1 agc /* whilst this (assigning the pu_privdata in the puffs
749 1.1 agc * usermount struct to be the fuse struct) might seem like
750 1.1 agc * we are chasing our tail here, the logic is as follows:
751 1.1 agc + the operation wrapper gets called with the puffs
752 1.1 agc calling conventions
753 1.1 agc + we need to fix up args first
754 1.1 agc + then call the fuse user-supplied operation
755 1.1 agc + then we fix up any values on return that we need to
756 1.1 agc + and fix up any nodes, etc
757 1.1 agc * so we need to be able to get at the fuse ops from within the
758 1.1 agc * puffs_usermount struct
759 1.1 agc */
760 1.1 agc if ((slash = strrchr(*argv, '/')) == NULL) {
761 1.1 agc slash = *argv;
762 1.1 agc } else {
763 1.1 agc slash += 1;
764 1.1 agc }
765 1.1 agc (void) snprintf(name, sizeof(name), "refuse:%s", slash);
766 1.1 agc pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
767 1.1 agc name, fuse,
768 1.1 agc PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
769 1.1 agc if (pu == NULL) {
770 1.1 agc err(EXIT_FAILURE, "puffs_mount");
771 1.1 agc }
772 1.1 agc
773 1.1 agc fuse->pu = pu;
774 1.1 agc pu->pu_pn_root = puffs_pn_new(pu, NULL);
775 1.1 agc po_root = puffs_getrootpathobj(pu);
776 1.1 agc po_root->po_path = strdup("/");
777 1.1 agc po_root->po_len = 1;
778 1.1 agc
779 1.1 agc statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
780 1.1 agc if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
781 1.1 agc err(EXIT_FAILURE, "puffs_start");
782 1.1 agc }
783 1.1 agc
784 1.1 agc ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
785 1.1 agc
786 1.1 agc (void) free(po_root->po_path);
787 1.1 agc FREE(fuse);
788 1.1 agc return ret;
789 1.1 agc }
790 1.1 agc
791 1.1 agc /* ARGSUSED0 */
792 1.1 agc int
793 1.1 agc fuse_opt_parse(struct fuse_args *args, void *data,
794 1.1 agc const struct fuse_opt *opts, fuse_opt_proc_t proc)
795 1.1 agc {
796 1.1 agc return 0;
797 1.1 agc }
798