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 30
27 static struct subdir
*subdir_get(void)
29 return fuse_get_context()->private_data
;
32 static int subdir_addpath(struct subdir
*d
, const char *path
, char **newpathp
)
37 unsigned newlen
= d
->baselen
+ strlen(path
);
39 newpath
= malloc(newlen
+ 2);
45 strcpy(newpath
, d
->base
);
46 strcpy(newpath
+ d
->baselen
, path
);
55 static int subdir_getattr(const char *path
, struct stat
*stbuf
)
57 struct subdir
*d
= subdir_get();
59 int err
= subdir_addpath(d
, path
, &newpath
);
61 err
= fuse_fs_getattr(d
->next
, newpath
, stbuf
);
67 static int subdir_fgetattr(const char *path
, struct stat
*stbuf
,
68 struct fuse_file_info
*fi
)
70 struct subdir
*d
= subdir_get();
72 int err
= subdir_addpath(d
, path
, &newpath
);
74 err
= fuse_fs_fgetattr(d
->next
, newpath
, stbuf
, fi
);
80 static int subdir_access(const char *path
, int mask
)
82 struct subdir
*d
= subdir_get();
84 int err
= subdir_addpath(d
, path
, &newpath
);
86 err
= fuse_fs_access(d
->next
, newpath
, mask
);
93 static int count_components(const char *p
)
97 for (; *p
== '/'; p
++);
98 for (ctr
= 0; *p
; ctr
++) {
99 for (; *p
&& *p
!= '/'; p
++);
100 for (; *p
== '/'; p
++);
105 static void strip_common(const char **sp
, const char **tp
)
110 for (; *s
== '/'; s
++);
111 for (; *t
== '/'; t
++);
114 for (; *s
== *t
&& *s
&& *s
!= '/'; s
++, t
++);
115 } while ((*s
== *t
&& *s
) || (!*s
&& *t
== '/') || (*s
== '/' && !*t
));
118 static void transform_symlink(struct subdir
*d
, const char *path
,
119 char *buf
, size_t size
)
127 if (l
[0] != '/' || d
->base
[0] != '/')
130 strip_common(&l
, &path
);
131 if (l
- buf
< (long) d
->baselen
)
134 dotdots
= count_components(path
);
140 if (dotdots
* 3 + llen
+ 2 > size
)
143 s
= buf
+ dotdots
* 3;
145 memmove(s
, l
, llen
+ 1);
151 for (s
= buf
, i
= 0; i
< dotdots
; i
++, s
+= 3)
156 static int subdir_readlink(const char *path
, char *buf
, size_t size
)
158 struct subdir
*d
= subdir_get();
160 int err
= subdir_addpath(d
, path
, &newpath
);
162 err
= fuse_fs_readlink(d
->next
, newpath
, buf
, size
);
163 if (!err
&& d
->rellinks
)
164 transform_symlink(d
, newpath
, buf
, size
);
170 static int subdir_opendir(const char *path
, struct fuse_file_info
*fi
)
172 struct subdir
*d
= subdir_get();
174 int err
= subdir_addpath(d
, path
, &newpath
);
176 err
= fuse_fs_opendir(d
->next
, newpath
, fi
);
182 static int subdir_readdir(const char *path
, void *buf
,
183 fuse_fill_dir_t filler
, off_t offset
,
184 struct fuse_file_info
*fi
,
185 enum fuse_readdir_flags flags
)
187 struct subdir
*d
= subdir_get();
189 int err
= subdir_addpath(d
, path
, &newpath
);
191 err
= fuse_fs_readdir(d
->next
, newpath
, buf
, filler
, offset
,
198 static int subdir_releasedir(const char *path
, struct fuse_file_info
*fi
)
200 struct subdir
*d
= subdir_get();
202 int err
= subdir_addpath(d
, path
, &newpath
);
204 err
= fuse_fs_releasedir(d
->next
, newpath
, fi
);
210 static int subdir_mknod(const char *path
, mode_t mode
, dev_t rdev
)
212 struct subdir
*d
= subdir_get();
214 int err
= subdir_addpath(d
, path
, &newpath
);
216 err
= fuse_fs_mknod(d
->next
, newpath
, mode
, rdev
);
222 static int subdir_mkdir(const char *path
, mode_t mode
)
224 struct subdir
*d
= subdir_get();
226 int err
= subdir_addpath(d
, path
, &newpath
);
228 err
= fuse_fs_mkdir(d
->next
, newpath
, mode
);
234 static int subdir_unlink(const char *path
)
236 struct subdir
*d
= subdir_get();
238 int err
= subdir_addpath(d
, path
, &newpath
);
240 err
= fuse_fs_unlink(d
->next
, newpath
);
246 static int subdir_rmdir(const char *path
)
248 struct subdir
*d
= subdir_get();
250 int err
= subdir_addpath(d
, path
, &newpath
);
252 err
= fuse_fs_rmdir(d
->next
, newpath
);
258 static int subdir_symlink(const char *from
, const char *path
)
260 struct subdir
*d
= subdir_get();
262 int err
= subdir_addpath(d
, path
, &newpath
);
264 err
= fuse_fs_symlink(d
->next
, from
, newpath
);
270 static int subdir_rename(const char *from
, const char *to
, unsigned int flags
)
272 struct subdir
*d
= subdir_get();
275 int err
= subdir_addpath(d
, from
, &newfrom
);
277 err
= subdir_addpath(d
, to
, &newto
);
279 err
= fuse_fs_rename(d
->next
, newfrom
, newto
, flags
);
287 static int subdir_link(const char *from
, const char *to
)
289 struct subdir
*d
= subdir_get();
292 int err
= subdir_addpath(d
, from
, &newfrom
);
294 err
= subdir_addpath(d
, to
, &newto
);
296 err
= fuse_fs_link(d
->next
, newfrom
, newto
);
304 static int subdir_chmod(const char *path
, mode_t mode
)
306 struct subdir
*d
= subdir_get();
308 int err
= subdir_addpath(d
, path
, &newpath
);
310 err
= fuse_fs_chmod(d
->next
, newpath
, mode
);
316 static int subdir_chown(const char *path
, uid_t uid
, gid_t gid
)
318 struct subdir
*d
= subdir_get();
320 int err
= subdir_addpath(d
, path
, &newpath
);
322 err
= fuse_fs_chown(d
->next
, newpath
, uid
, gid
);
328 static int subdir_truncate(const char *path
, off_t size
)
330 struct subdir
*d
= subdir_get();
332 int err
= subdir_addpath(d
, path
, &newpath
);
334 err
= fuse_fs_truncate(d
->next
, newpath
, size
);
340 static int subdir_ftruncate(const char *path
, off_t size
,
341 struct fuse_file_info
*fi
)
343 struct subdir
*d
= subdir_get();
345 int err
= subdir_addpath(d
, path
, &newpath
);
347 err
= fuse_fs_ftruncate(d
->next
, newpath
, size
, fi
);
353 static int subdir_utimens(const char *path
, const struct timespec ts
[2])
355 struct subdir
*d
= subdir_get();
357 int err
= subdir_addpath(d
, path
, &newpath
);
359 err
= fuse_fs_utimens(d
->next
, newpath
, ts
);
365 static int subdir_create(const char *path
, mode_t mode
,
366 struct fuse_file_info
*fi
)
368 struct subdir
*d
= subdir_get();
370 int err
= subdir_addpath(d
, path
, &newpath
);
372 err
= fuse_fs_create(d
->next
, newpath
, mode
, fi
);
378 static int subdir_open(const char *path
, struct fuse_file_info
*fi
)
380 struct subdir
*d
= subdir_get();
382 int err
= subdir_addpath(d
, path
, &newpath
);
384 err
= fuse_fs_open(d
->next
, newpath
, fi
);
390 static int subdir_read_buf(const char *path
, struct fuse_bufvec
**bufp
,
391 size_t size
, off_t offset
, struct fuse_file_info
*fi
)
393 struct subdir
*d
= subdir_get();
395 int err
= subdir_addpath(d
, path
, &newpath
);
397 err
= fuse_fs_read_buf(d
->next
, newpath
, bufp
, size
, offset
, fi
);
403 static int subdir_write_buf(const char *path
, struct fuse_bufvec
*buf
,
404 off_t offset
, struct fuse_file_info
*fi
)
406 struct subdir
*d
= subdir_get();
408 int err
= subdir_addpath(d
, path
, &newpath
);
410 err
= fuse_fs_write_buf(d
->next
, newpath
, buf
, offset
, fi
);
416 static int subdir_statfs(const char *path
, struct statvfs
*stbuf
)
418 struct subdir
*d
= subdir_get();
420 int err
= subdir_addpath(d
, path
, &newpath
);
422 err
= fuse_fs_statfs(d
->next
, newpath
, stbuf
);
428 static int subdir_flush(const char *path
, struct fuse_file_info
*fi
)
430 struct subdir
*d
= subdir_get();
432 int err
= subdir_addpath(d
, path
, &newpath
);
434 err
= fuse_fs_flush(d
->next
, newpath
, fi
);
440 static int subdir_release(const char *path
, struct fuse_file_info
*fi
)
442 struct subdir
*d
= subdir_get();
444 int err
= subdir_addpath(d
, path
, &newpath
);
446 err
= fuse_fs_release(d
->next
, newpath
, fi
);
452 static int subdir_fsync(const char *path
, int isdatasync
,
453 struct fuse_file_info
*fi
)
455 struct subdir
*d
= subdir_get();
457 int err
= subdir_addpath(d
, path
, &newpath
);
459 err
= fuse_fs_fsync(d
->next
, newpath
, isdatasync
, fi
);
465 static int subdir_fsyncdir(const char *path
, int isdatasync
,
466 struct fuse_file_info
*fi
)
468 struct subdir
*d
= subdir_get();
470 int err
= subdir_addpath(d
, path
, &newpath
);
472 err
= fuse_fs_fsyncdir(d
->next
, newpath
, isdatasync
, fi
);
478 static int subdir_setxattr(const char *path
, const char *name
,
479 const char *value
, size_t size
, int flags
)
481 struct subdir
*d
= subdir_get();
483 int err
= subdir_addpath(d
, path
, &newpath
);
485 err
= fuse_fs_setxattr(d
->next
, newpath
, name
, value
, size
,
492 static int subdir_getxattr(const char *path
, const char *name
, char *value
,
495 struct subdir
*d
= subdir_get();
497 int err
= subdir_addpath(d
, path
, &newpath
);
499 err
= fuse_fs_getxattr(d
->next
, newpath
, name
, value
, size
);
505 static int subdir_listxattr(const char *path
, char *list
, size_t size
)
507 struct subdir
*d
= subdir_get();
509 int err
= subdir_addpath(d
, path
, &newpath
);
511 err
= fuse_fs_listxattr(d
->next
, newpath
, list
, size
);
517 static int subdir_removexattr(const char *path
, const char *name
)
519 struct subdir
*d
= subdir_get();
521 int err
= subdir_addpath(d
, path
, &newpath
);
523 err
= fuse_fs_removexattr(d
->next
, newpath
, name
);
529 static int subdir_lock(const char *path
, struct fuse_file_info
*fi
, int cmd
,
532 struct subdir
*d
= subdir_get();
534 int err
= subdir_addpath(d
, path
, &newpath
);
536 err
= fuse_fs_lock(d
->next
, newpath
, fi
, cmd
, lock
);
542 static int subdir_flock(const char *path
, struct fuse_file_info
*fi
, int op
)
544 struct subdir
*d
= subdir_get();
546 int err
= subdir_addpath(d
, path
, &newpath
);
548 err
= fuse_fs_flock(d
->next
, newpath
, fi
, op
);
554 static int subdir_bmap(const char *path
, size_t blocksize
, uint64_t *idx
)
556 struct subdir
*d
= subdir_get();
558 int err
= subdir_addpath(d
, path
, &newpath
);
560 err
= fuse_fs_bmap(d
->next
, newpath
, blocksize
, idx
);
566 static void *subdir_init(struct fuse_conn_info
*conn
)
568 struct subdir
*d
= subdir_get();
569 fuse_fs_init(d
->next
, conn
);
573 static void subdir_destroy(void *data
)
575 struct subdir
*d
= data
;
576 fuse_fs_destroy(d
->next
);
581 static const struct fuse_operations subdir_oper
= {
582 .destroy
= subdir_destroy
,
584 .getattr
= subdir_getattr
,
585 .fgetattr
= subdir_fgetattr
,
586 .access
= subdir_access
,
587 .readlink
= subdir_readlink
,
588 .opendir
= subdir_opendir
,
589 .readdir
= subdir_readdir
,
590 .releasedir
= subdir_releasedir
,
591 .mknod
= subdir_mknod
,
592 .mkdir
= subdir_mkdir
,
593 .symlink
= subdir_symlink
,
594 .unlink
= subdir_unlink
,
595 .rmdir
= subdir_rmdir
,
596 .rename
= subdir_rename
,
598 .chmod
= subdir_chmod
,
599 .chown
= subdir_chown
,
600 .truncate
= subdir_truncate
,
601 .ftruncate
= subdir_ftruncate
,
602 .utimens
= subdir_utimens
,
603 .create
= subdir_create
,
605 .read_buf
= subdir_read_buf
,
606 .write_buf
= subdir_write_buf
,
607 .statfs
= subdir_statfs
,
608 .flush
= subdir_flush
,
609 .release
= subdir_release
,
610 .fsync
= subdir_fsync
,
611 .fsyncdir
= subdir_fsyncdir
,
612 .setxattr
= subdir_setxattr
,
613 .getxattr
= subdir_getxattr
,
614 .listxattr
= subdir_listxattr
,
615 .removexattr
= subdir_removexattr
,
617 .flock
= subdir_flock
,
623 static const struct fuse_opt subdir_opts
[] = {
624 FUSE_OPT_KEY("-h", 0),
625 FUSE_OPT_KEY("--help", 0),
626 { "subdir=%s", offsetof(struct subdir
, base
), 0 },
627 { "rellinks", offsetof(struct subdir
, rellinks
), 1 },
628 { "norellinks", offsetof(struct subdir
, rellinks
), 0 },
632 static void subdir_help(void)
635 " -o subdir=DIR prepend this directory to all paths (mandatory)\n"
636 " -o [no]rellinks transform absolute symlinks to relative\n");
639 static int subdir_opt_proc(void *data
, const char *arg
, int key
,
640 struct fuse_args
*outargs
)
642 (void) data
; (void) arg
; (void) outargs
;
652 static struct fuse_fs
*subdir_new(struct fuse_args
*args
,
653 struct fuse_fs
*next
[])
658 d
= calloc(1, sizeof(struct subdir
));
660 fprintf(stderr
, "fuse-subdir: memory allocation failed\n");
664 if (fuse_opt_parse(args
, d
, subdir_opts
, subdir_opt_proc
) == -1)
667 if (!next
[0] || next
[1]) {
668 fprintf(stderr
, "fuse-subdir: exactly one next filesystem required\n");
673 fprintf(stderr
, "fuse-subdir: missing 'subdir' option\n");
677 if (d
->base
[0] && d
->base
[strlen(d
->base
)-1] != '/') {
678 char *tmp
= realloc(d
->base
, strlen(d
->base
) + 2);
680 fprintf(stderr
, "fuse-subdir: memory allocation failed\n");
684 strcat(d
->base
, "/");
686 d
->baselen
= strlen(d
->base
);
688 fs
= fuse_fs_new(&subdir_oper
, sizeof(subdir_oper
), d
);
699 FUSE_REGISTER_MODULE(subdir
, subdir_new
);