Merge branch 'clone_fd'
[fuse.git] / lib / modules / subdir.c
bloba039b3cca6ae854de44307104556c3bb0d05bd0b
1 /*
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
7 */
9 #define FUSE_USE_VERSION 30
11 #include <config.h>
13 #include <fuse.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stddef.h>
17 #include <string.h>
18 #include <errno.h>
20 struct subdir {
21 char *base;
22 size_t baselen;
23 int rellinks;
24 struct fuse_fs *next;
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)
34 char *newpath = NULL;
36 if (path != NULL) {
37 unsigned newlen = d->baselen + strlen(path);
39 newpath = malloc(newlen + 2);
40 if (!newpath)
41 return -ENOMEM;
43 if (path[0] == '/')
44 path++;
45 strcpy(newpath, d->base);
46 strcpy(newpath + d->baselen, path);
47 if (!newpath[0])
48 strcpy(newpath, ".");
50 *newpathp = newpath;
52 return 0;
55 static int subdir_getattr(const char *path, struct stat *stbuf)
57 struct subdir *d = subdir_get();
58 char *newpath;
59 int err = subdir_addpath(d, path, &newpath);
60 if (!err) {
61 err = fuse_fs_getattr(d->next, newpath, stbuf);
62 free(newpath);
64 return err;
67 static int subdir_fgetattr(const char *path, struct stat *stbuf,
68 struct fuse_file_info *fi)
70 struct subdir *d = subdir_get();
71 char *newpath;
72 int err = subdir_addpath(d, path, &newpath);
73 if (!err) {
74 err = fuse_fs_fgetattr(d->next, newpath, stbuf, fi);
75 free(newpath);
77 return err;
80 static int subdir_access(const char *path, int mask)
82 struct subdir *d = subdir_get();
83 char *newpath;
84 int err = subdir_addpath(d, path, &newpath);
85 if (!err) {
86 err = fuse_fs_access(d->next, newpath, mask);
87 free(newpath);
89 return err;
93 static int count_components(const char *p)
95 int ctr;
97 for (; *p == '/'; p++);
98 for (ctr = 0; *p; ctr++) {
99 for (; *p && *p != '/'; p++);
100 for (; *p == '/'; p++);
102 return ctr;
105 static void strip_common(const char **sp, const char **tp)
107 const char *s = *sp;
108 const char *t = *tp;
109 do {
110 for (; *s == '/'; s++);
111 for (; *t == '/'; t++);
112 *tp = t;
113 *sp = s;
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)
121 const char *l = buf;
122 size_t llen;
123 char *s;
124 int dotdots;
125 int i;
127 if (l[0] != '/' || d->base[0] != '/')
128 return;
130 strip_common(&l, &path);
131 if (l - buf < (long) d->baselen)
132 return;
134 dotdots = count_components(path);
135 if (!dotdots)
136 return;
137 dotdots--;
139 llen = strlen(l);
140 if (dotdots * 3 + llen + 2 > size)
141 return;
143 s = buf + dotdots * 3;
144 if (llen)
145 memmove(s, l, llen + 1);
146 else if (!dotdots)
147 strcpy(s, ".");
148 else
149 *s = '\0';
151 for (s = buf, i = 0; i < dotdots; i++, s += 3)
152 memcpy(s, "../", 3);
156 static int subdir_readlink(const char *path, char *buf, size_t size)
158 struct subdir *d = subdir_get();
159 char *newpath;
160 int err = subdir_addpath(d, path, &newpath);
161 if (!err) {
162 err = fuse_fs_readlink(d->next, newpath, buf, size);
163 if (!err && d->rellinks)
164 transform_symlink(d, newpath, buf, size);
165 free(newpath);
167 return err;
170 static int subdir_opendir(const char *path, struct fuse_file_info *fi)
172 struct subdir *d = subdir_get();
173 char *newpath;
174 int err = subdir_addpath(d, path, &newpath);
175 if (!err) {
176 err = fuse_fs_opendir(d->next, newpath, fi);
177 free(newpath);
179 return err;
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();
188 char *newpath;
189 int err = subdir_addpath(d, path, &newpath);
190 if (!err) {
191 err = fuse_fs_readdir(d->next, newpath, buf, filler, offset,
192 fi, flags);
193 free(newpath);
195 return err;
198 static int subdir_releasedir(const char *path, struct fuse_file_info *fi)
200 struct subdir *d = subdir_get();
201 char *newpath;
202 int err = subdir_addpath(d, path, &newpath);
203 if (!err) {
204 err = fuse_fs_releasedir(d->next, newpath, fi);
205 free(newpath);
207 return err;
210 static int subdir_mknod(const char *path, mode_t mode, dev_t rdev)
212 struct subdir *d = subdir_get();
213 char *newpath;
214 int err = subdir_addpath(d, path, &newpath);
215 if (!err) {
216 err = fuse_fs_mknod(d->next, newpath, mode, rdev);
217 free(newpath);
219 return err;
222 static int subdir_mkdir(const char *path, mode_t mode)
224 struct subdir *d = subdir_get();
225 char *newpath;
226 int err = subdir_addpath(d, path, &newpath);
227 if (!err) {
228 err = fuse_fs_mkdir(d->next, newpath, mode);
229 free(newpath);
231 return err;
234 static int subdir_unlink(const char *path)
236 struct subdir *d = subdir_get();
237 char *newpath;
238 int err = subdir_addpath(d, path, &newpath);
239 if (!err) {
240 err = fuse_fs_unlink(d->next, newpath);
241 free(newpath);
243 return err;
246 static int subdir_rmdir(const char *path)
248 struct subdir *d = subdir_get();
249 char *newpath;
250 int err = subdir_addpath(d, path, &newpath);
251 if (!err) {
252 err = fuse_fs_rmdir(d->next, newpath);
253 free(newpath);
255 return err;
258 static int subdir_symlink(const char *from, const char *path)
260 struct subdir *d = subdir_get();
261 char *newpath;
262 int err = subdir_addpath(d, path, &newpath);
263 if (!err) {
264 err = fuse_fs_symlink(d->next, from, newpath);
265 free(newpath);
267 return err;
270 static int subdir_rename(const char *from, const char *to, unsigned int flags)
272 struct subdir *d = subdir_get();
273 char *newfrom;
274 char *newto;
275 int err = subdir_addpath(d, from, &newfrom);
276 if (!err) {
277 err = subdir_addpath(d, to, &newto);
278 if (!err) {
279 err = fuse_fs_rename(d->next, newfrom, newto, flags);
280 free(newto);
282 free(newfrom);
284 return err;
287 static int subdir_link(const char *from, const char *to)
289 struct subdir *d = subdir_get();
290 char *newfrom;
291 char *newto;
292 int err = subdir_addpath(d, from, &newfrom);
293 if (!err) {
294 err = subdir_addpath(d, to, &newto);
295 if (!err) {
296 err = fuse_fs_link(d->next, newfrom, newto);
297 free(newto);
299 free(newfrom);
301 return err;
304 static int subdir_chmod(const char *path, mode_t mode)
306 struct subdir *d = subdir_get();
307 char *newpath;
308 int err = subdir_addpath(d, path, &newpath);
309 if (!err) {
310 err = fuse_fs_chmod(d->next, newpath, mode);
311 free(newpath);
313 return err;
316 static int subdir_chown(const char *path, uid_t uid, gid_t gid)
318 struct subdir *d = subdir_get();
319 char *newpath;
320 int err = subdir_addpath(d, path, &newpath);
321 if (!err) {
322 err = fuse_fs_chown(d->next, newpath, uid, gid);
323 free(newpath);
325 return err;
328 static int subdir_truncate(const char *path, off_t size)
330 struct subdir *d = subdir_get();
331 char *newpath;
332 int err = subdir_addpath(d, path, &newpath);
333 if (!err) {
334 err = fuse_fs_truncate(d->next, newpath, size);
335 free(newpath);
337 return err;
340 static int subdir_ftruncate(const char *path, off_t size,
341 struct fuse_file_info *fi)
343 struct subdir *d = subdir_get();
344 char *newpath;
345 int err = subdir_addpath(d, path, &newpath);
346 if (!err) {
347 err = fuse_fs_ftruncate(d->next, newpath, size, fi);
348 free(newpath);
350 return err;
353 static int subdir_utimens(const char *path, const struct timespec ts[2])
355 struct subdir *d = subdir_get();
356 char *newpath;
357 int err = subdir_addpath(d, path, &newpath);
358 if (!err) {
359 err = fuse_fs_utimens(d->next, newpath, ts);
360 free(newpath);
362 return err;
365 static int subdir_create(const char *path, mode_t mode,
366 struct fuse_file_info *fi)
368 struct subdir *d = subdir_get();
369 char *newpath;
370 int err = subdir_addpath(d, path, &newpath);
371 if (!err) {
372 err = fuse_fs_create(d->next, newpath, mode, fi);
373 free(newpath);
375 return err;
378 static int subdir_open(const char *path, struct fuse_file_info *fi)
380 struct subdir *d = subdir_get();
381 char *newpath;
382 int err = subdir_addpath(d, path, &newpath);
383 if (!err) {
384 err = fuse_fs_open(d->next, newpath, fi);
385 free(newpath);
387 return err;
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();
394 char *newpath;
395 int err = subdir_addpath(d, path, &newpath);
396 if (!err) {
397 err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
398 free(newpath);
400 return err;
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();
407 char *newpath;
408 int err = subdir_addpath(d, path, &newpath);
409 if (!err) {
410 err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
411 free(newpath);
413 return err;
416 static int subdir_statfs(const char *path, struct statvfs *stbuf)
418 struct subdir *d = subdir_get();
419 char *newpath;
420 int err = subdir_addpath(d, path, &newpath);
421 if (!err) {
422 err = fuse_fs_statfs(d->next, newpath, stbuf);
423 free(newpath);
425 return err;
428 static int subdir_flush(const char *path, struct fuse_file_info *fi)
430 struct subdir *d = subdir_get();
431 char *newpath;
432 int err = subdir_addpath(d, path, &newpath);
433 if (!err) {
434 err = fuse_fs_flush(d->next, newpath, fi);
435 free(newpath);
437 return err;
440 static int subdir_release(const char *path, struct fuse_file_info *fi)
442 struct subdir *d = subdir_get();
443 char *newpath;
444 int err = subdir_addpath(d, path, &newpath);
445 if (!err) {
446 err = fuse_fs_release(d->next, newpath, fi);
447 free(newpath);
449 return err;
452 static int subdir_fsync(const char *path, int isdatasync,
453 struct fuse_file_info *fi)
455 struct subdir *d = subdir_get();
456 char *newpath;
457 int err = subdir_addpath(d, path, &newpath);
458 if (!err) {
459 err = fuse_fs_fsync(d->next, newpath, isdatasync, fi);
460 free(newpath);
462 return err;
465 static int subdir_fsyncdir(const char *path, int isdatasync,
466 struct fuse_file_info *fi)
468 struct subdir *d = subdir_get();
469 char *newpath;
470 int err = subdir_addpath(d, path, &newpath);
471 if (!err) {
472 err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi);
473 free(newpath);
475 return err;
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();
482 char *newpath;
483 int err = subdir_addpath(d, path, &newpath);
484 if (!err) {
485 err = fuse_fs_setxattr(d->next, newpath, name, value, size,
486 flags);
487 free(newpath);
489 return err;
492 static int subdir_getxattr(const char *path, const char *name, char *value,
493 size_t size)
495 struct subdir *d = subdir_get();
496 char *newpath;
497 int err = subdir_addpath(d, path, &newpath);
498 if (!err) {
499 err = fuse_fs_getxattr(d->next, newpath, name, value, size);
500 free(newpath);
502 return err;
505 static int subdir_listxattr(const char *path, char *list, size_t size)
507 struct subdir *d = subdir_get();
508 char *newpath;
509 int err = subdir_addpath(d, path, &newpath);
510 if (!err) {
511 err = fuse_fs_listxattr(d->next, newpath, list, size);
512 free(newpath);
514 return err;
517 static int subdir_removexattr(const char *path, const char *name)
519 struct subdir *d = subdir_get();
520 char *newpath;
521 int err = subdir_addpath(d, path, &newpath);
522 if (!err) {
523 err = fuse_fs_removexattr(d->next, newpath, name);
524 free(newpath);
526 return err;
529 static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd,
530 struct flock *lock)
532 struct subdir *d = subdir_get();
533 char *newpath;
534 int err = subdir_addpath(d, path, &newpath);
535 if (!err) {
536 err = fuse_fs_lock(d->next, newpath, fi, cmd, lock);
537 free(newpath);
539 return err;
542 static int subdir_flock(const char *path, struct fuse_file_info *fi, int op)
544 struct subdir *d = subdir_get();
545 char *newpath;
546 int err = subdir_addpath(d, path, &newpath);
547 if (!err) {
548 err = fuse_fs_flock(d->next, newpath, fi, op);
549 free(newpath);
551 return err;
554 static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx)
556 struct subdir *d = subdir_get();
557 char *newpath;
558 int err = subdir_addpath(d, path, &newpath);
559 if (!err) {
560 err = fuse_fs_bmap(d->next, newpath, blocksize, idx);
561 free(newpath);
563 return err;
566 static void *subdir_init(struct fuse_conn_info *conn)
568 struct subdir *d = subdir_get();
569 fuse_fs_init(d->next, conn);
570 return d;
573 static void subdir_destroy(void *data)
575 struct subdir *d = data;
576 fuse_fs_destroy(d->next);
577 free(d->base);
578 free(d);
581 static const struct fuse_operations subdir_oper = {
582 .destroy = subdir_destroy,
583 .init = subdir_init,
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,
597 .link = subdir_link,
598 .chmod = subdir_chmod,
599 .chown = subdir_chown,
600 .truncate = subdir_truncate,
601 .ftruncate = subdir_ftruncate,
602 .utimens = subdir_utimens,
603 .create = subdir_create,
604 .open = subdir_open,
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,
616 .lock = subdir_lock,
617 .flock = subdir_flock,
618 .bmap = subdir_bmap,
620 .flag_nopath = 1,
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 },
629 FUSE_OPT_END
632 static void subdir_help(void)
634 printf(
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;
644 if (!key) {
645 subdir_help();
646 return -1;
649 return 1;
652 static struct fuse_fs *subdir_new(struct fuse_args *args,
653 struct fuse_fs *next[])
655 struct fuse_fs *fs;
656 struct subdir *d;
658 d = calloc(1, sizeof(struct subdir));
659 if (d == NULL) {
660 fprintf(stderr, "fuse-subdir: memory allocation failed\n");
661 return NULL;
664 if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1)
665 goto out_free;
667 if (!next[0] || next[1]) {
668 fprintf(stderr, "fuse-subdir: exactly one next filesystem required\n");
669 goto out_free;
672 if (!d->base) {
673 fprintf(stderr, "fuse-subdir: missing 'subdir' option\n");
674 goto out_free;
677 if (d->base[0] && d->base[strlen(d->base)-1] != '/') {
678 char *tmp = realloc(d->base, strlen(d->base) + 2);
679 if (!tmp) {
680 fprintf(stderr, "fuse-subdir: memory allocation failed\n");
681 goto out_free;
683 d->base = tmp;
684 strcat(d->base, "/");
686 d->baselen = strlen(d->base);
687 d->next = next[0];
688 fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d);
689 if (!fs)
690 goto out_free;
691 return fs;
693 out_free:
694 free(d->base);
695 free(d);
696 return NULL;
699 FUSE_REGISTER_MODULE(subdir, subdir_new);