2 fuse subdir module: offset paths with a base directory
3 Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB
9 #define FUSE_USE_VERSION 26
25 static struct subdir
*subdir_get(void)
27 return fuse_get_context()->private_data
;
30 static int subdir_addpath(struct subdir
*d
, const char *path
, char **newpathp
)
35 unsigned newlen
= d
->baselen
+ strlen(path
);
37 newpath
= malloc(newlen
+ 2);
43 strcpy(newpath
, d
->base
);
44 strcpy(newpath
+ d
->baselen
, path
);
53 static int subdir_getattr(const char *path
, struct stat
*stbuf
)
55 struct subdir
*d
= subdir_get();
57 int err
= subdir_addpath(d
, path
, &newpath
);
59 err
= fuse_fs_getattr(d
->next
, newpath
, stbuf
);
65 static int subdir_fgetattr(const char *path
, struct stat
*stbuf
,
66 struct fuse_file_info
*fi
)
68 struct subdir
*d
= subdir_get();
70 int err
= subdir_addpath(d
, path
, &newpath
);
72 err
= fuse_fs_fgetattr(d
->next
, newpath
, stbuf
, fi
);
78 static int subdir_access(const char *path
, int mask
)
80 struct subdir
*d
= subdir_get();
82 int err
= subdir_addpath(d
, path
, &newpath
);
84 err
= fuse_fs_access(d
->next
, newpath
, mask
);
91 static int count_components(const char *p
)
95 for (; *p
== '/'; p
++);
96 for (ctr
= 0; *p
; ctr
++) {
97 for (; *p
&& *p
!= '/'; p
++);
98 for (; *p
== '/'; p
++);
103 static void strip_common(const char **sp
, const char **tp
)
108 for (; *s
== '/'; s
++);
109 for (; *t
== '/'; t
++);
112 for (; *s
== *t
&& *s
&& *s
!= '/'; s
++, t
++);
113 } while ((*s
== *t
&& *s
) || (!*s
&& *t
== '/') || (*s
== '/' && !*t
));
116 static void transform_symlink(struct subdir
*d
, const char *path
,
117 char *buf
, size_t size
)
125 if (l
[0] != '/' || d
->base
[0] != '/')
128 strip_common(&l
, &path
);
129 if (l
- buf
< (long) d
->baselen
)
132 dotdots
= count_components(path
);
138 if (dotdots
* 3 + llen
+ 2 > size
)
141 s
= buf
+ dotdots
* 3;
143 memmove(s
, l
, llen
+ 1);
149 for (s
= buf
, i
= 0; i
< dotdots
; i
++, s
+= 3)
154 static int subdir_readlink(const char *path
, char *buf
, size_t size
)
156 struct subdir
*d
= subdir_get();
158 int err
= subdir_addpath(d
, path
, &newpath
);
160 err
= fuse_fs_readlink(d
->next
, newpath
, buf
, size
);
161 if (!err
&& d
->rellinks
)
162 transform_symlink(d
, newpath
, buf
, size
);
168 static int subdir_opendir(const char *path
, struct fuse_file_info
*fi
)
170 struct subdir
*d
= subdir_get();
172 int err
= subdir_addpath(d
, path
, &newpath
);
174 err
= fuse_fs_opendir(d
->next
, newpath
, fi
);
180 static int subdir_readdir(const char *path
, void *buf
,
181 fuse_fill_dir_t filler
, off_t offset
,
182 struct fuse_file_info
*fi
)
184 struct subdir
*d
= subdir_get();
186 int err
= subdir_addpath(d
, path
, &newpath
);
188 err
= fuse_fs_readdir(d
->next
, newpath
, buf
, filler
, offset
,
195 static int subdir_releasedir(const char *path
, struct fuse_file_info
*fi
)
197 struct subdir
*d
= subdir_get();
199 int err
= subdir_addpath(d
, path
, &newpath
);
201 err
= fuse_fs_releasedir(d
->next
, newpath
, fi
);
207 static int subdir_mknod(const char *path
, mode_t mode
, dev_t rdev
)
209 struct subdir
*d
= subdir_get();
211 int err
= subdir_addpath(d
, path
, &newpath
);
213 err
= fuse_fs_mknod(d
->next
, newpath
, mode
, rdev
);
219 static int subdir_mkdir(const char *path
, mode_t mode
)
221 struct subdir
*d
= subdir_get();
223 int err
= subdir_addpath(d
, path
, &newpath
);
225 err
= fuse_fs_mkdir(d
->next
, newpath
, mode
);
231 static int subdir_unlink(const char *path
)
233 struct subdir
*d
= subdir_get();
235 int err
= subdir_addpath(d
, path
, &newpath
);
237 err
= fuse_fs_unlink(d
->next
, newpath
);
243 static int subdir_rmdir(const char *path
)
245 struct subdir
*d
= subdir_get();
247 int err
= subdir_addpath(d
, path
, &newpath
);
249 err
= fuse_fs_rmdir(d
->next
, newpath
);
255 static int subdir_symlink(const char *from
, const char *path
)
257 struct subdir
*d
= subdir_get();
259 int err
= subdir_addpath(d
, path
, &newpath
);
261 err
= fuse_fs_symlink(d
->next
, from
, newpath
);
267 static int subdir_rename(const char *from
, const char *to
)
269 struct subdir
*d
= subdir_get();
272 int err
= subdir_addpath(d
, from
, &newfrom
);
274 err
= subdir_addpath(d
, to
, &newto
);
276 err
= fuse_fs_rename(d
->next
, newfrom
, newto
);
284 static int subdir_link(const char *from
, const char *to
)
286 struct subdir
*d
= subdir_get();
289 int err
= subdir_addpath(d
, from
, &newfrom
);
291 err
= subdir_addpath(d
, to
, &newto
);
293 err
= fuse_fs_link(d
->next
, newfrom
, newto
);
301 static int subdir_chmod(const char *path
, mode_t mode
)
303 struct subdir
*d
= subdir_get();
305 int err
= subdir_addpath(d
, path
, &newpath
);
307 err
= fuse_fs_chmod(d
->next
, newpath
, mode
);
313 static int subdir_chown(const char *path
, uid_t uid
, gid_t gid
)
315 struct subdir
*d
= subdir_get();
317 int err
= subdir_addpath(d
, path
, &newpath
);
319 err
= fuse_fs_chown(d
->next
, newpath
, uid
, gid
);
325 static int subdir_truncate(const char *path
, off_t size
)
327 struct subdir
*d
= subdir_get();
329 int err
= subdir_addpath(d
, path
, &newpath
);
331 err
= fuse_fs_truncate(d
->next
, newpath
, size
);
337 static int subdir_ftruncate(const char *path
, off_t size
,
338 struct fuse_file_info
*fi
)
340 struct subdir
*d
= subdir_get();
342 int err
= subdir_addpath(d
, path
, &newpath
);
344 err
= fuse_fs_ftruncate(d
->next
, newpath
, size
, fi
);
350 static int subdir_utimens(const char *path
, const struct timespec ts
[2])
352 struct subdir
*d
= subdir_get();
354 int err
= subdir_addpath(d
, path
, &newpath
);
356 err
= fuse_fs_utimens(d
->next
, newpath
, ts
);
362 static int subdir_create(const char *path
, mode_t mode
,
363 struct fuse_file_info
*fi
)
365 struct subdir
*d
= subdir_get();
367 int err
= subdir_addpath(d
, path
, &newpath
);
369 err
= fuse_fs_create(d
->next
, newpath
, mode
, fi
);
375 static int subdir_open(const char *path
, struct fuse_file_info
*fi
)
377 struct subdir
*d
= subdir_get();
379 int err
= subdir_addpath(d
, path
, &newpath
);
381 err
= fuse_fs_open(d
->next
, newpath
, fi
);
387 static int subdir_read_buf(const char *path
, struct fuse_bufvec
**bufp
,
388 size_t size
, off_t offset
, struct fuse_file_info
*fi
)
390 struct subdir
*d
= subdir_get();
392 int err
= subdir_addpath(d
, path
, &newpath
);
394 err
= fuse_fs_read_buf(d
->next
, newpath
, bufp
, size
, offset
, fi
);
400 static int subdir_write_buf(const char *path
, struct fuse_bufvec
*buf
,
401 off_t offset
, struct fuse_file_info
*fi
)
403 struct subdir
*d
= subdir_get();
405 int err
= subdir_addpath(d
, path
, &newpath
);
407 err
= fuse_fs_write_buf(d
->next
, newpath
, buf
, offset
, fi
);
413 static int subdir_statfs(const char *path
, struct statvfs
*stbuf
)
415 struct subdir
*d
= subdir_get();
417 int err
= subdir_addpath(d
, path
, &newpath
);
419 err
= fuse_fs_statfs(d
->next
, newpath
, stbuf
);
425 static int subdir_flush(const char *path
, struct fuse_file_info
*fi
)
427 struct subdir
*d
= subdir_get();
429 int err
= subdir_addpath(d
, path
, &newpath
);
431 err
= fuse_fs_flush(d
->next
, newpath
, fi
);
437 static int subdir_release(const char *path
, struct fuse_file_info
*fi
)
439 struct subdir
*d
= subdir_get();
441 int err
= subdir_addpath(d
, path
, &newpath
);
443 err
= fuse_fs_release(d
->next
, newpath
, fi
);
449 static int subdir_fsync(const char *path
, int isdatasync
,
450 struct fuse_file_info
*fi
)
452 struct subdir
*d
= subdir_get();
454 int err
= subdir_addpath(d
, path
, &newpath
);
456 err
= fuse_fs_fsync(d
->next
, newpath
, isdatasync
, fi
);
462 static int subdir_fsyncdir(const char *path
, int isdatasync
,
463 struct fuse_file_info
*fi
)
465 struct subdir
*d
= subdir_get();
467 int err
= subdir_addpath(d
, path
, &newpath
);
469 err
= fuse_fs_fsyncdir(d
->next
, newpath
, isdatasync
, fi
);
475 static int subdir_setxattr(const char *path
, const char *name
,
476 const char *value
, size_t size
, int flags
)
478 struct subdir
*d
= subdir_get();
480 int err
= subdir_addpath(d
, path
, &newpath
);
482 err
= fuse_fs_setxattr(d
->next
, newpath
, name
, value
, size
,
489 static int subdir_getxattr(const char *path
, const char *name
, char *value
,
492 struct subdir
*d
= subdir_get();
494 int err
= subdir_addpath(d
, path
, &newpath
);
496 err
= fuse_fs_getxattr(d
->next
, newpath
, name
, value
, size
);
502 static int subdir_listxattr(const char *path
, char *list
, size_t size
)
504 struct subdir
*d
= subdir_get();
506 int err
= subdir_addpath(d
, path
, &newpath
);
508 err
= fuse_fs_listxattr(d
->next
, newpath
, list
, size
);
514 static int subdir_removexattr(const char *path
, const char *name
)
516 struct subdir
*d
= subdir_get();
518 int err
= subdir_addpath(d
, path
, &newpath
);
520 err
= fuse_fs_removexattr(d
->next
, newpath
, name
);
526 static int subdir_lock(const char *path
, struct fuse_file_info
*fi
, int cmd
,
529 struct subdir
*d
= subdir_get();
531 int err
= subdir_addpath(d
, path
, &newpath
);
533 err
= fuse_fs_lock(d
->next
, newpath
, fi
, cmd
, lock
);
539 static int subdir_flock(const char *path
, struct fuse_file_info
*fi
, int op
)
541 struct subdir
*d
= subdir_get();
543 int err
= subdir_addpath(d
, path
, &newpath
);
545 err
= fuse_fs_flock(d
->next
, newpath
, fi
, op
);
551 static int subdir_bmap(const char *path
, size_t blocksize
, uint64_t *idx
)
553 struct subdir
*d
= subdir_get();
555 int err
= subdir_addpath(d
, path
, &newpath
);
557 err
= fuse_fs_bmap(d
->next
, newpath
, blocksize
, idx
);
563 static void *subdir_init(struct fuse_conn_info
*conn
)
565 struct subdir
*d
= subdir_get();
566 fuse_fs_init(d
->next
, conn
);
570 static void subdir_destroy(void *data
)
572 struct subdir
*d
= data
;
573 fuse_fs_destroy(d
->next
);
578 static const struct fuse_operations subdir_oper
= {
579 .destroy
= subdir_destroy
,
581 .getattr
= subdir_getattr
,
582 .fgetattr
= subdir_fgetattr
,
583 .access
= subdir_access
,
584 .readlink
= subdir_readlink
,
585 .opendir
= subdir_opendir
,
586 .readdir
= subdir_readdir
,
587 .releasedir
= subdir_releasedir
,
588 .mknod
= subdir_mknod
,
589 .mkdir
= subdir_mkdir
,
590 .symlink
= subdir_symlink
,
591 .unlink
= subdir_unlink
,
592 .rmdir
= subdir_rmdir
,
593 .rename
= subdir_rename
,
595 .chmod
= subdir_chmod
,
596 .chown
= subdir_chown
,
597 .truncate
= subdir_truncate
,
598 .ftruncate
= subdir_ftruncate
,
599 .utimens
= subdir_utimens
,
600 .create
= subdir_create
,
602 .read_buf
= subdir_read_buf
,
603 .write_buf
= subdir_write_buf
,
604 .statfs
= subdir_statfs
,
605 .flush
= subdir_flush
,
606 .release
= subdir_release
,
607 .fsync
= subdir_fsync
,
608 .fsyncdir
= subdir_fsyncdir
,
609 .setxattr
= subdir_setxattr
,
610 .getxattr
= subdir_getxattr
,
611 .listxattr
= subdir_listxattr
,
612 .removexattr
= subdir_removexattr
,
614 .flock
= subdir_flock
,
617 .flag_nullpath_ok
= 1,
621 static const struct fuse_opt subdir_opts
[] = {
622 FUSE_OPT_KEY("-h", 0),
623 FUSE_OPT_KEY("--help", 0),
624 { "subdir=%s", offsetof(struct subdir
, base
), 0 },
625 { "rellinks", offsetof(struct subdir
, rellinks
), 1 },
626 { "norellinks", offsetof(struct subdir
, rellinks
), 0 },
630 static void subdir_help(void)
633 " -o subdir=DIR prepend this directory to all paths (mandatory)\n"
634 " -o [no]rellinks transform absolute symlinks to relative\n");
637 static int subdir_opt_proc(void *data
, const char *arg
, int key
,
638 struct fuse_args
*outargs
)
640 (void) data
; (void) arg
; (void) outargs
;
650 static struct fuse_fs
*subdir_new(struct fuse_args
*args
,
651 struct fuse_fs
*next
[])
656 d
= calloc(1, sizeof(struct subdir
));
658 fprintf(stderr
, "fuse-subdir: memory allocation failed\n");
662 if (fuse_opt_parse(args
, d
, subdir_opts
, subdir_opt_proc
) == -1)
665 if (!next
[0] || next
[1]) {
666 fprintf(stderr
, "fuse-subdir: exactly one next filesystem required\n");
671 fprintf(stderr
, "fuse-subdir: missing 'subdir' option\n");
675 if (d
->base
[0] && d
->base
[strlen(d
->base
)-1] != '/') {
676 char *tmp
= realloc(d
->base
, strlen(d
->base
) + 2);
678 fprintf(stderr
, "fuse-subdir: memory allocation failed\n");
682 strcat(d
->base
, "/");
684 d
->baselen
= strlen(d
->base
);
686 fs
= fuse_fs_new(&subdir_oper
, sizeof(subdir_oper
), d
);
697 FUSE_REGISTER_MODULE(subdir
, subdir_new
);