16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci fuse iconv module: file name charset conversion 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#include <iconv.h> 186881f68fSopenharmony_ci#include <pthread.h> 196881f68fSopenharmony_ci#include <locale.h> 206881f68fSopenharmony_ci#include <langinfo.h> 216881f68fSopenharmony_ci 226881f68fSopenharmony_cistruct iconv { 236881f68fSopenharmony_ci struct fuse_fs *next; 246881f68fSopenharmony_ci pthread_mutex_t lock; 256881f68fSopenharmony_ci char *from_code; 266881f68fSopenharmony_ci char *to_code; 276881f68fSopenharmony_ci iconv_t tofs; 286881f68fSopenharmony_ci iconv_t fromfs; 296881f68fSopenharmony_ci}; 306881f68fSopenharmony_ci 316881f68fSopenharmony_cistruct iconv_dh { 326881f68fSopenharmony_ci struct iconv *ic; 336881f68fSopenharmony_ci void *prev_buf; 346881f68fSopenharmony_ci fuse_fill_dir_t prev_filler; 356881f68fSopenharmony_ci}; 366881f68fSopenharmony_ci 376881f68fSopenharmony_cistatic struct iconv *iconv_get(void) 386881f68fSopenharmony_ci{ 396881f68fSopenharmony_ci return fuse_get_context()->private_data; 406881f68fSopenharmony_ci} 416881f68fSopenharmony_ci 426881f68fSopenharmony_cistatic int iconv_convpath(struct iconv *ic, const char *path, char **newpathp, 436881f68fSopenharmony_ci int fromfs) 446881f68fSopenharmony_ci{ 456881f68fSopenharmony_ci size_t pathlen; 466881f68fSopenharmony_ci size_t newpathlen; 476881f68fSopenharmony_ci char *newpath; 486881f68fSopenharmony_ci size_t plen; 496881f68fSopenharmony_ci char *p; 506881f68fSopenharmony_ci size_t res; 516881f68fSopenharmony_ci int err; 526881f68fSopenharmony_ci 536881f68fSopenharmony_ci if (path == NULL) { 546881f68fSopenharmony_ci *newpathp = NULL; 556881f68fSopenharmony_ci return 0; 566881f68fSopenharmony_ci } 576881f68fSopenharmony_ci 586881f68fSopenharmony_ci pathlen = strlen(path); 596881f68fSopenharmony_ci newpathlen = pathlen * 4; 606881f68fSopenharmony_ci newpath = malloc(newpathlen + 1); 616881f68fSopenharmony_ci if (!newpath) 626881f68fSopenharmony_ci return -ENOMEM; 636881f68fSopenharmony_ci 646881f68fSopenharmony_ci plen = newpathlen; 656881f68fSopenharmony_ci p = newpath; 666881f68fSopenharmony_ci pthread_mutex_lock(&ic->lock); 676881f68fSopenharmony_ci do { 686881f68fSopenharmony_ci res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path, 696881f68fSopenharmony_ci &pathlen, &p, &plen); 706881f68fSopenharmony_ci if (res == (size_t) -1) { 716881f68fSopenharmony_ci char *tmp; 726881f68fSopenharmony_ci size_t inc; 736881f68fSopenharmony_ci 746881f68fSopenharmony_ci err = -EILSEQ; 756881f68fSopenharmony_ci if (errno != E2BIG) 766881f68fSopenharmony_ci goto err; 776881f68fSopenharmony_ci 786881f68fSopenharmony_ci inc = (pathlen + 1) * 4; 796881f68fSopenharmony_ci newpathlen += inc; 806881f68fSopenharmony_ci int dp = p - newpath; 816881f68fSopenharmony_ci tmp = realloc(newpath, newpathlen + 1); 826881f68fSopenharmony_ci err = -ENOMEM; 836881f68fSopenharmony_ci if (!tmp) 846881f68fSopenharmony_ci goto err; 856881f68fSopenharmony_ci 866881f68fSopenharmony_ci p = tmp + dp; 876881f68fSopenharmony_ci plen += inc; 886881f68fSopenharmony_ci newpath = tmp; 896881f68fSopenharmony_ci } 906881f68fSopenharmony_ci } while (res == (size_t) -1); 916881f68fSopenharmony_ci pthread_mutex_unlock(&ic->lock); 926881f68fSopenharmony_ci *p = '\0'; 936881f68fSopenharmony_ci *newpathp = newpath; 946881f68fSopenharmony_ci return 0; 956881f68fSopenharmony_ci 966881f68fSopenharmony_cierr: 976881f68fSopenharmony_ci iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL); 986881f68fSopenharmony_ci pthread_mutex_unlock(&ic->lock); 996881f68fSopenharmony_ci free(newpath); 1006881f68fSopenharmony_ci return err; 1016881f68fSopenharmony_ci} 1026881f68fSopenharmony_ci 1036881f68fSopenharmony_cistatic int iconv_getattr(const char *path, struct stat *stbuf, 1046881f68fSopenharmony_ci struct fuse_file_info *fi) 1056881f68fSopenharmony_ci{ 1066881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 1076881f68fSopenharmony_ci char *newpath; 1086881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 1096881f68fSopenharmony_ci if (!err) { 1106881f68fSopenharmony_ci err = fuse_fs_getattr(ic->next, newpath, stbuf, fi); 1116881f68fSopenharmony_ci free(newpath); 1126881f68fSopenharmony_ci } 1136881f68fSopenharmony_ci return err; 1146881f68fSopenharmony_ci} 1156881f68fSopenharmony_ci 1166881f68fSopenharmony_cistatic int iconv_access(const char *path, int mask) 1176881f68fSopenharmony_ci{ 1186881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 1196881f68fSopenharmony_ci char *newpath; 1206881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 1216881f68fSopenharmony_ci if (!err) { 1226881f68fSopenharmony_ci err = fuse_fs_access(ic->next, newpath, mask); 1236881f68fSopenharmony_ci free(newpath); 1246881f68fSopenharmony_ci } 1256881f68fSopenharmony_ci return err; 1266881f68fSopenharmony_ci} 1276881f68fSopenharmony_ci 1286881f68fSopenharmony_cistatic int iconv_readlink(const char *path, char *buf, size_t size) 1296881f68fSopenharmony_ci{ 1306881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 1316881f68fSopenharmony_ci char *newpath; 1326881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 1336881f68fSopenharmony_ci if (!err) { 1346881f68fSopenharmony_ci err = fuse_fs_readlink(ic->next, newpath, buf, size); 1356881f68fSopenharmony_ci if (!err) { 1366881f68fSopenharmony_ci char *newlink; 1376881f68fSopenharmony_ci err = iconv_convpath(ic, buf, &newlink, 1); 1386881f68fSopenharmony_ci if (!err) { 1396881f68fSopenharmony_ci strncpy(buf, newlink, size - 1); 1406881f68fSopenharmony_ci buf[size - 1] = '\0'; 1416881f68fSopenharmony_ci free(newlink); 1426881f68fSopenharmony_ci } 1436881f68fSopenharmony_ci } 1446881f68fSopenharmony_ci free(newpath); 1456881f68fSopenharmony_ci } 1466881f68fSopenharmony_ci return err; 1476881f68fSopenharmony_ci} 1486881f68fSopenharmony_ci 1496881f68fSopenharmony_cistatic int iconv_opendir(const char *path, struct fuse_file_info *fi) 1506881f68fSopenharmony_ci{ 1516881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 1526881f68fSopenharmony_ci char *newpath; 1536881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 1546881f68fSopenharmony_ci if (!err) { 1556881f68fSopenharmony_ci err = fuse_fs_opendir(ic->next, newpath, fi); 1566881f68fSopenharmony_ci free(newpath); 1576881f68fSopenharmony_ci } 1586881f68fSopenharmony_ci return err; 1596881f68fSopenharmony_ci} 1606881f68fSopenharmony_ci 1616881f68fSopenharmony_cistatic int iconv_dir_fill(void *buf, const char *name, 1626881f68fSopenharmony_ci const struct stat *stbuf, off_t off, 1636881f68fSopenharmony_ci enum fuse_fill_dir_flags flags) 1646881f68fSopenharmony_ci{ 1656881f68fSopenharmony_ci struct iconv_dh *dh = buf; 1666881f68fSopenharmony_ci char *newname; 1676881f68fSopenharmony_ci int res = 0; 1686881f68fSopenharmony_ci if (iconv_convpath(dh->ic, name, &newname, 1) == 0) { 1696881f68fSopenharmony_ci res = dh->prev_filler(dh->prev_buf, newname, stbuf, off, flags); 1706881f68fSopenharmony_ci free(newname); 1716881f68fSopenharmony_ci } 1726881f68fSopenharmony_ci return res; 1736881f68fSopenharmony_ci} 1746881f68fSopenharmony_ci 1756881f68fSopenharmony_cistatic int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 1766881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi, 1776881f68fSopenharmony_ci enum fuse_readdir_flags flags) 1786881f68fSopenharmony_ci{ 1796881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 1806881f68fSopenharmony_ci char *newpath; 1816881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 1826881f68fSopenharmony_ci if (!err) { 1836881f68fSopenharmony_ci struct iconv_dh dh; 1846881f68fSopenharmony_ci dh.ic = ic; 1856881f68fSopenharmony_ci dh.prev_buf = buf; 1866881f68fSopenharmony_ci dh.prev_filler = filler; 1876881f68fSopenharmony_ci err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill, 1886881f68fSopenharmony_ci offset, fi, flags); 1896881f68fSopenharmony_ci free(newpath); 1906881f68fSopenharmony_ci } 1916881f68fSopenharmony_ci return err; 1926881f68fSopenharmony_ci} 1936881f68fSopenharmony_ci 1946881f68fSopenharmony_cistatic int iconv_releasedir(const char *path, struct fuse_file_info *fi) 1956881f68fSopenharmony_ci{ 1966881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 1976881f68fSopenharmony_ci char *newpath; 1986881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 1996881f68fSopenharmony_ci if (!err) { 2006881f68fSopenharmony_ci err = fuse_fs_releasedir(ic->next, newpath, fi); 2016881f68fSopenharmony_ci free(newpath); 2026881f68fSopenharmony_ci } 2036881f68fSopenharmony_ci return err; 2046881f68fSopenharmony_ci} 2056881f68fSopenharmony_ci 2066881f68fSopenharmony_cistatic int iconv_mknod(const char *path, mode_t mode, dev_t rdev) 2076881f68fSopenharmony_ci{ 2086881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 2096881f68fSopenharmony_ci char *newpath; 2106881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 2116881f68fSopenharmony_ci if (!err) { 2126881f68fSopenharmony_ci err = fuse_fs_mknod(ic->next, newpath, mode, rdev); 2136881f68fSopenharmony_ci free(newpath); 2146881f68fSopenharmony_ci } 2156881f68fSopenharmony_ci return err; 2166881f68fSopenharmony_ci} 2176881f68fSopenharmony_ci 2186881f68fSopenharmony_cistatic int iconv_mkdir(const char *path, mode_t mode) 2196881f68fSopenharmony_ci{ 2206881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 2216881f68fSopenharmony_ci char *newpath; 2226881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 2236881f68fSopenharmony_ci if (!err) { 2246881f68fSopenharmony_ci err = fuse_fs_mkdir(ic->next, newpath, mode); 2256881f68fSopenharmony_ci free(newpath); 2266881f68fSopenharmony_ci } 2276881f68fSopenharmony_ci return err; 2286881f68fSopenharmony_ci} 2296881f68fSopenharmony_ci 2306881f68fSopenharmony_cistatic int iconv_unlink(const char *path) 2316881f68fSopenharmony_ci{ 2326881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 2336881f68fSopenharmony_ci char *newpath; 2346881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 2356881f68fSopenharmony_ci if (!err) { 2366881f68fSopenharmony_ci err = fuse_fs_unlink(ic->next, newpath); 2376881f68fSopenharmony_ci free(newpath); 2386881f68fSopenharmony_ci } 2396881f68fSopenharmony_ci return err; 2406881f68fSopenharmony_ci} 2416881f68fSopenharmony_ci 2426881f68fSopenharmony_cistatic int iconv_rmdir(const char *path) 2436881f68fSopenharmony_ci{ 2446881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 2456881f68fSopenharmony_ci char *newpath; 2466881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 2476881f68fSopenharmony_ci if (!err) { 2486881f68fSopenharmony_ci err = fuse_fs_rmdir(ic->next, newpath); 2496881f68fSopenharmony_ci free(newpath); 2506881f68fSopenharmony_ci } 2516881f68fSopenharmony_ci return err; 2526881f68fSopenharmony_ci} 2536881f68fSopenharmony_ci 2546881f68fSopenharmony_cistatic int iconv_symlink(const char *from, const char *to) 2556881f68fSopenharmony_ci{ 2566881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 2576881f68fSopenharmony_ci char *newfrom; 2586881f68fSopenharmony_ci char *newto; 2596881f68fSopenharmony_ci int err = iconv_convpath(ic, from, &newfrom, 0); 2606881f68fSopenharmony_ci if (!err) { 2616881f68fSopenharmony_ci err = iconv_convpath(ic, to, &newto, 0); 2626881f68fSopenharmony_ci if (!err) { 2636881f68fSopenharmony_ci err = fuse_fs_symlink(ic->next, newfrom, newto); 2646881f68fSopenharmony_ci free(newto); 2656881f68fSopenharmony_ci } 2666881f68fSopenharmony_ci free(newfrom); 2676881f68fSopenharmony_ci } 2686881f68fSopenharmony_ci return err; 2696881f68fSopenharmony_ci} 2706881f68fSopenharmony_ci 2716881f68fSopenharmony_cistatic int iconv_rename(const char *from, const char *to, unsigned int flags) 2726881f68fSopenharmony_ci{ 2736881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 2746881f68fSopenharmony_ci char *newfrom; 2756881f68fSopenharmony_ci char *newto; 2766881f68fSopenharmony_ci int err = iconv_convpath(ic, from, &newfrom, 0); 2776881f68fSopenharmony_ci if (!err) { 2786881f68fSopenharmony_ci err = iconv_convpath(ic, to, &newto, 0); 2796881f68fSopenharmony_ci if (!err) { 2806881f68fSopenharmony_ci err = fuse_fs_rename(ic->next, newfrom, newto, flags); 2816881f68fSopenharmony_ci free(newto); 2826881f68fSopenharmony_ci } 2836881f68fSopenharmony_ci free(newfrom); 2846881f68fSopenharmony_ci } 2856881f68fSopenharmony_ci return err; 2866881f68fSopenharmony_ci} 2876881f68fSopenharmony_ci 2886881f68fSopenharmony_cistatic int iconv_link(const char *from, const char *to) 2896881f68fSopenharmony_ci{ 2906881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 2916881f68fSopenharmony_ci char *newfrom; 2926881f68fSopenharmony_ci char *newto; 2936881f68fSopenharmony_ci int err = iconv_convpath(ic, from, &newfrom, 0); 2946881f68fSopenharmony_ci if (!err) { 2956881f68fSopenharmony_ci err = iconv_convpath(ic, to, &newto, 0); 2966881f68fSopenharmony_ci if (!err) { 2976881f68fSopenharmony_ci err = fuse_fs_link(ic->next, newfrom, newto); 2986881f68fSopenharmony_ci free(newto); 2996881f68fSopenharmony_ci } 3006881f68fSopenharmony_ci free(newfrom); 3016881f68fSopenharmony_ci } 3026881f68fSopenharmony_ci return err; 3036881f68fSopenharmony_ci} 3046881f68fSopenharmony_ci 3056881f68fSopenharmony_cistatic int iconv_chmod(const char *path, mode_t mode, 3066881f68fSopenharmony_ci struct fuse_file_info *fi) 3076881f68fSopenharmony_ci{ 3086881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3096881f68fSopenharmony_ci char *newpath; 3106881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 3116881f68fSopenharmony_ci if (!err) { 3126881f68fSopenharmony_ci err = fuse_fs_chmod(ic->next, newpath, mode, fi); 3136881f68fSopenharmony_ci free(newpath); 3146881f68fSopenharmony_ci } 3156881f68fSopenharmony_ci return err; 3166881f68fSopenharmony_ci} 3176881f68fSopenharmony_ci 3186881f68fSopenharmony_cistatic int iconv_chown(const char *path, uid_t uid, gid_t gid, 3196881f68fSopenharmony_ci struct fuse_file_info *fi) 3206881f68fSopenharmony_ci{ 3216881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3226881f68fSopenharmony_ci char *newpath; 3236881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 3246881f68fSopenharmony_ci if (!err) { 3256881f68fSopenharmony_ci err = fuse_fs_chown(ic->next, newpath, uid, gid, fi); 3266881f68fSopenharmony_ci free(newpath); 3276881f68fSopenharmony_ci } 3286881f68fSopenharmony_ci return err; 3296881f68fSopenharmony_ci} 3306881f68fSopenharmony_ci 3316881f68fSopenharmony_cistatic int iconv_truncate(const char *path, off_t size, 3326881f68fSopenharmony_ci struct fuse_file_info *fi) 3336881f68fSopenharmony_ci{ 3346881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3356881f68fSopenharmony_ci char *newpath; 3366881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 3376881f68fSopenharmony_ci if (!err) { 3386881f68fSopenharmony_ci err = fuse_fs_truncate(ic->next, newpath, size, fi); 3396881f68fSopenharmony_ci free(newpath); 3406881f68fSopenharmony_ci } 3416881f68fSopenharmony_ci return err; 3426881f68fSopenharmony_ci} 3436881f68fSopenharmony_ci 3446881f68fSopenharmony_cistatic int iconv_utimens(const char *path, const struct timespec ts[2], 3456881f68fSopenharmony_ci struct fuse_file_info *fi) 3466881f68fSopenharmony_ci{ 3476881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3486881f68fSopenharmony_ci char *newpath; 3496881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 3506881f68fSopenharmony_ci if (!err) { 3516881f68fSopenharmony_ci err = fuse_fs_utimens(ic->next, newpath, ts, fi); 3526881f68fSopenharmony_ci free(newpath); 3536881f68fSopenharmony_ci } 3546881f68fSopenharmony_ci return err; 3556881f68fSopenharmony_ci} 3566881f68fSopenharmony_ci 3576881f68fSopenharmony_cistatic int iconv_create(const char *path, mode_t mode, 3586881f68fSopenharmony_ci struct fuse_file_info *fi) 3596881f68fSopenharmony_ci{ 3606881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3616881f68fSopenharmony_ci char *newpath; 3626881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 3636881f68fSopenharmony_ci if (!err) { 3646881f68fSopenharmony_ci err = fuse_fs_create(ic->next, newpath, mode, fi); 3656881f68fSopenharmony_ci free(newpath); 3666881f68fSopenharmony_ci } 3676881f68fSopenharmony_ci return err; 3686881f68fSopenharmony_ci} 3696881f68fSopenharmony_ci 3706881f68fSopenharmony_cistatic int iconv_open_file(const char *path, struct fuse_file_info *fi) 3716881f68fSopenharmony_ci{ 3726881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3736881f68fSopenharmony_ci char *newpath; 3746881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 3756881f68fSopenharmony_ci if (!err) { 3766881f68fSopenharmony_ci err = fuse_fs_open(ic->next, newpath, fi); 3776881f68fSopenharmony_ci free(newpath); 3786881f68fSopenharmony_ci } 3796881f68fSopenharmony_ci return err; 3806881f68fSopenharmony_ci} 3816881f68fSopenharmony_ci 3826881f68fSopenharmony_cistatic int iconv_read_buf(const char *path, struct fuse_bufvec **bufp, 3836881f68fSopenharmony_ci size_t size, off_t offset, struct fuse_file_info *fi) 3846881f68fSopenharmony_ci{ 3856881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3866881f68fSopenharmony_ci char *newpath; 3876881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 3886881f68fSopenharmony_ci if (!err) { 3896881f68fSopenharmony_ci err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi); 3906881f68fSopenharmony_ci free(newpath); 3916881f68fSopenharmony_ci } 3926881f68fSopenharmony_ci return err; 3936881f68fSopenharmony_ci} 3946881f68fSopenharmony_ci 3956881f68fSopenharmony_cistatic int iconv_write_buf(const char *path, struct fuse_bufvec *buf, 3966881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 3976881f68fSopenharmony_ci{ 3986881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 3996881f68fSopenharmony_ci char *newpath; 4006881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4016881f68fSopenharmony_ci if (!err) { 4026881f68fSopenharmony_ci err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi); 4036881f68fSopenharmony_ci free(newpath); 4046881f68fSopenharmony_ci } 4056881f68fSopenharmony_ci return err; 4066881f68fSopenharmony_ci} 4076881f68fSopenharmony_ci 4086881f68fSopenharmony_cistatic int iconv_statfs(const char *path, struct statvfs *stbuf) 4096881f68fSopenharmony_ci{ 4106881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 4116881f68fSopenharmony_ci char *newpath; 4126881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4136881f68fSopenharmony_ci if (!err) { 4146881f68fSopenharmony_ci err = fuse_fs_statfs(ic->next, newpath, stbuf); 4156881f68fSopenharmony_ci free(newpath); 4166881f68fSopenharmony_ci } 4176881f68fSopenharmony_ci return err; 4186881f68fSopenharmony_ci} 4196881f68fSopenharmony_ci 4206881f68fSopenharmony_cistatic int iconv_flush(const char *path, struct fuse_file_info *fi) 4216881f68fSopenharmony_ci{ 4226881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 4236881f68fSopenharmony_ci char *newpath; 4246881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4256881f68fSopenharmony_ci if (!err) { 4266881f68fSopenharmony_ci err = fuse_fs_flush(ic->next, newpath, fi); 4276881f68fSopenharmony_ci free(newpath); 4286881f68fSopenharmony_ci } 4296881f68fSopenharmony_ci return err; 4306881f68fSopenharmony_ci} 4316881f68fSopenharmony_ci 4326881f68fSopenharmony_cistatic int iconv_release(const char *path, struct fuse_file_info *fi) 4336881f68fSopenharmony_ci{ 4346881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 4356881f68fSopenharmony_ci char *newpath; 4366881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4376881f68fSopenharmony_ci if (!err) { 4386881f68fSopenharmony_ci err = fuse_fs_release(ic->next, newpath, fi); 4396881f68fSopenharmony_ci free(newpath); 4406881f68fSopenharmony_ci } 4416881f68fSopenharmony_ci return err; 4426881f68fSopenharmony_ci} 4436881f68fSopenharmony_ci 4446881f68fSopenharmony_cistatic int iconv_fsync(const char *path, int isdatasync, 4456881f68fSopenharmony_ci struct fuse_file_info *fi) 4466881f68fSopenharmony_ci{ 4476881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 4486881f68fSopenharmony_ci char *newpath; 4496881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4506881f68fSopenharmony_ci if (!err) { 4516881f68fSopenharmony_ci err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi); 4526881f68fSopenharmony_ci free(newpath); 4536881f68fSopenharmony_ci } 4546881f68fSopenharmony_ci return err; 4556881f68fSopenharmony_ci} 4566881f68fSopenharmony_ci 4576881f68fSopenharmony_cistatic int iconv_fsyncdir(const char *path, int isdatasync, 4586881f68fSopenharmony_ci struct fuse_file_info *fi) 4596881f68fSopenharmony_ci{ 4606881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 4616881f68fSopenharmony_ci char *newpath; 4626881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4636881f68fSopenharmony_ci if (!err) { 4646881f68fSopenharmony_ci err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi); 4656881f68fSopenharmony_ci free(newpath); 4666881f68fSopenharmony_ci } 4676881f68fSopenharmony_ci return err; 4686881f68fSopenharmony_ci} 4696881f68fSopenharmony_ci 4706881f68fSopenharmony_cistatic int iconv_setxattr(const char *path, const char *name, 4716881f68fSopenharmony_ci const char *value, size_t size, int flags) 4726881f68fSopenharmony_ci{ 4736881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 4746881f68fSopenharmony_ci char *newpath; 4756881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4766881f68fSopenharmony_ci if (!err) { 4776881f68fSopenharmony_ci err = fuse_fs_setxattr(ic->next, newpath, name, value, size, 4786881f68fSopenharmony_ci flags); 4796881f68fSopenharmony_ci free(newpath); 4806881f68fSopenharmony_ci } 4816881f68fSopenharmony_ci return err; 4826881f68fSopenharmony_ci} 4836881f68fSopenharmony_ci 4846881f68fSopenharmony_cistatic int iconv_getxattr(const char *path, const char *name, char *value, 4856881f68fSopenharmony_ci size_t size) 4866881f68fSopenharmony_ci{ 4876881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 4886881f68fSopenharmony_ci char *newpath; 4896881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 4906881f68fSopenharmony_ci if (!err) { 4916881f68fSopenharmony_ci err = fuse_fs_getxattr(ic->next, newpath, name, value, size); 4926881f68fSopenharmony_ci free(newpath); 4936881f68fSopenharmony_ci } 4946881f68fSopenharmony_ci return err; 4956881f68fSopenharmony_ci} 4966881f68fSopenharmony_ci 4976881f68fSopenharmony_cistatic int iconv_listxattr(const char *path, char *list, size_t size) 4986881f68fSopenharmony_ci{ 4996881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 5006881f68fSopenharmony_ci char *newpath; 5016881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 5026881f68fSopenharmony_ci if (!err) { 5036881f68fSopenharmony_ci err = fuse_fs_listxattr(ic->next, newpath, list, size); 5046881f68fSopenharmony_ci free(newpath); 5056881f68fSopenharmony_ci } 5066881f68fSopenharmony_ci return err; 5076881f68fSopenharmony_ci} 5086881f68fSopenharmony_ci 5096881f68fSopenharmony_cistatic int iconv_removexattr(const char *path, const char *name) 5106881f68fSopenharmony_ci{ 5116881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 5126881f68fSopenharmony_ci char *newpath; 5136881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 5146881f68fSopenharmony_ci if (!err) { 5156881f68fSopenharmony_ci err = fuse_fs_removexattr(ic->next, newpath, name); 5166881f68fSopenharmony_ci free(newpath); 5176881f68fSopenharmony_ci } 5186881f68fSopenharmony_ci return err; 5196881f68fSopenharmony_ci} 5206881f68fSopenharmony_ci 5216881f68fSopenharmony_cistatic int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd, 5226881f68fSopenharmony_ci struct flock *lock) 5236881f68fSopenharmony_ci{ 5246881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 5256881f68fSopenharmony_ci char *newpath; 5266881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 5276881f68fSopenharmony_ci if (!err) { 5286881f68fSopenharmony_ci err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock); 5296881f68fSopenharmony_ci free(newpath); 5306881f68fSopenharmony_ci } 5316881f68fSopenharmony_ci return err; 5326881f68fSopenharmony_ci} 5336881f68fSopenharmony_ci 5346881f68fSopenharmony_cistatic int iconv_flock(const char *path, struct fuse_file_info *fi, int op) 5356881f68fSopenharmony_ci{ 5366881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 5376881f68fSopenharmony_ci char *newpath; 5386881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 5396881f68fSopenharmony_ci if (!err) { 5406881f68fSopenharmony_ci err = fuse_fs_flock(ic->next, newpath, fi, op); 5416881f68fSopenharmony_ci free(newpath); 5426881f68fSopenharmony_ci } 5436881f68fSopenharmony_ci return err; 5446881f68fSopenharmony_ci} 5456881f68fSopenharmony_ci 5466881f68fSopenharmony_cistatic int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx) 5476881f68fSopenharmony_ci{ 5486881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 5496881f68fSopenharmony_ci char *newpath; 5506881f68fSopenharmony_ci int err = iconv_convpath(ic, path, &newpath, 0); 5516881f68fSopenharmony_ci if (!err) { 5526881f68fSopenharmony_ci err = fuse_fs_bmap(ic->next, newpath, blocksize, idx); 5536881f68fSopenharmony_ci free(newpath); 5546881f68fSopenharmony_ci } 5556881f68fSopenharmony_ci return err; 5566881f68fSopenharmony_ci} 5576881f68fSopenharmony_ci 5586881f68fSopenharmony_cistatic off_t iconv_lseek(const char *path, off_t off, int whence, 5596881f68fSopenharmony_ci struct fuse_file_info *fi) 5606881f68fSopenharmony_ci{ 5616881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 5626881f68fSopenharmony_ci char *newpath; 5636881f68fSopenharmony_ci int res = iconv_convpath(ic, path, &newpath, 0); 5646881f68fSopenharmony_ci if (!res) { 5656881f68fSopenharmony_ci res = fuse_fs_lseek(ic->next, newpath, off, whence, fi); 5666881f68fSopenharmony_ci free(newpath); 5676881f68fSopenharmony_ci } 5686881f68fSopenharmony_ci return res; 5696881f68fSopenharmony_ci} 5706881f68fSopenharmony_ci 5716881f68fSopenharmony_cistatic void *iconv_init(struct fuse_conn_info *conn, 5726881f68fSopenharmony_ci struct fuse_config *cfg) 5736881f68fSopenharmony_ci{ 5746881f68fSopenharmony_ci struct iconv *ic = iconv_get(); 5756881f68fSopenharmony_ci fuse_fs_init(ic->next, conn, cfg); 5766881f68fSopenharmony_ci /* Don't touch cfg->nullpath_ok, we can work with 5776881f68fSopenharmony_ci either */ 5786881f68fSopenharmony_ci return ic; 5796881f68fSopenharmony_ci} 5806881f68fSopenharmony_ci 5816881f68fSopenharmony_cistatic void iconv_destroy(void *data) 5826881f68fSopenharmony_ci{ 5836881f68fSopenharmony_ci struct iconv *ic = data; 5846881f68fSopenharmony_ci fuse_fs_destroy(ic->next); 5856881f68fSopenharmony_ci iconv_close(ic->tofs); 5866881f68fSopenharmony_ci iconv_close(ic->fromfs); 5876881f68fSopenharmony_ci pthread_mutex_destroy(&ic->lock); 5886881f68fSopenharmony_ci free(ic->from_code); 5896881f68fSopenharmony_ci free(ic->to_code); 5906881f68fSopenharmony_ci free(ic); 5916881f68fSopenharmony_ci} 5926881f68fSopenharmony_ci 5936881f68fSopenharmony_cistatic const struct fuse_operations iconv_oper = { 5946881f68fSopenharmony_ci .destroy = iconv_destroy, 5956881f68fSopenharmony_ci .init = iconv_init, 5966881f68fSopenharmony_ci .getattr = iconv_getattr, 5976881f68fSopenharmony_ci .access = iconv_access, 5986881f68fSopenharmony_ci .readlink = iconv_readlink, 5996881f68fSopenharmony_ci .opendir = iconv_opendir, 6006881f68fSopenharmony_ci .readdir = iconv_readdir, 6016881f68fSopenharmony_ci .releasedir = iconv_releasedir, 6026881f68fSopenharmony_ci .mknod = iconv_mknod, 6036881f68fSopenharmony_ci .mkdir = iconv_mkdir, 6046881f68fSopenharmony_ci .symlink = iconv_symlink, 6056881f68fSopenharmony_ci .unlink = iconv_unlink, 6066881f68fSopenharmony_ci .rmdir = iconv_rmdir, 6076881f68fSopenharmony_ci .rename = iconv_rename, 6086881f68fSopenharmony_ci .link = iconv_link, 6096881f68fSopenharmony_ci .chmod = iconv_chmod, 6106881f68fSopenharmony_ci .chown = iconv_chown, 6116881f68fSopenharmony_ci .truncate = iconv_truncate, 6126881f68fSopenharmony_ci .utimens = iconv_utimens, 6136881f68fSopenharmony_ci .create = iconv_create, 6146881f68fSopenharmony_ci .open = iconv_open_file, 6156881f68fSopenharmony_ci .read_buf = iconv_read_buf, 6166881f68fSopenharmony_ci .write_buf = iconv_write_buf, 6176881f68fSopenharmony_ci .statfs = iconv_statfs, 6186881f68fSopenharmony_ci .flush = iconv_flush, 6196881f68fSopenharmony_ci .release = iconv_release, 6206881f68fSopenharmony_ci .fsync = iconv_fsync, 6216881f68fSopenharmony_ci .fsyncdir = iconv_fsyncdir, 6226881f68fSopenharmony_ci .setxattr = iconv_setxattr, 6236881f68fSopenharmony_ci .getxattr = iconv_getxattr, 6246881f68fSopenharmony_ci .listxattr = iconv_listxattr, 6256881f68fSopenharmony_ci .removexattr = iconv_removexattr, 6266881f68fSopenharmony_ci .lock = iconv_lock, 6276881f68fSopenharmony_ci .flock = iconv_flock, 6286881f68fSopenharmony_ci .bmap = iconv_bmap, 6296881f68fSopenharmony_ci .lseek = iconv_lseek, 6306881f68fSopenharmony_ci}; 6316881f68fSopenharmony_ci 6326881f68fSopenharmony_cistatic const struct fuse_opt iconv_opts[] = { 6336881f68fSopenharmony_ci FUSE_OPT_KEY("-h", 0), 6346881f68fSopenharmony_ci FUSE_OPT_KEY("--help", 0), 6356881f68fSopenharmony_ci { "from_code=%s", offsetof(struct iconv, from_code), 0 }, 6366881f68fSopenharmony_ci { "to_code=%s", offsetof(struct iconv, to_code), 1 }, 6376881f68fSopenharmony_ci FUSE_OPT_END 6386881f68fSopenharmony_ci}; 6396881f68fSopenharmony_ci 6406881f68fSopenharmony_cistatic void iconv_help(void) 6416881f68fSopenharmony_ci{ 6426881f68fSopenharmony_ci char *charmap; 6436881f68fSopenharmony_ci const char *old = setlocale(LC_CTYPE, ""); 6446881f68fSopenharmony_ci 6456881f68fSopenharmony_ci charmap = strdup(nl_langinfo(CODESET)); 6466881f68fSopenharmony_ci if (old) 6476881f68fSopenharmony_ci setlocale(LC_CTYPE, old); 6486881f68fSopenharmony_ci else 6496881f68fSopenharmony_ci perror("setlocale"); 6506881f68fSopenharmony_ci 6516881f68fSopenharmony_ci printf( 6526881f68fSopenharmony_ci" -o from_code=CHARSET original encoding of file names (default: UTF-8)\n" 6536881f68fSopenharmony_ci" -o to_code=CHARSET new encoding of the file names (default: %s)\n", 6546881f68fSopenharmony_ci charmap); 6556881f68fSopenharmony_ci free(charmap); 6566881f68fSopenharmony_ci} 6576881f68fSopenharmony_ci 6586881f68fSopenharmony_cistatic int iconv_opt_proc(void *data, const char *arg, int key, 6596881f68fSopenharmony_ci struct fuse_args *outargs) 6606881f68fSopenharmony_ci{ 6616881f68fSopenharmony_ci (void) data; (void) arg; (void) outargs; 6626881f68fSopenharmony_ci 6636881f68fSopenharmony_ci if (!key) { 6646881f68fSopenharmony_ci iconv_help(); 6656881f68fSopenharmony_ci return -1; 6666881f68fSopenharmony_ci } 6676881f68fSopenharmony_ci 6686881f68fSopenharmony_ci return 1; 6696881f68fSopenharmony_ci} 6706881f68fSopenharmony_ci 6716881f68fSopenharmony_cistatic struct fuse_fs *iconv_new(struct fuse_args *args, 6726881f68fSopenharmony_ci struct fuse_fs *next[]) 6736881f68fSopenharmony_ci{ 6746881f68fSopenharmony_ci struct fuse_fs *fs; 6756881f68fSopenharmony_ci struct iconv *ic; 6766881f68fSopenharmony_ci const char *old = NULL; 6776881f68fSopenharmony_ci const char *from; 6786881f68fSopenharmony_ci const char *to; 6796881f68fSopenharmony_ci 6806881f68fSopenharmony_ci ic = calloc(1, sizeof(struct iconv)); 6816881f68fSopenharmony_ci if (ic == NULL) { 6826881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-iconv: memory allocation failed\n"); 6836881f68fSopenharmony_ci return NULL; 6846881f68fSopenharmony_ci } 6856881f68fSopenharmony_ci 6866881f68fSopenharmony_ci if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1) 6876881f68fSopenharmony_ci goto out_free; 6886881f68fSopenharmony_ci 6896881f68fSopenharmony_ci if (!next[0] || next[1]) { 6906881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-iconv: exactly one next filesystem required\n"); 6916881f68fSopenharmony_ci goto out_free; 6926881f68fSopenharmony_ci } 6936881f68fSopenharmony_ci 6946881f68fSopenharmony_ci from = ic->from_code ? ic->from_code : "UTF-8"; 6956881f68fSopenharmony_ci to = ic->to_code ? ic->to_code : ""; 6966881f68fSopenharmony_ci /* FIXME: detect charset equivalence? */ 6976881f68fSopenharmony_ci if (!to[0]) 6986881f68fSopenharmony_ci old = setlocale(LC_CTYPE, ""); 6996881f68fSopenharmony_ci ic->tofs = iconv_open(from, to); 7006881f68fSopenharmony_ci if (ic->tofs == (iconv_t) -1) { 7016881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-iconv: cannot convert from %s to %s\n", 7026881f68fSopenharmony_ci to, from); 7036881f68fSopenharmony_ci goto out_free; 7046881f68fSopenharmony_ci } 7056881f68fSopenharmony_ci ic->fromfs = iconv_open(to, from); 7066881f68fSopenharmony_ci if (ic->tofs == (iconv_t) -1) { 7076881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse-iconv: cannot convert from %s to %s\n", 7086881f68fSopenharmony_ci from, to); 7096881f68fSopenharmony_ci goto out_iconv_close_to; 7106881f68fSopenharmony_ci } 7116881f68fSopenharmony_ci if (old) { 7126881f68fSopenharmony_ci setlocale(LC_CTYPE, old); 7136881f68fSopenharmony_ci old = NULL; 7146881f68fSopenharmony_ci } 7156881f68fSopenharmony_ci 7166881f68fSopenharmony_ci ic->next = next[0]; 7176881f68fSopenharmony_ci fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic); 7186881f68fSopenharmony_ci if (!fs) 7196881f68fSopenharmony_ci goto out_iconv_close_from; 7206881f68fSopenharmony_ci 7216881f68fSopenharmony_ci return fs; 7226881f68fSopenharmony_ci 7236881f68fSopenharmony_ciout_iconv_close_from: 7246881f68fSopenharmony_ci iconv_close(ic->fromfs); 7256881f68fSopenharmony_ciout_iconv_close_to: 7266881f68fSopenharmony_ci iconv_close(ic->tofs); 7276881f68fSopenharmony_ciout_free: 7286881f68fSopenharmony_ci free(ic->from_code); 7296881f68fSopenharmony_ci free(ic->to_code); 7306881f68fSopenharmony_ci free(ic); 7316881f68fSopenharmony_ci if (old) { 7326881f68fSopenharmony_ci setlocale(LC_CTYPE, old); 7336881f68fSopenharmony_ci } 7346881f68fSopenharmony_ci return NULL; 7356881f68fSopenharmony_ci} 7366881f68fSopenharmony_ci 7376881f68fSopenharmony_ciFUSE_REGISTER_MODULE(iconv, iconv_new); 738