"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.1/lib/modules/iconv.c" (14 Nov 2017, 15937 Bytes) of package /linux/misc/fuse-3.2.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "iconv.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.0.2_vs_3.1.0.

    1 /*
    2   fuse iconv module: file name charset conversion
    3   Copyright (C) 2007  Miklos Szeredi <miklos@szeredi.hu>
    4 
    5   This program can be distributed under the terms of the GNU LGPLv2.
    6   See the file COPYING.LIB
    7 */
    8 
    9 #include <config.h>
   10 
   11 #include <fuse.h>
   12 #include <stdio.h>
   13 #include <stdlib.h>
   14 #include <stddef.h>
   15 #include <string.h>
   16 #include <errno.h>
   17 #include <iconv.h>
   18 #include <pthread.h>
   19 #include <locale.h>
   20 #include <langinfo.h>
   21 
   22 struct iconv {
   23     struct fuse_fs *next;
   24     pthread_mutex_t lock;
   25     char *from_code;
   26     char *to_code;
   27     iconv_t tofs;
   28     iconv_t fromfs;
   29 };
   30 
   31 struct iconv_dh {
   32     struct iconv *ic;
   33     void *prev_buf;
   34     fuse_fill_dir_t prev_filler;
   35 };
   36 
   37 static struct iconv *iconv_get(void)
   38 {
   39     return fuse_get_context()->private_data;
   40 }
   41 
   42 static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp,
   43               int fromfs)
   44 {
   45     size_t pathlen;
   46     size_t newpathlen;
   47     char *newpath;
   48     size_t plen;
   49     char *p;
   50     size_t res;
   51     int err;
   52 
   53     if (path == NULL) {
   54         *newpathp = NULL;
   55         return 0;
   56     }
   57 
   58     pathlen = strlen(path);
   59     newpathlen = pathlen * 4;
   60     newpath = malloc(newpathlen + 1);
   61     if (!newpath)
   62         return -ENOMEM;
   63 
   64     plen = newpathlen;
   65     p = newpath;
   66     pthread_mutex_lock(&ic->lock);
   67     do {
   68         res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path,
   69                 &pathlen, &p, &plen);
   70         if (res == (size_t) -1) {
   71             char *tmp;
   72             size_t inc;
   73 
   74             err = -EILSEQ;
   75             if (errno != E2BIG)
   76                 goto err;
   77 
   78             inc = (pathlen + 1) * 4;
   79             newpathlen += inc;
   80             tmp = realloc(newpath, newpathlen + 1);
   81             err = -ENOMEM;
   82             if (!tmp)
   83                 goto err;
   84 
   85             p = tmp + (p - newpath);
   86             plen += inc;
   87             newpath = tmp;
   88         }
   89     } while (res == (size_t) -1);
   90     pthread_mutex_unlock(&ic->lock);
   91     *p = '\0';
   92     *newpathp = newpath;
   93     return 0;
   94 
   95 err:
   96     iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL);
   97     pthread_mutex_unlock(&ic->lock);
   98     free(newpath);
   99     return err;
  100 }
  101 
  102 static int iconv_getattr(const char *path, struct stat *stbuf,
  103              struct fuse_file_info *fi)
  104 {
  105     struct iconv *ic = iconv_get();
  106     char *newpath;
  107     int err = iconv_convpath(ic, path, &newpath, 0);
  108     if (!err) {
  109         err = fuse_fs_getattr(ic->next, newpath, stbuf, fi);
  110         free(newpath);
  111     }
  112     return err;
  113 }
  114 
  115 static int iconv_access(const char *path, int mask)
  116 {
  117     struct iconv *ic = iconv_get();
  118     char *newpath;
  119     int err = iconv_convpath(ic, path, &newpath, 0);
  120     if (!err) {
  121         err = fuse_fs_access(ic->next, newpath, mask);
  122         free(newpath);
  123     }
  124     return err;
  125 }
  126 
  127 static int iconv_readlink(const char *path, char *buf, size_t size)
  128 {
  129     struct iconv *ic = iconv_get();
  130     char *newpath;
  131     int err = iconv_convpath(ic, path, &newpath, 0);
  132     if (!err) {
  133         err = fuse_fs_readlink(ic->next, newpath, buf, size);
  134         if (!err) {
  135             char *newlink;
  136             err = iconv_convpath(ic, buf, &newlink, 1);
  137             if (!err) {
  138                 strncpy(buf, newlink, size - 1);
  139                 buf[size - 1] = '\0';
  140                 free(newlink);
  141             }
  142         }
  143         free(newpath);
  144     }
  145     return err;
  146 }
  147 
  148 static int iconv_opendir(const char *path, struct fuse_file_info *fi)
  149 {
  150     struct iconv *ic = iconv_get();
  151     char *newpath;
  152     int err = iconv_convpath(ic, path, &newpath, 0);
  153     if (!err) {
  154         err = fuse_fs_opendir(ic->next, newpath, fi);
  155         free(newpath);
  156     }
  157     return err;
  158 }
  159 
  160 static int iconv_dir_fill(void *buf, const char *name,
  161               const struct stat *stbuf, off_t off,
  162               enum fuse_fill_dir_flags flags)
  163 {
  164     struct iconv_dh *dh = buf;
  165     char *newname;
  166     int res = 0;
  167     if (iconv_convpath(dh->ic, name, &newname, 1) == 0) {
  168         res = dh->prev_filler(dh->prev_buf, newname, stbuf, off, flags);
  169         free(newname);
  170     }
  171     return res;
  172 }
  173 
  174 static int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
  175              off_t offset, struct fuse_file_info *fi,
  176              enum fuse_readdir_flags flags)
  177 {
  178     struct iconv *ic = iconv_get();
  179     char *newpath;
  180     int err = iconv_convpath(ic, path, &newpath, 0);
  181     if (!err) {
  182         struct iconv_dh dh;
  183         dh.ic = ic;
  184         dh.prev_buf = buf;
  185         dh.prev_filler = filler;
  186         err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill,
  187                       offset, fi, flags);
  188         free(newpath);
  189     }
  190     return err;
  191 }
  192 
  193 static int iconv_releasedir(const char *path, struct fuse_file_info *fi)
  194 {
  195     struct iconv *ic = iconv_get();
  196     char *newpath;
  197     int err = iconv_convpath(ic, path, &newpath, 0);
  198     if (!err) {
  199         err = fuse_fs_releasedir(ic->next, newpath, fi);
  200         free(newpath);
  201     }
  202     return err;
  203 }
  204 
  205 static int iconv_mknod(const char *path, mode_t mode, dev_t rdev)
  206 {
  207     struct iconv *ic = iconv_get();
  208     char *newpath;
  209     int err = iconv_convpath(ic, path, &newpath, 0);
  210     if (!err) {
  211         err = fuse_fs_mknod(ic->next, newpath, mode, rdev);
  212         free(newpath);
  213     }
  214     return err;
  215 }
  216 
  217 static int iconv_mkdir(const char *path, mode_t mode)
  218 {
  219     struct iconv *ic = iconv_get();
  220     char *newpath;
  221     int err = iconv_convpath(ic, path, &newpath, 0);
  222     if (!err) {
  223         err = fuse_fs_mkdir(ic->next, newpath, mode);
  224         free(newpath);
  225     }
  226     return err;
  227 }
  228 
  229 static int iconv_unlink(const char *path)
  230 {
  231     struct iconv *ic = iconv_get();
  232     char *newpath;
  233     int err = iconv_convpath(ic, path, &newpath, 0);
  234     if (!err) {
  235         err = fuse_fs_unlink(ic->next, newpath);
  236         free(newpath);
  237     }
  238     return err;
  239 }
  240 
  241 static int iconv_rmdir(const char *path)
  242 {
  243     struct iconv *ic = iconv_get();
  244     char *newpath;
  245     int err = iconv_convpath(ic, path, &newpath, 0);
  246     if (!err) {
  247         err = fuse_fs_rmdir(ic->next, newpath);
  248         free(newpath);
  249     }
  250     return err;
  251 }
  252 
  253 static int iconv_symlink(const char *from, const char *to)
  254 {
  255     struct iconv *ic = iconv_get();
  256     char *newfrom;
  257     char *newto;
  258     int err = iconv_convpath(ic, from, &newfrom, 0);
  259     if (!err) {
  260         err = iconv_convpath(ic, to, &newto, 0);
  261         if (!err) {
  262             err = fuse_fs_symlink(ic->next, newfrom, newto);
  263             free(newto);
  264         }
  265         free(newfrom);
  266     }
  267     return err;
  268 }
  269 
  270 static int iconv_rename(const char *from, const char *to, unsigned int flags)
  271 {
  272     struct iconv *ic = iconv_get();
  273     char *newfrom;
  274     char *newto;
  275     int err = iconv_convpath(ic, from, &newfrom, 0);
  276     if (!err) {
  277         err = iconv_convpath(ic, to, &newto, 0);
  278         if (!err) {
  279             err = fuse_fs_rename(ic->next, newfrom, newto, flags);
  280             free(newto);
  281         }
  282         free(newfrom);
  283     }
  284     return err;
  285 }
  286 
  287 static int iconv_link(const char *from, const char *to)
  288 {
  289     struct iconv *ic = iconv_get();
  290     char *newfrom;
  291     char *newto;
  292     int err = iconv_convpath(ic, from, &newfrom, 0);
  293     if (!err) {
  294         err = iconv_convpath(ic, to, &newto, 0);
  295         if (!err) {
  296             err = fuse_fs_link(ic->next, newfrom, newto);
  297             free(newto);
  298         }
  299         free(newfrom);
  300     }
  301     return err;
  302 }
  303 
  304 static int iconv_chmod(const char *path, mode_t mode,
  305                struct fuse_file_info *fi)
  306 {
  307     struct iconv *ic = iconv_get();
  308     char *newpath;
  309     int err = iconv_convpath(ic, path, &newpath, 0);
  310     if (!err) {
  311         err = fuse_fs_chmod(ic->next, newpath, mode, fi);
  312         free(newpath);
  313     }
  314     return err;
  315 }
  316 
  317 static int iconv_chown(const char *path, uid_t uid, gid_t gid,
  318                struct fuse_file_info *fi)
  319 {
  320     struct iconv *ic = iconv_get();
  321     char *newpath;
  322     int err = iconv_convpath(ic, path, &newpath, 0);
  323     if (!err) {
  324         err = fuse_fs_chown(ic->next, newpath, uid, gid, fi);
  325         free(newpath);
  326     }
  327     return err;
  328 }
  329 
  330 static int iconv_truncate(const char *path, off_t size,
  331                struct fuse_file_info *fi)
  332 {
  333     struct iconv *ic = iconv_get();
  334     char *newpath;
  335     int err = iconv_convpath(ic, path, &newpath, 0);
  336     if (!err) {
  337         err = fuse_fs_truncate(ic->next, newpath, size, fi);
  338         free(newpath);
  339     }
  340     return err;
  341 }
  342 
  343 static int iconv_utimens(const char *path, const struct timespec ts[2],
  344              struct fuse_file_info *fi)
  345 {
  346     struct iconv *ic = iconv_get();
  347     char *newpath;
  348     int err = iconv_convpath(ic, path, &newpath, 0);
  349     if (!err) {
  350         err = fuse_fs_utimens(ic->next, newpath, ts, fi);
  351         free(newpath);
  352     }
  353     return err;
  354 }
  355 
  356 static int iconv_create(const char *path, mode_t mode,
  357             struct fuse_file_info *fi)
  358 {
  359     struct iconv *ic = iconv_get();
  360     char *newpath;
  361     int err = iconv_convpath(ic, path, &newpath, 0);
  362     if (!err) {
  363         err = fuse_fs_create(ic->next, newpath, mode, fi);
  364         free(newpath);
  365     }
  366     return err;
  367 }
  368 
  369 static int iconv_open_file(const char *path, struct fuse_file_info *fi)
  370 {
  371     struct iconv *ic = iconv_get();
  372     char *newpath;
  373     int err = iconv_convpath(ic, path, &newpath, 0);
  374     if (!err) {
  375         err = fuse_fs_open(ic->next, newpath, fi);
  376         free(newpath);
  377     }
  378     return err;
  379 }
  380 
  381 static int iconv_read_buf(const char *path, struct fuse_bufvec **bufp,
  382               size_t size, off_t offset, struct fuse_file_info *fi)
  383 {
  384     struct iconv *ic = iconv_get();
  385     char *newpath;
  386     int err = iconv_convpath(ic, path, &newpath, 0);
  387     if (!err) {
  388         err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi);
  389         free(newpath);
  390     }
  391     return err;
  392 }
  393 
  394 static int iconv_write_buf(const char *path, struct fuse_bufvec *buf,
  395                off_t offset, struct fuse_file_info *fi)
  396 {
  397     struct iconv *ic = iconv_get();
  398     char *newpath;
  399     int err = iconv_convpath(ic, path, &newpath, 0);
  400     if (!err) {
  401         err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi);
  402         free(newpath);
  403     }
  404     return err;
  405 }
  406 
  407 static int iconv_statfs(const char *path, struct statvfs *stbuf)
  408 {
  409     struct iconv *ic = iconv_get();
  410     char *newpath;
  411     int err = iconv_convpath(ic, path, &newpath, 0);
  412     if (!err) {
  413         err = fuse_fs_statfs(ic->next, newpath, stbuf);
  414         free(newpath);
  415     }
  416     return err;
  417 }
  418 
  419 static int iconv_flush(const char *path, struct fuse_file_info *fi)
  420 {
  421     struct iconv *ic = iconv_get();
  422     char *newpath;
  423     int err = iconv_convpath(ic, path, &newpath, 0);
  424     if (!err) {
  425         err = fuse_fs_flush(ic->next, newpath, fi);
  426         free(newpath);
  427     }
  428     return err;
  429 }
  430 
  431 static int iconv_release(const char *path, struct fuse_file_info *fi)
  432 {
  433     struct iconv *ic = iconv_get();
  434     char *newpath;
  435     int err = iconv_convpath(ic, path, &newpath, 0);
  436     if (!err) {
  437         err = fuse_fs_release(ic->next, newpath, fi);
  438         free(newpath);
  439     }
  440     return err;
  441 }
  442 
  443 static int iconv_fsync(const char *path, int isdatasync,
  444                struct fuse_file_info *fi)
  445 {
  446     struct iconv *ic = iconv_get();
  447     char *newpath;
  448     int err = iconv_convpath(ic, path, &newpath, 0);
  449     if (!err) {
  450         err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi);
  451         free(newpath);
  452     }
  453     return err;
  454 }
  455 
  456 static int iconv_fsyncdir(const char *path, int isdatasync,
  457               struct fuse_file_info *fi)
  458 {
  459     struct iconv *ic = iconv_get();
  460     char *newpath;
  461     int err = iconv_convpath(ic, path, &newpath, 0);
  462     if (!err) {
  463         err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi);
  464         free(newpath);
  465     }
  466     return err;
  467 }
  468 
  469 static int iconv_setxattr(const char *path, const char *name,
  470               const char *value, size_t size, int flags)
  471 {
  472     struct iconv *ic = iconv_get();
  473     char *newpath;
  474     int err = iconv_convpath(ic, path, &newpath, 0);
  475     if (!err) {
  476         err = fuse_fs_setxattr(ic->next, newpath, name, value, size,
  477                        flags);
  478         free(newpath);
  479     }
  480     return err;
  481 }
  482 
  483 static int iconv_getxattr(const char *path, const char *name, char *value,
  484               size_t size)
  485 {
  486     struct iconv *ic = iconv_get();
  487     char *newpath;
  488     int err = iconv_convpath(ic, path, &newpath, 0);
  489     if (!err) {
  490         err = fuse_fs_getxattr(ic->next, newpath, name, value, size);
  491         free(newpath);
  492     }
  493     return err;
  494 }
  495 
  496 static int iconv_listxattr(const char *path, char *list, size_t size)
  497 {
  498     struct iconv *ic = iconv_get();
  499     char *newpath;
  500     int err = iconv_convpath(ic, path, &newpath, 0);
  501     if (!err) {
  502         err = fuse_fs_listxattr(ic->next, newpath, list, size);
  503         free(newpath);
  504     }
  505     return err;
  506 }
  507 
  508 static int iconv_removexattr(const char *path, const char *name)
  509 {
  510     struct iconv *ic = iconv_get();
  511     char *newpath;
  512     int err = iconv_convpath(ic, path, &newpath, 0);
  513     if (!err) {
  514         err = fuse_fs_removexattr(ic->next, newpath, name);
  515         free(newpath);
  516     }
  517     return err;
  518 }
  519 
  520 static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd,
  521               struct flock *lock)
  522 {
  523     struct iconv *ic = iconv_get();
  524     char *newpath;
  525     int err = iconv_convpath(ic, path, &newpath, 0);
  526     if (!err) {
  527         err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock);
  528         free(newpath);
  529     }
  530     return err;
  531 }
  532 
  533 static int iconv_flock(const char *path, struct fuse_file_info *fi, int op)
  534 {
  535     struct iconv *ic = iconv_get();
  536     char *newpath;
  537     int err = iconv_convpath(ic, path, &newpath, 0);
  538     if (!err) {
  539         err = fuse_fs_flock(ic->next, newpath, fi, op);
  540         free(newpath);
  541     }
  542     return err;
  543 }
  544 
  545 static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx)
  546 {
  547     struct iconv *ic = iconv_get();
  548     char *newpath;
  549     int err = iconv_convpath(ic, path, &newpath, 0);
  550     if (!err) {
  551         err = fuse_fs_bmap(ic->next, newpath, blocksize, idx);
  552         free(newpath);
  553     }
  554     return err;
  555 }
  556 
  557 static void *iconv_init(struct fuse_conn_info *conn,
  558             struct fuse_config *cfg)
  559 {
  560     struct iconv *ic = iconv_get();
  561     fuse_fs_init(ic->next, conn, cfg);
  562     /* Don't touch cfg->nullpath_ok, we can work with
  563        either */
  564     return ic;
  565 }
  566 
  567 static void iconv_destroy(void *data)
  568 {
  569     struct iconv *ic = data;
  570     fuse_fs_destroy(ic->next);
  571     iconv_close(ic->tofs);
  572     iconv_close(ic->fromfs);
  573     pthread_mutex_destroy(&ic->lock);
  574     free(ic->from_code);
  575     free(ic->to_code);
  576     free(ic);
  577 }
  578 
  579 static const struct fuse_operations iconv_oper = {
  580     .destroy    = iconv_destroy,
  581     .init       = iconv_init,
  582     .getattr    = iconv_getattr,
  583     .access     = iconv_access,
  584     .readlink   = iconv_readlink,
  585     .opendir    = iconv_opendir,
  586     .readdir    = iconv_readdir,
  587     .releasedir = iconv_releasedir,
  588     .mknod      = iconv_mknod,
  589     .mkdir      = iconv_mkdir,
  590     .symlink    = iconv_symlink,
  591     .unlink     = iconv_unlink,
  592     .rmdir      = iconv_rmdir,
  593     .rename     = iconv_rename,
  594     .link       = iconv_link,
  595     .chmod      = iconv_chmod,
  596     .chown      = iconv_chown,
  597     .truncate   = iconv_truncate,
  598     .utimens    = iconv_utimens,
  599     .create     = iconv_create,
  600     .open       = iconv_open_file,
  601     .read_buf   = iconv_read_buf,
  602     .write_buf  = iconv_write_buf,
  603     .statfs     = iconv_statfs,
  604     .flush      = iconv_flush,
  605     .release    = iconv_release,
  606     .fsync      = iconv_fsync,
  607     .fsyncdir   = iconv_fsyncdir,
  608     .setxattr   = iconv_setxattr,
  609     .getxattr   = iconv_getxattr,
  610     .listxattr  = iconv_listxattr,
  611     .removexattr    = iconv_removexattr,
  612     .lock       = iconv_lock,
  613     .flock      = iconv_flock,
  614     .bmap       = iconv_bmap,
  615 };
  616 
  617 static const struct fuse_opt iconv_opts[] = {
  618     FUSE_OPT_KEY("-h", 0),
  619     FUSE_OPT_KEY("--help", 0),
  620     { "from_code=%s", offsetof(struct iconv, from_code), 0 },
  621     { "to_code=%s", offsetof(struct iconv, to_code), 1 },
  622     FUSE_OPT_END
  623 };
  624 
  625 static void iconv_help(void)
  626 {
  627     char *old = strdup(setlocale(LC_CTYPE, ""));
  628     char *charmap = strdup(nl_langinfo(CODESET));
  629     setlocale(LC_CTYPE, old);
  630     free(old);
  631     printf(
  632 "    -o from_code=CHARSET   original encoding of file names (default: UTF-8)\n"
  633 "    -o to_code=CHARSET     new encoding of the file names (default: %s)\n",
  634         charmap);
  635     free(charmap);
  636 }
  637 
  638 static int iconv_opt_proc(void *data, const char *arg, int key,
  639               struct fuse_args *outargs)
  640 {
  641     (void) data; (void) arg; (void) outargs;
  642 
  643     if (!key) {
  644         iconv_help();
  645         return -1;
  646     }
  647 
  648     return 1;
  649 }
  650 
  651 static struct fuse_fs *iconv_new(struct fuse_args *args,
  652                  struct fuse_fs *next[])
  653 {
  654     struct fuse_fs *fs;
  655     struct iconv *ic;
  656     char *old = NULL;
  657     const char *from;
  658     const char *to;
  659 
  660     ic = calloc(1, sizeof(struct iconv));
  661     if (ic == NULL) {
  662         fprintf(stderr, "fuse-iconv: memory allocation failed\n");
  663         return NULL;
  664     }
  665 
  666     if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1)
  667         goto out_free;
  668 
  669     if (!next[0] || next[1]) {
  670         fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n");
  671         goto out_free;
  672     }
  673 
  674     from = ic->from_code ? ic->from_code : "UTF-8";
  675     to = ic->to_code ? ic->to_code : "";
  676     /* FIXME: detect charset equivalence? */
  677     if (!to[0])
  678         old = strdup(setlocale(LC_CTYPE, ""));
  679     ic->tofs = iconv_open(from, to);
  680     if (ic->tofs == (iconv_t) -1) {
  681         fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
  682             to, from);
  683         goto out_free;
  684     }
  685     ic->fromfs = iconv_open(to, from);
  686     if (ic->tofs == (iconv_t) -1) {
  687         fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
  688             from, to);
  689         goto out_iconv_close_to;
  690     }
  691     if (old) {
  692         setlocale(LC_CTYPE, old);
  693         free(old);
  694     }
  695 
  696     ic->next = next[0];
  697     fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic);
  698     if (!fs)
  699         goto out_iconv_close_from;
  700 
  701     return fs;
  702 
  703 out_iconv_close_from:
  704     iconv_close(ic->fromfs);
  705 out_iconv_close_to:
  706     iconv_close(ic->tofs);
  707 out_free:
  708     free(ic->from_code);
  709     free(ic->to_code);
  710     free(ic);
  711     if (old) {
  712         setlocale(LC_CTYPE, old);
  713         free(old);
  714     }
  715     return NULL;
  716 }
  717 
  718 FUSE_REGISTER_MODULE(iconv, iconv_new);