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