"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.3/example/passthrough_fh.c" (11 May 2018, 11968 Bytes) of package /linux/misc/fuse-3.2.3.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. See also the last Fossies "Diffs" side-by-side code changes report for "passthrough_fh.c": 3.1.1_vs_3.2.0.

    1 /*
    2   FUSE: Filesystem in Userspace
    3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
    4   Copyright (C) 2011       Sebastian Pipping <sebastian@pipping.org>
    5 
    6   This program can be distributed under the terms of the GNU GPL.
    7   See the file COPYING.
    8 */
    9 
   10 /** @file
   11  *
   12  * This file system mirrors the existing file system hierarchy of the
   13  * system, starting at the root file system. This is implemented by
   14  * just "passing through" all requests to the corresponding user-space
   15  * libc functions. This implementation is a little more sophisticated
   16  * than the one in passthrough.c, so performance is not quite as bad.
   17  *
   18  * Compile with:
   19  *
   20  *     gcc -Wall passthrough_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr -o passthrough_fh
   21  *
   22  * ## Source code ##
   23  * \include passthrough_fh.c
   24  */
   25 
   26 #define FUSE_USE_VERSION 31
   27 
   28 #ifdef HAVE_CONFIG_H
   29 #include <config.h>
   30 #endif
   31 
   32 #define _GNU_SOURCE
   33 
   34 #include <fuse.h>
   35 
   36 #ifdef HAVE_LIBULOCKMGR
   37 #include <ulockmgr.h>
   38 #endif
   39 
   40 #include <stdio.h>
   41 #include <stdlib.h>
   42 #include <string.h>
   43 #include <unistd.h>
   44 #include <fcntl.h>
   45 #include <sys/stat.h>
   46 #include <dirent.h>
   47 #include <errno.h>
   48 #include <sys/time.h>
   49 #ifdef HAVE_SETXATTR
   50 #include <sys/xattr.h>
   51 #endif
   52 #include <sys/file.h> /* flock(2) */
   53 
   54 static void *xmp_init(struct fuse_conn_info *conn,
   55               struct fuse_config *cfg)
   56 {
   57     (void) conn;
   58     cfg->use_ino = 1;
   59     cfg->nullpath_ok = 1;
   60 
   61     /* Pick up changes from lower filesystem right away. This is
   62        also necessary for better hardlink support. When the kernel
   63        calls the unlink() handler, it does not know the inode of
   64        the to-be-removed entry and can therefore not invalidate
   65        the cache of the associated inode - resulting in an
   66        incorrect st_nlink value being reported for any remaining
   67        hardlinks to this inode. */
   68     cfg->entry_timeout = 0;
   69     cfg->attr_timeout = 0;
   70     cfg->negative_timeout = 0;
   71 
   72     return NULL;
   73 }
   74 
   75 static int xmp_getattr(const char *path, struct stat *stbuf,
   76             struct fuse_file_info *fi)
   77 {
   78     int res;
   79 
   80     (void) path;
   81 
   82     if(fi)
   83         res = fstat(fi->fh, stbuf);
   84     else
   85         res = lstat(path, stbuf);
   86     if (res == -1)
   87         return -errno;
   88 
   89     return 0;
   90 }
   91 
   92 static int xmp_access(const char *path, int mask)
   93 {
   94     int res;
   95 
   96     res = access(path, mask);
   97     if (res == -1)
   98         return -errno;
   99 
  100     return 0;
  101 }
  102 
  103 static int xmp_readlink(const char *path, char *buf, size_t size)
  104 {
  105     int res;
  106 
  107     res = readlink(path, buf, size - 1);
  108     if (res == -1)
  109         return -errno;
  110 
  111     buf[res] = '\0';
  112     return 0;
  113 }
  114 
  115 struct xmp_dirp {
  116     DIR *dp;
  117     struct dirent *entry;
  118     off_t offset;
  119 };
  120 
  121 static int xmp_opendir(const char *path, struct fuse_file_info *fi)
  122 {
  123     int res;
  124     struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
  125     if (d == NULL)
  126         return -ENOMEM;
  127 
  128     d->dp = opendir(path);
  129     if (d->dp == NULL) {
  130         res = -errno;
  131         free(d);
  132         return res;
  133     }
  134     d->offset = 0;
  135     d->entry = NULL;
  136 
  137     fi->fh = (unsigned long) d;
  138     return 0;
  139 }
  140 
  141 static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi)
  142 {
  143     return (struct xmp_dirp *) (uintptr_t) fi->fh;
  144 }
  145 
  146 static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
  147                off_t offset, struct fuse_file_info *fi,
  148                enum fuse_readdir_flags flags)
  149 {
  150     struct xmp_dirp *d = get_dirp(fi);
  151 
  152     (void) path;
  153     if (offset != d->offset) {
  154 #ifndef __FreeBSD__
  155         seekdir(d->dp, offset);
  156 #else
  157         /* Subtract the one that we add when calling
  158            telldir() below */
  159         seekdir(d->dp, offset-1);
  160 #endif
  161         d->entry = NULL;
  162         d->offset = offset;
  163     }
  164     while (1) {
  165         struct stat st;
  166         off_t nextoff;
  167         enum fuse_fill_dir_flags fill_flags = 0;
  168 
  169         if (!d->entry) {
  170             d->entry = readdir(d->dp);
  171             if (!d->entry)
  172                 break;
  173         }
  174 #ifdef HAVE_FSTATAT
  175         if (flags & FUSE_READDIR_PLUS) {
  176             int res;
  177 
  178             res = fstatat(dirfd(d->dp), d->entry->d_name, &st,
  179                       AT_SYMLINK_NOFOLLOW);
  180             if (res != -1)
  181                 fill_flags |= FUSE_FILL_DIR_PLUS;
  182         }
  183 #endif
  184         if (!(fill_flags & FUSE_FILL_DIR_PLUS)) {
  185             memset(&st, 0, sizeof(st));
  186             st.st_ino = d->entry->d_ino;
  187             st.st_mode = d->entry->d_type << 12;
  188         }
  189         nextoff = telldir(d->dp);
  190 #ifdef __FreeBSD__      
  191         /* Under FreeBSD, telldir() may return 0 the first time
  192            it is called. But for libfuse, an offset of zero
  193            means that offsets are not supported, so we shift
  194            everything by one. */
  195         nextoff++;
  196 #endif
  197         if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags))
  198             break;
  199 
  200         d->entry = NULL;
  201         d->offset = nextoff;
  202     }
  203 
  204     return 0;
  205 }
  206 
  207 static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
  208 {
  209     struct xmp_dirp *d = get_dirp(fi);
  210     (void) path;
  211     closedir(d->dp);
  212     free(d);
  213     return 0;
  214 }
  215 
  216 static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
  217 {
  218     int res;
  219 
  220     if (S_ISFIFO(mode))
  221         res = mkfifo(path, mode);
  222     else
  223         res = mknod(path, mode, rdev);
  224     if (res == -1)
  225         return -errno;
  226 
  227     return 0;
  228 }
  229 
  230 static int xmp_mkdir(const char *path, mode_t mode)
  231 {
  232     int res;
  233 
  234     res = mkdir(path, mode);
  235     if (res == -1)
  236         return -errno;
  237 
  238     return 0;
  239 }
  240 
  241 static int xmp_unlink(const char *path)
  242 {
  243     int res;
  244 
  245     res = unlink(path);
  246     if (res == -1)
  247         return -errno;
  248 
  249     return 0;
  250 }
  251 
  252 static int xmp_rmdir(const char *path)
  253 {
  254     int res;
  255 
  256     res = rmdir(path);
  257     if (res == -1)
  258         return -errno;
  259 
  260     return 0;
  261 }
  262 
  263 static int xmp_symlink(const char *from, const char *to)
  264 {
  265     int res;
  266 
  267     res = symlink(from, to);
  268     if (res == -1)
  269         return -errno;
  270 
  271     return 0;
  272 }
  273 
  274 static int xmp_rename(const char *from, const char *to, unsigned int flags)
  275 {
  276     int res;
  277 
  278     /* When we have renameat2() in libc, then we can implement flags */
  279     if (flags)
  280         return -EINVAL;
  281 
  282     res = rename(from, to);
  283     if (res == -1)
  284         return -errno;
  285 
  286     return 0;
  287 }
  288 
  289 static int xmp_link(const char *from, const char *to)
  290 {
  291     int res;
  292 
  293     res = link(from, to);
  294     if (res == -1)
  295         return -errno;
  296 
  297     return 0;
  298 }
  299 
  300 static int xmp_chmod(const char *path, mode_t mode,
  301              struct fuse_file_info *fi)
  302 {
  303     int res;
  304 
  305     if(fi)
  306         res = fchmod(fi->fh, mode);
  307     else
  308         res = chmod(path, mode);
  309     if (res == -1)
  310         return -errno;
  311 
  312     return 0;
  313 }
  314 
  315 static int xmp_chown(const char *path, uid_t uid, gid_t gid,
  316              struct fuse_file_info *fi)
  317 {
  318     int res;
  319 
  320     if (fi)
  321         res = fchown(fi->fh, uid, gid);
  322     else
  323         res = lchown(path, uid, gid);
  324     if (res == -1)
  325         return -errno;
  326 
  327     return 0;
  328 }
  329 
  330 static int xmp_truncate(const char *path, off_t size,
  331              struct fuse_file_info *fi)
  332 {
  333     int res;
  334 
  335     if(fi)
  336         res = ftruncate(fi->fh, size);
  337     else
  338         res = truncate(path, size);
  339 
  340     if (res == -1)
  341         return -errno;
  342 
  343     return 0;
  344 }
  345 
  346 #ifdef HAVE_UTIMENSAT
  347 static int xmp_utimens(const char *path, const struct timespec ts[2],
  348                struct fuse_file_info *fi)
  349 {
  350     int res;
  351 
  352     /* don't use utime/utimes since they follow symlinks */
  353     if (fi)
  354         res = futimens(fi->fh, ts);
  355     else
  356         res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
  357     if (res == -1)
  358         return -errno;
  359 
  360     return 0;
  361 }
  362 #endif
  363 
  364 static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
  365 {
  366     int fd;
  367 
  368     fd = open(path, fi->flags, mode);
  369     if (fd == -1)
  370         return -errno;
  371 
  372     fi->fh = fd;
  373     return 0;
  374 }
  375 
  376 static int xmp_open(const char *path, struct fuse_file_info *fi)
  377 {
  378     int fd;
  379 
  380     fd = open(path, fi->flags);
  381     if (fd == -1)
  382         return -errno;
  383 
  384     fi->fh = fd;
  385     return 0;
  386 }
  387 
  388 static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
  389             struct fuse_file_info *fi)
  390 {
  391     int res;
  392 
  393     (void) path;
  394     res = pread(fi->fh, buf, size, offset);
  395     if (res == -1)
  396         res = -errno;
  397 
  398     return res;
  399 }
  400 
  401 static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp,
  402             size_t size, off_t offset, struct fuse_file_info *fi)
  403 {
  404     struct fuse_bufvec *src;
  405 
  406     (void) path;
  407 
  408     src = malloc(sizeof(struct fuse_bufvec));
  409     if (src == NULL)
  410         return -ENOMEM;
  411 
  412     *src = FUSE_BUFVEC_INIT(size);
  413 
  414     src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
  415     src->buf[0].fd = fi->fh;
  416     src->buf[0].pos = offset;
  417 
  418     *bufp = src;
  419 
  420     return 0;
  421 }
  422 
  423 static int xmp_write(const char *path, const char *buf, size_t size,
  424              off_t offset, struct fuse_file_info *fi)
  425 {
  426     int res;
  427 
  428     (void) path;
  429     res = pwrite(fi->fh, buf, size, offset);
  430     if (res == -1)
  431         res = -errno;
  432 
  433     return res;
  434 }
  435 
  436 static int xmp_write_buf(const char *path, struct fuse_bufvec *buf,
  437              off_t offset, struct fuse_file_info *fi)
  438 {
  439     struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf));
  440 
  441     (void) path;
  442 
  443     dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
  444     dst.buf[0].fd = fi->fh;
  445     dst.buf[0].pos = offset;
  446 
  447     return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK);
  448 }
  449 
  450 static int xmp_statfs(const char *path, struct statvfs *stbuf)
  451 {
  452     int res;
  453 
  454     res = statvfs(path, stbuf);
  455     if (res == -1)
  456         return -errno;
  457 
  458     return 0;
  459 }
  460 
  461 static int xmp_flush(const char *path, struct fuse_file_info *fi)
  462 {
  463     int res;
  464 
  465     (void) path;
  466     /* This is called from every close on an open file, so call the
  467        close on the underlying filesystem.  But since flush may be
  468        called multiple times for an open file, this must not really
  469        close the file.  This is important if used on a network
  470        filesystem like NFS which flush the data/metadata on close() */
  471     res = close(dup(fi->fh));
  472     if (res == -1)
  473         return -errno;
  474 
  475     return 0;
  476 }
  477 
  478 static int xmp_release(const char *path, struct fuse_file_info *fi)
  479 {
  480     (void) path;
  481     close(fi->fh);
  482 
  483     return 0;
  484 }
  485 
  486 static int xmp_fsync(const char *path, int isdatasync,
  487              struct fuse_file_info *fi)
  488 {
  489     int res;
  490     (void) path;
  491 
  492 #ifndef HAVE_FDATASYNC
  493     (void) isdatasync;
  494 #else
  495     if (isdatasync)
  496         res = fdatasync(fi->fh);
  497     else
  498 #endif
  499         res = fsync(fi->fh);
  500     if (res == -1)
  501         return -errno;
  502 
  503     return 0;
  504 }
  505 
  506 #ifdef HAVE_POSIX_FALLOCATE
  507 static int xmp_fallocate(const char *path, int mode,
  508             off_t offset, off_t length, struct fuse_file_info *fi)
  509 {
  510     (void) path;
  511 
  512     if (mode)
  513         return -EOPNOTSUPP;
  514 
  515     return -posix_fallocate(fi->fh, offset, length);
  516 }
  517 #endif
  518 
  519 #ifdef HAVE_SETXATTR
  520 /* xattr operations are optional and can safely be left unimplemented */
  521 static int xmp_setxattr(const char *path, const char *name, const char *value,
  522             size_t size, int flags)
  523 {
  524     int res = lsetxattr(path, name, value, size, flags);
  525     if (res == -1)
  526         return -errno;
  527     return 0;
  528 }
  529 
  530 static int xmp_getxattr(const char *path, const char *name, char *value,
  531             size_t size)
  532 {
  533     int res = lgetxattr(path, name, value, size);
  534     if (res == -1)
  535         return -errno;
  536     return res;
  537 }
  538 
  539 static int xmp_listxattr(const char *path, char *list, size_t size)
  540 {
  541     int res = llistxattr(path, list, size);
  542     if (res == -1)
  543         return -errno;
  544     return res;
  545 }
  546 
  547 static int xmp_removexattr(const char *path, const char *name)
  548 {
  549     int res = lremovexattr(path, name);
  550     if (res == -1)
  551         return -errno;
  552     return 0;
  553 }
  554 #endif /* HAVE_SETXATTR */
  555 
  556 #ifdef HAVE_LIBULOCKMGR
  557 static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
  558             struct flock *lock)
  559 {
  560     (void) path;
  561 
  562     return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
  563                sizeof(fi->lock_owner));
  564 }
  565 #endif
  566 
  567 static int xmp_flock(const char *path, struct fuse_file_info *fi, int op)
  568 {
  569     int res;
  570     (void) path;
  571 
  572     res = flock(fi->fh, op);
  573     if (res == -1)
  574         return -errno;
  575 
  576     return 0;
  577 }
  578 
  579 static struct fuse_operations xmp_oper = {
  580     .init           = xmp_init,
  581     .getattr    = xmp_getattr,
  582     .access     = xmp_access,
  583     .readlink   = xmp_readlink,
  584     .opendir    = xmp_opendir,
  585     .readdir    = xmp_readdir,
  586     .releasedir = xmp_releasedir,
  587     .mknod      = xmp_mknod,
  588     .mkdir      = xmp_mkdir,
  589     .symlink    = xmp_symlink,
  590     .unlink     = xmp_unlink,
  591     .rmdir      = xmp_rmdir,
  592     .rename     = xmp_rename,
  593     .link       = xmp_link,
  594     .chmod      = xmp_chmod,
  595     .chown      = xmp_chown,
  596     .truncate   = xmp_truncate,
  597 #ifdef HAVE_UTIMENSAT
  598     .utimens    = xmp_utimens,
  599 #endif
  600     .create     = xmp_create,
  601     .open       = xmp_open,
  602     .read       = xmp_read,
  603     .read_buf   = xmp_read_buf,
  604     .write      = xmp_write,
  605     .write_buf  = xmp_write_buf,
  606     .statfs     = xmp_statfs,
  607     .flush      = xmp_flush,
  608     .release    = xmp_release,
  609     .fsync      = xmp_fsync,
  610 #ifdef HAVE_POSIX_FALLOCATE
  611     .fallocate  = xmp_fallocate,
  612 #endif
  613 #ifdef HAVE_SETXATTR
  614     .setxattr   = xmp_setxattr,
  615     .getxattr   = xmp_getxattr,
  616     .listxattr  = xmp_listxattr,
  617     .removexattr    = xmp_removexattr,
  618 #endif
  619 #ifdef HAVE_LIBULOCKMGR
  620     .lock       = xmp_lock,
  621 #endif
  622     .flock      = xmp_flock,
  623 };
  624 
  625 int main(int argc, char *argv[])
  626 {
  627     umask(0);
  628     return fuse_main(argc, argv, &xmp_oper, NULL);
  629 }