"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.10.4/example/passthrough_ll.c" (9 Jun 2021, 29189 Bytes) of package /linux/misc/fuse-3.10.4.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 latest Fossies "Diffs" side-by-side code changes report for "passthrough_ll.c": 3.10.3_vs_3.10.4.

    1 /*
    2   FUSE: Filesystem in Userspace
    3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
    4 
    5   This program can be distributed under the terms of the GNU GPLv2.
    6   See the file COPYING.
    7 */
    8 
    9 /** @file
   10  *
   11  * This file system mirrors the existing file system hierarchy of the
   12  * system, starting at the root file system. This is implemented by
   13  * just "passing through" all requests to the corresponding user-space
   14  * libc functions. In contrast to passthrough.c and passthrough_fh.c,
   15  * this implementation uses the low-level API. Its performance should
   16  * be the least bad among the three, but many operations are not
   17  * implemented. In particular, it is not possible to remove files (or
   18  * directories) because the code necessary to defer actual removal
   19  * until the file is not opened anymore would make the example much
   20  * more complicated.
   21  *
   22  * When writeback caching is enabled (-o writeback mount option), it
   23  * is only possible to write to files for which the mounting user has
   24  * read permissions. This is because the writeback cache requires the
   25  * kernel to be able to issue read requests for all files (which the
   26  * passthrough filesystem cannot satisfy if it can't read the file in
   27  * the underlying filesystem).
   28  *
   29  * Compile with:
   30  *
   31  *     gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll
   32  *
   33  * ## Source code ##
   34  * \include passthrough_ll.c
   35  */
   36 
   37 #define _GNU_SOURCE
   38 #define FUSE_USE_VERSION 34
   39 
   40 #include "config.h"
   41 
   42 #include <fuse_lowlevel.h>
   43 #include <unistd.h>
   44 #include <stdlib.h>
   45 #include <stdio.h>
   46 #include <stddef.h>
   47 #include <stdbool.h>
   48 #include <string.h>
   49 #include <limits.h>
   50 #include <dirent.h>
   51 #include <assert.h>
   52 #include <errno.h>
   53 #include <inttypes.h>
   54 #include <pthread.h>
   55 #include <sys/file.h>
   56 #include <sys/xattr.h>
   57 
   58 #include "passthrough_helpers.h"
   59 
   60 /* We are re-using pointers to our `struct lo_inode` and `struct
   61    lo_dirp` elements as inodes. This means that we must be able to
   62    store uintptr_t values in a fuse_ino_t variable. The following
   63    incantation checks this condition at compile time. */
   64 #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
   65 _Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
   66            "fuse_ino_t too small to hold uintptr_t values!");
   67 #else
   68 struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
   69     { unsigned _uintptr_to_must_hold_fuse_ino_t:
   70             ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
   71 #endif
   72 
   73 struct lo_inode {
   74     struct lo_inode *next; /* protected by lo->mutex */
   75     struct lo_inode *prev; /* protected by lo->mutex */
   76     int fd;
   77     ino_t ino;
   78     dev_t dev;
   79     uint64_t refcount; /* protected by lo->mutex */
   80 };
   81 
   82 enum {
   83     CACHE_NEVER,
   84     CACHE_NORMAL,
   85     CACHE_ALWAYS,
   86 };
   87 
   88 struct lo_data {
   89     pthread_mutex_t mutex;
   90     int debug;
   91     int writeback;
   92     int flock;
   93     int xattr;
   94     const char *source;
   95     double timeout;
   96     int cache;
   97     int timeout_set;
   98     struct lo_inode root; /* protected by lo->mutex */
   99 };
  100 
  101 static const struct fuse_opt lo_opts[] = {
  102     { "writeback",
  103       offsetof(struct lo_data, writeback), 1 },
  104     { "no_writeback",
  105       offsetof(struct lo_data, writeback), 0 },
  106     { "source=%s",
  107       offsetof(struct lo_data, source), 0 },
  108     { "flock",
  109       offsetof(struct lo_data, flock), 1 },
  110     { "no_flock",
  111       offsetof(struct lo_data, flock), 0 },
  112     { "xattr",
  113       offsetof(struct lo_data, xattr), 1 },
  114     { "no_xattr",
  115       offsetof(struct lo_data, xattr), 0 },
  116     { "timeout=%lf",
  117       offsetof(struct lo_data, timeout), 0 },
  118     { "timeout=",
  119       offsetof(struct lo_data, timeout_set), 1 },
  120     { "cache=never",
  121       offsetof(struct lo_data, cache), CACHE_NEVER },
  122     { "cache=auto",
  123       offsetof(struct lo_data, cache), CACHE_NORMAL },
  124     { "cache=always",
  125       offsetof(struct lo_data, cache), CACHE_ALWAYS },
  126 
  127     FUSE_OPT_END
  128 };
  129 
  130 static struct lo_data *lo_data(fuse_req_t req)
  131 {
  132     return (struct lo_data *) fuse_req_userdata(req);
  133 }
  134 
  135 static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
  136 {
  137     if (ino == FUSE_ROOT_ID)
  138         return &lo_data(req)->root;
  139     else
  140         return (struct lo_inode *) (uintptr_t) ino;
  141 }
  142 
  143 static int lo_fd(fuse_req_t req, fuse_ino_t ino)
  144 {
  145     return lo_inode(req, ino)->fd;
  146 }
  147 
  148 static bool lo_debug(fuse_req_t req)
  149 {
  150     return lo_data(req)->debug != 0;
  151 }
  152 
  153 static void lo_init(void *userdata,
  154             struct fuse_conn_info *conn)
  155 {
  156     struct lo_data *lo = (struct lo_data*) userdata;
  157 
  158     if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
  159         conn->want |= FUSE_CAP_EXPORT_SUPPORT;
  160 
  161     if (lo->writeback &&
  162         conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
  163         if (lo->debug)
  164             fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
  165         conn->want |= FUSE_CAP_WRITEBACK_CACHE;
  166     }
  167     if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
  168         if (lo->debug)
  169             fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
  170         conn->want |= FUSE_CAP_FLOCK_LOCKS;
  171     }
  172 }
  173 
  174 static void lo_destroy(void *userdata)
  175 {
  176     struct lo_data *lo = (struct lo_data*) userdata;
  177 
  178     while (lo->root.next != &lo->root) {
  179         struct lo_inode* next = lo->root.next;
  180         lo->root.next = next->next;
  181         free(next);
  182     }
  183 }
  184 
  185 static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
  186                  struct fuse_file_info *fi)
  187 {
  188     int res;
  189     struct stat buf;
  190     struct lo_data *lo = lo_data(req);
  191 
  192     (void) fi;
  193 
  194     res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
  195     if (res == -1)
  196         return (void) fuse_reply_err(req, errno);
  197 
  198     fuse_reply_attr(req, &buf, lo->timeout);
  199 }
  200 
  201 static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
  202                int valid, struct fuse_file_info *fi)
  203 {
  204     int saverr;
  205     char procname[64];
  206     struct lo_inode *inode = lo_inode(req, ino);
  207     int ifd = inode->fd;
  208     int res;
  209 
  210     if (valid & FUSE_SET_ATTR_MODE) {
  211         if (fi) {
  212             res = fchmod(fi->fh, attr->st_mode);
  213         } else {
  214             sprintf(procname, "/proc/self/fd/%i", ifd);
  215             res = chmod(procname, attr->st_mode);
  216         }
  217         if (res == -1)
  218             goto out_err;
  219     }
  220     if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
  221         uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
  222             attr->st_uid : (uid_t) -1;
  223         gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
  224             attr->st_gid : (gid_t) -1;
  225 
  226         res = fchownat(ifd, "", uid, gid,
  227                    AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
  228         if (res == -1)
  229             goto out_err;
  230     }
  231     if (valid & FUSE_SET_ATTR_SIZE) {
  232         if (fi) {
  233             res = ftruncate(fi->fh, attr->st_size);
  234         } else {
  235             sprintf(procname, "/proc/self/fd/%i", ifd);
  236             res = truncate(procname, attr->st_size);
  237         }
  238         if (res == -1)
  239             goto out_err;
  240     }
  241     if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
  242         struct timespec tv[2];
  243 
  244         tv[0].tv_sec = 0;
  245         tv[1].tv_sec = 0;
  246         tv[0].tv_nsec = UTIME_OMIT;
  247         tv[1].tv_nsec = UTIME_OMIT;
  248 
  249         if (valid & FUSE_SET_ATTR_ATIME_NOW)
  250             tv[0].tv_nsec = UTIME_NOW;
  251         else if (valid & FUSE_SET_ATTR_ATIME)
  252             tv[0] = attr->st_atim;
  253 
  254         if (valid & FUSE_SET_ATTR_MTIME_NOW)
  255             tv[1].tv_nsec = UTIME_NOW;
  256         else if (valid & FUSE_SET_ATTR_MTIME)
  257             tv[1] = attr->st_mtim;
  258 
  259         if (fi)
  260             res = futimens(fi->fh, tv);
  261         else {
  262             sprintf(procname, "/proc/self/fd/%i", ifd);
  263             res = utimensat(AT_FDCWD, procname, tv, 0);
  264         }
  265         if (res == -1)
  266             goto out_err;
  267     }
  268 
  269     return lo_getattr(req, ino, fi);
  270 
  271 out_err:
  272     saverr = errno;
  273     fuse_reply_err(req, saverr);
  274 }
  275 
  276 static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
  277 {
  278     struct lo_inode *p;
  279     struct lo_inode *ret = NULL;
  280 
  281     pthread_mutex_lock(&lo->mutex);
  282     for (p = lo->root.next; p != &lo->root; p = p->next) {
  283         if (p->ino == st->st_ino && p->dev == st->st_dev) {
  284             assert(p->refcount > 0);
  285             ret = p;
  286             ret->refcount++;
  287             break;
  288         }
  289     }
  290     pthread_mutex_unlock(&lo->mutex);
  291     return ret;
  292 }
  293 
  294 static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
  295              struct fuse_entry_param *e)
  296 {
  297     int newfd;
  298     int res;
  299     int saverr;
  300     struct lo_data *lo = lo_data(req);
  301     struct lo_inode *inode;
  302 
  303     memset(e, 0, sizeof(*e));
  304     e->attr_timeout = lo->timeout;
  305     e->entry_timeout = lo->timeout;
  306 
  307     newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
  308     if (newfd == -1)
  309         goto out_err;
  310 
  311     res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
  312     if (res == -1)
  313         goto out_err;
  314 
  315     inode = lo_find(lo_data(req), &e->attr);
  316     if (inode) {
  317         close(newfd);
  318         newfd = -1;
  319     } else {
  320         struct lo_inode *prev, *next;
  321 
  322         saverr = ENOMEM;
  323         inode = calloc(1, sizeof(struct lo_inode));
  324         if (!inode)
  325             goto out_err;
  326 
  327         inode->refcount = 1;
  328         inode->fd = newfd;
  329         inode->ino = e->attr.st_ino;
  330         inode->dev = e->attr.st_dev;
  331 
  332         pthread_mutex_lock(&lo->mutex);
  333         prev = &lo->root;
  334         next = prev->next;
  335         next->prev = inode;
  336         inode->next = next;
  337         inode->prev = prev;
  338         prev->next = inode;
  339         pthread_mutex_unlock(&lo->mutex);
  340     }
  341     e->ino = (uintptr_t) inode;
  342 
  343     if (lo_debug(req))
  344         fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
  345             (unsigned long long) parent, name, (unsigned long long) e->ino);
  346 
  347     return 0;
  348 
  349 out_err:
  350     saverr = errno;
  351     if (newfd != -1)
  352         close(newfd);
  353     return saverr;
  354 }
  355 
  356 static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
  357 {
  358     struct fuse_entry_param e;
  359     int err;
  360 
  361     if (lo_debug(req))
  362         fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
  363             parent, name);
  364 
  365     err = lo_do_lookup(req, parent, name, &e);
  366     if (err)
  367         fuse_reply_err(req, err);
  368     else
  369         fuse_reply_entry(req, &e);
  370 }
  371 
  372 static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
  373                  const char *name, mode_t mode, dev_t rdev,
  374                  const char *link)
  375 {
  376     int res;
  377     int saverr;
  378     struct lo_inode *dir = lo_inode(req, parent);
  379     struct fuse_entry_param e;
  380 
  381     res = mknod_wrapper(dir->fd, name, link, mode, rdev);
  382 
  383     saverr = errno;
  384     if (res == -1)
  385         goto out;
  386 
  387     saverr = lo_do_lookup(req, parent, name, &e);
  388     if (saverr)
  389         goto out;
  390 
  391     if (lo_debug(req))
  392         fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
  393             (unsigned long long) parent, name, (unsigned long long) e.ino);
  394 
  395     fuse_reply_entry(req, &e);
  396     return;
  397 
  398 out:
  399     fuse_reply_err(req, saverr);
  400 }
  401 
  402 static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
  403              const char *name, mode_t mode, dev_t rdev)
  404 {
  405     lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
  406 }
  407 
  408 static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
  409              mode_t mode)
  410 {
  411     lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
  412 }
  413 
  414 static void lo_symlink(fuse_req_t req, const char *link,
  415                fuse_ino_t parent, const char *name)
  416 {
  417     lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
  418 }
  419 
  420 static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
  421             const char *name)
  422 {
  423     int res;
  424     struct lo_data *lo = lo_data(req);
  425     struct lo_inode *inode = lo_inode(req, ino);
  426     struct fuse_entry_param e;
  427     char procname[64];
  428     int saverr;
  429 
  430     memset(&e, 0, sizeof(struct fuse_entry_param));
  431     e.attr_timeout = lo->timeout;
  432     e.entry_timeout = lo->timeout;
  433 
  434     sprintf(procname, "/proc/self/fd/%i", inode->fd);
  435     res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
  436              AT_SYMLINK_FOLLOW);
  437     if (res == -1)
  438         goto out_err;
  439 
  440     res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
  441     if (res == -1)
  442         goto out_err;
  443 
  444     pthread_mutex_lock(&lo->mutex);
  445     inode->refcount++;
  446     pthread_mutex_unlock(&lo->mutex);
  447     e.ino = (uintptr_t) inode;
  448 
  449     if (lo_debug(req))
  450         fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
  451             (unsigned long long) parent, name,
  452             (unsigned long long) e.ino);
  453 
  454     fuse_reply_entry(req, &e);
  455     return;
  456 
  457 out_err:
  458     saverr = errno;
  459     fuse_reply_err(req, saverr);
  460 }
  461 
  462 static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
  463 {
  464     int res;
  465 
  466     res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
  467 
  468     fuse_reply_err(req, res == -1 ? errno : 0);
  469 }
  470 
  471 static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
  472               fuse_ino_t newparent, const char *newname,
  473               unsigned int flags)
  474 {
  475     int res;
  476 
  477     if (flags) {
  478         fuse_reply_err(req, EINVAL);
  479         return;
  480     }
  481 
  482     res = renameat(lo_fd(req, parent), name,
  483             lo_fd(req, newparent), newname);
  484 
  485     fuse_reply_err(req, res == -1 ? errno : 0);
  486 }
  487 
  488 static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
  489 {
  490     int res;
  491 
  492     res = unlinkat(lo_fd(req, parent), name, 0);
  493 
  494     fuse_reply_err(req, res == -1 ? errno : 0);
  495 }
  496 
  497 static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
  498 {
  499     if (!inode)
  500         return;
  501 
  502     pthread_mutex_lock(&lo->mutex);
  503     assert(inode->refcount >= n);
  504     inode->refcount -= n;
  505     if (!inode->refcount) {
  506         struct lo_inode *prev, *next;
  507 
  508         prev = inode->prev;
  509         next = inode->next;
  510         next->prev = prev;
  511         prev->next = next;
  512 
  513         pthread_mutex_unlock(&lo->mutex);
  514         close(inode->fd);
  515         free(inode);
  516 
  517     } else {
  518         pthread_mutex_unlock(&lo->mutex);
  519     }
  520 }
  521 
  522 static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
  523 {
  524     struct lo_data *lo = lo_data(req);
  525     struct lo_inode *inode = lo_inode(req, ino);
  526 
  527     if (lo_debug(req)) {
  528         fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
  529             (unsigned long long) ino,
  530             (unsigned long long) inode->refcount,
  531             (unsigned long long) nlookup);
  532     }
  533 
  534     unref_inode(lo, inode, nlookup);
  535 }
  536 
  537 static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
  538 {
  539     lo_forget_one(req, ino, nlookup);
  540     fuse_reply_none(req);
  541 }
  542 
  543 static void lo_forget_multi(fuse_req_t req, size_t count,
  544                 struct fuse_forget_data *forgets)
  545 {
  546     int i;
  547 
  548     for (i = 0; i < count; i++)
  549         lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
  550     fuse_reply_none(req);
  551 }
  552 
  553 static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
  554 {
  555     char buf[PATH_MAX + 1];
  556     int res;
  557 
  558     res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
  559     if (res == -1)
  560         return (void) fuse_reply_err(req, errno);
  561 
  562     if (res == sizeof(buf))
  563         return (void) fuse_reply_err(req, ENAMETOOLONG);
  564 
  565     buf[res] = '\0';
  566 
  567     fuse_reply_readlink(req, buf);
  568 }
  569 
  570 struct lo_dirp {
  571     DIR *dp;
  572     struct dirent *entry;
  573     off_t offset;
  574 };
  575 
  576 static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
  577 {
  578     return (struct lo_dirp *) (uintptr_t) fi->fh;
  579 }
  580 
  581 static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
  582 {
  583     int error = ENOMEM;
  584     struct lo_data *lo = lo_data(req);
  585     struct lo_dirp *d;
  586     int fd;
  587 
  588     d = calloc(1, sizeof(struct lo_dirp));
  589     if (d == NULL)
  590         goto out_err;
  591 
  592     fd = openat(lo_fd(req, ino), ".", O_RDONLY);
  593     if (fd == -1)
  594         goto out_errno;
  595 
  596     d->dp = fdopendir(fd);
  597     if (d->dp == NULL)
  598         goto out_errno;
  599 
  600     d->offset = 0;
  601     d->entry = NULL;
  602 
  603     fi->fh = (uintptr_t) d;
  604     if (lo->cache == CACHE_ALWAYS)
  605         fi->cache_readdir = 1;
  606     fuse_reply_open(req, fi);
  607     return;
  608 
  609 out_errno:
  610     error = errno;
  611 out_err:
  612     if (d) {
  613         if (fd != -1)
  614             close(fd);
  615         free(d);
  616     }
  617     fuse_reply_err(req, error);
  618 }
  619 
  620 static int is_dot_or_dotdot(const char *name)
  621 {
  622     return name[0] == '.' && (name[1] == '\0' ||
  623                   (name[1] == '.' && name[2] == '\0'));
  624 }
  625 
  626 static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
  627               off_t offset, struct fuse_file_info *fi, int plus)
  628 {
  629     struct lo_dirp *d = lo_dirp(fi);
  630     char *buf;
  631     char *p;
  632     size_t rem = size;
  633     int err;
  634 
  635     (void) ino;
  636 
  637     buf = calloc(1, size);
  638     if (!buf) {
  639         err = ENOMEM;
  640         goto error;
  641     }
  642     p = buf;
  643 
  644     if (offset != d->offset) {
  645         seekdir(d->dp, offset);
  646         d->entry = NULL;
  647         d->offset = offset;
  648     }
  649     while (1) {
  650         size_t entsize;
  651         off_t nextoff;
  652         const char *name;
  653 
  654         if (!d->entry) {
  655             errno = 0;
  656             d->entry = readdir(d->dp);
  657             if (!d->entry) {
  658                 if (errno) {  // Error
  659                     err = errno;
  660                     goto error;
  661                 } else {  // End of stream
  662                     break; 
  663                 }
  664             }
  665         }
  666         nextoff = d->entry->d_off;
  667         name = d->entry->d_name;
  668         fuse_ino_t entry_ino = 0;
  669         if (plus) {
  670             struct fuse_entry_param e;
  671             if (is_dot_or_dotdot(name)) {
  672                 e = (struct fuse_entry_param) {
  673                     .attr.st_ino = d->entry->d_ino,
  674                     .attr.st_mode = d->entry->d_type << 12,
  675                 };
  676             } else {
  677                 err = lo_do_lookup(req, ino, name, &e);
  678                 if (err)
  679                     goto error;
  680                 entry_ino = e.ino;
  681             }
  682 
  683             entsize = fuse_add_direntry_plus(req, p, rem, name,
  684                              &e, nextoff);
  685         } else {
  686             struct stat st = {
  687                 .st_ino = d->entry->d_ino,
  688                 .st_mode = d->entry->d_type << 12,
  689             };
  690             entsize = fuse_add_direntry(req, p, rem, name,
  691                             &st, nextoff);
  692         }
  693         if (entsize > rem) {
  694             if (entry_ino != 0) 
  695                 lo_forget_one(req, entry_ino, 1);
  696             break;
  697         }
  698         
  699         p += entsize;
  700         rem -= entsize;
  701 
  702         d->entry = NULL;
  703         d->offset = nextoff;
  704     }
  705 
  706     err = 0;
  707 error:
  708     // If there's an error, we can only signal it if we haven't stored
  709     // any entries yet - otherwise we'd end up with wrong lookup
  710     // counts for the entries that are already in the buffer. So we
  711     // return what we've collected until that point.
  712     if (err && rem == size)
  713         fuse_reply_err(req, err);
  714     else
  715         fuse_reply_buf(req, buf, size - rem);
  716     free(buf);
  717 }
  718 
  719 static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
  720                off_t offset, struct fuse_file_info *fi)
  721 {
  722     lo_do_readdir(req, ino, size, offset, fi, 0);
  723 }
  724 
  725 static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
  726                off_t offset, struct fuse_file_info *fi)
  727 {
  728     lo_do_readdir(req, ino, size, offset, fi, 1);
  729 }
  730 
  731 static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
  732 {
  733     struct lo_dirp *d = lo_dirp(fi);
  734     (void) ino;
  735     closedir(d->dp);
  736     free(d);
  737     fuse_reply_err(req, 0);
  738 }
  739 
  740 static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
  741               mode_t mode, struct fuse_file_info *fi)
  742 {
  743     int fd;
  744     struct lo_data *lo = lo_data(req);
  745     struct fuse_entry_param e;
  746     int err;
  747 
  748     if (lo_debug(req))
  749         fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
  750             parent, name);
  751 
  752     fd = openat(lo_fd(req, parent), name,
  753             (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
  754     if (fd == -1)
  755         return (void) fuse_reply_err(req, errno);
  756 
  757     fi->fh = fd;
  758     if (lo->cache == CACHE_NEVER)
  759         fi->direct_io = 1;
  760     else if (lo->cache == CACHE_ALWAYS)
  761         fi->keep_cache = 1;
  762 
  763     err = lo_do_lookup(req, parent, name, &e);
  764     if (err)
  765         fuse_reply_err(req, err);
  766     else
  767         fuse_reply_create(req, &e, fi);
  768 }
  769 
  770 static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
  771             struct fuse_file_info *fi)
  772 {
  773     int res;
  774     int fd = dirfd(lo_dirp(fi)->dp);
  775     (void) ino;
  776     if (datasync)
  777         res = fdatasync(fd);
  778     else
  779         res = fsync(fd);
  780     fuse_reply_err(req, res == -1 ? errno : 0);
  781 }
  782 
  783 static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
  784 {
  785     int fd;
  786     char buf[64];
  787     struct lo_data *lo = lo_data(req);
  788 
  789     if (lo_debug(req))
  790         fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
  791             ino, fi->flags);
  792 
  793     /* With writeback cache, kernel may send read requests even
  794        when userspace opened write-only */
  795     if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
  796         fi->flags &= ~O_ACCMODE;
  797         fi->flags |= O_RDWR;
  798     }
  799 
  800     /* With writeback cache, O_APPEND is handled by the kernel.
  801        This breaks atomicity (since the file may change in the
  802        underlying filesystem, so that the kernel's idea of the
  803        end of the file isn't accurate anymore). In this example,
  804        we just accept that. A more rigorous filesystem may want
  805        to return an error here */
  806     if (lo->writeback && (fi->flags & O_APPEND))
  807         fi->flags &= ~O_APPEND;
  808 
  809     sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
  810     fd = open(buf, fi->flags & ~O_NOFOLLOW);
  811     if (fd == -1)
  812         return (void) fuse_reply_err(req, errno);
  813 
  814     fi->fh = fd;
  815     if (lo->cache == CACHE_NEVER)
  816         fi->direct_io = 1;
  817     else if (lo->cache == CACHE_ALWAYS)
  818         fi->keep_cache = 1;
  819     fuse_reply_open(req, fi);
  820 }
  821 
  822 static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
  823 {
  824     (void) ino;
  825 
  826     close(fi->fh);
  827     fuse_reply_err(req, 0);
  828 }
  829 
  830 static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
  831 {
  832     int res;
  833     (void) ino;
  834     res = close(dup(fi->fh));
  835     fuse_reply_err(req, res == -1 ? errno : 0);
  836 }
  837 
  838 static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
  839              struct fuse_file_info *fi)
  840 {
  841     int res;
  842     (void) ino;
  843     if (datasync)
  844         res = fdatasync(fi->fh);
  845     else
  846         res = fsync(fi->fh);
  847     fuse_reply_err(req, res == -1 ? errno : 0);
  848 }
  849 
  850 static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
  851             off_t offset, struct fuse_file_info *fi)
  852 {
  853     struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
  854 
  855     if (lo_debug(req))
  856         fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
  857             "off=%lu)\n", ino, size, (unsigned long) offset);
  858 
  859     buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
  860     buf.buf[0].fd = fi->fh;
  861     buf.buf[0].pos = offset;
  862 
  863     fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
  864 }
  865 
  866 static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
  867              struct fuse_bufvec *in_buf, off_t off,
  868              struct fuse_file_info *fi)
  869 {
  870     (void) ino;
  871     ssize_t res;
  872     struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
  873 
  874     out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
  875     out_buf.buf[0].fd = fi->fh;
  876     out_buf.buf[0].pos = off;
  877 
  878     if (lo_debug(req))
  879         fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
  880             ino, out_buf.buf[0].size, (unsigned long) off);
  881 
  882     res = fuse_buf_copy(&out_buf, in_buf, 0);
  883     if(res < 0)
  884         fuse_reply_err(req, -res);
  885     else
  886         fuse_reply_write(req, (size_t) res);
  887 }
  888 
  889 static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
  890 {
  891     int res;
  892     struct statvfs stbuf;
  893 
  894     res = fstatvfs(lo_fd(req, ino), &stbuf);
  895     if (res == -1)
  896         fuse_reply_err(req, errno);
  897     else
  898         fuse_reply_statfs(req, &stbuf);
  899 }
  900 
  901 static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
  902              off_t offset, off_t length, struct fuse_file_info *fi)
  903 {
  904     int err = EOPNOTSUPP;
  905     (void) ino;
  906 
  907 #ifdef HAVE_FALLOCATE
  908     err = fallocate(fi->fh, mode, offset, length);
  909     if (err < 0)
  910         err = errno;
  911 
  912 #elif defined(HAVE_POSIX_FALLOCATE)
  913     if (mode) {
  914         fuse_reply_err(req, EOPNOTSUPP);
  915         return;
  916     }
  917 
  918     err = posix_fallocate(fi->fh, offset, length);
  919 #endif
  920 
  921     fuse_reply_err(req, err);
  922 }
  923 
  924 static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
  925              int op)
  926 {
  927     int res;
  928     (void) ino;
  929 
  930     res = flock(fi->fh, op);
  931 
  932     fuse_reply_err(req, res == -1 ? errno : 0);
  933 }
  934 
  935 static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
  936             size_t size)
  937 {
  938     char *value = NULL;
  939     char procname[64];
  940     struct lo_inode *inode = lo_inode(req, ino);
  941     ssize_t ret;
  942     int saverr;
  943 
  944     saverr = ENOSYS;
  945     if (!lo_data(req)->xattr)
  946         goto out;
  947 
  948     if (lo_debug(req)) {
  949         fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
  950             ino, name, size);
  951     }
  952 
  953     sprintf(procname, "/proc/self/fd/%i", inode->fd);
  954 
  955     if (size) {
  956         value = malloc(size);
  957         if (!value)
  958             goto out_err;
  959 
  960         ret = getxattr(procname, name, value, size);
  961         if (ret == -1)
  962             goto out_err;
  963         saverr = 0;
  964         if (ret == 0)
  965             goto out;
  966 
  967         fuse_reply_buf(req, value, ret);
  968     } else {
  969         ret = getxattr(procname, name, NULL, 0);
  970         if (ret == -1)
  971             goto out_err;
  972 
  973         fuse_reply_xattr(req, ret);
  974     }
  975 out_free:
  976     free(value);
  977     return;
  978 
  979 out_err:
  980     saverr = errno;
  981 out:
  982     fuse_reply_err(req, saverr);
  983     goto out_free;
  984 }
  985 
  986 static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
  987 {
  988     char *value = NULL;
  989     char procname[64];
  990     struct lo_inode *inode = lo_inode(req, ino);
  991     ssize_t ret;
  992     int saverr;
  993 
  994     saverr = ENOSYS;
  995     if (!lo_data(req)->xattr)
  996         goto out;
  997 
  998     if (lo_debug(req)) {
  999         fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
 1000             ino, size);
 1001     }
 1002 
 1003     sprintf(procname, "/proc/self/fd/%i", inode->fd);
 1004 
 1005     if (size) {
 1006         value = malloc(size);
 1007         if (!value)
 1008             goto out_err;
 1009 
 1010         ret = listxattr(procname, value, size);
 1011         if (ret == -1)
 1012             goto out_err;
 1013         saverr = 0;
 1014         if (ret == 0)
 1015             goto out;
 1016 
 1017         fuse_reply_buf(req, value, ret);
 1018     } else {
 1019         ret = listxattr(procname, NULL, 0);
 1020         if (ret == -1)
 1021             goto out_err;
 1022 
 1023         fuse_reply_xattr(req, ret);
 1024     }
 1025 out_free:
 1026     free(value);
 1027     return;
 1028 
 1029 out_err:
 1030     saverr = errno;
 1031 out:
 1032     fuse_reply_err(req, saverr);
 1033     goto out_free;
 1034 }
 1035 
 1036 static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
 1037             const char *value, size_t size, int flags)
 1038 {
 1039     char procname[64];
 1040     struct lo_inode *inode = lo_inode(req, ino);
 1041     ssize_t ret;
 1042     int saverr;
 1043 
 1044     saverr = ENOSYS;
 1045     if (!lo_data(req)->xattr)
 1046         goto out;
 1047 
 1048     if (lo_debug(req)) {
 1049         fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
 1050             ino, name, value, size);
 1051     }
 1052 
 1053     sprintf(procname, "/proc/self/fd/%i", inode->fd);
 1054 
 1055     ret = setxattr(procname, name, value, size, flags);
 1056     saverr = ret == -1 ? errno : 0;
 1057 
 1058 out:
 1059     fuse_reply_err(req, saverr);
 1060 }
 1061 
 1062 static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
 1063 {
 1064     char procname[64];
 1065     struct lo_inode *inode = lo_inode(req, ino);
 1066     ssize_t ret;
 1067     int saverr;
 1068 
 1069     saverr = ENOSYS;
 1070     if (!lo_data(req)->xattr)
 1071         goto out;
 1072 
 1073     if (lo_debug(req)) {
 1074         fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
 1075             ino, name);
 1076     }
 1077 
 1078     sprintf(procname, "/proc/self/fd/%i", inode->fd);
 1079 
 1080     ret = removexattr(procname, name);
 1081     saverr = ret == -1 ? errno : 0;
 1082 
 1083 out:
 1084     fuse_reply_err(req, saverr);
 1085 }
 1086 
 1087 #ifdef HAVE_COPY_FILE_RANGE
 1088 static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
 1089                    struct fuse_file_info *fi_in,
 1090                    fuse_ino_t ino_out, off_t off_out,
 1091                    struct fuse_file_info *fi_out, size_t len,
 1092                    int flags)
 1093 {
 1094     ssize_t res;
 1095 
 1096     if (lo_debug(req))
 1097         fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
 1098                 "off=%lu, ino=%" PRIu64 "/fd=%lu, "
 1099                 "off=%lu, size=%zd, flags=0x%x)\n",
 1100             ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
 1101             len, flags);
 1102 
 1103     res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
 1104                   flags);
 1105     if (res < 0)
 1106         fuse_reply_err(req, errno);
 1107     else
 1108         fuse_reply_write(req, res);
 1109 }
 1110 #endif
 1111 
 1112 static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
 1113              struct fuse_file_info *fi)
 1114 {
 1115     off_t res;
 1116 
 1117     (void)ino;
 1118     res = lseek(fi->fh, off, whence);
 1119     if (res != -1)
 1120         fuse_reply_lseek(req, res);
 1121     else
 1122         fuse_reply_err(req, errno);
 1123 }
 1124 
 1125 static const struct fuse_lowlevel_ops lo_oper = {
 1126     .init       = lo_init,
 1127     .destroy    = lo_destroy,
 1128     .lookup     = lo_lookup,
 1129     .mkdir      = lo_mkdir,
 1130     .mknod      = lo_mknod,
 1131     .symlink    = lo_symlink,
 1132     .link       = lo_link,
 1133     .unlink     = lo_unlink,
 1134     .rmdir      = lo_rmdir,
 1135     .rename     = lo_rename,
 1136     .forget     = lo_forget,
 1137     .forget_multi   = lo_forget_multi,
 1138     .getattr    = lo_getattr,
 1139     .setattr    = lo_setattr,
 1140     .readlink   = lo_readlink,
 1141     .opendir    = lo_opendir,
 1142     .readdir    = lo_readdir,
 1143     .readdirplus    = lo_readdirplus,
 1144     .releasedir = lo_releasedir,
 1145     .fsyncdir   = lo_fsyncdir,
 1146     .create     = lo_create,
 1147     .open       = lo_open,
 1148     .release    = lo_release,
 1149     .flush      = lo_flush,
 1150     .fsync      = lo_fsync,
 1151     .read       = lo_read,
 1152     .write_buf      = lo_write_buf,
 1153     .statfs     = lo_statfs,
 1154     .fallocate  = lo_fallocate,
 1155     .flock      = lo_flock,
 1156     .getxattr   = lo_getxattr,
 1157     .listxattr  = lo_listxattr,
 1158     .setxattr   = lo_setxattr,
 1159     .removexattr    = lo_removexattr,
 1160 #ifdef HAVE_COPY_FILE_RANGE
 1161     .copy_file_range = lo_copy_file_range,
 1162 #endif
 1163     .lseek      = lo_lseek,
 1164 };
 1165 
 1166 int main(int argc, char *argv[])
 1167 {
 1168     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
 1169     struct fuse_session *se;
 1170     struct fuse_cmdline_opts opts;
 1171     struct fuse_loop_config config;
 1172     struct lo_data lo = { .debug = 0,
 1173                           .writeback = 0 };
 1174     int ret = -1;
 1175 
 1176     /* Don't mask creation mode, kernel already did that */
 1177     umask(0);
 1178 
 1179     pthread_mutex_init(&lo.mutex, NULL);
 1180     lo.root.next = lo.root.prev = &lo.root;
 1181     lo.root.fd = -1;
 1182     lo.cache = CACHE_NORMAL;
 1183 
 1184     if (fuse_parse_cmdline(&args, &opts) != 0)
 1185         return 1;
 1186     if (opts.show_help) {
 1187         printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
 1188         fuse_cmdline_help();
 1189         fuse_lowlevel_help();
 1190         ret = 0;
 1191         goto err_out1;
 1192     } else if (opts.show_version) {
 1193         printf("FUSE library version %s\n", fuse_pkgversion());
 1194         fuse_lowlevel_version();
 1195         ret = 0;
 1196         goto err_out1;
 1197     }
 1198 
 1199     if(opts.mountpoint == NULL) {
 1200         printf("usage: %s [options] <mountpoint>\n", argv[0]);
 1201         printf("       %s --help\n", argv[0]);
 1202         ret = 1;
 1203         goto err_out1;
 1204     }
 1205 
 1206     if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
 1207         return 1;
 1208 
 1209     lo.debug = opts.debug;
 1210     lo.root.refcount = 2;
 1211     if (lo.source) {
 1212         struct stat stat;
 1213         int res;
 1214 
 1215         res = lstat(lo.source, &stat);
 1216         if (res == -1) {
 1217             fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
 1218                  lo.source);
 1219             exit(1);
 1220         }
 1221         if (!S_ISDIR(stat.st_mode)) {
 1222             fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
 1223             exit(1);
 1224         }
 1225 
 1226     } else {
 1227         lo.source = "/";
 1228     }
 1229     if (!lo.timeout_set) {
 1230         switch (lo.cache) {
 1231         case CACHE_NEVER:
 1232             lo.timeout = 0.0;
 1233             break;
 1234 
 1235         case CACHE_NORMAL:
 1236             lo.timeout = 1.0;
 1237             break;
 1238 
 1239         case CACHE_ALWAYS:
 1240             lo.timeout = 86400.0;
 1241             break;
 1242         }
 1243     } else if (lo.timeout < 0) {
 1244         fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
 1245              lo.timeout);
 1246         exit(1);
 1247     }
 1248 
 1249     lo.root.fd = open(lo.source, O_PATH);
 1250     if (lo.root.fd == -1) {
 1251         fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
 1252              lo.source);
 1253         exit(1);
 1254     }
 1255 
 1256     se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
 1257     if (se == NULL)
 1258         goto err_out1;
 1259 
 1260     if (fuse_set_signal_handlers(se) != 0)
 1261         goto err_out2;
 1262 
 1263     if (fuse_session_mount(se, opts.mountpoint) != 0)
 1264         goto err_out3;
 1265 
 1266     fuse_daemonize(opts.foreground);
 1267 
 1268     /* Block until ctrl+c or fusermount -u */
 1269     if (opts.singlethread)
 1270         ret = fuse_session_loop(se);
 1271     else {
 1272         config.clone_fd = opts.clone_fd;
 1273         config.max_idle_threads = opts.max_idle_threads;
 1274         ret = fuse_session_loop_mt(se, &config);
 1275     }
 1276 
 1277     fuse_session_unmount(se);
 1278 err_out3:
 1279     fuse_remove_signal_handlers(se);
 1280 err_out2:
 1281     fuse_session_destroy(se);
 1282 err_out1:
 1283     free(opts.mountpoint);
 1284     fuse_opt_free_args(&args);
 1285 
 1286     if (lo.root.fd >= 0)
 1287         close(lo.root.fd);
 1288 
 1289     return ret ? 1 : 0;
 1290 }