9#include <fuse_config.h>
25static struct subdir *subdir_get(
void)
30static 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);
53static int subdir_getattr(
const char *path,
struct stat *stbuf,
56 struct subdir *d = subdir_get();
58 int err = subdir_addpath(d, path, &newpath);
60 err = fuse_fs_getattr(d->next, newpath, stbuf, fi);
66static int subdir_access(
const char *path,
int mask)
68 struct subdir *d = subdir_get();
70 int err = subdir_addpath(d, path, &newpath);
72 err = fuse_fs_access(d->next, newpath, mask);
79static int count_components(
const char *p)
83 for (; *p ==
'/'; p++);
84 for (ctr = 0; *p; ctr++) {
85 for (; *p && *p !=
'/'; p++);
86 for (; *p ==
'/'; p++);
91static void strip_common(
const char **sp,
const char **tp)
96 for (; *s ==
'/'; s++);
97 for (; *t ==
'/'; t++);
100 for (; *s == *t && *s && *s !=
'/'; s++, t++);
101 }
while ((*s == *t && *s) || (!*s && *t ==
'/') || (*s ==
'/' && !*t));
104static void transform_symlink(
struct subdir *d,
const char *path,
105 char *buf,
size_t size)
113 if (l[0] !=
'/' || d->base[0] !=
'/')
116 strip_common(&l, &path);
117 if (l - buf < (
long) d->baselen)
120 dotdots = count_components(path);
126 if (dotdots * 3 + llen + 2 > size)
129 s = buf + dotdots * 3;
131 memmove(s, l, llen + 1);
137 for (s = buf, i = 0; i < dotdots; i++, s += 3)
142static int subdir_readlink(
const char *path,
char *buf,
size_t size)
144 struct subdir *d = subdir_get();
146 int err = subdir_addpath(d, path, &newpath);
148 err = fuse_fs_readlink(d->next, newpath, buf, size);
149 if (!err && d->rellinks)
150 transform_symlink(d, newpath, buf, size);
156static int subdir_opendir(
const char *path,
struct fuse_file_info *fi)
158 struct subdir *d = subdir_get();
160 int err = subdir_addpath(d, path, &newpath);
162 err = fuse_fs_opendir(d->next, newpath, fi);
168static int subdir_readdir(
const char *path,
void *buf,
173 struct subdir *d = subdir_get();
175 int err = subdir_addpath(d, path, &newpath);
177 err = fuse_fs_readdir(d->next, newpath, buf, filler, offset,
184static int subdir_releasedir(
const char *path,
struct fuse_file_info *fi)
186 struct subdir *d = subdir_get();
188 int err = subdir_addpath(d, path, &newpath);
190 err = fuse_fs_releasedir(d->next, newpath, fi);
196static int subdir_mknod(
const char *path, mode_t mode, dev_t rdev)
198 struct subdir *d = subdir_get();
200 int err = subdir_addpath(d, path, &newpath);
202 err = fuse_fs_mknod(d->next, newpath, mode, rdev);
208static int subdir_mkdir(
const char *path, mode_t mode)
210 struct subdir *d = subdir_get();
212 int err = subdir_addpath(d, path, &newpath);
214 err = fuse_fs_mkdir(d->next, newpath, mode);
220static int subdir_unlink(
const char *path)
222 struct subdir *d = subdir_get();
224 int err = subdir_addpath(d, path, &newpath);
226 err = fuse_fs_unlink(d->next, newpath);
232static int subdir_rmdir(
const char *path)
234 struct subdir *d = subdir_get();
236 int err = subdir_addpath(d, path, &newpath);
238 err = fuse_fs_rmdir(d->next, newpath);
244static int subdir_symlink(
const char *from,
const char *path)
246 struct subdir *d = subdir_get();
248 int err = subdir_addpath(d, path, &newpath);
250 err = fuse_fs_symlink(d->next, from, newpath);
256static int subdir_rename(
const char *from,
const char *to,
unsigned int flags)
258 struct subdir *d = subdir_get();
261 int err = subdir_addpath(d, from, &newfrom);
263 err = subdir_addpath(d, to, &newto);
265 err = fuse_fs_rename(d->next, newfrom, newto, flags);
273static int subdir_link(
const char *from,
const char *to)
275 struct subdir *d = subdir_get();
278 int err = subdir_addpath(d, from, &newfrom);
280 err = subdir_addpath(d, to, &newto);
282 err = fuse_fs_link(d->next, newfrom, newto);
290static int subdir_chmod(
const char *path, mode_t mode,
293 struct subdir *d = subdir_get();
295 int err = subdir_addpath(d, path, &newpath);
297 err = fuse_fs_chmod(d->next, newpath, mode, fi);
303static int subdir_chown(
const char *path, uid_t uid, gid_t gid,
306 struct subdir *d = subdir_get();
308 int err = subdir_addpath(d, path, &newpath);
310 err = fuse_fs_chown(d->next, newpath, uid, gid, fi);
316static int subdir_truncate(
const char *path, off_t size,
319 struct subdir *d = subdir_get();
321 int err = subdir_addpath(d, path, &newpath);
323 err = fuse_fs_truncate(d->next, newpath, size, fi);
329static int subdir_utimens(
const char *path,
const struct timespec ts[2],
332 struct subdir *d = subdir_get();
334 int err = subdir_addpath(d, path, &newpath);
336 err = fuse_fs_utimens(d->next, newpath, ts, fi);
342static int subdir_create(
const char *path, mode_t mode,
345 struct subdir *d = subdir_get();
347 int err = subdir_addpath(d, path, &newpath);
349 err = fuse_fs_create(d->next, newpath, mode, fi);
355static int subdir_open(
const char *path,
struct fuse_file_info *fi)
357 struct subdir *d = subdir_get();
359 int err = subdir_addpath(d, path, &newpath);
361 err = fuse_fs_open(d->next, newpath, fi);
367static int subdir_read_buf(
const char *path,
struct fuse_bufvec **bufp,
370 struct subdir *d = subdir_get();
372 int err = subdir_addpath(d, path, &newpath);
374 err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
380static int subdir_write_buf(
const char *path,
struct fuse_bufvec *buf,
383 struct subdir *d = subdir_get();
385 int err = subdir_addpath(d, path, &newpath);
387 err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
393static int subdir_statfs(
const char *path,
struct statvfs *stbuf)
395 struct subdir *d = subdir_get();
397 int err = subdir_addpath(d, path, &newpath);
399 err = fuse_fs_statfs(d->next, newpath, stbuf);
405static int subdir_flush(
const char *path,
struct fuse_file_info *fi)
407 struct subdir *d = subdir_get();
409 int err = subdir_addpath(d, path, &newpath);
411 err = fuse_fs_flush(d->next, newpath, fi);
417static int subdir_release(
const char *path,
struct fuse_file_info *fi)
419 struct subdir *d = subdir_get();
421 int err = subdir_addpath(d, path, &newpath);
423 err = fuse_fs_release(d->next, newpath, fi);
429static int subdir_fsync(
const char *path,
int isdatasync,
432 struct subdir *d = subdir_get();
434 int err = subdir_addpath(d, path, &newpath);
436 err = fuse_fs_fsync(d->next, newpath, isdatasync, fi);
442static int subdir_fsyncdir(
const char *path,
int isdatasync,
445 struct subdir *d = subdir_get();
447 int err = subdir_addpath(d, path, &newpath);
449 err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi);
455static int subdir_setxattr(
const char *path,
const char *name,
456 const char *value,
size_t size,
int flags)
458 struct subdir *d = subdir_get();
460 int err = subdir_addpath(d, path, &newpath);
462 err = fuse_fs_setxattr(d->next, newpath, name, value, size,
469static int subdir_getxattr(
const char *path,
const char *name,
char *value,
472 struct subdir *d = subdir_get();
474 int err = subdir_addpath(d, path, &newpath);
476 err = fuse_fs_getxattr(d->next, newpath, name, value, size);
482static int subdir_listxattr(
const char *path,
char *list,
size_t size)
484 struct subdir *d = subdir_get();
486 int err = subdir_addpath(d, path, &newpath);
488 err = fuse_fs_listxattr(d->next, newpath, list, size);
494static int subdir_removexattr(
const char *path,
const char *name)
496 struct subdir *d = subdir_get();
498 int err = subdir_addpath(d, path, &newpath);
500 err = fuse_fs_removexattr(d->next, newpath, name);
506static int subdir_lock(
const char *path,
struct fuse_file_info *fi,
int cmd,
509 struct subdir *d = subdir_get();
511 int err = subdir_addpath(d, path, &newpath);
513 err = fuse_fs_lock(d->next, newpath, fi, cmd, lock);
519static int subdir_flock(
const char *path,
struct fuse_file_info *fi,
int op)
521 struct subdir *d = subdir_get();
523 int err = subdir_addpath(d, path, &newpath);
525 err = fuse_fs_flock(d->next, newpath, fi, op);
531static int subdir_bmap(
const char *path,
size_t blocksize, uint64_t *idx)
533 struct subdir *d = subdir_get();
535 int err = subdir_addpath(d, path, &newpath);
537 err = fuse_fs_bmap(d->next, newpath, blocksize, idx);
543static off_t subdir_lseek(
const char *path, off_t off,
int whence,
546 struct subdir *ic = subdir_get();
548 int res = subdir_addpath(ic, path, &newpath);
550 res = fuse_fs_lseek(ic->next, newpath, off, whence, fi);
559 struct subdir *d = subdir_get();
560 fuse_fs_init(d->next, conn, cfg);
566static void subdir_destroy(
void *data)
568 struct subdir *d = data;
569 fuse_fs_destroy(d->next);
577 .getattr = subdir_getattr,
578 .access = subdir_access,
579 .readlink = subdir_readlink,
580 .opendir = subdir_opendir,
581 .readdir = subdir_readdir,
582 .releasedir = subdir_releasedir,
583 .mknod = subdir_mknod,
584 .mkdir = subdir_mkdir,
585 .symlink = subdir_symlink,
586 .unlink = subdir_unlink,
587 .rmdir = subdir_rmdir,
588 .rename = subdir_rename,
590 .chmod = subdir_chmod,
591 .chown = subdir_chown,
592 .truncate = subdir_truncate,
593 .utimens = subdir_utimens,
594 .create = subdir_create,
596 .read_buf = subdir_read_buf,
597 .write_buf = subdir_write_buf,
598 .statfs = subdir_statfs,
599 .flush = subdir_flush,
600 .release = subdir_release,
601 .fsync = subdir_fsync,
602 .fsyncdir = subdir_fsyncdir,
603 .setxattr = subdir_setxattr,
604 .getxattr = subdir_getxattr,
605 .listxattr = subdir_listxattr,
606 .removexattr = subdir_removexattr,
608 .flock = subdir_flock,
610 .lseek = subdir_lseek,
613static const struct fuse_opt subdir_opts[] = {
616 {
"subdir=%s", offsetof(
struct subdir, base), 0 },
617 {
"rellinks", offsetof(
struct subdir, rellinks), 1 },
618 {
"norellinks", offsetof(
struct subdir, rellinks), 0 },
622static void subdir_help(
void)
625" -o subdir=DIR prepend this directory to all paths (mandatory)\n"
626" -o [no]rellinks transform absolute symlinks to relative\n");
629static int subdir_opt_proc(
void *data,
const char *arg,
int key,
632 (void) data; (void) arg; (void) outargs;
642static struct fuse_fs *subdir_new(
struct fuse_args *args,
643 struct fuse_fs *next[])
648 d = calloc(1,
sizeof(
struct subdir));
650 fuse_log(FUSE_LOG_ERR,
"fuse-subdir: memory allocation failed\n");
657 if (!next[0] || next[1]) {
658 fuse_log(FUSE_LOG_ERR,
"fuse-subdir: exactly one next filesystem required\n");
663 fuse_log(FUSE_LOG_ERR,
"fuse-subdir: missing 'subdir' option\n");
667 if (d->base[0] && d->base[strlen(d->base)-1] !=
'/') {
668 char *tmp = realloc(d->base, strlen(d->base) + 2);
670 fuse_log(FUSE_LOG_ERR,
"fuse-subdir: memory allocation failed\n");
674 strcat(d->base,
"/");
676 d->baselen = strlen(d->base);
678 fs =
fuse_fs_new(&subdir_oper,
sizeof(subdir_oper), d);
struct fuse_context * fuse_get_context(void)
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
#define FUSE_REGISTER_MODULE(name_, factory_)
void fuse_log(enum fuse_log_level level, const char *fmt,...)
#define FUSE_OPT_KEY(templ, key)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
void(* destroy)(void *private_data)