9#include <fuse_config.h>
37static struct iconv *iconv_get(
void)
42static int iconv_convpath(
struct iconv *ic,
const char *path,
char **newpathp,
58 pathlen = strlen(path);
59 newpathlen = pathlen * 4;
60 newpath = malloc(newpathlen + 1);
66 pthread_mutex_lock(&ic->lock);
68 res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path,
70 if (res == (
size_t) -1) {
78 inc = (pathlen + 1) * 4;
81 tmp = realloc(newpath, newpathlen + 1);
90 }
while (res == (
size_t) -1);
91 pthread_mutex_unlock(&ic->lock);
97 iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL);
98 pthread_mutex_unlock(&ic->lock);
103static int iconv_getattr(
const char *path,
struct stat *stbuf,
106 struct iconv *ic = iconv_get();
108 int err = iconv_convpath(ic, path, &newpath, 0);
110 err = fuse_fs_getattr(ic->next, newpath, stbuf, fi);
116static int iconv_access(
const char *path,
int mask)
118 struct iconv *ic = iconv_get();
120 int err = iconv_convpath(ic, path, &newpath, 0);
122 err = fuse_fs_access(ic->next, newpath, mask);
128static int iconv_readlink(
const char *path,
char *buf,
size_t size)
130 struct iconv *ic = iconv_get();
132 int err = iconv_convpath(ic, path, &newpath, 0);
134 err = fuse_fs_readlink(ic->next, newpath, buf, size);
137 err = iconv_convpath(ic, buf, &newlink, 1);
139 strncpy(buf, newlink, size - 1);
140 buf[size - 1] =
'\0';
149static int iconv_opendir(
const char *path,
struct fuse_file_info *fi)
151 struct iconv *ic = iconv_get();
153 int err = iconv_convpath(ic, path, &newpath, 0);
155 err = fuse_fs_opendir(ic->next, newpath, fi);
161static int iconv_dir_fill(
void *buf,
const char *name,
162 const struct stat *stbuf, off_t off,
165 struct iconv_dh *dh = buf;
168 if (iconv_convpath(dh->ic, name, &newname, 1) == 0) {
169 res = dh->prev_filler(dh->prev_buf, newname, stbuf, off, flags);
175static int iconv_readdir(
const char *path,
void *buf,
fuse_fill_dir_t filler,
179 struct iconv *ic = iconv_get();
181 int err = iconv_convpath(ic, path, &newpath, 0);
186 dh.prev_filler = filler;
187 err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill,
194static int iconv_releasedir(
const char *path,
struct fuse_file_info *fi)
196 struct iconv *ic = iconv_get();
198 int err = iconv_convpath(ic, path, &newpath, 0);
200 err = fuse_fs_releasedir(ic->next, newpath, fi);
206static int iconv_mknod(
const char *path, mode_t mode, dev_t rdev)
208 struct iconv *ic = iconv_get();
210 int err = iconv_convpath(ic, path, &newpath, 0);
212 err = fuse_fs_mknod(ic->next, newpath, mode, rdev);
218static int iconv_mkdir(
const char *path, mode_t mode)
220 struct iconv *ic = iconv_get();
222 int err = iconv_convpath(ic, path, &newpath, 0);
224 err = fuse_fs_mkdir(ic->next, newpath, mode);
230static int iconv_unlink(
const char *path)
232 struct iconv *ic = iconv_get();
234 int err = iconv_convpath(ic, path, &newpath, 0);
236 err = fuse_fs_unlink(ic->next, newpath);
242static int iconv_rmdir(
const char *path)
244 struct iconv *ic = iconv_get();
246 int err = iconv_convpath(ic, path, &newpath, 0);
248 err = fuse_fs_rmdir(ic->next, newpath);
254static int iconv_symlink(
const char *from,
const char *to)
256 struct iconv *ic = iconv_get();
259 int err = iconv_convpath(ic, from, &newfrom, 0);
261 err = iconv_convpath(ic, to, &newto, 0);
263 err = fuse_fs_symlink(ic->next, newfrom, newto);
271static int iconv_rename(
const char *from,
const char *to,
unsigned int flags)
273 struct iconv *ic = iconv_get();
276 int err = iconv_convpath(ic, from, &newfrom, 0);
278 err = iconv_convpath(ic, to, &newto, 0);
280 err = fuse_fs_rename(ic->next, newfrom, newto, flags);
288static int iconv_link(
const char *from,
const char *to)
290 struct iconv *ic = iconv_get();
293 int err = iconv_convpath(ic, from, &newfrom, 0);
295 err = iconv_convpath(ic, to, &newto, 0);
297 err = fuse_fs_link(ic->next, newfrom, newto);
305static int iconv_chmod(
const char *path, mode_t mode,
308 struct iconv *ic = iconv_get();
310 int err = iconv_convpath(ic, path, &newpath, 0);
312 err = fuse_fs_chmod(ic->next, newpath, mode, fi);
318static int iconv_chown(
const char *path, uid_t uid, gid_t gid,
321 struct iconv *ic = iconv_get();
323 int err = iconv_convpath(ic, path, &newpath, 0);
325 err = fuse_fs_chown(ic->next, newpath, uid, gid, fi);
331static int iconv_truncate(
const char *path, off_t size,
334 struct iconv *ic = iconv_get();
336 int err = iconv_convpath(ic, path, &newpath, 0);
338 err = fuse_fs_truncate(ic->next, newpath, size, fi);
344static int iconv_utimens(
const char *path,
const struct timespec ts[2],
347 struct iconv *ic = iconv_get();
349 int err = iconv_convpath(ic, path, &newpath, 0);
351 err = fuse_fs_utimens(ic->next, newpath, ts, fi);
357static int iconv_create(
const char *path, mode_t mode,
360 struct iconv *ic = iconv_get();
362 int err = iconv_convpath(ic, path, &newpath, 0);
364 err = fuse_fs_create(ic->next, newpath, mode, fi);
370static int iconv_open_file(
const char *path,
struct fuse_file_info *fi)
372 struct iconv *ic = iconv_get();
374 int err = iconv_convpath(ic, path, &newpath, 0);
376 err = fuse_fs_open(ic->next, newpath, fi);
382static int iconv_read_buf(
const char *path,
struct fuse_bufvec **bufp,
385 struct iconv *ic = iconv_get();
387 int err = iconv_convpath(ic, path, &newpath, 0);
389 err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi);
395static int iconv_write_buf(
const char *path,
struct fuse_bufvec *buf,
398 struct iconv *ic = iconv_get();
400 int err = iconv_convpath(ic, path, &newpath, 0);
402 err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi);
408static int iconv_statfs(
const char *path,
struct statvfs *stbuf)
410 struct iconv *ic = iconv_get();
412 int err = iconv_convpath(ic, path, &newpath, 0);
414 err = fuse_fs_statfs(ic->next, newpath, stbuf);
420static int iconv_flush(
const char *path,
struct fuse_file_info *fi)
422 struct iconv *ic = iconv_get();
424 int err = iconv_convpath(ic, path, &newpath, 0);
426 err = fuse_fs_flush(ic->next, newpath, fi);
432static int iconv_release(
const char *path,
struct fuse_file_info *fi)
434 struct iconv *ic = iconv_get();
436 int err = iconv_convpath(ic, path, &newpath, 0);
438 err = fuse_fs_release(ic->next, newpath, fi);
444static int iconv_fsync(
const char *path,
int isdatasync,
447 struct iconv *ic = iconv_get();
449 int err = iconv_convpath(ic, path, &newpath, 0);
451 err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi);
457static int iconv_fsyncdir(
const char *path,
int isdatasync,
460 struct iconv *ic = iconv_get();
462 int err = iconv_convpath(ic, path, &newpath, 0);
464 err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi);
470static int iconv_setxattr(
const char *path,
const char *name,
471 const char *value,
size_t size,
int flags)
473 struct iconv *ic = iconv_get();
475 int err = iconv_convpath(ic, path, &newpath, 0);
477 err = fuse_fs_setxattr(ic->next, newpath, name, value, size,
484static int iconv_getxattr(
const char *path,
const char *name,
char *value,
487 struct iconv *ic = iconv_get();
489 int err = iconv_convpath(ic, path, &newpath, 0);
491 err = fuse_fs_getxattr(ic->next, newpath, name, value, size);
497static int iconv_listxattr(
const char *path,
char *list,
size_t size)
499 struct iconv *ic = iconv_get();
501 int err = iconv_convpath(ic, path, &newpath, 0);
503 err = fuse_fs_listxattr(ic->next, newpath, list, size);
509static int iconv_removexattr(
const char *path,
const char *name)
511 struct iconv *ic = iconv_get();
513 int err = iconv_convpath(ic, path, &newpath, 0);
515 err = fuse_fs_removexattr(ic->next, newpath, name);
521static int iconv_lock(
const char *path,
struct fuse_file_info *fi,
int cmd,
524 struct iconv *ic = iconv_get();
526 int err = iconv_convpath(ic, path, &newpath, 0);
528 err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock);
534static int iconv_flock(
const char *path,
struct fuse_file_info *fi,
int op)
536 struct iconv *ic = iconv_get();
538 int err = iconv_convpath(ic, path, &newpath, 0);
540 err = fuse_fs_flock(ic->next, newpath, fi, op);
546static int iconv_bmap(
const char *path,
size_t blocksize, uint64_t *idx)
548 struct iconv *ic = iconv_get();
550 int err = iconv_convpath(ic, path, &newpath, 0);
552 err = fuse_fs_bmap(ic->next, newpath, blocksize, idx);
558static off_t iconv_lseek(
const char *path, off_t off,
int whence,
561 struct iconv *ic = iconv_get();
563 int res = iconv_convpath(ic, path, &newpath, 0);
565 res = fuse_fs_lseek(ic->next, newpath, off, whence, fi);
572static int iconv_statx(
const char *path,
int flags,
int mask,
struct statx *stxbuf,
575 struct iconv *ic = iconv_get();
577 int res = iconv_convpath(ic, path, &newpath, 0);
580 res = fuse_fs_statx(ic->next, newpath, flags, mask, stxbuf, fi);
590 struct iconv *ic = iconv_get();
591 fuse_fs_init(ic->next, conn, cfg);
597static void iconv_destroy(
void *data)
599 struct iconv *ic = data;
600 fuse_fs_destroy(ic->next);
601 iconv_close(ic->tofs);
602 iconv_close(ic->fromfs);
603 pthread_mutex_destroy(&ic->lock);
612 .getattr = iconv_getattr,
613 .access = iconv_access,
614 .readlink = iconv_readlink,
615 .opendir = iconv_opendir,
616 .readdir = iconv_readdir,
617 .releasedir = iconv_releasedir,
618 .mknod = iconv_mknod,
619 .mkdir = iconv_mkdir,
620 .symlink = iconv_symlink,
621 .unlink = iconv_unlink,
622 .rmdir = iconv_rmdir,
623 .rename = iconv_rename,
625 .chmod = iconv_chmod,
626 .chown = iconv_chown,
627 .truncate = iconv_truncate,
628 .utimens = iconv_utimens,
629 .create = iconv_create,
630 .open = iconv_open_file,
631 .read_buf = iconv_read_buf,
632 .write_buf = iconv_write_buf,
633 .statfs = iconv_statfs,
634 .flush = iconv_flush,
635 .release = iconv_release,
636 .fsync = iconv_fsync,
637 .fsyncdir = iconv_fsyncdir,
638 .setxattr = iconv_setxattr,
639 .getxattr = iconv_getxattr,
640 .listxattr = iconv_listxattr,
641 .removexattr = iconv_removexattr,
643 .flock = iconv_flock,
645 .lseek = iconv_lseek,
647 .statx = iconv_statx,
651static const struct fuse_opt iconv_opts[] = {
654 {
"from_code=%s", offsetof(
struct iconv, from_code), 0 },
655 {
"to_code=%s", offsetof(
struct iconv, to_code), 1 },
659static void iconv_help(
void)
662 const char *old = setlocale(LC_CTYPE,
"");
664 charmap = strdup(nl_langinfo(CODESET));
666 setlocale(LC_CTYPE, old);
671" -o from_code=CHARSET original encoding of file names (default: UTF-8)\n"
672" -o to_code=CHARSET new encoding of the file names (default: %s)\n",
677static int iconv_opt_proc(
void *data,
const char *arg,
int key,
680 (void) data; (void) arg; (void) outargs;
690static struct fuse_fs *iconv_new(
struct fuse_args *args,
691 struct fuse_fs *next[])
695 const char *old = NULL;
699 ic = calloc(1,
sizeof(
struct iconv));
701 fuse_log(FUSE_LOG_ERR,
"fuse-iconv: memory allocation failed\n");
708 if (!next[0] || next[1]) {
709 fuse_log(FUSE_LOG_ERR,
"fuse-iconv: exactly one next filesystem required\n");
713 from = ic->from_code ? ic->from_code :
"UTF-8";
714 to = ic->to_code ? ic->to_code :
"";
717 old = setlocale(LC_CTYPE,
"");
718 ic->tofs = iconv_open(from, to);
719 if (ic->tofs == (iconv_t) -1) {
720 fuse_log(FUSE_LOG_ERR,
"fuse-iconv: cannot convert from %s to %s\n",
724 ic->fromfs = iconv_open(to, from);
725 if (ic->tofs == (iconv_t) -1) {
726 fuse_log(FUSE_LOG_ERR,
"fuse-iconv: cannot convert from %s to %s\n",
728 goto out_iconv_close_to;
731 setlocale(LC_CTYPE, old);
736 fs =
fuse_fs_new(&iconv_oper,
sizeof(iconv_oper), ic);
738 goto out_iconv_close_from;
743 iconv_close(ic->fromfs);
745 iconv_close(ic->tofs);
751 setlocale(LC_CTYPE, old);
struct fuse_context * fuse_get_context(void)
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
#define FUSE_REGISTER_MODULE(name_, factory_)
void fuse_log(enum fuse_log_level level, const char *fmt,...)
#define FUSE_OPT_KEY(templ, key)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
void(* destroy)(void *private_data)