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);