"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.1/lib/modules/subdir.c" (14 Nov 2017, 14773 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 "subdir.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 subdir module: offset paths with a base directory
    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 
   18 struct subdir {
   19     char *base;
   20     size_t baselen;
   21     int rellinks;
   22     struct fuse_fs *next;
   23 };
   24 
   25 static struct subdir *subdir_get(void)
   26 {
   27     return fuse_get_context()->private_data;
   28 }
   29 
   30 static int subdir_addpath(struct subdir *d, const char *path, char **newpathp)
   31 {
   32     char *newpath = NULL;
   33 
   34     if (path != NULL) {
   35         unsigned newlen = d->baselen + strlen(path);
   36 
   37         newpath = malloc(newlen + 2);
   38         if (!newpath)
   39             return -ENOMEM;
   40 
   41         if (path[0] == '/')
   42             path++;
   43         strcpy(newpath, d->base);
   44         strcpy(newpath + d->baselen, path);
   45         if (!newpath[0])
   46             strcpy(newpath, ".");
   47     }
   48     *newpathp = newpath;
   49 
   50     return 0;
   51 }
   52 
   53 static int subdir_getattr(const char *path, struct stat *stbuf,
   54               struct fuse_file_info *fi)
   55 {
   56     struct subdir *d = subdir_get();
   57     char *newpath;
   58     int err = subdir_addpath(d, path, &newpath);
   59     if (!err) {
   60         err = fuse_fs_getattr(d->next, newpath, stbuf, fi);
   61         free(newpath);
   62     }
   63     return err;
   64 }
   65 
   66 static int subdir_access(const char *path, int mask)
   67 {
   68     struct subdir *d = subdir_get();
   69     char *newpath;
   70     int err = subdir_addpath(d, path, &newpath);
   71     if (!err) {
   72         err = fuse_fs_access(d->next, newpath, mask);
   73         free(newpath);
   74     }
   75     return err;
   76 }
   77 
   78 
   79 static int count_components(const char *p)
   80 {
   81     int ctr;
   82 
   83     for (; *p == '/'; p++);
   84     for (ctr = 0; *p; ctr++) {
   85         for (; *p && *p != '/'; p++);
   86         for (; *p == '/'; p++);
   87     }
   88     return ctr;
   89 }
   90 
   91 static void strip_common(const char **sp, const char **tp)
   92 {
   93     const char *s = *sp;
   94     const char *t = *tp;
   95     do {
   96         for (; *s == '/'; s++);
   97         for (; *t == '/'; t++);
   98         *tp = t;
   99         *sp = s;
  100         for (; *s == *t && *s && *s != '/'; s++, t++);
  101     } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
  102 }
  103 
  104 static void transform_symlink(struct subdir *d, const char *path,
  105                   char *buf, size_t size)
  106 {
  107     const char *l = buf;
  108     size_t llen;
  109     char *s;
  110     int dotdots;
  111     int i;
  112 
  113     if (l[0] != '/' || d->base[0] != '/')
  114         return;
  115 
  116     strip_common(&l, &path);
  117     if (l - buf < (long) d->baselen)
  118         return;
  119 
  120     dotdots = count_components(path);
  121     if (!dotdots)
  122         return;
  123     dotdots--;
  124 
  125     llen = strlen(l);
  126     if (dotdots * 3 + llen + 2 > size)
  127         return;
  128 
  129     s = buf + dotdots * 3;
  130     if (llen)
  131         memmove(s, l, llen + 1);
  132     else if (!dotdots)
  133         strcpy(s, ".");
  134     else
  135         *s = '\0';
  136 
  137     for (s = buf, i = 0; i < dotdots; i++, s += 3)
  138         memcpy(s, "../", 3);
  139 }
  140 
  141 
  142 static int subdir_readlink(const char *path, char *buf, size_t size)
  143 {
  144     struct subdir *d = subdir_get();
  145     char *newpath;
  146     int err = subdir_addpath(d, path, &newpath);
  147     if (!err) {
  148         err = fuse_fs_readlink(d->next, newpath, buf, size);
  149         if (!err && d->rellinks)
  150             transform_symlink(d, newpath, buf, size);
  151         free(newpath);
  152     }
  153     return err;
  154 }
  155 
  156 static int subdir_opendir(const char *path, struct fuse_file_info *fi)
  157 {
  158     struct subdir *d = subdir_get();
  159     char *newpath;
  160     int err = subdir_addpath(d, path, &newpath);
  161     if (!err) {
  162         err = fuse_fs_opendir(d->next, newpath, fi);
  163         free(newpath);
  164     }
  165     return err;
  166 }
  167 
  168 static int subdir_readdir(const char *path, void *buf,
  169               fuse_fill_dir_t filler, off_t offset,
  170               struct fuse_file_info *fi,
  171               enum fuse_readdir_flags flags)
  172 {
  173     struct subdir *d = subdir_get();
  174     char *newpath;
  175     int err = subdir_addpath(d, path, &newpath);
  176     if (!err) {
  177         err = fuse_fs_readdir(d->next, newpath, buf, filler, offset,
  178                       fi, flags);
  179         free(newpath);
  180     }
  181     return err;
  182 }
  183 
  184 static int subdir_releasedir(const char *path, struct fuse_file_info *fi)
  185 {
  186     struct subdir *d = subdir_get();
  187     char *newpath;
  188     int err = subdir_addpath(d, path, &newpath);
  189     if (!err) {
  190         err = fuse_fs_releasedir(d->next, newpath, fi);
  191         free(newpath);
  192     }
  193     return err;
  194 }
  195 
  196 static int subdir_mknod(const char *path, mode_t mode, dev_t rdev)
  197 {
  198     struct subdir *d = subdir_get();
  199     char *newpath;
  200     int err = subdir_addpath(d, path, &newpath);
  201     if (!err) {
  202         err = fuse_fs_mknod(d->next, newpath, mode, rdev);
  203         free(newpath);
  204     }
  205     return err;
  206 }
  207 
  208 static int subdir_mkdir(const char *path, mode_t mode)
  209 {
  210     struct subdir *d = subdir_get();
  211     char *newpath;
  212     int err = subdir_addpath(d, path, &newpath);
  213     if (!err) {
  214         err = fuse_fs_mkdir(d->next, newpath, mode);
  215         free(newpath);
  216     }
  217     return err;
  218 }
  219 
  220 static int subdir_unlink(const char *path)
  221 {
  222     struct subdir *d = subdir_get();
  223     char *newpath;
  224     int err = subdir_addpath(d, path, &newpath);
  225     if (!err) {
  226         err = fuse_fs_unlink(d->next, newpath);
  227         free(newpath);
  228     }
  229     return err;
  230 }
  231 
  232 static int subdir_rmdir(const char *path)
  233 {
  234     struct subdir *d = subdir_get();
  235     char *newpath;
  236     int err = subdir_addpath(d, path, &newpath);
  237     if (!err) {
  238         err = fuse_fs_rmdir(d->next, newpath);
  239         free(newpath);
  240     }
  241     return err;
  242 }
  243 
  244 static int subdir_symlink(const char *from, const char *path)
  245 {
  246     struct subdir *d = subdir_get();
  247     char *newpath;
  248     int err = subdir_addpath(d, path, &newpath);
  249     if (!err) {
  250         err = fuse_fs_symlink(d->next, from, newpath);
  251         free(newpath);
  252     }
  253     return err;
  254 }
  255 
  256 static int subdir_rename(const char *from, const char *to, unsigned int flags)
  257 {
  258     struct subdir *d = subdir_get();
  259     char *newfrom;
  260     char *newto;
  261     int err = subdir_addpath(d, from, &newfrom);
  262     if (!err) {
  263         err = subdir_addpath(d, to, &newto);
  264         if (!err) {
  265             err = fuse_fs_rename(d->next, newfrom, newto, flags);
  266             free(newto);
  267         }
  268         free(newfrom);
  269     }
  270     return err;
  271 }
  272 
  273 static int subdir_link(const char *from, const char *to)
  274 {
  275     struct subdir *d = subdir_get();
  276     char *newfrom;
  277     char *newto;
  278     int err = subdir_addpath(d, from, &newfrom);
  279     if (!err) {
  280         err = subdir_addpath(d, to, &newto);
  281         if (!err) {
  282             err = fuse_fs_link(d->next, newfrom, newto);
  283             free(newto);
  284         }
  285         free(newfrom);
  286     }
  287     return err;
  288 }
  289 
  290 static int subdir_chmod(const char *path, mode_t mode,
  291             struct fuse_file_info *fi)
  292 {
  293     struct subdir *d = subdir_get();
  294     char *newpath;
  295     int err = subdir_addpath(d, path, &newpath);
  296     if (!err) {
  297         err = fuse_fs_chmod(d->next, newpath, mode, fi);
  298         free(newpath);
  299     }
  300     return err;
  301 }
  302 
  303 static int subdir_chown(const char *path, uid_t uid, gid_t gid,
  304             struct fuse_file_info *fi)
  305 {
  306     struct subdir *d = subdir_get();
  307     char *newpath;
  308     int err = subdir_addpath(d, path, &newpath);
  309     if (!err) {
  310         err = fuse_fs_chown(d->next, newpath, uid, gid, fi);
  311         free(newpath);
  312     }
  313     return err;
  314 }
  315 
  316 static int subdir_truncate(const char *path, off_t size,
  317                struct fuse_file_info *fi)
  318 {
  319     struct subdir *d = subdir_get();
  320     char *newpath;
  321     int err = subdir_addpath(d, path, &newpath);
  322     if (!err) {
  323         err = fuse_fs_truncate(d->next, newpath, size, fi);
  324         free(newpath);
  325     }
  326     return err;
  327 }
  328 
  329 static int subdir_utimens(const char *path, const struct timespec ts[2],
  330               struct fuse_file_info *fi)
  331 {
  332     struct subdir *d = subdir_get();
  333     char *newpath;
  334     int err = subdir_addpath(d, path, &newpath);
  335     if (!err) {
  336         err = fuse_fs_utimens(d->next, newpath, ts, fi);
  337         free(newpath);
  338     }
  339     return err;
  340 }
  341 
  342 static int subdir_create(const char *path, mode_t mode,
  343              struct fuse_file_info *fi)
  344 {
  345     struct subdir *d = subdir_get();
  346     char *newpath;
  347     int err = subdir_addpath(d, path, &newpath);
  348     if (!err) {
  349         err = fuse_fs_create(d->next, newpath, mode, fi);
  350         free(newpath);
  351     }
  352     return err;
  353 }
  354 
  355 static int subdir_open(const char *path, struct fuse_file_info *fi)
  356 {
  357     struct subdir *d = subdir_get();
  358     char *newpath;
  359     int err = subdir_addpath(d, path, &newpath);
  360     if (!err) {
  361         err = fuse_fs_open(d->next, newpath, fi);
  362         free(newpath);
  363     }
  364     return err;
  365 }
  366 
  367 static int subdir_read_buf(const char *path, struct fuse_bufvec **bufp,
  368                size_t size, off_t offset, struct fuse_file_info *fi)
  369 {
  370     struct subdir *d = subdir_get();
  371     char *newpath;
  372     int err = subdir_addpath(d, path, &newpath);
  373     if (!err) {
  374         err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
  375         free(newpath);
  376     }
  377     return err;
  378 }
  379 
  380 static int subdir_write_buf(const char *path, struct fuse_bufvec *buf,
  381             off_t offset, struct fuse_file_info *fi)
  382 {
  383     struct subdir *d = subdir_get();
  384     char *newpath;
  385     int err = subdir_addpath(d, path, &newpath);
  386     if (!err) {
  387         err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
  388         free(newpath);
  389     }
  390     return err;
  391 }
  392 
  393 static int subdir_statfs(const char *path, struct statvfs *stbuf)
  394 {
  395     struct subdir *d = subdir_get();
  396     char *newpath;
  397     int err = subdir_addpath(d, path, &newpath);
  398     if (!err) {
  399         err = fuse_fs_statfs(d->next, newpath, stbuf);
  400         free(newpath);
  401     }
  402     return err;
  403 }
  404 
  405 static int subdir_flush(const char *path, struct fuse_file_info *fi)
  406 {
  407     struct subdir *d = subdir_get();
  408     char *newpath;
  409     int err = subdir_addpath(d, path, &newpath);
  410     if (!err) {
  411         err = fuse_fs_flush(d->next, newpath, fi);
  412         free(newpath);
  413     }
  414     return err;
  415 }
  416 
  417 static int subdir_release(const char *path, struct fuse_file_info *fi)
  418 {
  419     struct subdir *d = subdir_get();
  420     char *newpath;
  421     int err = subdir_addpath(d, path, &newpath);
  422     if (!err) {
  423         err = fuse_fs_release(d->next, newpath, fi);
  424         free(newpath);
  425     }
  426     return err;
  427 }
  428 
  429 static int subdir_fsync(const char *path, int isdatasync,
  430             struct fuse_file_info *fi)
  431 {
  432     struct subdir *d = subdir_get();
  433     char *newpath;
  434     int err = subdir_addpath(d, path, &newpath);
  435     if (!err) {
  436         err = fuse_fs_fsync(d->next, newpath, isdatasync, fi);
  437         free(newpath);
  438     }
  439     return err;
  440 }
  441 
  442 static int subdir_fsyncdir(const char *path, int isdatasync,
  443                struct fuse_file_info *fi)
  444 {
  445     struct subdir *d = subdir_get();
  446     char *newpath;
  447     int err = subdir_addpath(d, path, &newpath);
  448     if (!err) {
  449         err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi);
  450         free(newpath);
  451     }
  452     return err;
  453 }
  454 
  455 static int subdir_setxattr(const char *path, const char *name,
  456                const char *value, size_t size, int flags)
  457 {
  458     struct subdir *d = subdir_get();
  459     char *newpath;
  460     int err = subdir_addpath(d, path, &newpath);
  461     if (!err) {
  462         err = fuse_fs_setxattr(d->next, newpath, name, value, size,
  463                        flags);
  464         free(newpath);
  465     }
  466     return err;
  467 }
  468 
  469 static int subdir_getxattr(const char *path, const char *name, char *value,
  470                size_t size)
  471 {
  472     struct subdir *d = subdir_get();
  473     char *newpath;
  474     int err = subdir_addpath(d, path, &newpath);
  475     if (!err) {
  476         err = fuse_fs_getxattr(d->next, newpath, name, value, size);
  477         free(newpath);
  478     }
  479     return err;
  480 }
  481 
  482 static int subdir_listxattr(const char *path, char *list, size_t size)
  483 {
  484     struct subdir *d = subdir_get();
  485     char *newpath;
  486     int err = subdir_addpath(d, path, &newpath);
  487     if (!err) {
  488         err = fuse_fs_listxattr(d->next, newpath, list, size);
  489         free(newpath);
  490     }
  491     return err;
  492 }
  493 
  494 static int subdir_removexattr(const char *path, const char *name)
  495 {
  496     struct subdir *d = subdir_get();
  497     char *newpath;
  498     int err = subdir_addpath(d, path, &newpath);
  499     if (!err) {
  500         err = fuse_fs_removexattr(d->next, newpath, name);
  501         free(newpath);
  502     }
  503     return err;
  504 }
  505 
  506 static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd,
  507                struct flock *lock)
  508 {
  509     struct subdir *d = subdir_get();
  510     char *newpath;
  511     int err = subdir_addpath(d, path, &newpath);
  512     if (!err) {
  513         err = fuse_fs_lock(d->next, newpath, fi, cmd, lock);
  514         free(newpath);
  515     }
  516     return err;
  517 }
  518 
  519 static int subdir_flock(const char *path, struct fuse_file_info *fi, int op)
  520 {
  521     struct subdir *d = subdir_get();
  522     char *newpath;
  523     int err = subdir_addpath(d, path, &newpath);
  524     if (!err) {
  525         err = fuse_fs_flock(d->next, newpath, fi, op);
  526         free(newpath);
  527     }
  528     return err;
  529 }
  530 
  531 static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx)
  532 {
  533     struct subdir *d = subdir_get();
  534     char *newpath;
  535     int err = subdir_addpath(d, path, &newpath);
  536     if (!err) {
  537         err = fuse_fs_bmap(d->next, newpath, blocksize, idx);
  538         free(newpath);
  539     }
  540     return err;
  541 }
  542 
  543 static void *subdir_init(struct fuse_conn_info *conn,
  544              struct fuse_config *cfg)
  545 {
  546     struct subdir *d = subdir_get();
  547     fuse_fs_init(d->next, conn, cfg);
  548     /* Don't touch cfg->nullpath_ok, we can work with
  549        either */
  550     return d;
  551 }
  552 
  553 static void subdir_destroy(void *data)
  554 {
  555     struct subdir *d = data;
  556     fuse_fs_destroy(d->next);
  557     free(d->base);
  558     free(d);
  559 }
  560 
  561 static const struct fuse_operations subdir_oper = {
  562     .destroy    = subdir_destroy,
  563     .init       = subdir_init,
  564     .getattr    = subdir_getattr,
  565     .access     = subdir_access,
  566     .readlink   = subdir_readlink,
  567     .opendir    = subdir_opendir,
  568     .readdir    = subdir_readdir,
  569     .releasedir = subdir_releasedir,
  570     .mknod      = subdir_mknod,
  571     .mkdir      = subdir_mkdir,
  572     .symlink    = subdir_symlink,
  573     .unlink     = subdir_unlink,
  574     .rmdir      = subdir_rmdir,
  575     .rename     = subdir_rename,
  576     .link       = subdir_link,
  577     .chmod      = subdir_chmod,
  578     .chown      = subdir_chown,
  579     .truncate   = subdir_truncate,
  580     .utimens    = subdir_utimens,
  581     .create     = subdir_create,
  582     .open       = subdir_open,
  583     .read_buf   = subdir_read_buf,
  584     .write_buf  = subdir_write_buf,
  585     .statfs     = subdir_statfs,
  586     .flush      = subdir_flush,
  587     .release    = subdir_release,
  588     .fsync      = subdir_fsync,
  589     .fsyncdir   = subdir_fsyncdir,
  590     .setxattr   = subdir_setxattr,
  591     .getxattr   = subdir_getxattr,
  592     .listxattr  = subdir_listxattr,
  593     .removexattr    = subdir_removexattr,
  594     .lock       = subdir_lock,
  595     .flock      = subdir_flock,
  596     .bmap       = subdir_bmap,
  597 };
  598 
  599 static const struct fuse_opt subdir_opts[] = {
  600     FUSE_OPT_KEY("-h", 0),
  601     FUSE_OPT_KEY("--help", 0),
  602     { "subdir=%s", offsetof(struct subdir, base), 0 },
  603     { "rellinks", offsetof(struct subdir, rellinks), 1 },
  604     { "norellinks", offsetof(struct subdir, rellinks), 0 },
  605     FUSE_OPT_END
  606 };
  607 
  608 static void subdir_help(void)
  609 {
  610     printf(
  611 "    -o subdir=DIR      prepend this directory to all paths (mandatory)\n"
  612 "    -o [no]rellinks        transform absolute symlinks to relative\n");
  613 }
  614 
  615 static int subdir_opt_proc(void *data, const char *arg, int key,
  616                struct fuse_args *outargs)
  617 {
  618     (void) data; (void) arg; (void) outargs;
  619 
  620     if (!key) {
  621         subdir_help();
  622         return -1;
  623     }
  624 
  625     return 1;
  626 }
  627 
  628 static struct fuse_fs *subdir_new(struct fuse_args *args,
  629                   struct fuse_fs *next[])
  630 {
  631     struct fuse_fs *fs;
  632     struct subdir *d;
  633 
  634     d = calloc(1, sizeof(struct subdir));
  635     if (d == NULL) {
  636         fprintf(stderr, "fuse-subdir: memory allocation failed\n");
  637         return NULL;
  638     }
  639 
  640     if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1)
  641         goto out_free;
  642 
  643     if (!next[0] || next[1]) {
  644         fprintf(stderr, "fuse-subdir: exactly one next filesystem required\n");
  645         goto out_free;
  646     }
  647 
  648     if (!d->base) {
  649         fprintf(stderr, "fuse-subdir: missing 'subdir' option\n");
  650         goto out_free;
  651     }
  652 
  653     if (d->base[0] && d->base[strlen(d->base)-1] != '/') {
  654         char *tmp = realloc(d->base, strlen(d->base) + 2);
  655         if (!tmp) {
  656             fprintf(stderr, "fuse-subdir: memory allocation failed\n");
  657             goto out_free;
  658         }
  659         d->base = tmp;
  660         strcat(d->base, "/");
  661     }
  662     d->baselen = strlen(d->base);
  663     d->next = next[0];
  664     fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d);
  665     if (!fs)
  666         goto out_free;
  667     return fs;
  668 
  669 out_free:
  670     free(d->base);
  671     free(d);
  672     return NULL;
  673 }
  674 
  675 FUSE_REGISTER_MODULE(subdir, subdir_new);