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