2 fuse iconv module: file name charset conversion
3 Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB
9 #define FUSE_USE_VERSION 26
34 fuse_fill_dir_t prev_filler;
37 static struct iconv *iconv_get(void)
39 return fuse_get_context()->private_data;
42 static 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;
80 tmp = realloc(newpath, newpathlen + 1);
85 p = tmp + (p - newpath);
89 } while (res == (size_t) -1);
90 pthread_mutex_unlock(&ic->lock);
96 iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL);
97 pthread_mutex_unlock(&ic->lock);
102 static int iconv_getattr(const char *path, struct stat *stbuf)
104 struct iconv *ic = iconv_get();
106 int err = iconv_convpath(ic, path, &newpath, 0);
108 err = fuse_fs_getattr(ic->next, newpath, stbuf);
114 static int iconv_fgetattr(const char *path, struct stat *stbuf,
115 struct fuse_file_info *fi)
117 struct iconv *ic = iconv_get();
119 int err = iconv_convpath(ic, path, &newpath, 0);
121 err = fuse_fs_fgetattr(ic->next, newpath, stbuf, fi);
127 static int iconv_access(const char *path, int mask)
129 struct iconv *ic = iconv_get();
131 int err = iconv_convpath(ic, path, &newpath, 0);
133 err = fuse_fs_access(ic->next, newpath, mask);
139 static int iconv_readlink(const char *path, char *buf, size_t size)
141 struct iconv *ic = iconv_get();
143 int err = iconv_convpath(ic, path, &newpath, 0);
145 err = fuse_fs_readlink(ic->next, newpath, buf, size);
148 err = iconv_convpath(ic, buf, &newlink, 1);
150 strncpy(buf, newlink, size - 1);
151 buf[size - 1] = '\0';
160 static int iconv_opendir(const char *path, struct fuse_file_info *fi)
162 struct iconv *ic = iconv_get();
164 int err = iconv_convpath(ic, path, &newpath, 0);
166 err = fuse_fs_opendir(ic->next, newpath, fi);
172 static int iconv_dir_fill(void *buf, const char *name,
173 const struct stat *stbuf, off_t off)
175 struct iconv_dh *dh = buf;
178 if (iconv_convpath(dh->ic, name, &newname, 1) == 0) {
179 res = dh->prev_filler(dh->prev_buf, newname, stbuf, off);
185 static int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
186 off_t offset, struct fuse_file_info *fi)
188 struct iconv *ic = iconv_get();
190 int err = iconv_convpath(ic, path, &newpath, 0);
195 dh.prev_filler = filler;
196 err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill,
203 static int iconv_releasedir(const char *path, struct fuse_file_info *fi)
205 struct iconv *ic = iconv_get();
207 int err = iconv_convpath(ic, path, &newpath, 0);
209 err = fuse_fs_releasedir(ic->next, newpath, fi);
215 static int iconv_mknod(const char *path, mode_t mode, dev_t rdev)
217 struct iconv *ic = iconv_get();
219 int err = iconv_convpath(ic, path, &newpath, 0);
221 err = fuse_fs_mknod(ic->next, newpath, mode, rdev);
227 static int iconv_mkdir(const char *path, mode_t mode)
229 struct iconv *ic = iconv_get();
231 int err = iconv_convpath(ic, path, &newpath, 0);
233 err = fuse_fs_mkdir(ic->next, newpath, mode);
239 static int iconv_unlink(const char *path)
241 struct iconv *ic = iconv_get();
243 int err = iconv_convpath(ic, path, &newpath, 0);
245 err = fuse_fs_unlink(ic->next, newpath);
251 static int iconv_rmdir(const char *path)
253 struct iconv *ic = iconv_get();
255 int err = iconv_convpath(ic, path, &newpath, 0);
257 err = fuse_fs_rmdir(ic->next, newpath);
263 static int iconv_symlink(const char *from, const char *to)
265 struct iconv *ic = iconv_get();
268 int err = iconv_convpath(ic, from, &newfrom, 0);
270 err = iconv_convpath(ic, to, &newto, 0);
272 err = fuse_fs_symlink(ic->next, newfrom, newto);
280 static int iconv_rename(const char *from, const char *to)
282 struct iconv *ic = iconv_get();
285 int err = iconv_convpath(ic, from, &newfrom, 0);
287 err = iconv_convpath(ic, to, &newto, 0);
289 err = fuse_fs_rename(ic->next, newfrom, newto);
297 static int iconv_link(const char *from, const char *to)
299 struct iconv *ic = iconv_get();
302 int err = iconv_convpath(ic, from, &newfrom, 0);
304 err = iconv_convpath(ic, to, &newto, 0);
306 err = fuse_fs_link(ic->next, newfrom, newto);
314 static int iconv_chmod(const char *path, mode_t mode)
316 struct iconv *ic = iconv_get();
318 int err = iconv_convpath(ic, path, &newpath, 0);
320 err = fuse_fs_chmod(ic->next, newpath, mode);
326 static int iconv_chown(const char *path, uid_t uid, gid_t gid)
328 struct iconv *ic = iconv_get();
330 int err = iconv_convpath(ic, path, &newpath, 0);
332 err = fuse_fs_chown(ic->next, newpath, uid, gid);
338 static int iconv_truncate(const char *path, off_t size)
340 struct iconv *ic = iconv_get();
342 int err = iconv_convpath(ic, path, &newpath, 0);
344 err = fuse_fs_truncate(ic->next, newpath, size);
350 static int iconv_ftruncate(const char *path, off_t size,
351 struct fuse_file_info *fi)
353 struct iconv *ic = iconv_get();
355 int err = iconv_convpath(ic, path, &newpath, 0);
357 err = fuse_fs_ftruncate(ic->next, newpath, size, fi);
363 static int iconv_utimens(const char *path, const struct timespec ts[2])
365 struct iconv *ic = iconv_get();
367 int err = iconv_convpath(ic, path, &newpath, 0);
369 err = fuse_fs_utimens(ic->next, newpath, ts);
375 static int iconv_create(const char *path, mode_t mode,
376 struct fuse_file_info *fi)
378 struct iconv *ic = iconv_get();
380 int err = iconv_convpath(ic, path, &newpath, 0);
382 err = fuse_fs_create(ic->next, newpath, mode, fi);
388 static int iconv_open_file(const char *path, struct fuse_file_info *fi)
390 struct iconv *ic = iconv_get();
392 int err = iconv_convpath(ic, path, &newpath, 0);
394 err = fuse_fs_open(ic->next, newpath, fi);
400 static int iconv_read_buf(const char *path, struct fuse_bufvec **bufp,
401 size_t size, off_t offset, struct fuse_file_info *fi)
403 struct iconv *ic = iconv_get();
405 int err = iconv_convpath(ic, path, &newpath, 0);
407 err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi);
413 static int iconv_write_buf(const char *path, struct fuse_bufvec *buf,
414 off_t offset, struct fuse_file_info *fi)
416 struct iconv *ic = iconv_get();
418 int err = iconv_convpath(ic, path, &newpath, 0);
420 err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi);
426 static int iconv_statfs(const char *path, struct statvfs *stbuf)
428 struct iconv *ic = iconv_get();
430 int err = iconv_convpath(ic, path, &newpath, 0);
432 err = fuse_fs_statfs(ic->next, newpath, stbuf);
438 static int iconv_flush(const char *path, struct fuse_file_info *fi)
440 struct iconv *ic = iconv_get();
442 int err = iconv_convpath(ic, path, &newpath, 0);
444 err = fuse_fs_flush(ic->next, newpath, fi);
450 static int iconv_release(const char *path, struct fuse_file_info *fi)
452 struct iconv *ic = iconv_get();
454 int err = iconv_convpath(ic, path, &newpath, 0);
456 err = fuse_fs_release(ic->next, newpath, fi);
462 static int iconv_fsync(const char *path, int isdatasync,
463 struct fuse_file_info *fi)
465 struct iconv *ic = iconv_get();
467 int err = iconv_convpath(ic, path, &newpath, 0);
469 err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi);
475 static int iconv_fsyncdir(const char *path, int isdatasync,
476 struct fuse_file_info *fi)
478 struct iconv *ic = iconv_get();
480 int err = iconv_convpath(ic, path, &newpath, 0);
482 err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi);
488 static int iconv_setxattr(const char *path, const char *name,
489 const char *value, size_t size, int flags)
491 struct iconv *ic = iconv_get();
493 int err = iconv_convpath(ic, path, &newpath, 0);
495 err = fuse_fs_setxattr(ic->next, newpath, name, value, size,
502 static int iconv_getxattr(const char *path, const char *name, char *value,
505 struct iconv *ic = iconv_get();
507 int err = iconv_convpath(ic, path, &newpath, 0);
509 err = fuse_fs_getxattr(ic->next, newpath, name, value, size);
515 static int iconv_listxattr(const char *path, char *list, size_t size)
517 struct iconv *ic = iconv_get();
519 int err = iconv_convpath(ic, path, &newpath, 0);
521 err = fuse_fs_listxattr(ic->next, newpath, list, size);
527 static int iconv_removexattr(const char *path, const char *name)
529 struct iconv *ic = iconv_get();
531 int err = iconv_convpath(ic, path, &newpath, 0);
533 err = fuse_fs_removexattr(ic->next, newpath, name);
539 static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd,
542 struct iconv *ic = iconv_get();
544 int err = iconv_convpath(ic, path, &newpath, 0);
546 err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock);
552 static int iconv_flock(const char *path, struct fuse_file_info *fi, int op)
554 struct iconv *ic = iconv_get();
556 int err = iconv_convpath(ic, path, &newpath, 0);
558 err = fuse_fs_flock(ic->next, newpath, fi, op);
564 static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx)
566 struct iconv *ic = iconv_get();
568 int err = iconv_convpath(ic, path, &newpath, 0);
570 err = fuse_fs_bmap(ic->next, newpath, blocksize, idx);
576 static void *iconv_init(struct fuse_conn_info *conn)
578 struct iconv *ic = iconv_get();
579 fuse_fs_init(ic->next, conn);
583 static void iconv_destroy(void *data)
585 struct iconv *ic = data;
586 fuse_fs_destroy(ic->next);
587 iconv_close(ic->tofs);
588 iconv_close(ic->fromfs);
589 pthread_mutex_destroy(&ic->lock);
595 static struct fuse_operations iconv_oper = {
596 .destroy = iconv_destroy,
598 .getattr = iconv_getattr,
599 .fgetattr = iconv_fgetattr,
600 .access = iconv_access,
601 .readlink = iconv_readlink,
602 .opendir = iconv_opendir,
603 .readdir = iconv_readdir,
604 .releasedir = iconv_releasedir,
605 .mknod = iconv_mknod,
606 .mkdir = iconv_mkdir,
607 .symlink = iconv_symlink,
608 .unlink = iconv_unlink,
609 .rmdir = iconv_rmdir,
610 .rename = iconv_rename,
612 .chmod = iconv_chmod,
613 .chown = iconv_chown,
614 .truncate = iconv_truncate,
615 .ftruncate = iconv_ftruncate,
616 .utimens = iconv_utimens,
617 .create = iconv_create,
618 .open = iconv_open_file,
619 .read_buf = iconv_read_buf,
620 .write_buf = iconv_write_buf,
621 .statfs = iconv_statfs,
622 .flush = iconv_flush,
623 .release = iconv_release,
624 .fsync = iconv_fsync,
625 .fsyncdir = iconv_fsyncdir,
626 .setxattr = iconv_setxattr,
627 .getxattr = iconv_getxattr,
628 .listxattr = iconv_listxattr,
629 .removexattr = iconv_removexattr,
631 .flock = iconv_flock,
634 .flag_nullpath_ok = 1,
638 static struct fuse_opt iconv_opts[] = {
639 FUSE_OPT_KEY("-h", 0),
640 FUSE_OPT_KEY("--help", 0),
641 { "from_code=%s", offsetof(struct iconv, from_code), 0 },
642 { "to_code=%s", offsetof(struct iconv, to_code), 1 },
646 static void iconv_help(void)
648 char *old = strdup(setlocale(LC_CTYPE, ""));
649 char *charmap = strdup(nl_langinfo(CODESET));
650 setlocale(LC_CTYPE, old);
653 " -o from_code=CHARSET original encoding of file names (default: UTF-8)\n"
654 " -o to_code=CHARSET new encoding of the file names (default: %s)\n",
659 static int iconv_opt_proc(void *data, const char *arg, int key,
660 struct fuse_args *outargs)
662 (void) data; (void) arg; (void) outargs;
672 static struct fuse_fs *iconv_new(struct fuse_args *args,
673 struct fuse_fs *next[])
681 ic = calloc(1, sizeof(struct iconv));
683 fprintf(stderr, "fuse-iconv: memory allocation failed\n");
687 if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1)
690 if (!next[0] || next[1]) {
691 fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n");
695 from = ic->from_code ? ic->from_code : "UTF-8";
696 to = ic->to_code ? ic->to_code : "";
697 /* FIXME: detect charset equivalence? */
699 old = strdup(setlocale(LC_CTYPE, ""));
700 ic->tofs = iconv_open(from, to);
701 if (ic->tofs == (iconv_t) -1) {
702 fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
706 ic->fromfs = iconv_open(to, from);
707 if (ic->tofs == (iconv_t) -1) {
708 fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
710 goto out_iconv_close_to;
713 setlocale(LC_CTYPE, old);
718 fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic);
720 goto out_iconv_close_from;
724 out_iconv_close_from:
725 iconv_close(ic->fromfs);
727 iconv_close(ic->tofs);
733 setlocale(LC_CTYPE, old);
739 FUSE_REGISTER_MODULE(iconv, iconv_new);