16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci fuse subdir module: offset paths with a base directory 36881f68fSopenharmony_ci Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu> 46881f68fSopenharmony_ci 56881f68fSopenharmony_ci This program can be distributed under the terms of the GNU LGPLv2. 66881f68fSopenharmony_ci See the file COPYING.LIB 76881f68fSopenharmony_ci*/ 86881f68fSopenharmony_ci 96881f68fSopenharmony_ci#include <fuse_config.h> 106881f68fSopenharmony_ci 116881f68fSopenharmony_ci#include <fuse.h> 126881f68fSopenharmony_ci#include <stdio.h> 136881f68fSopenharmony_ci#include <stdlib.h> 146881f68fSopenharmony_ci#include <stddef.h> 156881f68fSopenharmony_ci#include <string.h> 166881f68fSopenharmony_ci#include <errno.h> 176881f68fSopenharmony_ci 186881f68fSopenharmony_cistruct subdir { 196881f68fSopenharmony_ci char *base; 206881f68fSopenharmony_ci size_t baselen; 216881f68fSopenharmony_ci int rellinks; 226881f68fSopenharmony_ci struct fuse_fs *next; 236881f68fSopenharmony_ci}; 246881f68fSopenharmony_ci 256881f68fSopenharmony_cistatic struct subdir *subdir_get(void) 266881f68fSopenharmony_ci{ 276881f68fSopenharmony_ci return fuse_get_context()->private_data; 286881f68fSopenharmony_ci} 296881f68fSopenharmony_ci 306881f68fSopenharmony_cistatic int subdir_addpath(struct subdir *d, const char *path, char **newpathp) 316881f68fSopenharmony_ci{ 326881f68fSopenharmony_ci char *newpath = NULL; 336881f68fSopenharmony_ci 346881f68fSopenharmony_ci if (path != NULL) { 356881f68fSopenharmony_ci unsigned newlen = d->baselen + strlen(path); 366881f68fSopenharmony_ci 376881f68fSopenharmony_ci newpath = malloc(newlen + 2); 386881f68fSopenharmony_ci if (!newpath) 396881f68fSopenharmony_ci return -ENOMEM; 406881f68fSopenharmony_ci 416881f68fSopenharmony_ci if (path[0] == '/') 426881f68fSopenharmony_ci path++; 436881f68fSopenharmony_ci strcpy(newpath, d->base); 446881f68fSopenharmony_ci strcpy(newpath + d->baselen, path); 456881f68fSopenharmony_ci if (!newpath[0]) 466881f68fSopenharmony_ci strcpy(newpath, "."); 476881f68fSopenharmony_ci } 486881f68fSopenharmony_ci *newpathp = newpath; 496881f68fSopenharmony_ci 506881f68fSopenharmony_ci return 0; 516881f68fSopenharmony_ci} 526881f68fSopenharmony_ci 536881f68fSopenharmony_cistatic int subdir_getattr(const char *path, struct stat *stbuf, 546881f68fSopenharmony_ci struct fuse_file_info *fi) 556881f68fSopenharmony_ci{ 566881f68fSopenharmony_ci struct subdir *d = subdir_get(); 576881f68fSopenharmony_ci char *newpath; 586881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 596881f68fSopenharmony_ci if (!err) { 606881f68fSopenharmony_ci err = fuse_fs_getattr(d->next, newpath, stbuf, fi); 616881f68fSopenharmony_ci free(newpath); 626881f68fSopenharmony_ci } 636881f68fSopenharmony_ci return err; 646881f68fSopenharmony_ci} 656881f68fSopenharmony_ci 666881f68fSopenharmony_cistatic int subdir_access(const char *path, int mask) 676881f68fSopenharmony_ci{ 686881f68fSopenharmony_ci struct subdir *d = subdir_get(); 696881f68fSopenharmony_ci char *newpath; 706881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 716881f68fSopenharmony_ci if (!err) { 726881f68fSopenharmony_ci err = fuse_fs_access(d->next, newpath, mask); 736881f68fSopenharmony_ci free(newpath); 746881f68fSopenharmony_ci } 756881f68fSopenharmony_ci return err; 766881f68fSopenharmony_ci} 776881f68fSopenharmony_ci 786881f68fSopenharmony_ci 796881f68fSopenharmony_cistatic int count_components(const char *p) 806881f68fSopenharmony_ci{ 816881f68fSopenharmony_ci int ctr; 826881f68fSopenharmony_ci 836881f68fSopenharmony_ci for (; *p == '/'; p++); 846881f68fSopenharmony_ci for (ctr = 0; *p; ctr++) { 856881f68fSopenharmony_ci for (; *p && *p != '/'; p++); 866881f68fSopenharmony_ci for (; *p == '/'; p++); 876881f68fSopenharmony_ci } 886881f68fSopenharmony_ci return ctr; 896881f68fSopenharmony_ci} 906881f68fSopenharmony_ci 916881f68fSopenharmony_cistatic void strip_common(const char **sp, const char **tp) 926881f68fSopenharmony_ci{ 936881f68fSopenharmony_ci const char *s = *sp; 946881f68fSopenharmony_ci const char *t = *tp; 956881f68fSopenharmony_ci do { 966881f68fSopenharmony_ci for (; *s == '/'; s++); 976881f68fSopenharmony_ci for (; *t == '/'; t++); 986881f68fSopenharmony_ci *tp = t; 996881f68fSopenharmony_ci *sp = s; 1006881f68fSopenharmony_ci for (; *s == *t && *s && *s != '/'; s++, t++); 1016881f68fSopenharmony_ci } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); 1026881f68fSopenharmony_ci} 1036881f68fSopenharmony_ci 1046881f68fSopenharmony_cistatic void transform_symlink(struct subdir *d, const char *path, 1056881f68fSopenharmony_ci char *buf, size_t size) 1066881f68fSopenharmony_ci{ 1076881f68fSopenharmony_ci const char *l = buf; 1086881f68fSopenharmony_ci size_t llen; 1096881f68fSopenharmony_ci char *s; 1106881f68fSopenharmony_ci int dotdots; 1116881f68fSopenharmony_ci int i; 1126881f68fSopenharmony_ci 1136881f68fSopenharmony_ci if (l[0] != '/' || d->base[0] != '/') 1146881f68fSopenharmony_ci return; 1156881f68fSopenharmony_ci 1166881f68fSopenharmony_ci strip_common(&l, &path); 1176881f68fSopenharmony_ci if (l - buf < (long) d->baselen) 1186881f68fSopenharmony_ci return; 1196881f68fSopenharmony_ci 1206881f68fSopenharmony_ci dotdots = count_components(path); 1216881f68fSopenharmony_ci if (!dotdots) 1226881f68fSopenharmony_ci return; 1236881f68fSopenharmony_ci dotdots--; 1246881f68fSopenharmony_ci 1256881f68fSopenharmony_ci llen = strlen(l); 1266881f68fSopenharmony_ci if (dotdots * 3 + llen + 2 > size) 1276881f68fSopenharmony_ci return; 1286881f68fSopenharmony_ci 1296881f68fSopenharmony_ci s = buf + dotdots * 3; 1306881f68fSopenharmony_ci if (llen) 1316881f68fSopenharmony_ci memmove(s, l, llen + 1); 1326881f68fSopenharmony_ci else if (!dotdots) 1336881f68fSopenharmony_ci strcpy(s, "."); 1346881f68fSopenharmony_ci else 1356881f68fSopenharmony_ci *s = '\0'; 1366881f68fSopenharmony_ci 1376881f68fSopenharmony_ci for (s = buf, i = 0; i < dotdots; i++, s += 3) 1386881f68fSopenharmony_ci memcpy(s, "../", 3); 1396881f68fSopenharmony_ci} 1406881f68fSopenharmony_ci 1416881f68fSopenharmony_ci 1426881f68fSopenharmony_cistatic int subdir_readlink(const char *path, char *buf, size_t size) 1436881f68fSopenharmony_ci{ 1446881f68fSopenharmony_ci struct subdir *d = subdir_get(); 1456881f68fSopenharmony_ci char *newpath; 1466881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 1476881f68fSopenharmony_ci if (!err) { 1486881f68fSopenharmony_ci err = fuse_fs_readlink(d->next, newpath, buf, size); 1496881f68fSopenharmony_ci if (!err && d->rellinks) 1506881f68fSopenharmony_ci transform_symlink(d, newpath, buf, size); 1516881f68fSopenharmony_ci free(newpath); 1526881f68fSopenharmony_ci } 1536881f68fSopenharmony_ci return err; 1546881f68fSopenharmony_ci} 1556881f68fSopenharmony_ci 1566881f68fSopenharmony_cistatic int subdir_opendir(const char *path, struct fuse_file_info *fi) 1576881f68fSopenharmony_ci{ 1586881f68fSopenharmony_ci struct subdir *d = subdir_get(); 1596881f68fSopenharmony_ci char *newpath; 1606881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 1616881f68fSopenharmony_ci if (!err) { 1626881f68fSopenharmony_ci err = fuse_fs_opendir(d->next, newpath, fi); 1636881f68fSopenharmony_ci free(newpath); 1646881f68fSopenharmony_ci } 1656881f68fSopenharmony_ci return err; 1666881f68fSopenharmony_ci} 1676881f68fSopenharmony_ci 1686881f68fSopenharmony_cistatic int subdir_readdir(const char *path, void *buf, 1696881f68fSopenharmony_ci fuse_fill_dir_t filler, off_t offset, 1706881f68fSopenharmony_ci struct fuse_file_info *fi, 1716881f68fSopenharmony_ci enum fuse_readdir_flags flags) 1726881f68fSopenharmony_ci{ 1736881f68fSopenharmony_ci struct subdir *d = subdir_get(); 1746881f68fSopenharmony_ci char *newpath; 1756881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 1766881f68fSopenharmony_ci if (!err) { 1776881f68fSopenharmony_ci err = fuse_fs_readdir(d->next, newpath, buf, filler, offset, 1786881f68fSopenharmony_ci fi, flags); 1796881f68fSopenharmony_ci free(newpath); 1806881f68fSopenharmony_ci } 1816881f68fSopenharmony_ci return err; 1826881f68fSopenharmony_ci} 1836881f68fSopenharmony_ci 1846881f68fSopenharmony_cistatic int subdir_releasedir(const char *path, struct fuse_file_info *fi) 1856881f68fSopenharmony_ci{ 1866881f68fSopenharmony_ci struct subdir *d = subdir_get(); 1876881f68fSopenharmony_ci char *newpath; 1886881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 1896881f68fSopenharmony_ci if (!err) { 1906881f68fSopenharmony_ci err = fuse_fs_releasedir(d->next, newpath, fi); 1916881f68fSopenharmony_ci free(newpath); 1926881f68fSopenharmony_ci } 1936881f68fSopenharmony_ci return err; 1946881f68fSopenharmony_ci} 1956881f68fSopenharmony_ci 1966881f68fSopenharmony_cistatic int subdir_mknod(const char *path, mode_t mode, dev_t rdev) 1976881f68fSopenharmony_ci{ 1986881f68fSopenharmony_ci struct subdir *d = subdir_get(); 1996881f68fSopenharmony_ci char *newpath; 2006881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 2016881f68fSopenharmony_ci if (!err) { 2026881f68fSopenharmony_ci err = fuse_fs_mknod(d->next, newpath, mode, rdev); 2036881f68fSopenharmony_ci free(newpath); 2046881f68fSopenharmony_ci } 2056881f68fSopenharmony_ci return err; 2066881f68fSopenharmony_ci} 2076881f68fSopenharmony_ci 2086881f68fSopenharmony_cistatic int subdir_mkdir(const char *path, mode_t mode) 2096881f68fSopenharmony_ci{ 2106881f68fSopenharmony_ci struct subdir *d = subdir_get(); 2116881f68fSopenharmony_ci char *newpath; 2126881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 2136881f68fSopenharmony_ci if (!err) { 2146881f68fSopenharmony_ci err = fuse_fs_mkdir(d->next, newpath, mode); 2156881f68fSopenharmony_ci free(newpath); 2166881f68fSopenharmony_ci } 2176881f68fSopenharmony_ci return err; 2186881f68fSopenharmony_ci} 2196881f68fSopenharmony_ci 2206881f68fSopenharmony_cistatic int subdir_unlink(const char *path) 2216881f68fSopenharmony_ci{ 2226881f68fSopenharmony_ci struct subdir *d = subdir_get(); 2236881f68fSopenharmony_ci char *newpath; 2246881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 2256881f68fSopenharmony_ci if (!err) { 2266881f68fSopenharmony_ci err = fuse_fs_unlink(d->next, newpath); 2276881f68fSopenharmony_ci free(newpath); 2286881f68fSopenharmony_ci } 2296881f68fSopenharmony_ci return err; 2306881f68fSopenharmony_ci} 2316881f68fSopenharmony_ci 2326881f68fSopenharmony_cistatic int subdir_rmdir(const char *path) 2336881f68fSopenharmony_ci{ 2346881f68fSopenharmony_ci struct subdir *d = subdir_get(); 2356881f68fSopenharmony_ci char *newpath; 2366881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 2376881f68fSopenharmony_ci if (!err) { 2386881f68fSopenharmony_ci err = fuse_fs_rmdir(d->next, newpath); 2396881f68fSopenharmony_ci free(newpath); 2406881f68fSopenharmony_ci } 2416881f68fSopenharmony_ci return err; 2426881f68fSopenharmony_ci} 2436881f68fSopenharmony_ci 2446881f68fSopenharmony_cistatic int subdir_symlink(const char *from, const char *path) 2456881f68fSopenharmony_ci{ 2466881f68fSopenharmony_ci struct subdir *d = subdir_get(); 2476881f68fSopenharmony_ci char *newpath; 2486881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 2496881f68fSopenharmony_ci if (!err) { 2506881f68fSopenharmony_ci err = fuse_fs_symlink(d->next, from, newpath); 2516881f68fSopenharmony_ci free(newpath); 2526881f68fSopenharmony_ci } 2536881f68fSopenharmony_ci return err; 2546881f68fSopenharmony_ci} 2556881f68fSopenharmony_ci 2566881f68fSopenharmony_cistatic int subdir_rename(const char *from, const char *to, unsigned int flags) 2576881f68fSopenharmony_ci{ 2586881f68fSopenharmony_ci struct subdir *d = subdir_get(); 2596881f68fSopenharmony_ci char *newfrom; 2606881f68fSopenharmony_ci char *newto; 2616881f68fSopenharmony_ci int err = subdir_addpath(d, from, &newfrom); 2626881f68fSopenharmony_ci if (!err) { 2636881f68fSopenharmony_ci err = subdir_addpath(d, to, &newto); 2646881f68fSopenharmony_ci if (!err) { 2656881f68fSopenharmony_ci err = fuse_fs_rename(d->next, newfrom, newto, flags); 2666881f68fSopenharmony_ci free(newto); 2676881f68fSopenharmony_ci } 2686881f68fSopenharmony_ci free(newfrom); 2696881f68fSopenharmony_ci } 2706881f68fSopenharmony_ci return err; 2716881f68fSopenharmony_ci} 2726881f68fSopenharmony_ci 2736881f68fSopenharmony_cistatic int subdir_link(const char *from, const char *to) 2746881f68fSopenharmony_ci{ 2756881f68fSopenharmony_ci struct subdir *d = subdir_get(); 2766881f68fSopenharmony_ci char *newfrom; 2776881f68fSopenharmony_ci char *newto; 2786881f68fSopenharmony_ci int err = subdir_addpath(d, from, &newfrom); 2796881f68fSopenharmony_ci if (!err) { 2806881f68fSopenharmony_ci err = subdir_addpath(d, to, &newto); 2816881f68fSopenharmony_ci if (!err) { 2826881f68fSopenharmony_ci err = fuse_fs_link(d->next, newfrom, newto); 2836881f68fSopenharmony_ci free(newto); 2846881f68fSopenharmony_ci } 2856881f68fSopenharmony_ci free(newfrom); 2866881f68fSopenharmony_ci } 2876881f68fSopenharmony_ci return err; 2886881f68fSopenharmony_ci} 2896881f68fSopenharmony_ci 2906881f68fSopenharmony_cistatic int subdir_chmod(const char *path, mode_t mode, 2916881f68fSopenharmony_ci struct fuse_file_info *fi) 2926881f68fSopenharmony_ci{ 2936881f68fSopenharmony_ci struct subdir *d = subdir_get(); 2946881f68fSopenharmony_ci char *newpath; 2956881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 2966881f68fSopenharmony_ci if (!err) { 2976881f68fSopenharmony_ci err = fuse_fs_chmod(d->next, newpath, mode, fi); 2986881f68fSopenharmony_ci free(newpath); 2996881f68fSopenharmony_ci } 3006881f68fSopenharmony_ci return err; 3016881f68fSopenharmony_ci} 3026881f68fSopenharmony_ci 3036881f68fSopenharmony_cistatic int subdir_chown(const char *path, uid_t uid, gid_t gid, 3046881f68fSopenharmony_ci struct fuse_file_info *fi) 3056881f68fSopenharmony_ci{ 3066881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3076881f68fSopenharmony_ci char *newpath; 3086881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3096881f68fSopenharmony_ci if (!err) { 3106881f68fSopenharmony_ci err = fuse_fs_chown(d->next, newpath, uid, gid, fi); 3116881f68fSopenharmony_ci free(newpath); 3126881f68fSopenharmony_ci } 3136881f68fSopenharmony_ci return err; 3146881f68fSopenharmony_ci} 3156881f68fSopenharmony_ci 3166881f68fSopenharmony_cistatic int subdir_truncate(const char *path, off_t size, 3176881f68fSopenharmony_ci struct fuse_file_info *fi) 3186881f68fSopenharmony_ci{ 3196881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3206881f68fSopenharmony_ci char *newpath; 3216881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3226881f68fSopenharmony_ci if (!err) { 3236881f68fSopenharmony_ci err = fuse_fs_truncate(d->next, newpath, size, fi); 3246881f68fSopenharmony_ci free(newpath); 3256881f68fSopenharmony_ci } 3266881f68fSopenharmony_ci return err; 3276881f68fSopenharmony_ci} 3286881f68fSopenharmony_ci 3296881f68fSopenharmony_cistatic int subdir_utimens(const char *path, const struct timespec ts[2], 3306881f68fSopenharmony_ci struct fuse_file_info *fi) 3316881f68fSopenharmony_ci{ 3326881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3336881f68fSopenharmony_ci char *newpath; 3346881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3356881f68fSopenharmony_ci if (!err) { 3366881f68fSopenharmony_ci err = fuse_fs_utimens(d->next, newpath, ts, fi); 3376881f68fSopenharmony_ci free(newpath); 3386881f68fSopenharmony_ci } 3396881f68fSopenharmony_ci return err; 3406881f68fSopenharmony_ci} 3416881f68fSopenharmony_ci 3426881f68fSopenharmony_cistatic int subdir_create(const char *path, mode_t mode, 3436881f68fSopenharmony_ci struct fuse_file_info *fi) 3446881f68fSopenharmony_ci{ 3456881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3466881f68fSopenharmony_ci char *newpath; 3476881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3486881f68fSopenharmony_ci if (!err) { 3496881f68fSopenharmony_ci err = fuse_fs_create(d->next, newpath, mode, fi); 3506881f68fSopenharmony_ci free(newpath); 3516881f68fSopenharmony_ci } 3526881f68fSopenharmony_ci return err; 3536881f68fSopenharmony_ci} 3546881f68fSopenharmony_ci 3556881f68fSopenharmony_cistatic int subdir_open(const char *path, struct fuse_file_info *fi) 3566881f68fSopenharmony_ci{ 3576881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3586881f68fSopenharmony_ci char *newpath; 3596881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3606881f68fSopenharmony_ci if (!err) { 3616881f68fSopenharmony_ci err = fuse_fs_open(d->next, newpath, fi); 3626881f68fSopenharmony_ci free(newpath); 3636881f68fSopenharmony_ci } 3646881f68fSopenharmony_ci return err; 3656881f68fSopenharmony_ci} 3666881f68fSopenharmony_ci 3676881f68fSopenharmony_cistatic int subdir_read_buf(const char *path, struct fuse_bufvec **bufp, 3686881f68fSopenharmony_ci size_t size, off_t offset, struct fuse_file_info *fi) 3696881f68fSopenharmony_ci{ 3706881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3716881f68fSopenharmony_ci char *newpath; 3726881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3736881f68fSopenharmony_ci if (!err) { 3746881f68fSopenharmony_ci err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi); 3756881f68fSopenharmony_ci free(newpath); 3766881f68fSopenharmony_ci } 3776881f68fSopenharmony_ci return err; 3786881f68fSopenharmony_ci} 3796881f68fSopenharmony_ci 3806881f68fSopenharmony_cistatic int subdir_write_buf(const char *path, struct fuse_bufvec *buf, 3816881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 3826881f68fSopenharmony_ci{ 3836881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3846881f68fSopenharmony_ci char *newpath; 3856881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3866881f68fSopenharmony_ci if (!err) { 3876881f68fSopenharmony_ci err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi); 3886881f68fSopenharmony_ci free(newpath); 3896881f68fSopenharmony_ci } 3906881f68fSopenharmony_ci return err; 3916881f68fSopenharmony_ci} 3926881f68fSopenharmony_ci 3936881f68fSopenharmony_cistatic int subdir_statfs(const char *path, struct statvfs *stbuf) 3946881f68fSopenharmony_ci{ 3956881f68fSopenharmony_ci struct subdir *d = subdir_get(); 3966881f68fSopenharmony_ci char *newpath; 3976881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 3986881f68fSopenharmony_ci if (!err) { 3996881f68fSopenharmony_ci err = fuse_fs_statfs(d->next, newpath, stbuf); 4006881f68fSopenharmony_ci free(newpath); 4016881f68fSopenharmony_ci } 4026881f68fSopenharmony_ci return err; 4036881f68fSopenharmony_ci} 4046881f68fSopenharmony_ci 4056881f68fSopenharmony_cistatic int subdir_flush(const char *path, struct fuse_file_info *fi) 4066881f68fSopenharmony_ci{ 4076881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4086881f68fSopenharmony_ci char *newpath; 4096881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4106881f68fSopenharmony_ci if (!err) { 4116881f68fSopenharmony_ci err = fuse_fs_flush(d->next, newpath, fi); 4126881f68fSopenharmony_ci free(newpath); 4136881f68fSopenharmony_ci } 4146881f68fSopenharmony_ci return err; 4156881f68fSopenharmony_ci} 4166881f68fSopenharmony_ci 4176881f68fSopenharmony_cistatic int subdir_release(const char *path, struct fuse_file_info *fi) 4186881f68fSopenharmony_ci{ 4196881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4206881f68fSopenharmony_ci char *newpath; 4216881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4226881f68fSopenharmony_ci if (!err) { 4236881f68fSopenharmony_ci err = fuse_fs_release(d->next, newpath, fi); 4246881f68fSopenharmony_ci free(newpath); 4256881f68fSopenharmony_ci } 4266881f68fSopenharmony_ci return err; 4276881f68fSopenharmony_ci} 4286881f68fSopenharmony_ci 4296881f68fSopenharmony_cistatic int subdir_fsync(const char *path, int isdatasync, 4306881f68fSopenharmony_ci struct fuse_file_info *fi) 4316881f68fSopenharmony_ci{ 4326881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4336881f68fSopenharmony_ci char *newpath; 4346881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4356881f68fSopenharmony_ci if (!err) { 4366881f68fSopenharmony_ci err = fuse_fs_fsync(d->next, newpath, isdatasync, fi); 4376881f68fSopenharmony_ci free(newpath); 4386881f68fSopenharmony_ci } 4396881f68fSopenharmony_ci return err; 4406881f68fSopenharmony_ci} 4416881f68fSopenharmony_ci 4426881f68fSopenharmony_cistatic int subdir_fsyncdir(const char *path, int isdatasync, 4436881f68fSopenharmony_ci struct fuse_file_info *fi) 4446881f68fSopenharmony_ci{ 4456881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4466881f68fSopenharmony_ci char *newpath; 4476881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4486881f68fSopenharmony_ci if (!err) { 4496881f68fSopenharmony_ci err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi); 4506881f68fSopenharmony_ci free(newpath); 4516881f68fSopenharmony_ci } 4526881f68fSopenharmony_ci return err; 4536881f68fSopenharmony_ci} 4546881f68fSopenharmony_ci 4556881f68fSopenharmony_cistatic int subdir_setxattr(const char *path, const char *name, 4566881f68fSopenharmony_ci const char *value, size_t size, int flags) 4576881f68fSopenharmony_ci{ 4586881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4596881f68fSopenharmony_ci char *newpath; 4606881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4616881f68fSopenharmony_ci if (!err) { 4626881f68fSopenharmony_ci err = fuse_fs_setxattr(d->next, newpath, name, value, size, 4636881f68fSopenharmony_ci flags); 4646881f68fSopenharmony_ci free(newpath); 4656881f68fSopenharmony_ci } 4666881f68fSopenharmony_ci return err; 4676881f68fSopenharmony_ci} 4686881f68fSopenharmony_ci 4696881f68fSopenharmony_cistatic int subdir_getxattr(const char *path, const char *name, char *value, 4706881f68fSopenharmony_ci size_t size) 4716881f68fSopenharmony_ci{ 4726881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4736881f68fSopenharmony_ci char *newpath; 4746881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4756881f68fSopenharmony_ci if (!err) { 4766881f68fSopenharmony_ci err = fuse_fs_getxattr(d->next, newpath, name, value, size); 4776881f68fSopenharmony_ci free(newpath); 4786881f68fSopenharmony_ci } 4796881f68fSopenharmony_ci return err; 4806881f68fSopenharmony_ci} 4816881f68fSopenharmony_ci 4826881f68fSopenharmony_cistatic int subdir_listxattr(const char *path, char *list, size_t size) 4836881f68fSopenharmony_ci{ 4846881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4856881f68fSopenharmony_ci char *newpath; 4866881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4876881f68fSopenharmony_ci if (!err) { 4886881f68fSopenharmony_ci err = fuse_fs_listxattr(d->next, newpath, list, size); 4896881f68fSopenharmony_ci free(newpath); 4906881f68fSopenharmony_ci } 4916881f68fSopenharmony_ci return err; 4926881f68fSopenharmony_ci} 4936881f68fSopenharmony_ci 4946881f68fSopenharmony_cistatic int subdir_removexattr(const char *path, const char *name) 4956881f68fSopenharmony_ci{ 4966881f68fSopenharmony_ci struct subdir *d = subdir_get(); 4976881f68fSopenharmony_ci char *newpath; 4986881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 4996881f68fSopenharmony_ci if (!err) { 5006881f68fSopenharmony_ci err = fuse_fs_removexattr(d->next, newpath, name); 5016881f68fSopenharmony_ci free(newpath); 5026881f68fSopenharmony_ci } 5036881f68fSopenharmony_ci return err; 5046881f68fSopenharmony_ci} 5056881f68fSopenharmony_ci 5066881f68fSopenharmony_cistatic int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd, 5076881f68fSopenharmony_ci struct flock *lock) 5086881f68fSopenharmony_ci{ 5096881f68fSopenharmony_ci struct subdir *d = subdir_get(); 5106881f68fSopenharmony_ci char *newpath; 5116881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 5126881f68fSopenharmony_ci if (!err) { 5136881f68fSopenharmony_ci err = fuse_fs_lock(d->next, newpath, fi, cmd, lock); 5146881f68fSopenharmony_ci free(newpath); 5156881f68fSopenharmony_ci } 5166881f68fSopenharmony_ci return err; 5176881f68fSopenharmony_ci} 5186881f68fSopenharmony_ci 5196881f68fSopenharmony_cistatic int subdir_flock(const char *path, struct fuse_file_info *fi, int op) 5206881f68fSopenharmony_ci{ 5216881f68fSopenharmony_ci struct subdir *d = subdir_get(); 5226881f68fSopenharmony_ci char *newpath; 5236881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 5246881f68fSopenharmony_ci if (!err) { 5256881f68fSopenharmony_ci err = fuse_fs_flock(d->next, newpath, fi, op); 5266881f68fSopenharmony_ci free(newpath); 5276881f68fSopenharmony_ci } 5286881f68fSopenharmony_ci return err; 5296881f68fSopenharmony_ci} 5306881f68fSopenharmony_ci 5316881f68fSopenharmony_cistatic int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx) 5326881f68fSopenharmony_ci{ 5336881f68fSopenharmony_ci struct subdir *d = subdir_get(); 5346881f68fSopenharmony_ci char *newpath; 5356881f68fSopenharmony_ci int err = subdir_addpath(d, path, &newpath); 5366881f68fSopenharmony_ci if (!err) { 5376881f68fSopenharmony_ci err = fuse_fs_bmap(d->next, newpath, blocksize, idx); 5386881f68fSopenharmony_ci free(newpath); 5396881f68fSopenharmony_ci } 5406881f68fSopenharmony_ci return err; 5416881f68fSopenharmony_ci} 5426881f68fSopenharmony_ci 5436881f68fSopenharmony_cistatic off_t subdir_lseek(const char *path, off_t off, int whence, 5446881f68fSopenharmony_ci struct fuse_file_info *fi) 5456881f68fSopenharmony_ci{ 5466881f68fSopenharmony_ci struct subdir *ic = subdir_get(); 5476881f68fSopenharmony_ci char *newpath; 5486881f68fSopenharmony_ci int res = subdir_addpath(ic, path, &newpath); 5496881f68fSopenharmony_ci if (!res) { 5506881f68fSopenharmony_ci res = fuse_fs_lseek(ic->next, newpath, off, whence, fi); 5516881f68fSopenharmony_ci free(newpath); 5526881f68fSopenharmony_ci } 5536881f68fSopenharmony_ci return res; 5546881f68fSopenharmony_ci} 5556881f68fSopenharmony_ci 5566881f68fSopenharmony_cistatic void *subdir_init(struct fuse_conn_info *conn, 5576881f68fSopenharmony_ci struct fuse_config *cfg) 5586881f68fSopenharmony_ci{ 5596881f68fSopenharmony_ci struct subdir *d = subdir_get(); 5606881f68fSopenharmony_ci fuse_fs_init(d->next, conn, cfg); 5616881f68fSopenharmony_ci /* Don't touch cfg->nullpath_ok, we can work with 5626881f68fSopenharmony_ci either */ 5636881f68fSopenharmony_ci return d; 5646881f68fSopenharmony_ci} 5656881f68fSopenharmony_ci 5666881f68fSopenharmony_cistatic void subdir_destroy(void *data) 5676881f68fSopenharmony_ci{ 5686881f68fSopenharmony_ci struct subdir *d = data; 5696881f68fSopenharmony_ci fuse_fs_destroy(d->next); 5706881f68fSopenharmony_ci free(d->base); 5716881f68fSopenharmony_ci free(d); 5726881f68fSopenharmony_ci} 5736881f68fSopenharmony_ci 5746881f68fSopenharmony_cistatic const struct fuse_operations subdir_oper = { 5756881f68fSopenharmony_ci .destroy = subdir_destroy, 5766881f68fSopenharmony_ci .init = subdir_init, 5776881f68fSopenharmony_ci .getattr = subdir_getattr, 5786881f68fSopenharmony_ci .access = subdir_access, 5796881f68fSopenharmony_ci .readlink = subdir_readlink, 5806881f68fSopenharmony_ci .opendir = subdir_opendir, 5816881f68fSopenharmony_ci .readdir = subdir_readdir, 5826881f68fSopenharmony_ci .releasedir = subdir_releasedir, 5836881f68fSopenharmony_ci .mknod = subdir_mknod, 5846881f68fSopenharmony_ci .mkdir = subdir_mkdir, 5856881f68fSopenharmony_ci .symlink = subdir_symlink, 5866881f68fSopenharmony_ci .unlink = subdir_unlink, 5876881f68fSopenharmony_ci .rmdir = subdir_rmdir, 5886881f68fSopenharmony_ci .rename = subdir_rename, 5896881f68fSopenharmony_ci .link = subdir_link, 5906881f68fSopenharmony_ci .chmod = subdir_chmod, 5916881f68fSopenharmony_ci .chown = subdir_chown, 5926881f68fSopenharmony_ci .truncate = subdir_truncate, 5936881f68fSopenharmony_ci .utimens = subdir_utimens, 5946881f68fSopenharmony_ci .create = subdir_create, 5956881f68fSopenharmony_ci .open = subdir_open, 5966881f68fSopenharmony_ci .read_buf = subdir_read_buf, 5976881f68fSopenharmony_ci .write_buf = subdir_write_buf, 5986881f68fSopenharmony_ci .statfs = subdir_statfs, 5996881f68fSopenharmony_ci .flush = subdir_flush, 6006881f68fSopenharmony_ci .release = subdir_release, 6016881f68fSopenharmony_ci .fsync = subdir_fsync, 6026881f68fSopenharmony_ci .fsyncdir = subdir_fsyncdir, 6036881f68fSopenharmony_ci .setxattr = subdir_setxattr, 6046881f68fSopenharmony_ci .getxattr = subdir_getxattr, 6056881f68fSopenharmony_ci .listxattr = subdir_listxattr, 6066881f68fSopenharmony_ci .removexattr = subdir_removexattr, 6076881f68fSopenharmony_ci .lock = subdir_lock, 6086881f68fSopenharmony_ci .flock = subdir_flock, 6096881f68fSopenharmony_ci .bmap = subdir_bmap, 6106881f68fSopenharmony_ci .lseek = subdir_lseek, 6116881f68fSopenharmony_ci}; 6126881f68fSopenharmony_ci 6136881f68fSopenharmony_cistatic const struct fuse_opt subdir_opts[] = { 6146881f68fSopenharmony_ci FUSE_OPT_KEY("-h", 0), 6156881f68fSopenharmony_ci FUSE_OPT_KEY("--help", 0), 6166881f68fSopenharmony_ci { "subdir=%s", offsetof(struct subdir, base), 0 }, 6176881f68fSopenharmony_ci { "rellinks", offsetof(struct subdir, rellinks), 1 }, 6186881f68fSopenharmony_ci { "norellinks", offsetof(struct subdir, rellinks), 0 }, 6196881f68fSopenharmony_ci FUSE_OPT_END 6206881f68fSopenharmony_ci}; 6216881f68fSopenharmony_ci 6226881f68fSopenharmony_cistatic void subdir_help(void) 6236881f68fSopenharmony_ci{ 6246881f68fSopenharmony_ci printf( 6256881f68fSopenharmony_ci" -o subdir=DIR prepend this directory to all paths (mandatory)\n" 6266881f68fSopenharmony_ci" -o [no]rellinks transform absolute symlinks to relative\n"); 6276881f68fSopenharmony_ci} 6286881f68fSopenharmony_ci 6296881f68fSopenharmony_cistatic int subdir_opt_proc(void *data, const char *arg, int key, 6306881f68fSopenharmony_ci struct fuse_args *outargs) 6316881f68fSopenharmony_ci{ 6326881f68fSopenharmony_ci (void) data; (void) arg; (void) outargs; 6336881f68fSopenharmony_ci 6346881f68fSopenharmony_ci if (!key) { 6356881f68fSopenharmony_ci subdir_help(); 6366881f68fSopenharmony_ci return -1; 6376881f68fSopenharmony_ci } 6386881f68fSopenharmony_ci 6396881f68fSopenharmony_ci return 1; 6406881f68fSopenharmony_ci} 6416881f68fSopenharmony_ci 6426881f68fSopenharmony_cistatic struct fuse_fs *subdir_new(struct fuse_args *args, 6436881f68fSopenharmony_ci struct fuse_fs *next[]) 6446881f68fSopenharmony_ci{ 6456881f68fSopenharmony_ci struct fuse_fs *fs; 6466881f68fSopenharmony_ci struct subdir *d; 6476881f68fSopenharmony_ci 6486881f68fSopenharmony_ci d = calloc(1, sizeof(struct subdir)); 6496881f68fSopenharmony_ci if (d == NULL) { 6506881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n"); 6516881f68fSopenharmony_ci return NULL; 6526881f68fSopenharmony_ci } 6536881f68fSopenharmony_ci 6546881f68fSopenharmony_ci if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1) 6556881f68fSopenharmony_ci goto out_free; 6566881f68fSopenharmony_ci 6576881f68fSopenharmony_ci if (!next[0] || next[1]) { 6586881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-subdir: exactly one next filesystem required\n"); 6596881f68fSopenharmony_ci goto out_free; 6606881f68fSopenharmony_ci } 6616881f68fSopenharmony_ci 6626881f68fSopenharmony_ci if (!d->base) { 6636881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-subdir: missing 'subdir' option\n"); 6646881f68fSopenharmony_ci goto out_free; 6656881f68fSopenharmony_ci } 6666881f68fSopenharmony_ci 6676881f68fSopenharmony_ci if (d->base[0] && d->base[strlen(d->base)-1] != '/') { 6686881f68fSopenharmony_ci char *tmp = realloc(d->base, strlen(d->base) + 2); 6696881f68fSopenharmony_ci if (!tmp) { 6706881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n"); 6716881f68fSopenharmony_ci goto out_free; 6726881f68fSopenharmony_ci } 6736881f68fSopenharmony_ci d->base = tmp; 6746881f68fSopenharmony_ci strcat(d->base, "/"); 6756881f68fSopenharmony_ci } 6766881f68fSopenharmony_ci d->baselen = strlen(d->base); 6776881f68fSopenharmony_ci d->next = next[0]; 6786881f68fSopenharmony_ci fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d); 6796881f68fSopenharmony_ci if (!fs) 6806881f68fSopenharmony_ci goto out_free; 6816881f68fSopenharmony_ci return fs; 6826881f68fSopenharmony_ci 6836881f68fSopenharmony_ciout_free: 6846881f68fSopenharmony_ci free(d->base); 6856881f68fSopenharmony_ci free(d); 6866881f68fSopenharmony_ci return NULL; 6876881f68fSopenharmony_ci} 6886881f68fSopenharmony_ci 6896881f68fSopenharmony_ciFUSE_REGISTER_MODULE(subdir, subdir_new); 690