aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/virtiofsd/buffer.c434
-rw-r--r--tools/virtiofsd/fuse.h1572
-rw-r--r--tools/virtiofsd/fuse_common.h730
-rw-r--r--tools/virtiofsd/fuse_i.h121
-rw-r--r--tools/virtiofsd/fuse_log.c38
-rw-r--r--tools/virtiofsd/fuse_log.h32
-rw-r--r--tools/virtiofsd/fuse_lowlevel.c3638
-rw-r--r--tools/virtiofsd/fuse_lowlevel.h2392
-rw-r--r--tools/virtiofsd/fuse_misc.h30
-rw-r--r--tools/virtiofsd/fuse_opt.c659
-rw-r--r--tools/virtiofsd/fuse_opt.h79
-rw-r--r--tools/virtiofsd/fuse_signals.c118
-rw-r--r--tools/virtiofsd/helper.c506
-rw-r--r--tools/virtiofsd/passthrough_helpers.h33
-rw-r--r--tools/virtiofsd/passthrough_ll.c2061
15 files changed, 6382 insertions, 6061 deletions
diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
index aefb7dbf15..5df946c82c 100644
--- a/tools/virtiofsd/buffer.c
+++ b/tools/virtiofsd/buffer.c
@@ -1,252 +1,272 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
-
- Functions for dealing with `struct fuse_buf` and `struct
- fuse_bufvec`.
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * Functions for dealing with `struct fuse_buf` and `struct
+ * fuse_bufvec`.
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB
+ */
#define _GNU_SOURCE
#include "config.h"
#include "fuse_i.h"
#include "fuse_lowlevel.h"
+#include <assert.h>
+#include <errno.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <assert.h>
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
{
- size_t i;
- size_t size = 0;
-
- for (i = 0; i < bufv->count; i++) {
- if (bufv->buf[i].size == SIZE_MAX)
- size = SIZE_MAX;
- else
- size += bufv->buf[i].size;
- }
-
- return size;
+ size_t i;
+ size_t size = 0;
+
+ for (i = 0; i < bufv->count; i++) {
+ if (bufv->buf[i].size == SIZE_MAX) {
+ size = SIZE_MAX;
+ } else {
+ size += bufv->buf[i].size;
+ }
+ }
+
+ return size;
}
static size_t min_size(size_t s1, size_t s2)
{
- return s1 < s2 ? s1 : s2;
+ return s1 < s2 ? s1 : s2;
}
static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
- const struct fuse_buf *src, size_t src_off,
- size_t len)
+ const struct fuse_buf *src, size_t src_off,
+ size_t len)
{
- ssize_t res = 0;
- size_t copied = 0;
-
- while (len) {
- if (dst->flags & FUSE_BUF_FD_SEEK) {
- res = pwrite(dst->fd, (char *)src->mem + src_off, len,
- dst->pos + dst_off);
- } else {
- res = write(dst->fd, (char *)src->mem + src_off, len);
- }
- if (res == -1) {
- if (!copied)
- return -errno;
- break;
- }
- if (res == 0)
- break;
-
- copied += res;
- if (!(dst->flags & FUSE_BUF_FD_RETRY))
- break;
-
- src_off += res;
- dst_off += res;
- len -= res;
- }
-
- return copied;
+ ssize_t res = 0;
+ size_t copied = 0;
+
+ while (len) {
+ if (dst->flags & FUSE_BUF_FD_SEEK) {
+ res = pwrite(dst->fd, (char *)src->mem + src_off, len,
+ dst->pos + dst_off);
+ } else {
+ res = write(dst->fd, (char *)src->mem + src_off, len);
+ }
+ if (res == -1) {
+ if (!copied) {
+ return -errno;
+ }
+ break;
+ }
+ if (res == 0) {
+ break;
+ }
+
+ copied += res;
+ if (!(dst->flags & FUSE_BUF_FD_RETRY)) {
+ break;
+ }
+
+ src_off += res;
+ dst_off += res;
+ len -= res;
+ }
+
+ return copied;
}
static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
- const struct fuse_buf *src, size_t src_off,
- size_t len)
+ const struct fuse_buf *src, size_t src_off,
+ size_t len)
{
- ssize_t res = 0;
- size_t copied = 0;
-
- while (len) {
- if (src->flags & FUSE_BUF_FD_SEEK) {
- res = pread(src->fd, (char *)dst->mem + dst_off, len,
- src->pos + src_off);
- } else {
- res = read(src->fd, (char *)dst->mem + dst_off, len);
- }
- if (res == -1) {
- if (!copied)
- return -errno;
- break;
- }
- if (res == 0)
- break;
-
- copied += res;
- if (!(src->flags & FUSE_BUF_FD_RETRY))
- break;
-
- dst_off += res;
- src_off += res;
- len -= res;
- }
-
- return copied;
+ ssize_t res = 0;
+ size_t copied = 0;
+
+ while (len) {
+ if (src->flags & FUSE_BUF_FD_SEEK) {
+ res = pread(src->fd, (char *)dst->mem + dst_off, len,
+ src->pos + src_off);
+ } else {
+ res = read(src->fd, (char *)dst->mem + dst_off, len);
+ }
+ if (res == -1) {
+ if (!copied) {
+ return -errno;
+ }
+ break;
+ }
+ if (res == 0) {
+ break;
+ }
+
+ copied += res;
+ if (!(src->flags & FUSE_BUF_FD_RETRY)) {
+ break;
+ }
+
+ dst_off += res;
+ src_off += res;
+ len -= res;
+ }
+
+ return copied;
}
static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
- const struct fuse_buf *src, size_t src_off,
- size_t len)
+ const struct fuse_buf *src, size_t src_off,
+ size_t len)
{
- char buf[4096];
- struct fuse_buf tmp = {
- .size = sizeof(buf),
- .flags = 0,
- };
- ssize_t res;
- size_t copied = 0;
-
- tmp.mem = buf;
-
- while (len) {
- size_t this_len = min_size(tmp.size, len);
- size_t read_len;
-
- res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
- if (res < 0) {
- if (!copied)
- return res;
- break;
- }
- if (res == 0)
- break;
-
- read_len = res;
- res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
- if (res < 0) {
- if (!copied)
- return res;
- break;
- }
- if (res == 0)
- break;
-
- copied += res;
-
- if (res < this_len)
- break;
-
- dst_off += res;
- src_off += res;
- len -= res;
- }
-
- return copied;
+ char buf[4096];
+ struct fuse_buf tmp = {
+ .size = sizeof(buf),
+ .flags = 0,
+ };
+ ssize_t res;
+ size_t copied = 0;
+
+ tmp.mem = buf;
+
+ while (len) {
+ size_t this_len = min_size(tmp.size, len);
+ size_t read_len;
+
+ res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
+ if (res < 0) {
+ if (!copied) {
+ return res;
+ }
+ break;
+ }
+ if (res == 0) {
+ break;
+ }
+
+ read_len = res;
+ res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
+ if (res < 0) {
+ if (!copied) {
+ return res;
+ }
+ break;
+ }
+ if (res == 0) {
+ break;
+ }
+
+ copied += res;
+
+ if (res < this_len) {
+ break;
+ }
+
+ dst_off += res;
+ src_off += res;
+ len -= res;
+ }
+
+ return copied;
}
static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
- const struct fuse_buf *src, size_t src_off,
- size_t len, enum fuse_buf_copy_flags flags)
+ const struct fuse_buf *src, size_t src_off,
+ size_t len, enum fuse_buf_copy_flags flags)
{
- int src_is_fd = src->flags & FUSE_BUF_IS_FD;
- int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
-
- if (!src_is_fd && !dst_is_fd) {
- char *dstmem = (char *)dst->mem + dst_off;
- char *srcmem = (char *)src->mem + src_off;
-
- if (dstmem != srcmem) {
- if (dstmem + len <= srcmem || srcmem + len <= dstmem)
- memcpy(dstmem, srcmem, len);
- else
- memmove(dstmem, srcmem, len);
- }
-
- return len;
- } else if (!src_is_fd) {
- return fuse_buf_write(dst, dst_off, src, src_off, len);
- } else if (!dst_is_fd) {
- return fuse_buf_read(dst, dst_off, src, src_off, len);
- } else {
- return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
- }
+ int src_is_fd = src->flags & FUSE_BUF_IS_FD;
+ int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
+
+ if (!src_is_fd && !dst_is_fd) {
+ char *dstmem = (char *)dst->mem + dst_off;
+ char *srcmem = (char *)src->mem + src_off;
+
+ if (dstmem != srcmem) {
+ if (dstmem + len <= srcmem || srcmem + len <= dstmem) {
+ memcpy(dstmem, srcmem, len);
+ } else {
+ memmove(dstmem, srcmem, len);
+ }
+ }
+
+ return len;
+ } else if (!src_is_fd) {
+ return fuse_buf_write(dst, dst_off, src, src_off, len);
+ } else if (!dst_is_fd) {
+ return fuse_buf_read(dst, dst_off, src, src_off, len);
+ } else {
+ return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
+ }
}
static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
{
- if (bufv->idx < bufv->count)
- return &bufv->buf[bufv->idx];
- else
- return NULL;
+ if (bufv->idx < bufv->count) {
+ return &bufv->buf[bufv->idx];
+ } else {
+ return NULL;
+ }
}
static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
{
- const struct fuse_buf *buf = fuse_bufvec_current(bufv);
-
- bufv->off += len;
- assert(bufv->off <= buf->size);
- if (bufv->off == buf->size) {
- assert(bufv->idx < bufv->count);
- bufv->idx++;
- if (bufv->idx == bufv->count)
- return 0;
- bufv->off = 0;
- }
- return 1;
+ const struct fuse_buf *buf = fuse_bufvec_current(bufv);
+
+ bufv->off += len;
+ assert(bufv->off <= buf->size);
+ if (bufv->off == buf->size) {
+ assert(bufv->idx < bufv->count);
+ bufv->idx++;
+ if (bufv->idx == bufv->count) {
+ return 0;
+ }
+ bufv->off = 0;
+ }
+ return 1;
}
ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
- enum fuse_buf_copy_flags flags)
+ enum fuse_buf_copy_flags flags)
{
- size_t copied = 0;
-
- if (dstv == srcv)
- return fuse_buf_size(dstv);
-
- for (;;) {
- const struct fuse_buf *src = fuse_bufvec_current(srcv);
- const struct fuse_buf *dst = fuse_bufvec_current(dstv);
- size_t src_len;
- size_t dst_len;
- size_t len;
- ssize_t res;
-
- if (src == NULL || dst == NULL)
- break;
-
- src_len = src->size - srcv->off;
- dst_len = dst->size - dstv->off;
- len = min_size(src_len, dst_len);
-
- res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
- if (res < 0) {
- if (!copied)
- return res;
- break;
- }
- copied += res;
-
- if (!fuse_bufvec_advance(srcv, res) ||
- !fuse_bufvec_advance(dstv, res))
- break;
-
- if (res < len)
- break;
- }
-
- return copied;
+ size_t copied = 0;
+
+ if (dstv == srcv) {
+ return fuse_buf_size(dstv);
+ }
+
+ for (;;) {
+ const struct fuse_buf *src = fuse_bufvec_current(srcv);
+ const struct fuse_buf *dst = fuse_bufvec_current(dstv);
+ size_t src_len;
+ size_t dst_len;
+ size_t len;
+ ssize_t res;
+
+ if (src == NULL || dst == NULL) {
+ break;
+ }
+
+ src_len = src->size - srcv->off;
+ dst_len = dst->size - dstv->off;
+ len = min_size(src_len, dst_len);
+
+ res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
+ if (res < 0) {
+ if (!copied) {
+ return res;
+ }
+ break;
+ }
+ copied += res;
+
+ if (!fuse_bufvec_advance(srcv, res) ||
+ !fuse_bufvec_advance(dstv, res)) {
+ break;
+ }
+
+ if (res < len) {
+ break;
+ }
+ }
+
+ return copied;
}
diff --git a/tools/virtiofsd/fuse.h b/tools/virtiofsd/fuse.h
index 3202fba6bb..7a4c713559 100644
--- a/tools/virtiofsd/fuse.h
+++ b/tools/virtiofsd/fuse.h
@@ -1,15 +1,15 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB.
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB.
+ */
#ifndef FUSE_H_
#define FUSE_H_
-/** @file
+/*
*
* This file defines the library interface of FUSE
*
@@ -19,15 +19,15 @@
#include "fuse_common.h"
#include <fcntl.h>
-#include <time.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
+#include <sys/types.h>
#include <sys/uio.h>
+#include <time.h>
-/* ----------------------------------------------------------- *
- * Basic FUSE API *
- * ----------------------------------------------------------- */
+/*
+ * Basic FUSE API
+ */
/** Handle for a FUSE filesystem */
struct fuse;
@@ -36,38 +36,39 @@ struct fuse;
* Readdir flags, passed to ->readdir()
*/
enum fuse_readdir_flags {
- /**
- * "Plus" mode.
- *
- * The kernel wants to prefill the inode cache during readdir. The
- * filesystem may honour this by filling in the attributes and setting
- * FUSE_FILL_DIR_FLAGS for the filler function. The filesystem may also
- * just ignore this flag completely.
- */
- FUSE_READDIR_PLUS = (1 << 0),
+ /**
+ * "Plus" mode.
+ *
+ * The kernel wants to prefill the inode cache during readdir. The
+ * filesystem may honour this by filling in the attributes and setting
+ * FUSE_FILL_DIR_FLAGS for the filler function. The filesystem may also
+ * just ignore this flag completely.
+ */
+ FUSE_READDIR_PLUS = (1 << 0),
};
enum fuse_fill_dir_flags {
- /**
- * "Plus" mode: all file attributes are valid
- *
- * The attributes are used by the kernel to prefill the inode cache
- * during a readdir.
- *
- * It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set
- * and vice versa.
- */
- FUSE_FILL_DIR_PLUS = (1 << 1),
+ /**
+ * "Plus" mode: all file attributes are valid
+ *
+ * The attributes are used by the kernel to prefill the inode cache
+ * during a readdir.
+ *
+ * It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set
+ * and vice versa.
+ */
+ FUSE_FILL_DIR_PLUS = (1 << 1),
};
-/** Function to add an entry in a readdir() operation
+/**
+ * Function to add an entry in a readdir() operation
*
* The *off* parameter can be any non-zero value that enables the
* filesystem to identify the current point in the directory
* stream. It does not need to be the actual physical position. A
* value of zero is reserved to indicate that seeking in directories
* is not supported.
- *
+ *
* @param buf the buffer passed to the readdir() operation
* @param name the file name of the directory entry
* @param stat file attributes, can be NULL
@@ -75,9 +76,9 @@ enum fuse_fill_dir_flags {
* @param flags fill flags
* @return 1 if buffer is full, zero otherwise
*/
-typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
- const struct stat *stbuf, off_t off,
- enum fuse_fill_dir_flags flags);
+typedef int (*fuse_fill_dir_t)(void *buf, const char *name,
+ const struct stat *stbuf, off_t off,
+ enum fuse_fill_dir_flags flags);
/**
* Configuration of the high-level API
*
@@ -87,186 +88,186 @@ typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
* file system implementation.
*/
struct fuse_config {
- /**
- * If `set_gid` is non-zero, the st_gid attribute of each file
- * is overwritten with the value of `gid`.
- */
- int set_gid;
- unsigned int gid;
-
- /**
- * If `set_uid` is non-zero, the st_uid attribute of each file
- * is overwritten with the value of `uid`.
- */
- int set_uid;
- unsigned int uid;
-
- /**
- * If `set_mode` is non-zero, the any permissions bits set in
- * `umask` are unset in the st_mode attribute of each file.
- */
- int set_mode;
- unsigned int umask;
-
- /**
- * The timeout in seconds for which name lookups will be
- * cached.
- */
- double entry_timeout;
-
- /**
- * The timeout in seconds for which a negative lookup will be
- * cached. This means, that if file did not exist (lookup
- * retuned ENOENT), the lookup will only be redone after the
- * timeout, and the file/directory will be assumed to not
- * exist until then. A value of zero means that negative
- * lookups are not cached.
- */
- double negative_timeout;
-
- /**
- * The timeout in seconds for which file/directory attributes
- * (as returned by e.g. the `getattr` handler) are cached.
- */
- double attr_timeout;
-
- /**
- * Allow requests to be interrupted
- */
- int intr;
-
- /**
- * Specify which signal number to send to the filesystem when
- * a request is interrupted. The default is hardcoded to
- * USR1.
- */
- int intr_signal;
-
- /**
- * Normally, FUSE assigns inodes to paths only for as long as
- * the kernel is aware of them. With this option inodes are
- * instead remembered for at least this many seconds. This
- * will require more memory, but may be necessary when using
- * applications that make use of inode numbers.
- *
- * A number of -1 means that inodes will be remembered for the
- * entire life-time of the file-system process.
- */
- int remember;
-
- /**
- * The default behavior is that if an open file is deleted,
- * the file is renamed to a hidden file (.fuse_hiddenXXX), and
- * only removed when the file is finally released. This
- * relieves the filesystem implementation of having to deal
- * with this problem. This option disables the hiding
- * behavior, and files are removed immediately in an unlink
- * operation (or in a rename operation which overwrites an
- * existing file).
- *
- * It is recommended that you not use the hard_remove
- * option. When hard_remove is set, the following libc
- * functions fail on unlinked files (returning errno of
- * ENOENT): read(2), write(2), fsync(2), close(2), f*xattr(2),
- * ftruncate(2), fstat(2), fchmod(2), fchown(2)
- */
- int hard_remove;
-
- /**
- * Honor the st_ino field in the functions getattr() and
- * fill_dir(). This value is used to fill in the st_ino field
- * in the stat(2), lstat(2), fstat(2) functions and the d_ino
- * field in the readdir(2) function. The filesystem does not
- * have to guarantee uniqueness, however some applications
- * rely on this value being unique for the whole filesystem.
- *
- * Note that this does *not* affect the inode that libfuse
- * and the kernel use internally (also called the "nodeid").
- */
- int use_ino;
-
- /**
- * If use_ino option is not given, still try to fill in the
- * d_ino field in readdir(2). If the name was previously
- * looked up, and is still in the cache, the inode number
- * found there will be used. Otherwise it will be set to -1.
- * If use_ino option is given, this option is ignored.
- */
- int readdir_ino;
-
- /**
- * This option disables the use of page cache (file content cache)
- * in the kernel for this filesystem. This has several affects:
- *
- * 1. Each read(2) or write(2) system call will initiate one
- * or more read or write operations, data will not be
- * cached in the kernel.
- *
- * 2. The return value of the read() and write() system calls
- * will correspond to the return values of the read and
- * write operations. This is useful for example if the
- * file size is not known in advance (before reading it).
- *
- * Internally, enabling this option causes fuse to set the
- * `direct_io` field of `struct fuse_file_info` - overwriting
- * any value that was put there by the file system.
- */
- int direct_io;
-
- /**
- * This option disables flushing the cache of the file
- * contents on every open(2). This should only be enabled on
- * filesystems where the file data is never changed
- * externally (not through the mounted FUSE filesystem). Thus
- * it is not suitable for network filesystems and other
- * intermediate filesystems.
- *
- * NOTE: if this option is not specified (and neither
- * direct_io) data is still cached after the open(2), so a
- * read(2) system call will not always initiate a read
- * operation.
- *
- * Internally, enabling this option causes fuse to set the
- * `keep_cache` field of `struct fuse_file_info` - overwriting
- * any value that was put there by the file system.
- */
- int kernel_cache;
-
- /**
- * This option is an alternative to `kernel_cache`. Instead of
- * unconditionally keeping cached data, the cached data is
- * invalidated on open(2) if if the modification time or the
- * size of the file has changed since it was last opened.
- */
- int auto_cache;
-
- /**
- * The timeout in seconds for which file attributes are cached
- * for the purpose of checking if auto_cache should flush the
- * file data on open.
- */
- int ac_attr_timeout_set;
- double ac_attr_timeout;
-
- /**
- * If this option is given the file-system handlers for the
- * following operations will not receive path information:
- * read, write, flush, release, fsync, readdir, releasedir,
- * fsyncdir, lock, ioctl and poll.
- *
- * For the truncate, getattr, chmod, chown and utimens
- * operations the path will be provided only if the struct
- * fuse_file_info argument is NULL.
- */
- int nullpath_ok;
-
- /**
- * The remaining options are used by libfuse internally and
- * should not be touched.
- */
- int show_help;
- char *modules;
- int debug;
+ /**
+ * If `set_gid` is non-zero, the st_gid attribute of each file
+ * is overwritten with the value of `gid`.
+ */
+ int set_gid;
+ unsigned int gid;
+
+ /**
+ * If `set_uid` is non-zero, the st_uid attribute of each file
+ * is overwritten with the value of `uid`.
+ */
+ int set_uid;
+ unsigned int uid;
+
+ /**
+ * If `set_mode` is non-zero, the any permissions bits set in
+ * `umask` are unset in the st_mode attribute of each file.
+ */
+ int set_mode;
+ unsigned int umask;
+
+ /**
+ * The timeout in seconds for which name lookups will be
+ * cached.
+ */
+ double entry_timeout;
+
+ /**
+ * The timeout in seconds for which a negative lookup will be
+ * cached. This means, that if file did not exist (lookup
+ * retuned ENOENT), the lookup will only be redone after the
+ * timeout, and the file/directory will be assumed to not
+ * exist until then. A value of zero means that negative
+ * lookups are not cached.
+ */
+ double negative_timeout;
+
+ /**
+ * The timeout in seconds for which file/directory attributes
+ * (as returned by e.g. the `getattr` handler) are cached.
+ */
+ double attr_timeout;
+
+ /**
+ * Allow requests to be interrupted
+ */
+ int intr;
+
+ /**
+ * Specify which signal number to send to the filesystem when
+ * a request is interrupted. The default is hardcoded to
+ * USR1.
+ */
+ int intr_signal;
+
+ /**
+ * Normally, FUSE assigns inodes to paths only for as long as
+ * the kernel is aware of them. With this option inodes are
+ * instead remembered for at least this many seconds. This
+ * will require more memory, but may be necessary when using
+ * applications that make use of inode numbers.
+ *
+ * A number of -1 means that inodes will be remembered for the
+ * entire life-time of the file-system process.
+ */
+ int remember;
+
+ /**
+ * The default behavior is that if an open file is deleted,
+ * the file is renamed to a hidden file (.fuse_hiddenXXX), and
+ * only removed when the file is finally released. This
+ * relieves the filesystem implementation of having to deal
+ * with this problem. This option disables the hiding
+ * behavior, and files are removed immediately in an unlink
+ * operation (or in a rename operation which overwrites an
+ * existing file).
+ *
+ * It is recommended that you not use the hard_remove
+ * option. When hard_remove is set, the following libc
+ * functions fail on unlinked files (returning errno of
+ * ENOENT): read(2), write(2), fsync(2), close(2), f*xattr(2),
+ * ftruncate(2), fstat(2), fchmod(2), fchown(2)
+ */
+ int hard_remove;
+
+ /**
+ * Honor the st_ino field in the functions getattr() and
+ * fill_dir(). This value is used to fill in the st_ino field
+ * in the stat(2), lstat(2), fstat(2) functions and the d_ino
+ * field in the readdir(2) function. The filesystem does not
+ * have to guarantee uniqueness, however some applications
+ * rely on this value being unique for the whole filesystem.
+ *
+ * Note that this does *not* affect the inode that libfuse
+ * and the kernel use internally (also called the "nodeid").
+ */
+ int use_ino;
+
+ /**
+ * If use_ino option is not given, still try to fill in the
+ * d_ino field in readdir(2). If the name was previously
+ * looked up, and is still in the cache, the inode number
+ * found there will be used. Otherwise it will be set to -1.
+ * If use_ino option is given, this option is ignored.
+ */
+ int readdir_ino;
+
+ /**
+ * This option disables the use of page cache (file content cache)
+ * in the kernel for this filesystem. This has several affects:
+ *
+ * 1. Each read(2) or write(2) system call will initiate one
+ * or more read or write operations, data will not be
+ * cached in the kernel.
+ *
+ * 2. The return value of the read() and write() system calls
+ * will correspond to the return values of the read and
+ * write operations. This is useful for example if the
+ * file size is not known in advance (before reading it).
+ *
+ * Internally, enabling this option causes fuse to set the
+ * `direct_io` field of `struct fuse_file_info` - overwriting
+ * any value that was put there by the file system.
+ */
+ int direct_io;
+
+ /**
+ * This option disables flushing the cache of the file
+ * contents on every open(2). This should only be enabled on
+ * filesystems where the file data is never changed
+ * externally (not through the mounted FUSE filesystem). Thus
+ * it is not suitable for network filesystems and other
+ * intermediate filesystems.
+ *
+ * NOTE: if this option is not specified (and neither
+ * direct_io) data is still cached after the open(2), so a
+ * read(2) system call will not always initiate a read
+ * operation.
+ *
+ * Internally, enabling this option causes fuse to set the
+ * `keep_cache` field of `struct fuse_file_info` - overwriting
+ * any value that was put there by the file system.
+ */
+ int kernel_cache;
+
+ /**
+ * This option is an alternative to `kernel_cache`. Instead of
+ * unconditionally keeping cached data, the cached data is
+ * invalidated on open(2) if if the modification time or the
+ * size of the file has changed since it was last opened.
+ */
+ int auto_cache;
+
+ /**
+ * The timeout in seconds for which file attributes are cached
+ * for the purpose of checking if auto_cache should flush the
+ * file data on open.
+ */
+ int ac_attr_timeout_set;
+ double ac_attr_timeout;
+
+ /**
+ * If this option is given the file-system handlers for the
+ * following operations will not receive path information:
+ * read, write, flush, release, fsync, readdir, releasedir,
+ * fsyncdir, lock, ioctl and poll.
+ *
+ * For the truncate, getattr, chmod, chown and utimens
+ * operations the path will be provided only if the struct
+ * fuse_file_info argument is NULL.
+ */
+ int nullpath_ok;
+
+ /**
+ * The remaining options are used by libfuse internally and
+ * should not be touched.
+ */
+ int show_help;
+ char *modules;
+ int debug;
};
@@ -293,515 +294,535 @@ struct fuse_config {
* Almost all operations take a path which can be of any length.
*/
struct fuse_operations {
- /** Get file attributes.
- *
- * Similar to stat(). The 'st_dev' and 'st_blksize' fields are
- * ignored. The 'st_ino' field is ignored except if the 'use_ino'
- * mount option is given. In that case it is passed to userspace,
- * but libfuse and the kernel will still assign a different
- * inode for internal use (called the "nodeid").
- *
- * `fi` will always be NULL if the file is not currently open, but
- * may also be NULL if the file is open.
- */
- int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi);
-
- /** Read the target of a symbolic link
- *
- * The buffer should be filled with a null terminated string. The
- * buffer size argument includes the space for the terminating
- * null character. If the linkname is too long to fit in the
- * buffer, it should be truncated. The return value should be 0
- * for success.
- */
- int (*readlink) (const char *, char *, size_t);
-
- /** Create a file node
- *
- * This is called for creation of all non-directory, non-symlink
- * nodes. If the filesystem defines a create() method, then for
- * regular files that will be called instead.
- */
- int (*mknod) (const char *, mode_t, dev_t);
-
- /** Create a directory
- *
- * Note that the mode argument may not have the type specification
- * bits set, i.e. S_ISDIR(mode) can be false. To obtain the
- * correct directory type bits use mode|S_IFDIR
- * */
- int (*mkdir) (const char *, mode_t);
-
- /** Remove a file */
- int (*unlink) (const char *);
-
- /** Remove a directory */
- int (*rmdir) (const char *);
-
- /** Create a symbolic link */
- int (*symlink) (const char *, const char *);
-
- /** Rename a file
- *
- * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
- * RENAME_NOREPLACE is specified, the filesystem must not
- * overwrite *newname* if it exists and return an error
- * instead. If `RENAME_EXCHANGE` is specified, the filesystem
- * must atomically exchange the two files, i.e. both must
- * exist and neither may be deleted.
- */
- int (*rename) (const char *, const char *, unsigned int flags);
-
- /** Create a hard link to a file */
- int (*link) (const char *, const char *);
-
- /** Change the permission bits of a file
- *
- * `fi` will always be NULL if the file is not currenlty open, but
- * may also be NULL if the file is open.
- */
- int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
-
- /** Change the owner and group of a file
- *
- * `fi` will always be NULL if the file is not currenlty open, but
- * may also be NULL if the file is open.
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits.
- */
- int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi);
-
- /** Change the size of a file
- *
- * `fi` will always be NULL if the file is not currenlty open, but
- * may also be NULL if the file is open.
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits.
- */
- int (*truncate) (const char *, off_t, struct fuse_file_info *fi);
-
- /** Open a file
- *
- * Open flags are available in fi->flags. The following rules
- * apply.
- *
- * - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
- * filtered out / handled by the kernel.
- *
- * - Access modes (O_RDONLY, O_WRONLY, O_RDWR, O_EXEC, O_SEARCH)
- * should be used by the filesystem to check if the operation is
- * permitted. If the ``-o default_permissions`` mount option is
- * given, this check is already done by the kernel before calling
- * open() and may thus be omitted by the filesystem.
- *
- * - When writeback caching is enabled, the kernel may send
- * read requests even for files opened with O_WRONLY. The
- * filesystem should be prepared to handle this.
- *
- * - When writeback caching is disabled, the filesystem is
- * expected to properly handle the O_APPEND flag and ensure
- * that each write is appending to the end of the file.
- *
- * - When writeback caching is enabled, the kernel will
- * handle O_APPEND. However, unless all changes to the file
- * come through the kernel this will not work reliably. The
- * filesystem should thus either ignore the O_APPEND flag
- * (and let the kernel handle it), or return an error
- * (indicating that reliably O_APPEND is not available).
- *
- * Filesystem may store an arbitrary file handle (pointer,
- * index, etc) in fi->fh, and use this in other all other file
- * operations (read, write, flush, release, fsync).
- *
- * Filesystem may also implement stateless file I/O and not store
- * anything in fi->fh.
- *
- * There are also some flags (direct_io, keep_cache) which the
- * filesystem may set in fi, to change the way the file is opened.
- * See fuse_file_info structure in <fuse_common.h> for more details.
- *
- * If this request is answered with an error code of ENOSYS
- * and FUSE_CAP_NO_OPEN_SUPPORT is set in
- * `fuse_conn_info.capable`, this is treated as success and
- * future calls to open will also succeed without being send
- * to the filesystem process.
- *
- */
- int (*open) (const char *, struct fuse_file_info *);
-
- /** Read data from an open file
- *
- * Read should return exactly the number of bytes requested except
- * on EOF or error, otherwise the rest of the data will be
- * substituted with zeroes. An exception to this is when the
- * 'direct_io' mount option is specified, in which case the return
- * value of the read system call will reflect the return value of
- * this operation.
- */
- int (*read) (const char *, char *, size_t, off_t,
- struct fuse_file_info *);
-
- /** Write data to an open file
- *
- * Write should return exactly the number of bytes requested
- * except on error. An exception to this is when the 'direct_io'
- * mount option is specified (see read operation).
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits.
- */
- int (*write) (const char *, const char *, size_t, off_t,
- struct fuse_file_info *);
-
- /** Get file system statistics
- *
- * The 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
- */
- int (*statfs) (const char *, struct statvfs *);
-
- /** Possibly flush cached data
- *
- * BIG NOTE: This is not equivalent to fsync(). It's not a
- * request to sync dirty data.
- *
- * Flush is called on each close() of a file descriptor, as opposed to
- * release which is called on the close of the last file descriptor for
- * a file. Under Linux, errors returned by flush() will be passed to
- * userspace as errors from close(), so flush() is a good place to write
- * back any cached dirty data. However, many applications ignore errors
- * on close(), and on non-Linux systems, close() may succeed even if flush()
- * returns an error. For these reasons, filesystems should not assume
- * that errors returned by flush will ever be noticed or even
- * delivered.
- *
- * NOTE: The flush() method may be called more than once for each
- * open(). This happens if more than one file descriptor refers to an
- * open file handle, e.g. due to dup(), dup2() or fork() calls. It is
- * not possible to determine if a flush is final, so each flush should
- * be treated equally. Multiple write-flush sequences are relatively
- * rare, so this shouldn't be a problem.
- *
- * Filesystems shouldn't assume that flush will be called at any
- * particular point. It may be called more times than expected, or not
- * at all.
- *
- * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
- */
- int (*flush) (const char *, struct fuse_file_info *);
-
- /** Release an open file
- *
- * Release is called when there are no more references to an open
- * file: all file descriptors are closed and all memory mappings
- * are unmapped.
- *
- * For every open() call there will be exactly one release() call
- * with the same flags and file handle. It is possible to
- * have a file opened more than once, in which case only the last
- * release will mean, that no more reads/writes will happen on the
- * file. The return value of release is ignored.
- */
- int (*release) (const char *, struct fuse_file_info *);
-
- /** Synchronize file contents
- *
- * If the datasync parameter is non-zero, then only the user data
- * should be flushed, not the meta data.
- */
- int (*fsync) (const char *, int, struct fuse_file_info *);
-
- /** Set extended attributes */
- int (*setxattr) (const char *, const char *, const char *, size_t, int);
-
- /** Get extended attributes */
- int (*getxattr) (const char *, const char *, char *, size_t);
-
- /** List extended attributes */
- int (*listxattr) (const char *, char *, size_t);
-
- /** Remove extended attributes */
- int (*removexattr) (const char *, const char *);
-
- /** Open directory
- *
- * Unless the 'default_permissions' mount option is given,
- * this method should check if opendir is permitted for this
- * directory. Optionally opendir may also return an arbitrary
- * filehandle in the fuse_file_info structure, which will be
- * passed to readdir, releasedir and fsyncdir.
- */
- int (*opendir) (const char *, struct fuse_file_info *);
-
- /** Read directory
- *
- * The filesystem may choose between two modes of operation:
- *
- * 1) The readdir implementation ignores the offset parameter, and
- * passes zero to the filler function's offset. The filler
- * function will not return '1' (unless an error happens), so the
- * whole directory is read in a single readdir operation.
- *
- * 2) The readdir implementation keeps track of the offsets of the
- * directory entries. It uses the offset parameter and always
- * passes non-zero offset to the filler function. When the buffer
- * is full (or an error happens) the filler function will return
- * '1'.
- */
- int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
- struct fuse_file_info *, enum fuse_readdir_flags);
-
- /** Release directory
- */
- int (*releasedir) (const char *, struct fuse_file_info *);
-
- /** Synchronize directory contents
- *
- * If the datasync parameter is non-zero, then only the user data
- * should be flushed, not the meta data
- */
- int (*fsyncdir) (const char *, int, struct fuse_file_info *);
-
- /**
- * Initialize filesystem
- *
- * The return value will passed in the `private_data` field of
- * `struct fuse_context` to all file operations, and as a
- * parameter to the destroy() method. It overrides the initial
- * value provided to fuse_main() / fuse_new().
- */
- void *(*init) (struct fuse_conn_info *conn,
- struct fuse_config *cfg);
-
- /**
- * Clean up filesystem
- *
- * Called on filesystem exit.
- */
- void (*destroy) (void *private_data);
-
- /**
- * Check file access permissions
- *
- * This will be called for the access() system call. If the
- * 'default_permissions' mount option is given, this method is not
- * called.
- *
- * This method is not called under Linux kernel versions 2.4.x
- */
- int (*access) (const char *, int);
-
- /**
- * Create and open a file
- *
- * If the file does not exist, first create it with the specified
- * mode, and then open it.
- *
- * If this method is not implemented or under Linux kernel
- * versions earlier than 2.6.15, the mknod() and open() methods
- * will be called instead.
- */
- int (*create) (const char *, mode_t, struct fuse_file_info *);
-
- /**
- * Perform POSIX file locking operation
- *
- * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
- *
- * For the meaning of fields in 'struct flock' see the man page
- * for fcntl(2). The l_whence field will always be set to
- * SEEK_SET.
- *
- * For checking lock ownership, the 'fuse_file_info->owner'
- * argument must be used.
- *
- * For F_GETLK operation, the library will first check currently
- * held locks, and if a conflicting lock is found it will return
- * information without calling this method. This ensures, that
- * for local locks the l_pid field is correctly filled in. The
- * results may not be accurate in case of race conditions and in
- * the presence of hard links, but it's unlikely that an
- * application would rely on accurate GETLK results in these
- * cases. If a conflicting lock is not found, this method will be
- * called, and the filesystem may fill out l_pid by a meaningful
- * value, or it may leave this field zero.
- *
- * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
- * of the process performing the locking operation.
- *
- * Note: if this method is not implemented, the kernel will still
- * allow file locking to work locally. Hence it is only
- * interesting for network filesystems and similar.
- */
- int (*lock) (const char *, struct fuse_file_info *, int cmd,
- struct flock *);
-
- /**
- * Change the access and modification times of a file with
- * nanosecond resolution
- *
- * This supersedes the old utime() interface. New applications
- * should use this.
- *
- * `fi` will always be NULL if the file is not currenlty open, but
- * may also be NULL if the file is open.
- *
- * See the utimensat(2) man page for details.
- */
- int (*utimens) (const char *, const struct timespec tv[2],
- struct fuse_file_info *fi);
-
- /**
- * Map block index within file to block index within device
- *
- * Note: This makes sense only for block device backed filesystems
- * mounted with the 'blkdev' option
- */
- int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
-
- /**
- * Ioctl
- *
- * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
- * 64bit environment. The size and direction of data is
- * determined by _IOC_*() decoding of cmd. For _IOC_NONE,
- * data will be NULL, for _IOC_WRITE data is out area, for
- * _IOC_READ in area and if both are set in/out area. In all
- * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
- *
- * If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a
- * directory file handle.
- *
- * Note : the unsigned long request submitted by the application
- * is truncated to 32 bits.
- */
- int (*ioctl) (const char *, unsigned int cmd, void *arg,
- struct fuse_file_info *, unsigned int flags, void *data);
-
- /**
- * Poll for IO readiness events
- *
- * Note: If ph is non-NULL, the client should notify
- * when IO readiness events occur by calling
- * fuse_notify_poll() with the specified ph.
- *
- * Regardless of the number of times poll with a non-NULL ph
- * is received, single notification is enough to clear all.
- * Notifying more times incurs overhead but doesn't harm
- * correctness.
- *
- * The callee is responsible for destroying ph with
- * fuse_pollhandle_destroy() when no longer in use.
- */
- int (*poll) (const char *, struct fuse_file_info *,
- struct fuse_pollhandle *ph, unsigned *reventsp);
-
- /** Write contents of buffer to an open file
- *
- * Similar to the write() method, but data is supplied in a
- * generic buffer. Use fuse_buf_copy() to transfer data to
- * the destination.
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits.
- */
- int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
- struct fuse_file_info *);
-
- /** Store data from an open file in a buffer
- *
- * Similar to the read() method, but data is stored and
- * returned in a generic buffer.
- *
- * No actual copying of data has to take place, the source
- * file descriptor may simply be stored in the buffer for
- * later data transfer.
- *
- * The buffer must be allocated dynamically and stored at the
- * location pointed to by bufp. If the buffer contains memory
- * regions, they too must be allocated using malloc(). The
- * allocated memory will be freed by the caller.
- */
- int (*read_buf) (const char *, struct fuse_bufvec **bufp,
- size_t size, off_t off, struct fuse_file_info *);
- /**
- * Perform BSD file locking operation
- *
- * The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN
- *
- * Nonblocking requests will be indicated by ORing LOCK_NB to
- * the above operations
- *
- * For more information see the flock(2) manual page.
- *
- * Additionally fi->owner will be set to a value unique to
- * this open file. This same value will be supplied to
- * ->release() when the file is released.
- *
- * Note: if this method is not implemented, the kernel will still
- * allow file locking to work locally. Hence it is only
- * interesting for network filesystems and similar.
- */
- int (*flock) (const char *, struct fuse_file_info *, int op);
-
- /**
- * Allocates space for an open file
- *
- * This function ensures that required space is allocated for specified
- * file. If this function returns success then any subsequent write
- * request to specified range is guaranteed not to fail because of lack
- * of space on the file system media.
- */
- int (*fallocate) (const char *, int, off_t, off_t,
- struct fuse_file_info *);
-
- /**
- * Copy a range of data from one file to another
- *
- * Performs an optimized copy between two file descriptors without the
- * additional cost of transferring data through the FUSE kernel module
- * to user space (glibc) and then back into the FUSE filesystem again.
- *
- * In case this method is not implemented, glibc falls back to reading
- * data from the source and writing to the destination. Effectively
- * doing an inefficient copy of the data.
- */
- ssize_t (*copy_file_range) (const char *path_in,
- struct fuse_file_info *fi_in,
- off_t offset_in, const char *path_out,
- struct fuse_file_info *fi_out,
- off_t offset_out, size_t size, int flags);
-
- /**
- * Find next data or hole after the specified offset
- */
- off_t (*lseek) (const char *, off_t off, int whence, struct fuse_file_info *);
+ /**
+ * Get file attributes.
+ *
+ * Similar to stat(). The 'st_dev' and 'st_blksize' fields are
+ * ignored. The 'st_ino' field is ignored except if the 'use_ino'
+ * mount option is given. In that case it is passed to userspace,
+ * but libfuse and the kernel will still assign a different
+ * inode for internal use (called the "nodeid").
+ *
+ * `fi` will always be NULL if the file is not currently open, but
+ * may also be NULL if the file is open.
+ */
+ int (*getattr)(const char *, struct stat *, struct fuse_file_info *fi);
+
+ /**
+ * Read the target of a symbolic link
+ *
+ * The buffer should be filled with a null terminated string. The
+ * buffer size argument includes the space for the terminating
+ * null character. If the linkname is too long to fit in the
+ * buffer, it should be truncated. The return value should be 0
+ * for success.
+ */
+ int (*readlink)(const char *, char *, size_t);
+
+ /**
+ * Create a file node
+ *
+ * This is called for creation of all non-directory, non-symlink
+ * nodes. If the filesystem defines a create() method, then for
+ * regular files that will be called instead.
+ */
+ int (*mknod)(const char *, mode_t, dev_t);
+
+ /**
+ * Create a directory
+ *
+ * Note that the mode argument may not have the type specification
+ * bits set, i.e. S_ISDIR(mode) can be false. To obtain the
+ * correct directory type bits use mode|S_IFDIR
+ */
+ int (*mkdir)(const char *, mode_t);
+
+ /** Remove a file */
+ int (*unlink)(const char *);
+
+ /** Remove a directory */
+ int (*rmdir)(const char *);
+
+ /** Create a symbolic link */
+ int (*symlink)(const char *, const char *);
+
+ /**
+ * Rename a file
+ *
+ * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
+ * RENAME_NOREPLACE is specified, the filesystem must not
+ * overwrite *newname* if it exists and return an error
+ * instead. If `RENAME_EXCHANGE` is specified, the filesystem
+ * must atomically exchange the two files, i.e. both must
+ * exist and neither may be deleted.
+ */
+ int (*rename)(const char *, const char *, unsigned int flags);
+
+ /** Create a hard link to a file */
+ int (*link)(const char *, const char *);
+
+ /**
+ * Change the permission bits of a file
+ *
+ * `fi` will always be NULL if the file is not currenlty open, but
+ * may also be NULL if the file is open.
+ */
+ int (*chmod)(const char *, mode_t, struct fuse_file_info *fi);
+
+ /**
+ * Change the owner and group of a file
+ *
+ * `fi` will always be NULL if the file is not currenlty open, but
+ * may also be NULL if the file is open.
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits.
+ */
+ int (*chown)(const char *, uid_t, gid_t, struct fuse_file_info *fi);
+
+ /**
+ * Change the size of a file
+ *
+ * `fi` will always be NULL if the file is not currenlty open, but
+ * may also be NULL if the file is open.
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits.
+ */
+ int (*truncate)(const char *, off_t, struct fuse_file_info *fi);
+
+ /**
+ * Open a file
+ *
+ * Open flags are available in fi->flags. The following rules
+ * apply.
+ *
+ * - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
+ * filtered out / handled by the kernel.
+ *
+ * - Access modes (O_RDONLY, O_WRONLY, O_RDWR, O_EXEC, O_SEARCH)
+ * should be used by the filesystem to check if the operation is
+ * permitted. If the ``-o default_permissions`` mount option is
+ * given, this check is already done by the kernel before calling
+ * open() and may thus be omitted by the filesystem.
+ *
+ * - When writeback caching is enabled, the kernel may send
+ * read requests even for files opened with O_WRONLY. The
+ * filesystem should be prepared to handle this.
+ *
+ * - When writeback caching is disabled, the filesystem is
+ * expected to properly handle the O_APPEND flag and ensure
+ * that each write is appending to the end of the file.
+ *
+ * - When writeback caching is enabled, the kernel will
+ * handle O_APPEND. However, unless all changes to the file
+ * come through the kernel this will not work reliably. The
+ * filesystem should thus either ignore the O_APPEND flag
+ * (and let the kernel handle it), or return an error
+ * (indicating that reliably O_APPEND is not available).
+ *
+ * Filesystem may store an arbitrary file handle (pointer,
+ * index, etc) in fi->fh, and use this in other all other file
+ * operations (read, write, flush, release, fsync).
+ *
+ * Filesystem may also implement stateless file I/O and not store
+ * anything in fi->fh.
+ *
+ * There are also some flags (direct_io, keep_cache) which the
+ * filesystem may set in fi, to change the way the file is opened.
+ * See fuse_file_info structure in <fuse_common.h> for more details.
+ *
+ * If this request is answered with an error code of ENOSYS
+ * and FUSE_CAP_NO_OPEN_SUPPORT is set in
+ * `fuse_conn_info.capable`, this is treated as success and
+ * future calls to open will also succeed without being send
+ * to the filesystem process.
+ *
+ */
+ int (*open)(const char *, struct fuse_file_info *);
+
+ /**
+ * Read data from an open file
+ *
+ * Read should return exactly the number of bytes requested except
+ * on EOF or error, otherwise the rest of the data will be
+ * substituted with zeroes. An exception to this is when the
+ * 'direct_io' mount option is specified, in which case the return
+ * value of the read system call will reflect the return value of
+ * this operation.
+ */
+ int (*read)(const char *, char *, size_t, off_t, struct fuse_file_info *);
+
+ /**
+ * Write data to an open file
+ *
+ * Write should return exactly the number of bytes requested
+ * except on error. An exception to this is when the 'direct_io'
+ * mount option is specified (see read operation).
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits.
+ */
+ int (*write)(const char *, const char *, size_t, off_t,
+ struct fuse_file_info *);
+
+ /**
+ * Get file system statistics
+ *
+ * The 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
+ */
+ int (*statfs)(const char *, struct statvfs *);
+
+ /**
+ * Possibly flush cached data
+ *
+ * BIG NOTE: This is not equivalent to fsync(). It's not a
+ * request to sync dirty data.
+ *
+ * Flush is called on each close() of a file descriptor, as opposed to
+ * release which is called on the close of the last file descriptor for
+ * a file. Under Linux, errors returned by flush() will be passed to
+ * userspace as errors from close(), so flush() is a good place to write
+ * back any cached dirty data. However, many applications ignore errors
+ * on close(), and on non-Linux systems, close() may succeed even if flush()
+ * returns an error. For these reasons, filesystems should not assume
+ * that errors returned by flush will ever be noticed or even
+ * delivered.
+ *
+ * NOTE: The flush() method may be called more than once for each
+ * open(). This happens if more than one file descriptor refers to an
+ * open file handle, e.g. due to dup(), dup2() or fork() calls. It is
+ * not possible to determine if a flush is final, so each flush should
+ * be treated equally. Multiple write-flush sequences are relatively
+ * rare, so this shouldn't be a problem.
+ *
+ * Filesystems shouldn't assume that flush will be called at any
+ * particular point. It may be called more times than expected, or not
+ * at all.
+ *
+ * [close]:
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
+ */
+ int (*flush)(const char *, struct fuse_file_info *);
+
+ /**
+ * Release an open file
+ *
+ * Release is called when there are no more references to an open
+ * file: all file descriptors are closed and all memory mappings
+ * are unmapped.
+ *
+ * For every open() call there will be exactly one release() call
+ * with the same flags and file handle. It is possible to
+ * have a file opened more than once, in which case only the last
+ * release will mean, that no more reads/writes will happen on the
+ * file. The return value of release is ignored.
+ */
+ int (*release)(const char *, struct fuse_file_info *);
+
+ /*
+ * Synchronize file contents
+ *
+ * If the datasync parameter is non-zero, then only the user data
+ * should be flushed, not the meta data.
+ */
+ int (*fsync)(const char *, int, struct fuse_file_info *);
+
+ /** Set extended attributes */
+ int (*setxattr)(const char *, const char *, const char *, size_t, int);
+
+ /** Get extended attributes */
+ int (*getxattr)(const char *, const char *, char *, size_t);
+
+ /** List extended attributes */
+ int (*listxattr)(const char *, char *, size_t);
+
+ /** Remove extended attributes */
+ int (*removexattr)(const char *, const char *);
+
+ /*
+ * Open directory
+ *
+ * Unless the 'default_permissions' mount option is given,
+ * this method should check if opendir is permitted for this
+ * directory. Optionally opendir may also return an arbitrary
+ * filehandle in the fuse_file_info structure, which will be
+ * passed to readdir, releasedir and fsyncdir.
+ */
+ int (*opendir)(const char *, struct fuse_file_info *);
+
+ /*
+ * Read directory
+ *
+ * The filesystem may choose between two modes of operation:
+ *
+ * 1) The readdir implementation ignores the offset parameter, and
+ * passes zero to the filler function's offset. The filler
+ * function will not return '1' (unless an error happens), so the
+ * whole directory is read in a single readdir operation.
+ *
+ * 2) The readdir implementation keeps track of the offsets of the
+ * directory entries. It uses the offset parameter and always
+ * passes non-zero offset to the filler function. When the buffer
+ * is full (or an error happens) the filler function will return
+ * '1'.
+ */
+ int (*readdir)(const char *, void *, fuse_fill_dir_t, off_t,
+ struct fuse_file_info *, enum fuse_readdir_flags);
+
+ /**
+ * Release directory
+ */
+ int (*releasedir)(const char *, struct fuse_file_info *);
+
+ /**
+ * Synchronize directory contents
+ *
+ * If the datasync parameter is non-zero, then only the user data
+ * should be flushed, not the meta data
+ */
+ int (*fsyncdir)(const char *, int, struct fuse_file_info *);
+
+ /**
+ * Initialize filesystem
+ *
+ * The return value will passed in the `private_data` field of
+ * `struct fuse_context` to all file operations, and as a
+ * parameter to the destroy() method. It overrides the initial
+ * value provided to fuse_main() / fuse_new().
+ */
+ void *(*init)(struct fuse_conn_info *conn, struct fuse_config *cfg);
+
+ /**
+ * Clean up filesystem
+ *
+ * Called on filesystem exit.
+ */
+ void (*destroy)(void *private_data);
+
+ /**
+ * Check file access permissions
+ *
+ * This will be called for the access() system call. If the
+ * 'default_permissions' mount option is given, this method is not
+ * called.
+ *
+ * This method is not called under Linux kernel versions 2.4.x
+ */
+ int (*access)(const char *, int);
+
+ /**
+ * Create and open a file
+ *
+ * If the file does not exist, first create it with the specified
+ * mode, and then open it.
+ *
+ * If this method is not implemented or under Linux kernel
+ * versions earlier than 2.6.15, the mknod() and open() methods
+ * will be called instead.
+ */
+ int (*create)(const char *, mode_t, struct fuse_file_info *);
+
+ /**
+ * Perform POSIX file locking operation
+ *
+ * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
+ *
+ * For the meaning of fields in 'struct flock' see the man page
+ * for fcntl(2). The l_whence field will always be set to
+ * SEEK_SET.
+ *
+ * For checking lock ownership, the 'fuse_file_info->owner'
+ * argument must be used.
+ *
+ * For F_GETLK operation, the library will first check currently
+ * held locks, and if a conflicting lock is found it will return
+ * information without calling this method. This ensures, that
+ * for local locks the l_pid field is correctly filled in. The
+ * results may not be accurate in case of race conditions and in
+ * the presence of hard links, but it's unlikely that an
+ * application would rely on accurate GETLK results in these
+ * cases. If a conflicting lock is not found, this method will be
+ * called, and the filesystem may fill out l_pid by a meaningful
+ * value, or it may leave this field zero.
+ *
+ * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
+ * of the process performing the locking operation.
+ *
+ * Note: if this method is not implemented, the kernel will still
+ * allow file locking to work locally. Hence it is only
+ * interesting for network filesystems and similar.
+ */
+ int (*lock)(const char *, struct fuse_file_info *, int cmd, struct flock *);
+
+ /**
+ * Change the access and modification times of a file with
+ * nanosecond resolution
+ *
+ * This supersedes the old utime() interface. New applications
+ * should use this.
+ *
+ * `fi` will always be NULL if the file is not currenlty open, but
+ * may also be NULL if the file is open.
+ *
+ * See the utimensat(2) man page for details.
+ */
+ int (*utimens)(const char *, const struct timespec tv[2],
+ struct fuse_file_info *fi);
+
+ /**
+ * Map block index within file to block index within device
+ *
+ * Note: This makes sense only for block device backed filesystems
+ * mounted with the 'blkdev' option
+ */
+ int (*bmap)(const char *, size_t blocksize, uint64_t *idx);
+
+ /**
+ * Ioctl
+ *
+ * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
+ * 64bit environment. The size and direction of data is
+ * determined by _IOC_*() decoding of cmd. For _IOC_NONE,
+ * data will be NULL, for _IOC_WRITE data is out area, for
+ * _IOC_READ in area and if both are set in/out area. In all
+ * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
+ *
+ * If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a
+ * directory file handle.
+ *
+ * Note : the unsigned long request submitted by the application
+ * is truncated to 32 bits.
+ */
+ int (*ioctl)(const char *, unsigned int cmd, void *arg,
+ struct fuse_file_info *, unsigned int flags, void *data);
+
+ /**
+ * Poll for IO readiness events
+ *
+ * Note: If ph is non-NULL, the client should notify
+ * when IO readiness events occur by calling
+ * fuse_notify_poll() with the specified ph.
+ *
+ * Regardless of the number of times poll with a non-NULL ph
+ * is received, single notification is enough to clear all.
+ * Notifying more times incurs overhead but doesn't harm
+ * correctness.
+ *
+ * The callee is responsible for destroying ph with
+ * fuse_pollhandle_destroy() when no longer in use.
+ */
+ int (*poll)(const char *, struct fuse_file_info *,
+ struct fuse_pollhandle *ph, unsigned *reventsp);
+
+ /*
+ * Write contents of buffer to an open file
+ *
+ * Similar to the write() method, but data is supplied in a
+ * generic buffer. Use fuse_buf_copy() to transfer data to
+ * the destination.
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits.
+ */
+ int (*write_buf)(const char *, struct fuse_bufvec *buf, off_t off,
+ struct fuse_file_info *);
+
+ /*
+ * Store data from an open file in a buffer
+ *
+ * Similar to the read() method, but data is stored and
+ * returned in a generic buffer.
+ *
+ * No actual copying of data has to take place, the source
+ * file descriptor may simply be stored in the buffer for
+ * later data transfer.
+ *
+ * The buffer must be allocated dynamically and stored at the
+ * location pointed to by bufp. If the buffer contains memory
+ * regions, they too must be allocated using malloc(). The
+ * allocated memory will be freed by the caller.
+ */
+ int (*read_buf)(const char *, struct fuse_bufvec **bufp, size_t size,
+ off_t off, struct fuse_file_info *);
+ /**
+ * Perform BSD file locking operation
+ *
+ * The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN
+ *
+ * Nonblocking requests will be indicated by ORing LOCK_NB to
+ * the above operations
+ *
+ * For more information see the flock(2) manual page.
+ *
+ * Additionally fi->owner will be set to a value unique to
+ * this open file. This same value will be supplied to
+ * ->release() when the file is released.
+ *
+ * Note: if this method is not implemented, the kernel will still
+ * allow file locking to work locally. Hence it is only
+ * interesting for network filesystems and similar.
+ */
+ int (*flock)(const char *, struct fuse_file_info *, int op);
+
+ /**
+ * Allocates space for an open file
+ *
+ * This function ensures that required space is allocated for specified
+ * file. If this function returns success then any subsequent write
+ * request to specified range is guaranteed not to fail because of lack
+ * of space on the file system media.
+ */
+ int (*fallocate)(const char *, int, off_t, off_t, struct fuse_file_info *);
+
+ /**
+ * Copy a range of data from one file to another
+ *
+ * Performs an optimized copy between two file descriptors without the
+ * additional cost of transferring data through the FUSE kernel module
+ * to user space (glibc) and then back into the FUSE filesystem again.
+ *
+ * In case this method is not implemented, glibc falls back to reading
+ * data from the source and writing to the destination. Effectively
+ * doing an inefficient copy of the data.
+ */
+ ssize_t (*copy_file_range)(const char *path_in,
+ struct fuse_file_info *fi_in, off_t offset_in,
+ const char *path_out,
+ struct fuse_file_info *fi_out, off_t offset_out,
+ size_t size, int flags);
+
+ /**
+ * Find next data or hole after the specified offset
+ */
+ off_t (*lseek)(const char *, off_t off, int whence,
+ struct fuse_file_info *);
};
-/** Extra context that may be needed by some filesystems
+/*
+ * Extra context that may be needed by some filesystems
*
* The uid, gid and pid fields are not filled in case of a writepage
* operation.
*/
struct fuse_context {
- /** Pointer to the fuse object */
- struct fuse *fuse;
+ /** Pointer to the fuse object */
+ struct fuse *fuse;
- /** User ID of the calling process */
- uid_t uid;
+ /** User ID of the calling process */
+ uid_t uid;
- /** Group ID of the calling process */
- gid_t gid;
+ /** Group ID of the calling process */
+ gid_t gid;
- /** Process ID of the calling thread */
- pid_t pid;
+ /** Process ID of the calling thread */
+ pid_t pid;
- /** Private filesystem data */
- void *private_data;
+ /** Private filesystem data */
+ void *private_data;
- /** Umask of the calling process */
- mode_t umask;
+ /** Umask of the calling process */
+ mode_t umask;
};
/**
@@ -859,15 +880,15 @@ struct fuse_context {
* Example usage, see hello.c
*/
/*
- int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
- void *private_data);
-*/
-#define fuse_main(argc, argv, op, private_data) \
- fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)
+ * int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
+ * void *private_data);
+ */
+#define fuse_main(argc, argv, op, private_data) \
+ fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)
-/* ----------------------------------------------------------- *
- * More detailed API *
- * ----------------------------------------------------------- */
+/*
+ * More detailed API
+ */
/**
* Print available options (high- and low-level) to stdout. This is
@@ -910,12 +931,13 @@ void fuse_lib_help(struct fuse_args *args);
* @return the created FUSE handle
*/
#if FUSE_USE_VERSION == 30
-struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op,
- size_t op_size, void *private_data);
+struct fuse *fuse_new_30(struct fuse_args *args,
+ const struct fuse_operations *op, size_t op_size,
+ void *private_data);
#define fuse_new(args, op, size, data) fuse_new_30(args, op, size, data)
#else
struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op,
- size_t op_size, void *private_data);
+ size_t op_size, void *private_data);
#endif
/**
@@ -940,7 +962,7 @@ void fuse_unmount(struct fuse *f);
/**
* Destroy the FUSE handle.
*
- * NOTE: This function does not unmount the filesystem. If this is
+ * NOTE: This function does not unmount the filesystem. If this is
* needed, call fuse_unmount() before calling this function.
*
* @param f the FUSE handle
@@ -1030,7 +1052,7 @@ int fuse_invalidate_path(struct fuse *f, const char *path);
* Do not call this directly, use fuse_main()
*/
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
- size_t op_size, void *private_data);
+ size_t op_size, void *private_data);
/**
* Start the cleanup thread when using option "remember".
@@ -1081,89 +1103,87 @@ struct fuse_fs;
*/
int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf,
- struct fuse_file_info *fi);
-int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
- const char *newpath, unsigned int flags);
+ struct fuse_file_info *fi);
+int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, const char *newpath,
+ unsigned int flags);
int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
-int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
- const char *path);
+int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path);
int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
-int fuse_fs_release(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi);
+int fuse_fs_release(struct fuse_fs *fs, const char *path,
+ struct fuse_file_info *fi);
int fuse_fs_open(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
- off_t off, struct fuse_file_info *fi);
+ off_t off, struct fuse_file_info *fi);
int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
- struct fuse_bufvec **bufp, size_t size, off_t off,
- struct fuse_file_info *fi);
+ struct fuse_bufvec **bufp, size_t size, off_t off,
+ struct fuse_file_info *fi);
int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
- size_t size, off_t off, struct fuse_file_info *fi);
+ size_t size, off_t off, struct fuse_file_info *fi);
int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
- struct fuse_bufvec *buf, off_t off,
- struct fuse_file_info *fi);
+ struct fuse_bufvec *buf, off_t off,
+ struct fuse_file_info *fi);
int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_flush(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
- fuse_fill_dir_t filler, off_t off,
- struct fuse_file_info *fi, enum fuse_readdir_flags flags);
+ fuse_fill_dir_t filler, off_t off,
+ struct fuse_file_info *fi, enum fuse_readdir_flags flags);
int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_lock(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi, int cmd, struct flock *lock);
+ struct fuse_file_info *fi, int cmd, struct flock *lock);
int fuse_fs_flock(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi, int op);
+ struct fuse_file_info *fi, int op);
int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
- const struct timespec tv[2], struct fuse_file_info *fi);
+ const struct timespec tv[2], struct fuse_file_info *fi);
int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
- size_t len);
+ size_t len);
int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
- dev_t rdev);
+ dev_t rdev);
int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
- const char *value, size_t size, int flags);
+ const char *value, size_t size, int flags);
int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
- char *value, size_t size);
+ char *value, size_t size);
int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
- size_t size);
-int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
- const char *name);
+ size_t size);
+int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name);
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
- uint64_t *idx);
+ uint64_t *idx);
int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd,
- void *arg, struct fuse_file_info *fi, unsigned int flags,
- void *data);
+ void *arg, struct fuse_file_info *fi, unsigned int flags,
+ void *data);
int fuse_fs_poll(struct fuse_fs *fs, const char *path,
- struct fuse_file_info *fi, struct fuse_pollhandle *ph,
- unsigned *reventsp);
+ struct fuse_file_info *fi, struct fuse_pollhandle *ph,
+ unsigned *reventsp);
int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
- off_t offset, off_t length, struct fuse_file_info *fi);
+ off_t offset, off_t length, struct fuse_file_info *fi);
ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
- struct fuse_file_info *fi_in, off_t off_in,
- const char *path_out,
- struct fuse_file_info *fi_out, off_t off_out,
- size_t len, int flags);
+ struct fuse_file_info *fi_in, off_t off_in,
+ const char *path_out,
+ struct fuse_file_info *fi_out, off_t off_out,
+ size_t len, int flags);
off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence,
- struct fuse_file_info *fi);
+ struct fuse_file_info *fi);
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
- struct fuse_config *cfg);
+ struct fuse_config *cfg);
void fuse_fs_destroy(struct fuse_fs *fs);
int fuse_notify_poll(struct fuse_pollhandle *ph);
@@ -1182,7 +1202,7 @@ int fuse_notify_poll(struct fuse_pollhandle *ph);
* @return a new filesystem object
*/
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
- void *private_data);
+ void *private_data);
/**
* Factory for creating filesystem objects
@@ -1199,7 +1219,7 @@ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
* @return the new filesystem object
*/
typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args,
- struct fuse_fs *fs[]);
+ struct fuse_fs *fs[]);
/**
* Register filesystem module
*
@@ -1211,7 +1231,7 @@ typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args,
* @param factory_ the factory function for this filesystem module
*/
#define FUSE_REGISTER_MODULE(name_, factory_) \
- fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
+ fuse_module_factory_t fuse_module_##name_##_factory = factory_
/** Get session from fuse object */
struct fuse_session *fuse_get_session(struct fuse *f);
diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
index bf8f8cc865..bd9bf861f0 100644
--- a/tools/virtiofsd/fuse_common.h
+++ b/tools/virtiofsd/fuse_common.h
@@ -1,21 +1,23 @@
-/* FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB.
-*/
+/*
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB.
+ */
/** @file */
#if !defined(FUSE_H_) && !defined(FUSE_LOWLEVEL_H_)
-#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
+#error \
+ "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
#endif
#ifndef FUSE_COMMON_H_
#define FUSE_COMMON_H_
-#include "fuse_opt.h"
#include "fuse_log.h"
+#include "fuse_opt.h"
#include <stdint.h>
#include <sys/types.h>
@@ -25,7 +27,7 @@
/** Minor version of FUSE library interface */
#define FUSE_MINOR_VERSION 2
-#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
+#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
/**
@@ -38,67 +40,83 @@
* descriptors can share a single file handle.
*/
struct fuse_file_info {
- /** Open flags. Available in open() and release() */
- int flags;
-
- /** In case of a write operation indicates if this was caused
- by a delayed write from the page cache. If so, then the
- context's pid, uid, and gid fields will not be valid, and
- the *fh* value may not match the *fh* value that would
- have been sent with the corresponding individual write
- requests if write caching had been disabled. */
- unsigned int writepage : 1;
-
- /** Can be filled in by open, to use direct I/O on this file. */
- unsigned int direct_io : 1;
-
- /** Can be filled in by open. It signals the kernel that any
- currently cached file data (ie., data that the filesystem
- provided the last time the file was open) need not be
- invalidated. Has no effect when set in other contexts (in
- particular it does nothing when set by opendir()). */
- unsigned int keep_cache : 1;
-
- /** Indicates a flush operation. Set in flush operation, also
- maybe set in highlevel lock operation and lowlevel release
- operation. */
- unsigned int flush : 1;
-
- /** Can be filled in by open, to indicate that the file is not
- seekable. */
- unsigned int nonseekable : 1;
-
- /* Indicates that flock locks for this file should be
- released. If set, lock_owner shall contain a valid value.
- May only be set in ->release(). */
- unsigned int flock_release : 1;
-
- /** Can be filled in by opendir. It signals the kernel to
- enable caching of entries returned by readdir(). Has no
- effect when set in other contexts (in particular it does
- nothing when set by open()). */
- unsigned int cache_readdir : 1;
-
- /** Padding. Reserved for future use*/
- unsigned int padding : 25;
- unsigned int padding2 : 32;
-
- /** File handle id. May be filled in by filesystem in create,
- * open, and opendir(). Available in most other file operations on the
- * same file handle. */
- uint64_t fh;
-
- /** Lock owner id. Available in locking operations and flush */
- uint64_t lock_owner;
-
- /** Requested poll events. Available in ->poll. Only set on kernels
- which support it. If unsupported, this field is set to zero. */
- uint32_t poll_events;
+ /** Open flags. Available in open() and release() */
+ int flags;
+
+ /*
+ * In case of a write operation indicates if this was caused
+ * by a delayed write from the page cache. If so, then the
+ * context's pid, uid, and gid fields will not be valid, and
+ * the *fh* value may not match the *fh* value that would
+ * have been sent with the corresponding individual write
+ * requests if write caching had been disabled.
+ */
+ unsigned int writepage:1;
+
+ /** Can be filled in by open, to use direct I/O on this file. */
+ unsigned int direct_io:1;
+
+ /*
+ * Can be filled in by open. It signals the kernel that any
+ * currently cached file data (ie., data that the filesystem
+ * provided the last time the file was open) need not be
+ * invalidated. Has no effect when set in other contexts (in
+ * particular it does nothing when set by opendir()).
+ */
+ unsigned int keep_cache:1;
+
+ /*
+ * Indicates a flush operation. Set in flush operation, also
+ * maybe set in highlevel lock operation and lowlevel release
+ * operation.
+ */
+ unsigned int flush:1;
+
+ /*
+ * Can be filled in by open, to indicate that the file is not
+ * seekable.
+ */
+ unsigned int nonseekable:1;
+
+ /*
+ * Indicates that flock locks for this file should be
+ * released. If set, lock_owner shall contain a valid value.
+ * May only be set in ->release().
+ */
+ unsigned int flock_release:1;
+
+ /*
+ * Can be filled in by opendir. It signals the kernel to
+ * enable caching of entries returned by readdir(). Has no
+ * effect when set in other contexts (in particular it does
+ * nothing when set by open()).
+ */
+ unsigned int cache_readdir:1;
+
+ /** Padding. Reserved for future use*/
+ unsigned int padding:25;
+ unsigned int padding2:32;
+
+ /*
+ * File handle id. May be filled in by filesystem in create,
+ * open, and opendir(). Available in most other file operations on the
+ * same file handle.
+ */
+ uint64_t fh;
+
+ /** Lock owner id. Available in locking operations and flush */
+ uint64_t lock_owner;
+
+ /*
+ * Requested poll events. Available in ->poll. Only set on kernels
+ * which support it. If unsupported, this field is set to zero.
+ */
+ uint32_t poll_events;
};
-/**************************************************************************
- * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' *
- **************************************************************************/
+/*
+ * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
+ */
/**
* Indicates that the filesystem supports asynchronous read requests.
@@ -110,7 +128,7 @@ struct fuse_file_info {
*
* This feature is enabled by default when supported by the kernel.
*/
-#define FUSE_CAP_ASYNC_READ (1 << 0)
+#define FUSE_CAP_ASYNC_READ (1 << 0)
/**
* Indicates that the filesystem supports "remote" locking.
@@ -118,7 +136,7 @@ struct fuse_file_info {
* This feature is enabled by default when supported by the kernel,
* and if getlk() and setlk() handlers are implemented.
*/
-#define FUSE_CAP_POSIX_LOCKS (1 << 1)
+#define FUSE_CAP_POSIX_LOCKS (1 << 1)
/**
* Indicates that the filesystem supports the O_TRUNC open flag. If
@@ -127,14 +145,14 @@ struct fuse_file_info {
*
* This feature is enabled by default when supported by the kernel.
*/
-#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
+#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
/**
* Indicates that the filesystem supports lookups of "." and "..".
*
* This feature is disabled by default.
*/
-#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
+#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
/**
* Indicates that the kernel should not apply the umask to the
@@ -142,7 +160,7 @@ struct fuse_file_info {
*
* This feature is disabled by default.
*/
-#define FUSE_CAP_DONT_MASK (1 << 6)
+#define FUSE_CAP_DONT_MASK (1 << 6)
/**
* Indicates that libfuse should try to use splice() when writing to
@@ -150,7 +168,7 @@ struct fuse_file_info {
*
* This feature is disabled by default.
*/
-#define FUSE_CAP_SPLICE_WRITE (1 << 7)
+#define FUSE_CAP_SPLICE_WRITE (1 << 7)
/**
* Indicates that libfuse should try to move pages instead of copying when
@@ -158,7 +176,7 @@ struct fuse_file_info {
*
* This feature is disabled by default.
*/
-#define FUSE_CAP_SPLICE_MOVE (1 << 8)
+#define FUSE_CAP_SPLICE_MOVE (1 << 8)
/**
* Indicates that libfuse should try to use splice() when reading from
@@ -167,7 +185,7 @@ struct fuse_file_info {
* This feature is enabled by default when supported by the kernel and
* if the filesystem implements a write_buf() handler.
*/
-#define FUSE_CAP_SPLICE_READ (1 << 9)
+#define FUSE_CAP_SPLICE_READ (1 << 9)
/**
* If set, the calls to flock(2) will be emulated using POSIX locks and must
@@ -180,14 +198,14 @@ struct fuse_file_info {
* This feature is enabled by default when supported by the kernel and
* if the filesystem implements a flock() handler.
*/
-#define FUSE_CAP_FLOCK_LOCKS (1 << 10)
+#define FUSE_CAP_FLOCK_LOCKS (1 << 10)
/**
* Indicates that the filesystem supports ioctl's on directories.
*
* This feature is enabled by default when supported by the kernel.
*/
-#define FUSE_CAP_IOCTL_DIR (1 << 11)
+#define FUSE_CAP_IOCTL_DIR (1 << 11)
/**
* Traditionally, while a file is open the FUSE kernel module only
@@ -209,7 +227,7 @@ struct fuse_file_info {
*
* This feature is enabled by default when supported by the kernel.
*/
-#define FUSE_CAP_AUTO_INVAL_DATA (1 << 12)
+#define FUSE_CAP_AUTO_INVAL_DATA (1 << 12)
/**
* Indicates that the filesystem supports readdirplus.
@@ -217,7 +235,7 @@ struct fuse_file_info {
* This feature is enabled by default when supported by the kernel and if the
* filesystem implements a readdirplus() handler.
*/
-#define FUSE_CAP_READDIRPLUS (1 << 13)
+#define FUSE_CAP_READDIRPLUS (1 << 13)
/**
* Indicates that the filesystem supports adaptive readdirplus.
@@ -245,7 +263,7 @@ struct fuse_file_info {
* if the filesystem implements both a readdirplus() and a readdir()
* handler.
*/
-#define FUSE_CAP_READDIRPLUS_AUTO (1 << 14)
+#define FUSE_CAP_READDIRPLUS_AUTO (1 << 14)
/**
* Indicates that the filesystem supports asynchronous direct I/O submission.
@@ -256,7 +274,7 @@ struct fuse_file_info {
*
* This feature is enabled by default when supported by the kernel.
*/
-#define FUSE_CAP_ASYNC_DIO (1 << 15)
+#define FUSE_CAP_ASYNC_DIO (1 << 15)
/**
* Indicates that writeback caching should be enabled. This means that
@@ -265,7 +283,7 @@ struct fuse_file_info {
*
* This feature is disabled by default.
*/
-#define FUSE_CAP_WRITEBACK_CACHE (1 << 16)
+#define FUSE_CAP_WRITEBACK_CACHE (1 << 16)
/**
* Indicates support for zero-message opens. If this flag is set in
@@ -278,7 +296,7 @@ struct fuse_file_info {
* Setting (or unsetting) this flag in the `want` field has *no
* effect*.
*/
-#define FUSE_CAP_NO_OPEN_SUPPORT (1 << 17)
+#define FUSE_CAP_NO_OPEN_SUPPORT (1 << 17)
/**
* Indicates support for parallel directory operations. If this flag
@@ -288,7 +306,7 @@ struct fuse_file_info {
*
* This feature is enabled by default when supported by the kernel.
*/
-#define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
+#define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
/**
* Indicates support for POSIX ACLs.
@@ -307,7 +325,7 @@ struct fuse_file_info {
*
* This feature is disabled by default.
*/
-#define FUSE_CAP_POSIX_ACL (1 << 19)
+#define FUSE_CAP_POSIX_ACL (1 << 19)
/**
* Indicates that the filesystem is responsible for unsetting
@@ -316,7 +334,7 @@ struct fuse_file_info {
*
* This feature is enabled by default when supported by the kernel.
*/
-#define FUSE_CAP_HANDLE_KILLPRIV (1 << 20)
+#define FUSE_CAP_HANDLE_KILLPRIV (1 << 20)
/**
* Indicates support for zero-message opendirs. If this flag is set in
@@ -328,7 +346,7 @@ struct fuse_file_info {
*
* Setting (or unsetting) this flag in the `want` field has *no effect*.
*/
-#define FUSE_CAP_NO_OPENDIR_SUPPORT (1 << 24)
+#define FUSE_CAP_NO_OPENDIR_SUPPORT (1 << 24)
/**
* Ioctl flags
@@ -340,12 +358,12 @@ struct fuse_file_info {
*
* FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
*/
-#define FUSE_IOCTL_COMPAT (1 << 0)
-#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
-#define FUSE_IOCTL_RETRY (1 << 2)
-#define FUSE_IOCTL_DIR (1 << 4)
+#define FUSE_IOCTL_COMPAT (1 << 0)
+#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
+#define FUSE_IOCTL_RETRY (1 << 2)
+#define FUSE_IOCTL_DIR (1 << 4)
-#define FUSE_IOCTL_MAX_IOV 256
+#define FUSE_IOCTL_MAX_IOV 256
/**
* Connection information, passed to the ->init() method
@@ -355,114 +373,114 @@ struct fuse_file_info {
* value must usually be smaller than the indicated value.
*/
struct fuse_conn_info {
- /**
- * Major version of the protocol (read-only)
- */
- unsigned proto_major;
-
- /**
- * Minor version of the protocol (read-only)
- */
- unsigned proto_minor;
-
- /**
- * Maximum size of the write buffer
- */
- unsigned max_write;
-
- /**
- * Maximum size of read requests. A value of zero indicates no
- * limit. However, even if the filesystem does not specify a
- * limit, the maximum size of read requests will still be
- * limited by the kernel.
- *
- * NOTE: For the time being, the maximum size of read requests
- * must be set both here *and* passed to fuse_session_new()
- * using the ``-o max_read=<n>`` mount option. At some point
- * in the future, specifying the mount option will no longer
- * be necessary.
- */
- unsigned max_read;
-
- /**
- * Maximum readahead
- */
- unsigned max_readahead;
-
- /**
- * Capability flags that the kernel supports (read-only)
- */
- unsigned capable;
-
- /**
- * Capability flags that the filesystem wants to enable.
- *
- * libfuse attempts to initialize this field with
- * reasonable default values before calling the init() handler.
- */
- unsigned want;
-
- /**
- * Maximum number of pending "background" requests. A
- * background request is any type of request for which the
- * total number is not limited by other means. As of kernel
- * 4.8, only two types of requests fall into this category:
- *
- * 1. Read-ahead requests
- * 2. Asynchronous direct I/O requests
- *
- * Read-ahead requests are generated (if max_readahead is
- * non-zero) by the kernel to preemptively fill its caches
- * when it anticipates that userspace will soon read more
- * data.
- *
- * Asynchronous direct I/O requests are generated if
- * FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large
- * direct I/O request. In this case the kernel will internally
- * split it up into multiple smaller requests and submit them
- * to the filesystem concurrently.
- *
- * Note that the following requests are *not* background
- * requests: writeback requests (limited by the kernel's
- * flusher algorithm), regular (i.e., synchronous and
- * buffered) userspace read/write requests (limited to one per
- * thread), asynchronous read requests (Linux's io_submit(2)
- * call actually blocks, so these are also limited to one per
- * thread).
- */
- unsigned max_background;
-
- /**
- * Kernel congestion threshold parameter. If the number of pending
- * background requests exceeds this number, the FUSE kernel module will
- * mark the filesystem as "congested". This instructs the kernel to
- * expect that queued requests will take some time to complete, and to
- * adjust its algorithms accordingly (e.g. by putting a waiting thread
- * to sleep instead of using a busy-loop).
- */
- unsigned congestion_threshold;
-
- /**
- * When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible
- * for updating mtime and ctime when write requests are received. The
- * updated values are passed to the filesystem with setattr() requests.
- * However, if the filesystem does not support the full resolution of
- * the kernel timestamps (nanoseconds), the mtime and ctime values used
- * by kernel and filesystem will differ (and result in an apparent
- * change of times after a cache flush).
- *
- * To prevent this problem, this variable can be used to inform the
- * kernel about the timestamp granularity supported by the file-system.
- * The value should be power of 10. The default is 1, i.e. full
- * nano-second resolution. Filesystems supporting only second resolution
- * should set this to 1000000000.
- */
- unsigned time_gran;
-
- /**
- * For future use.
- */
- unsigned reserved[22];
+ /**
+ * Major version of the protocol (read-only)
+ */
+ unsigned proto_major;
+
+ /**
+ * Minor version of the protocol (read-only)
+ */
+ unsigned proto_minor;
+
+ /**
+ * Maximum size of the write buffer
+ */
+ unsigned max_write;
+
+ /**
+ * Maximum size of read requests. A value of zero indicates no
+ * limit. However, even if the filesystem does not specify a
+ * limit, the maximum size of read requests will still be
+ * limited by the kernel.
+ *
+ * NOTE: For the time being, the maximum size of read requests
+ * must be set both here *and* passed to fuse_session_new()
+ * using the ``-o max_read=<n>`` mount option. At some point
+ * in the future, specifying the mount option will no longer
+ * be necessary.
+ */
+ unsigned max_read;
+
+ /**
+ * Maximum readahead
+ */
+ unsigned max_readahead;
+
+ /**
+ * Capability flags that the kernel supports (read-only)
+ */
+ unsigned capable;
+
+ /**
+ * Capability flags that the filesystem wants to enable.
+ *
+ * libfuse attempts to initialize this field with
+ * reasonable default values before calling the init() handler.
+ */
+ unsigned want;
+
+ /**
+ * Maximum number of pending "background" requests. A
+ * background request is any type of request for which the
+ * total number is not limited by other means. As of kernel
+ * 4.8, only two types of requests fall into this category:
+ *
+ * 1. Read-ahead requests
+ * 2. Asynchronous direct I/O requests
+ *
+ * Read-ahead requests are generated (if max_readahead is
+ * non-zero) by the kernel to preemptively fill its caches
+ * when it anticipates that userspace will soon read more
+ * data.
+ *
+ * Asynchronous direct I/O requests are generated if
+ * FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large
+ * direct I/O request. In this case the kernel will internally
+ * split it up into multiple smaller requests and submit them
+ * to the filesystem concurrently.
+ *
+ * Note that the following requests are *not* background
+ * requests: writeback requests (limited by the kernel's
+ * flusher algorithm), regular (i.e., synchronous and
+ * buffered) userspace read/write requests (limited to one per
+ * thread), asynchronous read requests (Linux's io_submit(2)
+ * call actually blocks, so these are also limited to one per
+ * thread).
+ */
+ unsigned max_background;
+
+ /**
+ * Kernel congestion threshold parameter. If the number of pending
+ * background requests exceeds this number, the FUSE kernel module will
+ * mark the filesystem as "congested". This instructs the kernel to
+ * expect that queued requests will take some time to complete, and to
+ * adjust its algorithms accordingly (e.g. by putting a waiting thread
+ * to sleep instead of using a busy-loop).
+ */
+ unsigned congestion_threshold;
+
+ /**
+ * When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible
+ * for updating mtime and ctime when write requests are received. The
+ * updated values are passed to the filesystem with setattr() requests.
+ * However, if the filesystem does not support the full resolution of
+ * the kernel timestamps (nanoseconds), the mtime and ctime values used
+ * by kernel and filesystem will differ (and result in an apparent
+ * change of times after a cache flush).
+ *
+ * To prevent this problem, this variable can be used to inform the
+ * kernel about the timestamp granularity supported by the file-system.
+ * The value should be power of 10. The default is 1, i.e. full
+ * nano-second resolution. Filesystems supporting only second resolution
+ * should set this to 1000000000.
+ */
+ unsigned time_gran;
+
+ /**
+ * For future use.
+ */
+ unsigned reserved[22];
};
struct fuse_session;
@@ -489,21 +507,20 @@ struct fuse_conn_info_opts;
* -o async_read sets FUSE_CAP_ASYNC_READ in conn->want
* -o sync_read unsets FUSE_CAP_ASYNC_READ in conn->want
* -o atomic_o_trunc sets FUSE_CAP_ATOMIC_O_TRUNC in conn->want
- * -o no_remote_lock Equivalent to -o no_remote_flock,no_remote_posix_lock
- * -o no_remote_flock Unsets FUSE_CAP_FLOCK_LOCKS in conn->want
- * -o no_remote_posix_lock Unsets FUSE_CAP_POSIX_LOCKS in conn->want
- * -o [no_]splice_write (un-)sets FUSE_CAP_SPLICE_WRITE in conn->want
- * -o [no_]splice_move (un-)sets FUSE_CAP_SPLICE_MOVE in conn->want
- * -o [no_]splice_read (un-)sets FUSE_CAP_SPLICE_READ in conn->want
- * -o [no_]auto_inval_data (un-)sets FUSE_CAP_AUTO_INVAL_DATA in conn->want
- * -o readdirplus=no unsets FUSE_CAP_READDIRPLUS in conn->want
- * -o readdirplus=yes sets FUSE_CAP_READDIRPLUS and unsets
- * FUSE_CAP_READDIRPLUS_AUTO in conn->want
- * -o readdirplus=auto sets FUSE_CAP_READDIRPLUS and
- * FUSE_CAP_READDIRPLUS_AUTO in conn->want
- * -o [no_]async_dio (un-)sets FUSE_CAP_ASYNC_DIO in conn->want
- * -o [no_]writeback_cache (un-)sets FUSE_CAP_WRITEBACK_CACHE in conn->want
- * -o time_gran=N sets conn->time_gran
+ * -o no_remote_lock Equivalent to -o
+ *no_remote_flock,no_remote_posix_lock -o no_remote_flock Unsets
+ *FUSE_CAP_FLOCK_LOCKS in conn->want -o no_remote_posix_lock Unsets
+ *FUSE_CAP_POSIX_LOCKS in conn->want -o [no_]splice_write (un-)sets
+ *FUSE_CAP_SPLICE_WRITE in conn->want -o [no_]splice_move (un-)sets
+ *FUSE_CAP_SPLICE_MOVE in conn->want -o [no_]splice_read (un-)sets
+ *FUSE_CAP_SPLICE_READ in conn->want -o [no_]auto_inval_data (un-)sets
+ *FUSE_CAP_AUTO_INVAL_DATA in conn->want -o readdirplus=no unsets
+ *FUSE_CAP_READDIRPLUS in conn->want -o readdirplus=yes sets
+ *FUSE_CAP_READDIRPLUS and unsets FUSE_CAP_READDIRPLUS_AUTO in conn->want -o
+ *readdirplus=auto sets FUSE_CAP_READDIRPLUS and FUSE_CAP_READDIRPLUS_AUTO
+ *in conn->want -o [no_]async_dio (un-)sets FUSE_CAP_ASYNC_DIO in
+ *conn->want -o [no_]writeback_cache (un-)sets FUSE_CAP_WRITEBACK_CACHE in
+ *conn->want -o time_gran=N sets conn->time_gran
*
* Known options will be removed from *args*, unknown options will be
* passed through unchanged.
@@ -511,7 +528,7 @@ struct fuse_conn_info_opts;
* @param args argument vector (input+output)
* @return parsed options
**/
-struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args);
+struct fuse_conn_info_opts *fuse_parse_conn_info_opts(struct fuse_args *args);
/**
* This function applies the (parsed) parameters in *opts* to the
@@ -521,7 +538,7 @@ struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args);
* option has been explicitly set.
*/
void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
- struct fuse_conn_info *conn);
+ struct fuse_conn_info *conn);
/**
* Go into the background
@@ -552,81 +569,81 @@ const char *fuse_pkgversion(void);
*/
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph);
-/* ----------------------------------------------------------- *
- * Data buffer *
- * ----------------------------------------------------------- */
+/*
+ * Data buffer
+ */
/**
* Buffer flags
*/
enum fuse_buf_flags {
- /**
- * Buffer contains a file descriptor
- *
- * If this flag is set, the .fd field is valid, otherwise the
- * .mem fields is valid.
- */
- FUSE_BUF_IS_FD = (1 << 1),
-
- /**
- * Seek on the file descriptor
- *
- * If this flag is set then the .pos field is valid and is
- * used to seek to the given offset before performing
- * operation on file descriptor.
- */
- FUSE_BUF_FD_SEEK = (1 << 2),
-
- /**
- * Retry operation on file descriptor
- *
- * If this flag is set then retry operation on file descriptor
- * until .size bytes have been copied or an error or EOF is
- * detected.
- */
- FUSE_BUF_FD_RETRY = (1 << 3),
+ /**
+ * Buffer contains a file descriptor
+ *
+ * If this flag is set, the .fd field is valid, otherwise the
+ * .mem fields is valid.
+ */
+ FUSE_BUF_IS_FD = (1 << 1),
+
+ /**
+ * Seek on the file descriptor
+ *
+ * If this flag is set then the .pos field is valid and is
+ * used to seek to the given offset before performing
+ * operation on file descriptor.
+ */
+ FUSE_BUF_FD_SEEK = (1 << 2),
+
+ /**
+ * Retry operation on file descriptor
+ *
+ * If this flag is set then retry operation on file descriptor
+ * until .size bytes have been copied or an error or EOF is
+ * detected.
+ */
+ FUSE_BUF_FD_RETRY = (1 << 3),
};
/**
* Buffer copy flags
*/
enum fuse_buf_copy_flags {
- /**
- * Don't use splice(2)
- *
- * Always fall back to using read and write instead of
- * splice(2) to copy data from one file descriptor to another.
- *
- * If this flag is not set, then only fall back if splice is
- * unavailable.
- */
- FUSE_BUF_NO_SPLICE = (1 << 1),
-
- /**
- * Force splice
- *
- * Always use splice(2) to copy data from one file descriptor
- * to another. If splice is not available, return -EINVAL.
- */
- FUSE_BUF_FORCE_SPLICE = (1 << 2),
-
- /**
- * Try to move data with splice.
- *
- * If splice is used, try to move pages from the source to the
- * destination instead of copying. See documentation of
- * SPLICE_F_MOVE in splice(2) man page.
- */
- FUSE_BUF_SPLICE_MOVE = (1 << 3),
-
- /**
- * Don't block on the pipe when copying data with splice
- *
- * Makes the operations on the pipe non-blocking (if the pipe
- * is full or empty). See SPLICE_F_NONBLOCK in the splice(2)
- * man page.
- */
- FUSE_BUF_SPLICE_NONBLOCK= (1 << 4),
+ /**
+ * Don't use splice(2)
+ *
+ * Always fall back to using read and write instead of
+ * splice(2) to copy data from one file descriptor to another.
+ *
+ * If this flag is not set, then only fall back if splice is
+ * unavailable.
+ */
+ FUSE_BUF_NO_SPLICE = (1 << 1),
+
+ /**
+ * Force splice
+ *
+ * Always use splice(2) to copy data from one file descriptor
+ * to another. If splice is not available, return -EINVAL.
+ */
+ FUSE_BUF_FORCE_SPLICE = (1 << 2),
+
+ /**
+ * Try to move data with splice.
+ *
+ * If splice is used, try to move pages from the source to the
+ * destination instead of copying. See documentation of
+ * SPLICE_F_MOVE in splice(2) man page.
+ */
+ FUSE_BUF_SPLICE_MOVE = (1 << 3),
+
+ /**
+ * Don't block on the pipe when copying data with splice
+ *
+ * Makes the operations on the pipe non-blocking (if the pipe
+ * is full or empty). See SPLICE_F_NONBLOCK in the splice(2)
+ * man page.
+ */
+ FUSE_BUF_SPLICE_NONBLOCK = (1 << 4),
};
/**
@@ -636,36 +653,36 @@ enum fuse_buf_copy_flags {
* be supplied as a memory pointer or as a file descriptor
*/
struct fuse_buf {
- /**
- * Size of data in bytes
- */
- size_t size;
-
- /**
- * Buffer flags
- */
- enum fuse_buf_flags flags;
-
- /**
- * Memory pointer
- *
- * Used unless FUSE_BUF_IS_FD flag is set.
- */
- void *mem;
-
- /**
- * File descriptor
- *
- * Used if FUSE_BUF_IS_FD flag is set.
- */
- int fd;
-
- /**
- * File position
- *
- * Used if FUSE_BUF_FD_SEEK flag is set.
- */
- off_t pos;
+ /**
+ * Size of data in bytes
+ */
+ size_t size;
+
+ /**
+ * Buffer flags
+ */
+ enum fuse_buf_flags flags;
+
+ /**
+ * Memory pointer
+ *
+ * Used unless FUSE_BUF_IS_FD flag is set.
+ */
+ void *mem;
+
+ /**
+ * File descriptor
+ *
+ * Used if FUSE_BUF_IS_FD flag is set.
+ */
+ int fd;
+
+ /**
+ * File position
+ *
+ * Used if FUSE_BUF_FD_SEEK flag is set.
+ */
+ off_t pos;
};
/**
@@ -677,41 +694,39 @@ struct fuse_buf {
* Allocate dynamically to add more than one buffer.
*/
struct fuse_bufvec {
- /**
- * Number of buffers in the array
- */
- size_t count;
-
- /**
- * Index of current buffer within the array
- */
- size_t idx;
-
- /**
- * Current offset within the current buffer
- */
- size_t off;
-
- /**
- * Array of buffers
- */
- struct fuse_buf buf[1];
+ /**
+ * Number of buffers in the array
+ */
+ size_t count;
+
+ /**
+ * Index of current buffer within the array
+ */
+ size_t idx;
+
+ /**
+ * Current offset within the current buffer
+ */
+ size_t off;
+
+ /**
+ * Array of buffers
+ */
+ struct fuse_buf buf[1];
};
/* Initialize bufvec with a single buffer of given size */
-#define FUSE_BUFVEC_INIT(size__) \
- ((struct fuse_bufvec) { \
- /* .count= */ 1, \
- /* .idx = */ 0, \
- /* .off = */ 0, \
- /* .buf = */ { /* [0] = */ { \
- /* .size = */ (size__), \
- /* .flags = */ (enum fuse_buf_flags) 0, \
- /* .mem = */ NULL, \
- /* .fd = */ -1, \
- /* .pos = */ 0, \
- } } \
- } )
+#define FUSE_BUFVEC_INIT(size__) \
+ ((struct fuse_bufvec){ /* .count= */ 1, \
+ /* .idx = */ 0, \
+ /* .off = */ 0, /* .buf = */ \
+ { /* [0] = */ { \
+ /* .size = */ (size__), \
+ /* .flags = */ (enum fuse_buf_flags)0, \
+ /* .mem = */ NULL, \
+ /* .fd = */ -1, \
+ /* .pos = */ 0, \
+ } } })
/**
* Get total size of data in a fuse buffer vector
@@ -730,16 +745,16 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv);
* @return actual number of bytes copied or -errno on error
*/
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
- enum fuse_buf_copy_flags flags);
+ enum fuse_buf_copy_flags flags);
-/* ----------------------------------------------------------- *
- * Signal handling *
- * ----------------------------------------------------------- */
+/*
+ * Signal handling
+ */
/**
* Exit session on HUP, TERM and INT signals and ignore PIPE signal
*
- * Stores session in a global variable. May only be called once per
+ * Stores session in a global variable. May only be called once per
* process until fuse_remove_signal_handlers() is called.
*
* Once either of the POSIX signals arrives, the signal handler calls
@@ -766,12 +781,12 @@ int fuse_set_signal_handlers(struct fuse_session *se);
*/
void fuse_remove_signal_handlers(struct fuse_session *se);
-/* ----------------------------------------------------------- *
- * Compatibility stuff *
- * ----------------------------------------------------------- */
+/*
+ * Compatibility stuff
+ */
#if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30
-# error only API version 30 or greater is supported
+#error only API version 30 or greater is supported
#endif
@@ -781,11 +796,14 @@ void fuse_remove_signal_handlers(struct fuse_session *se);
* On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags!
*/
-#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
+#if defined(__GNUC__) && \
+ (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
+ !defined __cplusplus
_Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit");
#else
-struct _fuse_off_t_must_be_64bit_dummy_struct \
- { unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); };
+struct _fuse_off_t_must_be_64bit_dummy_struct {
+ unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1);
+};
#endif
#endif /* FUSE_COMMON_H_ */
diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
index b39522e3ca..e63cb58388 100644
--- a/tools/virtiofsd/fuse_i.h
+++ b/tools/virtiofsd/fuse_i.h
@@ -1,71 +1,71 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB
+ */
#include "fuse.h"
#include "fuse_lowlevel.h"
struct fuse_req {
- struct fuse_session *se;
- uint64_t unique;
- int ctr;
- pthread_mutex_t lock;
- struct fuse_ctx ctx;
- struct fuse_chan *ch;
- int interrupted;
- unsigned int ioctl_64bit : 1;
- union {
- struct {
- uint64_t unique;
- } i;
- struct {
- fuse_interrupt_func_t func;
- void *data;
- } ni;
- } u;
- struct fuse_req *next;
- struct fuse_req *prev;
+ struct fuse_session *se;
+ uint64_t unique;
+ int ctr;
+ pthread_mutex_t lock;
+ struct fuse_ctx ctx;
+ struct fuse_chan *ch;
+ int interrupted;
+ unsigned int ioctl_64bit:1;
+ union {
+ struct {
+ uint64_t unique;
+ } i;
+ struct {
+ fuse_interrupt_func_t func;
+ void *data;
+ } ni;
+ } u;
+ struct fuse_req *next;
+ struct fuse_req *prev;
};
struct fuse_notify_req {
- uint64_t unique;
- void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
- const void *, const struct fuse_buf *);
- struct fuse_notify_req *next;
- struct fuse_notify_req *prev;
+ uint64_t unique;
+ void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
+ const void *, const struct fuse_buf *);
+ struct fuse_notify_req *next;
+ struct fuse_notify_req *prev;
};
struct fuse_session {
- char *mountpoint;
- volatile int exited;
- int fd;
- int debug;
- int deny_others;
- struct fuse_lowlevel_ops op;
- int got_init;
- struct cuse_data *cuse_data;
- void *userdata;
- uid_t owner;
- struct fuse_conn_info conn;
- struct fuse_req list;
- struct fuse_req interrupts;
- pthread_mutex_t lock;
- int got_destroy;
- int broken_splice_nonblock;
- uint64_t notify_ctr;
- struct fuse_notify_req notify_list;
- size_t bufsize;
- int error;
+ char *mountpoint;
+ volatile int exited;
+ int fd;
+ int debug;
+ int deny_others;
+ struct fuse_lowlevel_ops op;
+ int got_init;
+ struct cuse_data *cuse_data;
+ void *userdata;
+ uid_t owner;
+ struct fuse_conn_info conn;
+ struct fuse_req list;
+ struct fuse_req interrupts;
+ pthread_mutex_t lock;
+ int got_destroy;
+ int broken_splice_nonblock;
+ uint64_t notify_ctr;
+ struct fuse_notify_req notify_list;
+ size_t bufsize;
+ int error;
};
struct fuse_chan {
- pthread_mutex_t lock;
- int ctr;
- int fd;
+ pthread_mutex_t lock;
+ int ctr;
+ int fd;
};
/**
@@ -76,19 +76,20 @@ struct fuse_chan {
*
*/
struct fuse_module {
- char *name;
- fuse_module_factory_t factory;
- struct fuse_module *next;
- struct fusemod_so *so;
- int ctr;
+ char *name;
+ fuse_module_factory_t factory;
+ struct fuse_module *next;
+ struct fusemod_so *so;
+ int ctr;
};
int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
- int count);
+ int count);
void fuse_free_req(fuse_req_t req);
void fuse_session_process_buf_int(struct fuse_session *se,
- const struct fuse_buf *buf, struct fuse_chan *ch);
+ const struct fuse_buf *buf,
+ struct fuse_chan *ch);
#define FUSE_MAX_MAX_PAGES 256
diff --git a/tools/virtiofsd/fuse_log.c b/tools/virtiofsd/fuse_log.c
index 0d268ab014..11345f9ec8 100644
--- a/tools/virtiofsd/fuse_log.c
+++ b/tools/virtiofsd/fuse_log.c
@@ -1,40 +1,40 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2019 Red Hat, Inc.
-
- Logging API.
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Logging API.
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB
+ */
#include "fuse_log.h"
#include <stdarg.h>
#include <stdio.h>
-static void default_log_func(
- __attribute__(( unused )) enum fuse_log_level level,
- const char *fmt, va_list ap)
+static void default_log_func(__attribute__((unused)) enum fuse_log_level level,
+ const char *fmt, va_list ap)
{
- vfprintf(stderr, fmt, ap);
+ vfprintf(stderr, fmt, ap);
}
static fuse_log_func_t log_func = default_log_func;
void fuse_set_log_func(fuse_log_func_t func)
{
- if (!func)
- func = default_log_func;
+ if (!func) {
+ func = default_log_func;
+ }
- log_func = func;
+ log_func = func;
}
void fuse_log(enum fuse_log_level level, const char *fmt, ...)
{
- va_list ap;
+ va_list ap;
- va_start(ap, fmt);
- log_func(level, fmt, ap);
- va_end(ap);
+ va_start(ap, fmt);
+ log_func(level, fmt, ap);
+ va_end(ap);
}
diff --git a/tools/virtiofsd/fuse_log.h b/tools/virtiofsd/fuse_log.h
index 0af700da6b..bf6c11ff11 100644
--- a/tools/virtiofsd/fuse_log.h
+++ b/tools/virtiofsd/fuse_log.h
@@ -1,10 +1,10 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2019 Red Hat, Inc.
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB.
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB.
+ */
#ifndef FUSE_LOG_H_
#define FUSE_LOG_H_
@@ -22,14 +22,14 @@
* These levels correspond to syslog(2) log levels since they are widely used.
*/
enum fuse_log_level {
- FUSE_LOG_EMERG,
- FUSE_LOG_ALERT,
- FUSE_LOG_CRIT,
- FUSE_LOG_ERR,
- FUSE_LOG_WARNING,
- FUSE_LOG_NOTICE,
- FUSE_LOG_INFO,
- FUSE_LOG_DEBUG
+ FUSE_LOG_EMERG,
+ FUSE_LOG_ALERT,
+ FUSE_LOG_CRIT,
+ FUSE_LOG_ERR,
+ FUSE_LOG_WARNING,
+ FUSE_LOG_NOTICE,
+ FUSE_LOG_INFO,
+ FUSE_LOG_DEBUG
};
/**
@@ -45,8 +45,8 @@ enum fuse_log_level {
* @param fmt sprintf-style format string including newline
* @param ap format string arguments
*/
-typedef void (*fuse_log_func_t)(enum fuse_log_level level,
- const char *fmt, va_list ap);
+typedef void (*fuse_log_func_t)(enum fuse_log_level level, const char *fmt,
+ va_list ap);
/**
* Install a custom log handler function.
diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
index e6fa247924..5c9cb52f2a 100644
--- a/tools/virtiofsd/fuse_lowlevel.c
+++ b/tools/virtiofsd/fuse_lowlevel.c
@@ -1,2380 +1,2515 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- Implementation of (most of) the low-level FUSE API. The session loop
- functions are implemented in separate files.
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * Implementation of (most of) the low-level FUSE API. The session loop
+ * functions are implemented in separate files.
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB
+ */
#define _GNU_SOURCE
#include "config.h"
#include "fuse_i.h"
#include "fuse_kernel.h"
-#include "fuse_opt.h"
#include "fuse_misc.h"
+#include "fuse_opt.h"
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
#include <string.h>
-#include <unistd.h>
-#include <limits.h>
-#include <errno.h>
-#include <assert.h>
#include <sys/file.h>
-
+#include <unistd.h>
#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
#define OFFSET_MAX 0x7fffffffffffffffLL
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
+#define container_of(ptr, type, member) \
+ ({ \
+ const typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); \
+ })
struct fuse_pollhandle {
- uint64_t kh;
- struct fuse_session *se;
+ uint64_t kh;
+ struct fuse_session *se;
};
static size_t pagesize;
static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
{
- pagesize = getpagesize();
+ pagesize = getpagesize();
}
static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
{
- attr->ino = stbuf->st_ino;
- attr->mode = stbuf->st_mode;
- attr->nlink = stbuf->st_nlink;
- attr->uid = stbuf->st_uid;
- attr->gid = stbuf->st_gid;
- attr->rdev = stbuf->st_rdev;
- attr->size = stbuf->st_size;
- attr->blksize = stbuf->st_blksize;
- attr->blocks = stbuf->st_blocks;
- attr->atime = stbuf->st_atime;
- attr->mtime = stbuf->st_mtime;
- attr->ctime = stbuf->st_ctime;
- attr->atimensec = ST_ATIM_NSEC(stbuf);
- attr->mtimensec = ST_MTIM_NSEC(stbuf);
- attr->ctimensec = ST_CTIM_NSEC(stbuf);
+ attr->ino = stbuf->st_ino;
+ attr->mode = stbuf->st_mode;
+ attr->nlink = stbuf->st_nlink;
+ attr->uid = stbuf->st_uid;
+ attr->gid = stbuf->st_gid;
+ attr->rdev = stbuf->st_rdev;
+ attr->size = stbuf->st_size;
+ attr->blksize = stbuf->st_blksize;
+ attr->blocks = stbuf->st_blocks;
+ attr->atime = stbuf->st_atime;
+ attr->mtime = stbuf->st_mtime;
+ attr->ctime = stbuf->st_ctime;
+ attr->atimensec = ST_ATIM_NSEC(stbuf);
+ attr->mtimensec = ST_MTIM_NSEC(stbuf);
+ attr->ctimensec = ST_CTIM_NSEC(stbuf);
}
static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
{
- stbuf->st_mode = attr->mode;
- stbuf->st_uid = attr->uid;
- stbuf->st_gid = attr->gid;
- stbuf->st_size = attr->size;
- stbuf->st_atime = attr->atime;
- stbuf->st_mtime = attr->mtime;
- stbuf->st_ctime = attr->ctime;
- ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
- ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
- ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
+ stbuf->st_mode = attr->mode;
+ stbuf->st_uid = attr->uid;
+ stbuf->st_gid = attr->gid;
+ stbuf->st_size = attr->size;
+ stbuf->st_atime = attr->atime;
+ stbuf->st_mtime = attr->mtime;
+ stbuf->st_ctime = attr->ctime;
+ ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
+ ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
+ ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
}
-static size_t iov_length(const struct iovec *iov, size_t count)
+static size_t iov_length(const struct iovec *iov, size_t count)
{
- size_t seg;
- size_t ret = 0;
+ size_t seg;
+ size_t ret = 0;
- for (seg = 0; seg < count; seg++)
- ret += iov[seg].iov_len;
- return ret;
+ for (seg = 0; seg < count; seg++) {
+ ret += iov[seg].iov_len;
+ }
+ return ret;
}
static void list_init_req(struct fuse_req *req)
{
- req->next = req;
- req->prev = req;
+ req->next = req;
+ req->prev = req;
}
static void list_del_req(struct fuse_req *req)
{
- struct fuse_req *prev = req->prev;
- struct fuse_req *next = req->next;
- prev->next = next;
- next->prev = prev;
+ struct fuse_req *prev = req->prev;
+ struct fuse_req *next = req->next;
+ prev->next = next;
+ next->prev = prev;
}
static void list_add_req(struct fuse_req *req, struct fuse_req *next)
{
- struct fuse_req *prev = next->prev;
- req->next = next;
- req->prev = prev;
- prev->next = req;
- next->prev = req;
+ struct fuse_req *prev = next->prev;
+ req->next = next;
+ req->prev = prev;
+ prev->next = req;
+ next->prev = req;
}
static void destroy_req(fuse_req_t req)
{
- pthread_mutex_destroy(&req->lock);
- free(req);
+ pthread_mutex_destroy(&req->lock);
+ free(req);
}
void fuse_free_req(fuse_req_t req)
{
- int ctr;
- struct fuse_session *se = req->se;
+ int ctr;
+ struct fuse_session *se = req->se;
- pthread_mutex_lock(&se->lock);
- req->u.ni.func = NULL;
- req->u.ni.data = NULL;
- list_del_req(req);
- ctr = --req->ctr;
- req->ch = NULL;
- pthread_mutex_unlock(&se->lock);
- if (!ctr)
- destroy_req(req);
+ pthread_mutex_lock(&se->lock);
+ req->u.ni.func = NULL;
+ req->u.ni.data = NULL;
+ list_del_req(req);
+ ctr = --req->ctr;
+ req->ch = NULL;
+ pthread_mutex_unlock(&se->lock);
+ if (!ctr) {
+ destroy_req(req);
+ }
}
static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
{
- struct fuse_req *req;
+ struct fuse_req *req;
- req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
- if (req == NULL) {
- fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
- } else {
- req->se = se;
- req->ctr = 1;
- list_init_req(req);
- fuse_mutex_init(&req->lock);
- }
+ req = (struct fuse_req *)calloc(1, sizeof(struct fuse_req));
+ if (req == NULL) {
+ fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
+ } else {
+ req->se = se;
+ req->ctr = 1;
+ list_init_req(req);
+ fuse_mutex_init(&req->lock);
+ }
- return req;
+ return req;
}
/* Send data. If *ch* is NULL, send via session master fd */
static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
- struct iovec *iov, int count)
+ struct iovec *iov, int count)
{
- struct fuse_out_header *out = iov[0].iov_base;
+ struct fuse_out_header *out = iov[0].iov_base;
- out->len = iov_length(iov, count);
- if (se->debug) {
- if (out->unique == 0) {
- fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
- out->error, out->len);
- } else if (out->error) {
- fuse_log(FUSE_LOG_DEBUG,
- " unique: %llu, error: %i (%s), outsize: %i\n",
- (unsigned long long) out->unique, out->error,
- strerror(-out->error), out->len);
- } else {
- fuse_log(FUSE_LOG_DEBUG,
- " unique: %llu, success, outsize: %i\n",
- (unsigned long long) out->unique, out->len);
- }
- }
+ out->len = iov_length(iov, count);
+ if (se->debug) {
+ if (out->unique == 0) {
+ fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n", out->error,
+ out->len);
+ } else if (out->error) {
+ fuse_log(FUSE_LOG_DEBUG,
+ " unique: %llu, error: %i (%s), outsize: %i\n",
+ (unsigned long long)out->unique, out->error,
+ strerror(-out->error), out->len);
+ } else {
+ fuse_log(FUSE_LOG_DEBUG, " unique: %llu, success, outsize: %i\n",
+ (unsigned long long)out->unique, out->len);
+ }
+ }
- abort(); /* virtio should have taken it before here */
- return 0;
+ abort(); /* virtio should have taken it before here */
+ return 0;
}
int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
- int count)
+ int count)
{
- struct fuse_out_header out;
+ struct fuse_out_header out;
- if (error <= -1000 || error > 0) {
- fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
- error = -ERANGE;
- }
+ if (error <= -1000 || error > 0) {
+ fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
+ error = -ERANGE;
+ }
- out.unique = req->unique;
- out.error = error;
+ out.unique = req->unique;
+ out.error = error;
- iov[0].iov_base = &out;
- iov[0].iov_len = sizeof(struct fuse_out_header);
+ iov[0].iov_base = &out;
+ iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(req->se, req->ch, iov, count);
+ return fuse_send_msg(req->se, req->ch, iov, count);
}
static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
- int count)
+ int count)
{
- int res;
+ int res;
- res = fuse_send_reply_iov_nofree(req, error, iov, count);
- fuse_free_req(req);
- return res;
+ res = fuse_send_reply_iov_nofree(req, error, iov, count);
+ fuse_free_req(req);
+ return res;
}
static int send_reply(fuse_req_t req, int error, const void *arg,
- size_t argsize)
+ size_t argsize)
{
- struct iovec iov[2];
- int count = 1;
- if (argsize) {
- iov[1].iov_base = (void *) arg;
- iov[1].iov_len = argsize;
- count++;
- }
- return send_reply_iov(req, error, iov, count);
+ struct iovec iov[2];
+ int count = 1;
+ if (argsize) {
+ iov[1].iov_base = (void *)arg;
+ iov[1].iov_len = argsize;
+ count++;
+ }
+ return send_reply_iov(req, error, iov, count);
}
int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
{
- int res;
- struct iovec *padded_iov;
+ int res;
+ struct iovec *padded_iov;
- padded_iov = malloc((count + 1) * sizeof(struct iovec));
- if (padded_iov == NULL)
- return fuse_reply_err(req, ENOMEM);
+ padded_iov = malloc((count + 1) * sizeof(struct iovec));
+ if (padded_iov == NULL) {
+ return fuse_reply_err(req, ENOMEM);
+ }
- memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
- count++;
+ memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
+ count++;
- res = send_reply_iov(req, 0, padded_iov, count);
- free(padded_iov);
+ res = send_reply_iov(req, 0, padded_iov, count);
+ free(padded_iov);
- return res;
+ return res;
}
-/* `buf` is allowed to be empty so that the proper size may be
- allocated by the caller */
+/*
+ * 'buf` is allowed to be empty so that the proper size may be
+ * allocated by the caller
+ */
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
- const char *name, const struct stat *stbuf, off_t off)
+ const char *name, const struct stat *stbuf, off_t off)
{
- (void)req;
- size_t namelen;
- size_t entlen;
- size_t entlen_padded;
- struct fuse_dirent *dirent;
+ (void)req;
+ size_t namelen;
+ size_t entlen;
+ size_t entlen_padded;
+ struct fuse_dirent *dirent;
- namelen = strlen(name);
- entlen = FUSE_NAME_OFFSET + namelen;
- entlen_padded = FUSE_DIRENT_ALIGN(entlen);
+ namelen = strlen(name);
+ entlen = FUSE_NAME_OFFSET + namelen;
+ entlen_padded = FUSE_DIRENT_ALIGN(entlen);
- if ((buf == NULL) || (entlen_padded > bufsize))
- return entlen_padded;
+ if ((buf == NULL) || (entlen_padded > bufsize)) {
+ return entlen_padded;
+ }
- dirent = (struct fuse_dirent*) buf;
- dirent->ino = stbuf->st_ino;
- dirent->off = off;
- dirent->namelen = namelen;
- dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
- memcpy(dirent->name, name, namelen);
- memset(dirent->name + namelen, 0, entlen_padded - entlen);
+ dirent = (struct fuse_dirent *)buf;
+ dirent->ino = stbuf->st_ino;
+ dirent->off = off;
+ dirent->namelen = namelen;
+ dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
+ memcpy(dirent->name, name, namelen);
+ memset(dirent->name + namelen, 0, entlen_padded - entlen);
- return entlen_padded;
+ return entlen_padded;
}
static void convert_statfs(const struct statvfs *stbuf,
- struct fuse_kstatfs *kstatfs)
+ struct fuse_kstatfs *kstatfs)
{
- kstatfs->bsize = stbuf->f_bsize;
- kstatfs->frsize = stbuf->f_frsize;
- kstatfs->blocks = stbuf->f_blocks;
- kstatfs->bfree = stbuf->f_bfree;
- kstatfs->bavail = stbuf->f_bavail;
- kstatfs->files = stbuf->f_files;
- kstatfs->ffree = stbuf->f_ffree;
- kstatfs->namelen = stbuf->f_namemax;
+ kstatfs->bsize = stbuf->f_bsize;
+ kstatfs->frsize = stbuf->f_frsize;
+ kstatfs->blocks = stbuf->f_blocks;
+ kstatfs->bfree = stbuf->f_bfree;
+ kstatfs->bavail = stbuf->f_bavail;
+ kstatfs->files = stbuf->f_files;
+ kstatfs->ffree = stbuf->f_ffree;
+ kstatfs->namelen = stbuf->f_namemax;
}
static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
{
- return send_reply(req, 0, arg, argsize);
+ return send_reply(req, 0, arg, argsize);
}
int fuse_reply_err(fuse_req_t req, int err)
{
- return send_reply(req, -err, NULL, 0);
+ return send_reply(req, -err, NULL, 0);
}
void fuse_reply_none(fuse_req_t req)
{
- fuse_free_req(req);
+ fuse_free_req(req);
}
static unsigned long calc_timeout_sec(double t)
{
- if (t > (double) ULONG_MAX)
- return ULONG_MAX;
- else if (t < 0.0)
- return 0;
- else
- return (unsigned long) t;
+ if (t > (double)ULONG_MAX) {
+ return ULONG_MAX;
+ } else if (t < 0.0) {
+ return 0;
+ } else {
+ return (unsigned long)t;
+ }
}
static unsigned int calc_timeout_nsec(double t)
{
- double f = t - (double) calc_timeout_sec(t);
- if (f < 0.0)
- return 0;
- else if (f >= 0.999999999)
- return 999999999;
- else
- return (unsigned int) (f * 1.0e9);
+ double f = t - (double)calc_timeout_sec(t);
+ if (f < 0.0) {
+ return 0;
+ } else if (f >= 0.999999999) {
+ return 999999999;
+ } else {
+ return (unsigned int)(f * 1.0e9);
+ }
}
static void fill_entry(struct fuse_entry_out *arg,
- const struct fuse_entry_param *e)
+ const struct fuse_entry_param *e)
{
- arg->nodeid = e->ino;
- arg->generation = e->generation;
- arg->entry_valid = calc_timeout_sec(e->entry_timeout);
- arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
- arg->attr_valid = calc_timeout_sec(e->attr_timeout);
- arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
- convert_stat(&e->attr, &arg->attr);
+ arg->nodeid = e->ino;
+ arg->generation = e->generation;
+ arg->entry_valid = calc_timeout_sec(e->entry_timeout);
+ arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
+ arg->attr_valid = calc_timeout_sec(e->attr_timeout);
+ arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
+ convert_stat(&e->attr, &arg->attr);
}
-/* `buf` is allowed to be empty so that the proper size may be
- allocated by the caller */
+/*
+ * `buf` is allowed to be empty so that the proper size may be
+ * allocated by the caller
+ */
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
- const char *name,
- const struct fuse_entry_param *e, off_t off)
-{
- (void)req;
- size_t namelen;
- size_t entlen;
- size_t entlen_padded;
-
- namelen = strlen(name);
- entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
- entlen_padded = FUSE_DIRENT_ALIGN(entlen);
- if ((buf == NULL) || (entlen_padded > bufsize))
- return entlen_padded;
-
- struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
- memset(&dp->entry_out, 0, sizeof(dp->entry_out));
- fill_entry(&dp->entry_out, e);
-
- struct fuse_dirent *dirent = &dp->dirent;
- dirent->ino = e->attr.st_ino;
- dirent->off = off;
- dirent->namelen = namelen;
- dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
- memcpy(dirent->name, name, namelen);
- memset(dirent->name + namelen, 0, entlen_padded - entlen);
-
- return entlen_padded;
-}
-
-static void fill_open(struct fuse_open_out *arg,
- const struct fuse_file_info *f)
-{
- arg->fh = f->fh;
- if (f->direct_io)
- arg->open_flags |= FOPEN_DIRECT_IO;
- if (f->keep_cache)
- arg->open_flags |= FOPEN_KEEP_CACHE;
- if (f->cache_readdir)
- arg->open_flags |= FOPEN_CACHE_DIR;
- if (f->nonseekable)
- arg->open_flags |= FOPEN_NONSEEKABLE;
+ const char *name,
+ const struct fuse_entry_param *e, off_t off)
+{
+ (void)req;
+ size_t namelen;
+ size_t entlen;
+ size_t entlen_padded;
+
+ namelen = strlen(name);
+ entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
+ entlen_padded = FUSE_DIRENT_ALIGN(entlen);
+ if ((buf == NULL) || (entlen_padded > bufsize)) {
+ return entlen_padded;
+ }
+
+ struct fuse_direntplus *dp = (struct fuse_direntplus *)buf;
+ memset(&dp->entry_out, 0, sizeof(dp->entry_out));
+ fill_entry(&dp->entry_out, e);
+
+ struct fuse_dirent *dirent = &dp->dirent;
+ dirent->ino = e->attr.st_ino;
+ dirent->off = off;
+ dirent->namelen = namelen;
+ dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
+ memcpy(dirent->name, name, namelen);
+ memset(dirent->name + namelen, 0, entlen_padded - entlen);
+
+ return entlen_padded;
+}
+
+static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f)
+{
+ arg->fh = f->fh;
+ if (f->direct_io) {
+ arg->open_flags |= FOPEN_DIRECT_IO;
+ }
+ if (f->keep_cache) {
+ arg->open_flags |= FOPEN_KEEP_CACHE;
+ }
+ if (f->cache_readdir) {
+ arg->open_flags |= FOPEN_CACHE_DIR;
+ }
+ if (f->nonseekable) {
+ arg->open_flags |= FOPEN_NONSEEKABLE;
+ }
}
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
{
- struct fuse_entry_out arg;
- size_t size = req->se->conn.proto_minor < 9 ?
- FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
+ struct fuse_entry_out arg;
+ size_t size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE :
+ sizeof(arg);
- /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
- negative entry */
- if (!e->ino && req->se->conn.proto_minor < 4)
- return fuse_reply_err(req, ENOENT);
+ /*
+ * before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
+ * negative entry
+ */
+ if (!e->ino && req->se->conn.proto_minor < 4) {
+ return fuse_reply_err(req, ENOENT);
+ }
- memset(&arg, 0, sizeof(arg));
- fill_entry(&arg, e);
- return send_reply_ok(req, &arg, size);
+ memset(&arg, 0, sizeof(arg));
+ fill_entry(&arg, e);
+ return send_reply_ok(req, &arg, size);
}
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
- const struct fuse_file_info *f)
+ const struct fuse_file_info *f)
{
- char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
- size_t entrysize = req->se->conn.proto_minor < 9 ?
- FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
- struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
- struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
+ char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
+ size_t entrysize = req->se->conn.proto_minor < 9 ?
+ FUSE_COMPAT_ENTRY_OUT_SIZE :
+ sizeof(struct fuse_entry_out);
+ struct fuse_entry_out *earg = (struct fuse_entry_out *)buf;
+ struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize);
- memset(buf, 0, sizeof(buf));
- fill_entry(earg, e);
- fill_open(oarg, f);
- return send_reply_ok(req, buf,
- entrysize + sizeof(struct fuse_open_out));
+ memset(buf, 0, sizeof(buf));
+ fill_entry(earg, e);
+ fill_open(oarg, f);
+ return send_reply_ok(req, buf, entrysize + sizeof(struct fuse_open_out));
}
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
- double attr_timeout)
+ double attr_timeout)
{
- struct fuse_attr_out arg;
- size_t size = req->se->conn.proto_minor < 9 ?
- FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
+ struct fuse_attr_out arg;
+ size_t size =
+ req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
- memset(&arg, 0, sizeof(arg));
- arg.attr_valid = calc_timeout_sec(attr_timeout);
- arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
- convert_stat(attr, &arg.attr);
+ memset(&arg, 0, sizeof(arg));
+ arg.attr_valid = calc_timeout_sec(attr_timeout);
+ arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
+ convert_stat(attr, &arg.attr);
- return send_reply_ok(req, &arg, size);
+ return send_reply_ok(req, &arg, size);
}
int fuse_reply_readlink(fuse_req_t req, const char *linkname)
{
- return send_reply_ok(req, linkname, strlen(linkname));
+ return send_reply_ok(req, linkname, strlen(linkname));
}
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
{
- struct fuse_open_out arg;
+ struct fuse_open_out arg;
- memset(&arg, 0, sizeof(arg));
- fill_open(&arg, f);
- return send_reply_ok(req, &arg, sizeof(arg));
+ memset(&arg, 0, sizeof(arg));
+ fill_open(&arg, f);
+ return send_reply_ok(req, &arg, sizeof(arg));
}
int fuse_reply_write(fuse_req_t req, size_t count)
{
- struct fuse_write_out arg;
+ struct fuse_write_out arg;
- memset(&arg, 0, sizeof(arg));
- arg.size = count;
+ memset(&arg, 0, sizeof(arg));
+ arg.size = count;
- return send_reply_ok(req, &arg, sizeof(arg));
+ return send_reply_ok(req, &arg, sizeof(arg));
}
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
{
- return send_reply_ok(req, buf, size);
+ return send_reply_ok(req, buf, size);
}
static int fuse_send_data_iov_fallback(struct fuse_session *se,
- struct fuse_chan *ch,
- struct iovec *iov, int iov_count,
- struct fuse_bufvec *buf,
- size_t len)
+ struct fuse_chan *ch, struct iovec *iov,
+ int iov_count, struct fuse_bufvec *buf,
+ size_t len)
{
- /* Optimize common case */
- if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
- !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
- /* FIXME: also avoid memory copy if there are multiple buffers
- but none of them contain an fd */
+ /* Optimize common case */
+ if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
+ !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
+ /*
+ * FIXME: also avoid memory copy if there are multiple buffers
+ * but none of them contain an fd
+ */
- iov[iov_count].iov_base = buf->buf[0].mem;
- iov[iov_count].iov_len = len;
- iov_count++;
- return fuse_send_msg(se, ch, iov, iov_count);
- }
+ iov[iov_count].iov_base = buf->buf[0].mem;
+ iov[iov_count].iov_len = len;
+ iov_count++;
+ return fuse_send_msg(se, ch, iov, iov_count);
+ }
- abort(); /* Will have taken vhost path */
- return 0;
+ abort(); /* Will have taken vhost path */
+ return 0;
}
static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
- struct iovec *iov, int iov_count,
- struct fuse_bufvec *buf, unsigned int flags)
+ struct iovec *iov, int iov_count,
+ struct fuse_bufvec *buf, unsigned int flags)
{
- size_t len = fuse_buf_size(buf);
- (void) flags;
+ size_t len = fuse_buf_size(buf);
+ (void)flags;
- return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
+ return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
}
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
- enum fuse_buf_copy_flags flags)
+ enum fuse_buf_copy_flags flags)
{
- struct iovec iov[2];
- struct fuse_out_header out;
- int res;
+ struct iovec iov[2];
+ struct fuse_out_header out;
+ int res;
- iov[0].iov_base = &out;
- iov[0].iov_len = sizeof(struct fuse_out_header);
+ iov[0].iov_base = &out;
+ iov[0].iov_len = sizeof(struct fuse_out_header);
- out.unique = req->unique;
- out.error = 0;
+ out.unique = req->unique;
+ out.error = 0;
- res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
- if (res <= 0) {
- fuse_free_req(req);
- return res;
- } else {
- return fuse_reply_err(req, res);
- }
+ res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
+ if (res <= 0) {
+ fuse_free_req(req);
+ return res;
+ } else {
+ return fuse_reply_err(req, res);
+ }
}
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
{
- struct fuse_statfs_out arg;
- size_t size = req->se->conn.proto_minor < 4 ?
- FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
+ struct fuse_statfs_out arg;
+ size_t size =
+ req->se->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
- memset(&arg, 0, sizeof(arg));
- convert_statfs(stbuf, &arg.st);
+ memset(&arg, 0, sizeof(arg));
+ convert_statfs(stbuf, &arg.st);
- return send_reply_ok(req, &arg, size);
+ return send_reply_ok(req, &arg, size);
}
int fuse_reply_xattr(fuse_req_t req, size_t count)
{
- struct fuse_getxattr_out arg;
+ struct fuse_getxattr_out arg;
- memset(&arg, 0, sizeof(arg));
- arg.size = count;
+ memset(&arg, 0, sizeof(arg));
+ arg.size = count;
- return send_reply_ok(req, &arg, sizeof(arg));
+ return send_reply_ok(req, &arg, sizeof(arg));
}
int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
{
- struct fuse_lk_out arg;
+ struct fuse_lk_out arg;
- memset(&arg, 0, sizeof(arg));
- arg.lk.type = lock->l_type;
- if (lock->l_type != F_UNLCK) {
- arg.lk.start = lock->l_start;
- if (lock->l_len == 0)
- arg.lk.end = OFFSET_MAX;
- else
- arg.lk.end = lock->l_start + lock->l_len - 1;
- }
- arg.lk.pid = lock->l_pid;
- return send_reply_ok(req, &arg, sizeof(arg));
+ memset(&arg, 0, sizeof(arg));
+ arg.lk.type = lock->l_type;
+ if (lock->l_type != F_UNLCK) {
+ arg.lk.start = lock->l_start;
+ if (lock->l_len == 0) {
+ arg.lk.end = OFFSET_MAX;
+ } else {
+ arg.lk.end = lock->l_start + lock->l_len - 1;
+ }
+ }
+ arg.lk.pid = lock->l_pid;
+ return send_reply_ok(req, &arg, sizeof(arg));
}
int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
{
- struct fuse_bmap_out arg;
+ struct fuse_bmap_out arg;
- memset(&arg, 0, sizeof(arg));
- arg.block = idx;
+ memset(&arg, 0, sizeof(arg));
+ arg.block = idx;
- return send_reply_ok(req, &arg, sizeof(arg));
+ return send_reply_ok(req, &arg, sizeof(arg));
}
static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
- size_t count)
-{
- struct fuse_ioctl_iovec *fiov;
- size_t i;
-
- fiov = malloc(sizeof(fiov[0]) * count);
- if (!fiov)
- return NULL;
-
- for (i = 0; i < count; i++) {
- fiov[i].base = (uintptr_t) iov[i].iov_base;
- fiov[i].len = iov[i].iov_len;
- }
-
- return fiov;
-}
-
-int fuse_reply_ioctl_retry(fuse_req_t req,
- const struct iovec *in_iov, size_t in_count,
- const struct iovec *out_iov, size_t out_count)
-{
- struct fuse_ioctl_out arg;
- struct fuse_ioctl_iovec *in_fiov = NULL;
- struct fuse_ioctl_iovec *out_fiov = NULL;
- struct iovec iov[4];
- size_t count = 1;
- int res;
-
- memset(&arg, 0, sizeof(arg));
- arg.flags |= FUSE_IOCTL_RETRY;
- arg.in_iovs = in_count;
- arg.out_iovs = out_count;
- iov[count].iov_base = &arg;
- iov[count].iov_len = sizeof(arg);
- count++;
-
- if (req->se->conn.proto_minor < 16) {
- if (in_count) {
- iov[count].iov_base = (void *)in_iov;
- iov[count].iov_len = sizeof(in_iov[0]) * in_count;
- count++;
- }
-
- if (out_count) {
- iov[count].iov_base = (void *)out_iov;
- iov[count].iov_len = sizeof(out_iov[0]) * out_count;
- count++;
- }
- } else {
- /* Can't handle non-compat 64bit ioctls on 32bit */
- if (sizeof(void *) == 4 && req->ioctl_64bit) {
- res = fuse_reply_err(req, EINVAL);
- goto out;
- }
-
- if (in_count) {
- in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
- if (!in_fiov)
- goto enomem;
-
- iov[count].iov_base = (void *)in_fiov;
- iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
- count++;
- }
- if (out_count) {
- out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
- if (!out_fiov)
- goto enomem;
-
- iov[count].iov_base = (void *)out_fiov;
- iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
- count++;
- }
- }
-
- res = send_reply_iov(req, 0, iov, count);
+ size_t count)
+{
+ struct fuse_ioctl_iovec *fiov;
+ size_t i;
+
+ fiov = malloc(sizeof(fiov[0]) * count);
+ if (!fiov) {
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++) {
+ fiov[i].base = (uintptr_t)iov[i].iov_base;
+ fiov[i].len = iov[i].iov_len;
+ }
+
+ return fiov;
+}
+
+int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov,
+ size_t in_count, const struct iovec *out_iov,
+ size_t out_count)
+{
+ struct fuse_ioctl_out arg;
+ struct fuse_ioctl_iovec *in_fiov = NULL;
+ struct fuse_ioctl_iovec *out_fiov = NULL;
+ struct iovec iov[4];
+ size_t count = 1;
+ int res;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.flags |= FUSE_IOCTL_RETRY;
+ arg.in_iovs = in_count;
+ arg.out_iovs = out_count;
+ iov[count].iov_base = &arg;
+ iov[count].iov_len = sizeof(arg);
+ count++;
+
+ if (req->se->conn.proto_minor < 16) {
+ if (in_count) {
+ iov[count].iov_base = (void *)in_iov;
+ iov[count].iov_len = sizeof(in_iov[0]) * in_count;
+ count++;
+ }
+
+ if (out_count) {
+ iov[count].iov_base = (void *)out_iov;
+ iov[count].iov_len = sizeof(out_iov[0]) * out_count;
+ count++;
+ }
+ } else {
+ /* Can't handle non-compat 64bit ioctls on 32bit */
+ if (sizeof(void *) == 4 && req->ioctl_64bit) {
+ res = fuse_reply_err(req, EINVAL);
+ goto out;
+ }
+
+ if (in_count) {
+ in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
+ if (!in_fiov) {
+ goto enomem;
+ }
+
+ iov[count].iov_base = (void *)in_fiov;
+ iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
+ count++;
+ }
+ if (out_count) {
+ out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
+ if (!out_fiov) {
+ goto enomem;
+ }
+
+ iov[count].iov_base = (void *)out_fiov;
+ iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
+ count++;
+ }
+ }
+
+ res = send_reply_iov(req, 0, iov, count);
out:
- free(in_fiov);
- free(out_fiov);
+ free(in_fiov);
+ free(out_fiov);
- return res;
+ return res;
enomem:
- res = fuse_reply_err(req, ENOMEM);
- goto out;
+ res = fuse_reply_err(req, ENOMEM);
+ goto out;
}
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
{
- struct fuse_ioctl_out arg;
- struct iovec iov[3];
- size_t count = 1;
+ struct fuse_ioctl_out arg;
+ struct iovec iov[3];
+ size_t count = 1;
- memset(&arg, 0, sizeof(arg));
- arg.result = result;
- iov[count].iov_base = &arg;
- iov[count].iov_len = sizeof(arg);
- count++;
+ memset(&arg, 0, sizeof(arg));
+ arg.result = result;
+ iov[count].iov_base = &arg;
+ iov[count].iov_len = sizeof(arg);
+ count++;
- if (size) {
- iov[count].iov_base = (char *) buf;
- iov[count].iov_len = size;
- count++;
- }
+ if (size) {
+ iov[count].iov_base = (char *)buf;
+ iov[count].iov_len = size;
+ count++;
+ }
- return send_reply_iov(req, 0, iov, count);
+ return send_reply_iov(req, 0, iov, count);
}
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
- int count)
+ int count)
{
- struct iovec *padded_iov;
- struct fuse_ioctl_out arg;
- int res;
+ struct iovec *padded_iov;
+ struct fuse_ioctl_out arg;
+ int res;
- padded_iov = malloc((count + 2) * sizeof(struct iovec));
- if (padded_iov == NULL)
- return fuse_reply_err(req, ENOMEM);
+ padded_iov = malloc((count + 2) * sizeof(struct iovec));
+ if (padded_iov == NULL) {
+ return fuse_reply_err(req, ENOMEM);
+ }
- memset(&arg, 0, sizeof(arg));
- arg.result = result;
- padded_iov[1].iov_base = &arg;
- padded_iov[1].iov_len = sizeof(arg);
+ memset(&arg, 0, sizeof(arg));
+ arg.result = result;
+ padded_iov[1].iov_base = &arg;
+ padded_iov[1].iov_len = sizeof(arg);
- memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
+ memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
- res = send_reply_iov(req, 0, padded_iov, count + 2);
- free(padded_iov);
+ res = send_reply_iov(req, 0, padded_iov, count + 2);
+ free(padded_iov);
- return res;
+ return res;
}
int fuse_reply_poll(fuse_req_t req, unsigned revents)
{
- struct fuse_poll_out arg;
+ struct fuse_poll_out arg;
- memset(&arg, 0, sizeof(arg));
- arg.revents = revents;
+ memset(&arg, 0, sizeof(arg));
+ arg.revents = revents;
- return send_reply_ok(req, &arg, sizeof(arg));
+ return send_reply_ok(req, &arg, sizeof(arg));
}
int fuse_reply_lseek(fuse_req_t req, off_t off)
{
- struct fuse_lseek_out arg;
+ struct fuse_lseek_out arg;
- memset(&arg, 0, sizeof(arg));
- arg.offset = off;
+ memset(&arg, 0, sizeof(arg));
+ arg.offset = off;
- return send_reply_ok(req, &arg, sizeof(arg));
+ return send_reply_ok(req, &arg, sizeof(arg));
}
static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- char *name = (char *) inarg;
+ char *name = (char *)inarg;
- if (req->se->op.lookup)
- req->se->op.lookup(req, nodeid, name);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.lookup) {
+ req->se->op.lookup(req, nodeid, name);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
+ struct fuse_forget_in *arg = (struct fuse_forget_in *)inarg;
- if (req->se->op.forget)
- req->se->op.forget(req, nodeid, arg->nlookup);
- else
- fuse_reply_none(req);
+ if (req->se->op.forget) {
+ req->se->op.forget(req, nodeid, arg->nlookup);
+ } else {
+ fuse_reply_none(req);
+ }
}
static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
- const void *inarg)
+ const void *inarg)
{
- struct fuse_batch_forget_in *arg = (void *) inarg;
- struct fuse_forget_one *param = (void *) PARAM(arg);
- unsigned int i;
+ struct fuse_batch_forget_in *arg = (void *)inarg;
+ struct fuse_forget_one *param = (void *)PARAM(arg);
+ unsigned int i;
- (void) nodeid;
+ (void)nodeid;
- if (req->se->op.forget_multi) {
- req->se->op.forget_multi(req, arg->count,
- (struct fuse_forget_data *) param);
- } else if (req->se->op.forget) {
- for (i = 0; i < arg->count; i++) {
- struct fuse_forget_one *forget = &param[i];
- struct fuse_req *dummy_req;
+ if (req->se->op.forget_multi) {
+ req->se->op.forget_multi(req, arg->count,
+ (struct fuse_forget_data *)param);
+ } else if (req->se->op.forget) {
+ for (i = 0; i < arg->count; i++) {
+ struct fuse_forget_one *forget = &param[i];
+ struct fuse_req *dummy_req;
- dummy_req = fuse_ll_alloc_req(req->se);
- if (dummy_req == NULL)
- break;
+ dummy_req = fuse_ll_alloc_req(req->se);
+ if (dummy_req == NULL) {
+ break;
+ }
- dummy_req->unique = req->unique;
- dummy_req->ctx = req->ctx;
- dummy_req->ch = NULL;
+ dummy_req->unique = req->unique;
+ dummy_req->ctx = req->ctx;
+ dummy_req->ch = NULL;
- req->se->op.forget(dummy_req, forget->nodeid,
- forget->nlookup);
- }
- fuse_reply_none(req);
- } else {
- fuse_reply_none(req);
- }
+ req->se->op.forget(dummy_req, forget->nodeid, forget->nlookup);
+ }
+ fuse_reply_none(req);
+ } else {
+ fuse_reply_none(req);
+ }
}
static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_file_info *fip = NULL;
- struct fuse_file_info fi;
+ struct fuse_file_info *fip = NULL;
+ struct fuse_file_info fi;
- if (req->se->conn.proto_minor >= 9) {
- struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
+ if (req->se->conn.proto_minor >= 9) {
+ struct fuse_getattr_in *arg = (struct fuse_getattr_in *)inarg;
- if (arg->getattr_flags & FUSE_GETATTR_FH) {
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fip = &fi;
- }
- }
+ if (arg->getattr_flags & FUSE_GETATTR_FH) {
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fip = &fi;
+ }
+ }
- if (req->se->op.getattr)
- req->se->op.getattr(req, nodeid, fip);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.getattr) {
+ req->se->op.getattr(req, nodeid, fip);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
-
- if (req->se->op.setattr) {
- struct fuse_file_info *fi = NULL;
- struct fuse_file_info fi_store;
- struct stat stbuf;
- memset(&stbuf, 0, sizeof(stbuf));
- convert_attr(arg, &stbuf);
- if (arg->valid & FATTR_FH) {
- arg->valid &= ~FATTR_FH;
- memset(&fi_store, 0, sizeof(fi_store));
- fi = &fi_store;
- fi->fh = arg->fh;
- }
- arg->valid &=
- FUSE_SET_ATTR_MODE |
- FUSE_SET_ATTR_UID |
- FUSE_SET_ATTR_GID |
- FUSE_SET_ATTR_SIZE |
- FUSE_SET_ATTR_ATIME |
- FUSE_SET_ATTR_MTIME |
- FUSE_SET_ATTR_ATIME_NOW |
- FUSE_SET_ATTR_MTIME_NOW |
- FUSE_SET_ATTR_CTIME;
-
- req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
- } else
- fuse_reply_err(req, ENOSYS);
+ struct fuse_setattr_in *arg = (struct fuse_setattr_in *)inarg;
+
+ if (req->se->op.setattr) {
+ struct fuse_file_info *fi = NULL;
+ struct fuse_file_info fi_store;
+ struct stat stbuf;
+ memset(&stbuf, 0, sizeof(stbuf));
+ convert_attr(arg, &stbuf);
+ if (arg->valid & FATTR_FH) {
+ arg->valid &= ~FATTR_FH;
+ memset(&fi_store, 0, sizeof(fi_store));
+ fi = &fi_store;
+ fi->fh = arg->fh;
+ }
+ arg->valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID |
+ FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE |
+ FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME |
+ FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW |
+ FUSE_SET_ATTR_CTIME;
+
+ req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
+ struct fuse_access_in *arg = (struct fuse_access_in *)inarg;
- if (req->se->op.access)
- req->se->op.access(req, nodeid, arg->mask);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.access) {
+ req->se->op.access(req, nodeid, arg->mask);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- (void) inarg;
+ (void)inarg;
- if (req->se->op.readlink)
- req->se->op.readlink(req, nodeid);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.readlink) {
+ req->se->op.readlink(req, nodeid);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
- char *name = PARAM(arg);
+ struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg;
+ char *name = PARAM(arg);
- if (req->se->conn.proto_minor >= 12)
- req->ctx.umask = arg->umask;
- else
- name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
+ if (req->se->conn.proto_minor >= 12) {
+ req->ctx.umask = arg->umask;
+ } else {
+ name = (char *)inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
+ }
- if (req->se->op.mknod)
- req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.mknod) {
+ req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
+ struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *)inarg;
- if (req->se->conn.proto_minor >= 12)
- req->ctx.umask = arg->umask;
+ if (req->se->conn.proto_minor >= 12) {
+ req->ctx.umask = arg->umask;
+ }
- if (req->se->op.mkdir)
- req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.mkdir) {
+ req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- char *name = (char *) inarg;
+ char *name = (char *)inarg;
- if (req->se->op.unlink)
- req->se->op.unlink(req, nodeid, name);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.unlink) {
+ req->se->op.unlink(req, nodeid, name);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- char *name = (char *) inarg;
+ char *name = (char *)inarg;
- if (req->se->op.rmdir)
- req->se->op.rmdir(req, nodeid, name);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.rmdir) {
+ req->se->op.rmdir(req, nodeid, name);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- char *name = (char *) inarg;
- char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
+ char *name = (char *)inarg;
+ char *linkname = ((char *)inarg) + strlen((char *)inarg) + 1;
- if (req->se->op.symlink)
- req->se->op.symlink(req, linkname, nodeid, name);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.symlink) {
+ req->se->op.symlink(req, linkname, nodeid, name);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
- char *oldname = PARAM(arg);
- char *newname = oldname + strlen(oldname) + 1;
+ struct fuse_rename_in *arg = (struct fuse_rename_in *)inarg;
+ char *oldname = PARAM(arg);
+ char *newname = oldname + strlen(oldname) + 1;
- if (req->se->op.rename)
- req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
- 0);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.rename) {
+ req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, 0);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_rename2_in *arg = (struct fuse_rename2_in *) inarg;
- char *oldname = PARAM(arg);
- char *newname = oldname + strlen(oldname) + 1;
+ struct fuse_rename2_in *arg = (struct fuse_rename2_in *)inarg;
+ char *oldname = PARAM(arg);
+ char *newname = oldname + strlen(oldname) + 1;
- if (req->se->op.rename)
- req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
- arg->flags);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.rename) {
+ req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
+ arg->flags);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
+ struct fuse_link_in *arg = (struct fuse_link_in *)inarg;
- if (req->se->op.link)
- req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.link) {
+ req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
+ struct fuse_create_in *arg = (struct fuse_create_in *)inarg;
- if (req->se->op.create) {
- struct fuse_file_info fi;
- char *name = PARAM(arg);
+ if (req->se->op.create) {
+ struct fuse_file_info fi;
+ char *name = PARAM(arg);
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = arg->flags;
- if (req->se->conn.proto_minor >= 12)
- req->ctx.umask = arg->umask;
- else
- name = (char *) inarg + sizeof(struct fuse_open_in);
+ if (req->se->conn.proto_minor >= 12) {
+ req->ctx.umask = arg->umask;
+ } else {
+ name = (char *)inarg + sizeof(struct fuse_open_in);
+ }
- req->se->op.create(req, nodeid, name, arg->mode, &fi);
- } else
- fuse_reply_err(req, ENOSYS);
+ req->se->op.create(req, nodeid, name, arg->mode, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = arg->flags;
- if (req->se->op.open)
- req->se->op.open(req, nodeid, &fi);
- else
- fuse_reply_open(req, &fi);
+ if (req->se->op.open) {
+ req->se->op.open(req, nodeid, &fi);
+ } else {
+ fuse_reply_open(req, &fi);
+ }
}
static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+ struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
- if (req->se->op.read) {
- struct fuse_file_info fi;
+ if (req->se->op.read) {
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- if (req->se->conn.proto_minor >= 9) {
- fi.lock_owner = arg->lock_owner;
- fi.flags = arg->flags;
- }
- req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
- } else
- fuse_reply_err(req, ENOSYS);
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ if (req->se->conn.proto_minor >= 9) {
+ fi.lock_owner = arg->lock_owner;
+ fi.flags = arg->flags;
+ }
+ req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
- struct fuse_file_info fi;
- char *param;
+ struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
+ struct fuse_file_info fi;
+ char *param;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
- if (req->se->conn.proto_minor < 9) {
- param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
- } else {
- fi.lock_owner = arg->lock_owner;
- fi.flags = arg->flags;
- param = PARAM(arg);
- }
+ if (req->se->conn.proto_minor < 9) {
+ param = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+ } else {
+ fi.lock_owner = arg->lock_owner;
+ fi.flags = arg->flags;
+ param = PARAM(arg);
+ }
- if (req->se->op.write)
- req->se->op.write(req, nodeid, param, arg->size,
- arg->offset, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.write) {
+ req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
- const struct fuse_buf *ibuf)
-{
- struct fuse_session *se = req->se;
- struct fuse_bufvec bufv = {
- .buf[0] = *ibuf,
- .count = 1,
- };
- struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
-
- if (se->conn.proto_minor < 9) {
- bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
- bufv.buf[0].size -= sizeof(struct fuse_in_header) +
- FUSE_COMPAT_WRITE_IN_SIZE;
- assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
- } else {
- fi.lock_owner = arg->lock_owner;
- fi.flags = arg->flags;
- if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
- bufv.buf[0].mem = PARAM(arg);
-
- bufv.buf[0].size -= sizeof(struct fuse_in_header) +
- sizeof(struct fuse_write_in);
- }
- if (bufv.buf[0].size < arg->size) {
- fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
- fuse_reply_err(req, EIO);
- return;
- }
- bufv.buf[0].size = arg->size;
-
- se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
+ const struct fuse_buf *ibuf)
+{
+ struct fuse_session *se = req->se;
+ struct fuse_bufvec bufv = {
+ .buf[0] = *ibuf,
+ .count = 1,
+ };
+ struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
+ struct fuse_file_info fi;
+
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
+
+ if (se->conn.proto_minor < 9) {
+ bufv.buf[0].mem = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+ bufv.buf[0].size -=
+ sizeof(struct fuse_in_header) + FUSE_COMPAT_WRITE_IN_SIZE;
+ assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
+ } else {
+ fi.lock_owner = arg->lock_owner;
+ fi.flags = arg->flags;
+ if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
+ bufv.buf[0].mem = PARAM(arg);
+ }
+
+ bufv.buf[0].size -=
+ sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
+ }
+ if (bufv.buf[0].size < arg->size) {
+ fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
+ fuse_reply_err(req, EIO);
+ return;
+ }
+ bufv.buf[0].size = arg->size;
+
+ se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
}
static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_flush_in *arg = (struct fuse_flush_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fi.flush = 1;
- if (req->se->conn.proto_minor >= 7)
- fi.lock_owner = arg->lock_owner;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fi.flush = 1;
+ if (req->se->conn.proto_minor >= 7) {
+ fi.lock_owner = arg->lock_owner;
+ }
- if (req->se->op.flush)
- req->se->op.flush(req, nodeid, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.flush) {
+ req->se->op.flush(req, nodeid, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
- fi.fh = arg->fh;
- if (req->se->conn.proto_minor >= 8) {
- fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
- fi.lock_owner = arg->lock_owner;
- }
- if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
- fi.flock_release = 1;
- fi.lock_owner = arg->lock_owner;
- }
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = arg->flags;
+ fi.fh = arg->fh;
+ if (req->se->conn.proto_minor >= 8) {
+ fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
+ fi.lock_owner = arg->lock_owner;
+ }
+ if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
+ fi.flock_release = 1;
+ fi.lock_owner = arg->lock_owner;
+ }
- if (req->se->op.release)
- req->se->op.release(req, nodeid, &fi);
- else
- fuse_reply_err(req, 0);
+ if (req->se->op.release) {
+ req->se->op.release(req, nodeid, &fi);
+ } else {
+ fuse_reply_err(req, 0);
+ }
}
static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
- struct fuse_file_info fi;
- int datasync = arg->fsync_flags & 1;
+ struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
+ struct fuse_file_info fi;
+ int datasync = arg->fsync_flags & 1;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- if (req->se->op.fsync)
- req->se->op.fsync(req, nodeid, datasync, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.fsync) {
+ req->se->op.fsync(req, nodeid, datasync, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = arg->flags;
- if (req->se->op.opendir)
- req->se->op.opendir(req, nodeid, &fi);
- else
- fuse_reply_open(req, &fi);
+ if (req->se->op.opendir) {
+ req->se->op.opendir(req, nodeid, &fi);
+ } else {
+ fuse_reply_open(req, &fi);
+ }
}
static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- if (req->se->op.readdir)
- req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.readdir) {
+ req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- if (req->se->op.readdirplus)
- req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.readdirplus) {
+ req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = arg->flags;
+ fi.fh = arg->fh;
- if (req->se->op.releasedir)
- req->se->op.releasedir(req, nodeid, &fi);
- else
- fuse_reply_err(req, 0);
+ if (req->se->op.releasedir) {
+ req->se->op.releasedir(req, nodeid, &fi);
+ } else {
+ fuse_reply_err(req, 0);
+ }
}
static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
- struct fuse_file_info fi;
- int datasync = arg->fsync_flags & 1;
+ struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
+ struct fuse_file_info fi;
+ int datasync = arg->fsync_flags & 1;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- if (req->se->op.fsyncdir)
- req->se->op.fsyncdir(req, nodeid, datasync, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.fsyncdir) {
+ req->se->op.fsyncdir(req, nodeid, datasync, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- (void) nodeid;
- (void) inarg;
+ (void)nodeid;
+ (void)inarg;
- if (req->se->op.statfs)
- req->se->op.statfs(req, nodeid);
- else {
- struct statvfs buf = {
- .f_namemax = 255,
- .f_bsize = 512,
- };
- fuse_reply_statfs(req, &buf);
- }
+ if (req->se->op.statfs) {
+ req->se->op.statfs(req, nodeid);
+ } else {
+ struct statvfs buf = {
+ .f_namemax = 255,
+ .f_bsize = 512,
+ };
+ fuse_reply_statfs(req, &buf);
+ }
}
static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
- char *name = PARAM(arg);
- char *value = name + strlen(name) + 1;
+ struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *)inarg;
+ char *name = PARAM(arg);
+ char *value = name + strlen(name) + 1;
- if (req->se->op.setxattr)
- req->se->op.setxattr(req, nodeid, name, value, arg->size,
- arg->flags);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.setxattr) {
+ req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
+ struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
- if (req->se->op.getxattr)
- req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.getxattr) {
+ req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
+ struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
- if (req->se->op.listxattr)
- req->se->op.listxattr(req, nodeid, arg->size);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.listxattr) {
+ req->se->op.listxattr(req, nodeid, arg->size);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- char *name = (char *) inarg;
+ char *name = (char *)inarg;
- if (req->se->op.removexattr)
- req->se->op.removexattr(req, nodeid, name);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.removexattr) {
+ req->se->op.removexattr(req, nodeid, name);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void convert_fuse_file_lock(struct fuse_file_lock *fl,
- struct flock *flock)
+ struct flock *flock)
{
- memset(flock, 0, sizeof(struct flock));
- flock->l_type = fl->type;
- flock->l_whence = SEEK_SET;
- flock->l_start = fl->start;
- if (fl->end == OFFSET_MAX)
- flock->l_len = 0;
- else
- flock->l_len = fl->end - fl->start + 1;
- flock->l_pid = fl->pid;
+ memset(flock, 0, sizeof(struct flock));
+ flock->l_type = fl->type;
+ flock->l_whence = SEEK_SET;
+ flock->l_start = fl->start;
+ if (fl->end == OFFSET_MAX) {
+ flock->l_len = 0;
+ } else {
+ flock->l_len = fl->end - fl->start + 1;
+ }
+ flock->l_pid = fl->pid;
}
static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
- struct fuse_file_info fi;
- struct flock flock;
+ struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
+ struct fuse_file_info fi;
+ struct flock flock;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fi.lock_owner = arg->owner;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fi.lock_owner = arg->owner;
- convert_fuse_file_lock(&arg->lk, &flock);
- if (req->se->op.getlk)
- req->se->op.getlk(req, nodeid, &fi, &flock);
- else
- fuse_reply_err(req, ENOSYS);
+ convert_fuse_file_lock(&arg->lk, &flock);
+ if (req->se->op.getlk) {
+ req->se->op.getlk(req, nodeid, &fi, &flock);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
- const void *inarg, int sleep)
-{
- struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
- struct fuse_file_info fi;
- struct flock flock;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fi.lock_owner = arg->owner;
-
- if (arg->lk_flags & FUSE_LK_FLOCK) {
- int op = 0;
-
- switch (arg->lk.type) {
- case F_RDLCK:
- op = LOCK_SH;
- break;
- case F_WRLCK:
- op = LOCK_EX;
- break;
- case F_UNLCK:
- op = LOCK_UN;
- break;
- }
- if (!sleep)
- op |= LOCK_NB;
-
- if (req->se->op.flock)
- req->se->op.flock(req, nodeid, &fi, op);
- else
- fuse_reply_err(req, ENOSYS);
- } else {
- convert_fuse_file_lock(&arg->lk, &flock);
- if (req->se->op.setlk)
- req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
- else
- fuse_reply_err(req, ENOSYS);
- }
+ const void *inarg, int sleep)
+{
+ struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
+ struct fuse_file_info fi;
+ struct flock flock;
+
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fi.lock_owner = arg->owner;
+
+ if (arg->lk_flags & FUSE_LK_FLOCK) {
+ int op = 0;
+
+ switch (arg->lk.type) {
+ case F_RDLCK:
+ op = LOCK_SH;
+ break;
+ case F_WRLCK:
+ op = LOCK_EX;
+ break;
+ case F_UNLCK:
+ op = LOCK_UN;
+ break;
+ }
+ if (!sleep) {
+ op |= LOCK_NB;
+ }
+
+ if (req->se->op.flock) {
+ req->se->op.flock(req, nodeid, &fi, op);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
+ } else {
+ convert_fuse_file_lock(&arg->lk, &flock);
+ if (req->se->op.setlk) {
+ req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
+ }
}
static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- do_setlk_common(req, nodeid, inarg, 0);
+ do_setlk_common(req, nodeid, inarg, 0);
}
static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- do_setlk_common(req, nodeid, inarg, 1);
+ do_setlk_common(req, nodeid, inarg, 1);
}
static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
{
- struct fuse_req *curr;
-
- for (curr = se->list.next; curr != &se->list; curr = curr->next) {
- if (curr->unique == req->u.i.unique) {
- fuse_interrupt_func_t func;
- void *data;
-
- curr->ctr++;
- pthread_mutex_unlock(&se->lock);
-
- /* Ugh, ugly locking */
- pthread_mutex_lock(&curr->lock);
- pthread_mutex_lock(&se->lock);
- curr->interrupted = 1;
- func = curr->u.ni.func;
- data = curr->u.ni.data;
- pthread_mutex_unlock(&se->lock);
- if (func)
- func(curr, data);
- pthread_mutex_unlock(&curr->lock);
-
- pthread_mutex_lock(&se->lock);
- curr->ctr--;
- if (!curr->ctr)
- destroy_req(curr);
-
- return 1;
- }
- }
- for (curr = se->interrupts.next; curr != &se->interrupts;
- curr = curr->next) {
- if (curr->u.i.unique == req->u.i.unique)
- return 1;
- }
- return 0;
+ struct fuse_req *curr;
+
+ for (curr = se->list.next; curr != &se->list; curr = curr->next) {
+ if (curr->unique == req->u.i.unique) {
+ fuse_interrupt_func_t func;
+ void *data;
+
+ curr->ctr++;
+ pthread_mutex_unlock(&se->lock);
+
+ /* Ugh, ugly locking */
+ pthread_mutex_lock(&curr->lock);
+ pthread_mutex_lock(&se->lock);
+ curr->interrupted = 1;
+ func = curr->u.ni.func;
+ data = curr->u.ni.data;
+ pthread_mutex_unlock(&se->lock);
+ if (func) {
+ func(curr, data);
+ }
+ pthread_mutex_unlock(&curr->lock);
+
+ pthread_mutex_lock(&se->lock);
+ curr->ctr--;
+ if (!curr->ctr) {
+ destroy_req(curr);
+ }
+
+ return 1;
+ }
+ }
+ for (curr = se->interrupts.next; curr != &se->interrupts;
+ curr = curr->next) {
+ if (curr->u.i.unique == req->u.i.unique) {
+ return 1;
+ }
+ }
+ return 0;
}
static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
- struct fuse_session *se = req->se;
+ struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *)inarg;
+ struct fuse_session *se = req->se;
- (void) nodeid;
- if (se->debug)
- fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
- (unsigned long long) arg->unique);
+ (void)nodeid;
+ if (se->debug) {
+ fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
+ (unsigned long long)arg->unique);
+ }
- req->u.i.unique = arg->unique;
+ req->u.i.unique = arg->unique;
- pthread_mutex_lock(&se->lock);
- if (find_interrupted(se, req))
- destroy_req(req);
- else
- list_add_req(req, &se->interrupts);
- pthread_mutex_unlock(&se->lock);
+ pthread_mutex_lock(&se->lock);
+ if (find_interrupted(se, req)) {
+ destroy_req(req);
+ } else {
+ list_add_req(req, &se->interrupts);
+ }
+ pthread_mutex_unlock(&se->lock);
}
static struct fuse_req *check_interrupt(struct fuse_session *se,
- struct fuse_req *req)
-{
- struct fuse_req *curr;
-
- for (curr = se->interrupts.next; curr != &se->interrupts;
- curr = curr->next) {
- if (curr->u.i.unique == req->unique) {
- req->interrupted = 1;
- list_del_req(curr);
- free(curr);
- return NULL;
- }
- }
- curr = se->interrupts.next;
- if (curr != &se->interrupts) {
- list_del_req(curr);
- list_init_req(curr);
- return curr;
- } else
- return NULL;
+ struct fuse_req *req)
+{
+ struct fuse_req *curr;
+
+ for (curr = se->interrupts.next; curr != &se->interrupts;
+ curr = curr->next) {
+ if (curr->u.i.unique == req->unique) {
+ req->interrupted = 1;
+ list_del_req(curr);
+ free(curr);
+ return NULL;
+ }
+ }
+ curr = se->interrupts.next;
+ if (curr != &se->interrupts) {
+ list_del_req(curr);
+ list_init_req(curr);
+ return curr;
+ } else {
+ return NULL;
+ }
}
static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
+ struct fuse_bmap_in *arg = (struct fuse_bmap_in *)inarg;
- if (req->se->op.bmap)
- req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.bmap) {
+ req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
- unsigned int flags = arg->flags;
- void *in_buf = arg->in_size ? PARAM(arg) : NULL;
- struct fuse_file_info fi;
+ struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *)inarg;
+ unsigned int flags = arg->flags;
+ void *in_buf = arg->in_size ? PARAM(arg) : NULL;
+ struct fuse_file_info fi;
- if (flags & FUSE_IOCTL_DIR &&
- !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
- fuse_reply_err(req, ENOTTY);
- return;
- }
+ if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
+ fuse_reply_err(req, ENOTTY);
+ return;
+ }
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
- !(flags & FUSE_IOCTL_32BIT)) {
- req->ioctl_64bit = 1;
- }
+ if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
+ !(flags & FUSE_IOCTL_32BIT)) {
+ req->ioctl_64bit = 1;
+ }
- if (req->se->op.ioctl)
- req->se->op.ioctl(req, nodeid, arg->cmd,
- (void *)(uintptr_t)arg->arg, &fi, flags,
- in_buf, arg->in_size, arg->out_size);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.ioctl) {
+ req->se->op.ioctl(req, nodeid, arg->cmd, (void *)(uintptr_t)arg->arg,
+ &fi, flags, in_buf, arg->in_size, arg->out_size);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
{
- free(ph);
+ free(ph);
}
static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_poll_in *arg = (struct fuse_poll_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fi.poll_events = arg->events;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fi.poll_events = arg->events;
- if (req->se->op.poll) {
- struct fuse_pollhandle *ph = NULL;
+ if (req->se->op.poll) {
+ struct fuse_pollhandle *ph = NULL;
- if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
- ph = malloc(sizeof(struct fuse_pollhandle));
- if (ph == NULL) {
- fuse_reply_err(req, ENOMEM);
- return;
- }
- ph->kh = arg->kh;
- ph->se = req->se;
- }
+ if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
+ ph = malloc(sizeof(struct fuse_pollhandle));
+ if (ph == NULL) {
+ fuse_reply_err(req, ENOMEM);
+ return;
+ }
+ ph->kh = arg->kh;
+ ph->se = req->se;
+ }
- req->se->op.poll(req, nodeid, &fi, ph);
- } else {
- fuse_reply_err(req, ENOSYS);
- }
+ req->se->op.poll(req, nodeid, &fi, ph);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- if (req->se->op.fallocate)
- req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.fallocate) {
+ req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length,
+ &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
-static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void *inarg)
+static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
+ const void *inarg)
{
- struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in *) inarg;
- struct fuse_file_info fi_in, fi_out;
+ struct fuse_copy_file_range_in *arg =
+ (struct fuse_copy_file_range_in *)inarg;
+ struct fuse_file_info fi_in, fi_out;
- memset(&fi_in, 0, sizeof(fi_in));
- fi_in.fh = arg->fh_in;
+ memset(&fi_in, 0, sizeof(fi_in));
+ fi_in.fh = arg->fh_in;
- memset(&fi_out, 0, sizeof(fi_out));
- fi_out.fh = arg->fh_out;
+ memset(&fi_out, 0, sizeof(fi_out));
+ fi_out.fh = arg->fh_out;
- if (req->se->op.copy_file_range)
- req->se->op.copy_file_range(req, nodeid_in, arg->off_in,
- &fi_in, arg->nodeid_out,
- arg->off_out, &fi_out, arg->len,
- arg->flags);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.copy_file_range) {
+ req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in,
+ arg->nodeid_out, arg->off_out, &fi_out,
+ arg->len, arg->flags);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_lseek_in *arg = (struct fuse_lseek_in *) inarg;
- struct fuse_file_info fi;
+ struct fuse_lseek_in *arg = (struct fuse_lseek_in *)inarg;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- if (req->se->op.lseek)
- req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
- else
- fuse_reply_err(req, ENOSYS);
+ if (req->se->op.lseek) {
+ req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
+ } else {
+ fuse_reply_err(req, ENOSYS);
+ }
}
static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
- struct fuse_init_out outarg;
- struct fuse_session *se = req->se;
- size_t bufsize = se->bufsize;
- size_t outargsize = sizeof(outarg);
-
- (void) nodeid;
- if (se->debug) {
- fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
- if (arg->major == 7 && arg->minor >= 6) {
- fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
- fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
- arg->max_readahead);
- }
- }
- se->conn.proto_major = arg->major;
- se->conn.proto_minor = arg->minor;
- se->conn.capable = 0;
- se->conn.want = 0;
-
- memset(&outarg, 0, sizeof(outarg));
- outarg.major = FUSE_KERNEL_VERSION;
- outarg.minor = FUSE_KERNEL_MINOR_VERSION;
-
- if (arg->major < 7) {
- fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
- arg->major, arg->minor);
- fuse_reply_err(req, EPROTO);
- return;
- }
-
- if (arg->major > 7) {
- /* Wait for a second INIT request with a 7.X version */
- send_reply_ok(req, &outarg, sizeof(outarg));
- return;
- }
-
- if (arg->minor >= 6) {
- if (arg->max_readahead < se->conn.max_readahead)
- se->conn.max_readahead = arg->max_readahead;
- if (arg->flags & FUSE_ASYNC_READ)
- se->conn.capable |= FUSE_CAP_ASYNC_READ;
- if (arg->flags & FUSE_POSIX_LOCKS)
- se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
- if (arg->flags & FUSE_ATOMIC_O_TRUNC)
- se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
- if (arg->flags & FUSE_EXPORT_SUPPORT)
- se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
- if (arg->flags & FUSE_DONT_MASK)
- se->conn.capable |= FUSE_CAP_DONT_MASK;
- if (arg->flags & FUSE_FLOCK_LOCKS)
- se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
- if (arg->flags & FUSE_AUTO_INVAL_DATA)
- se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
- if (arg->flags & FUSE_DO_READDIRPLUS)
- se->conn.capable |= FUSE_CAP_READDIRPLUS;
- if (arg->flags & FUSE_READDIRPLUS_AUTO)
- se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
- if (arg->flags & FUSE_ASYNC_DIO)
- se->conn.capable |= FUSE_CAP_ASYNC_DIO;
- if (arg->flags & FUSE_WRITEBACK_CACHE)
- se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
- if (arg->flags & FUSE_NO_OPEN_SUPPORT)
- se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
- if (arg->flags & FUSE_PARALLEL_DIROPS)
- se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
- if (arg->flags & FUSE_POSIX_ACL)
- se->conn.capable |= FUSE_CAP_POSIX_ACL;
- if (arg->flags & FUSE_HANDLE_KILLPRIV)
- se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
- if (arg->flags & FUSE_NO_OPENDIR_SUPPORT)
- se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
- if (!(arg->flags & FUSE_MAX_PAGES)) {
- size_t max_bufsize =
- FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
- + FUSE_BUFFER_HEADER_SIZE;
- if (bufsize > max_bufsize) {
- bufsize = max_bufsize;
- }
- }
- } else {
- se->conn.max_readahead = 0;
- }
-
- if (se->conn.proto_minor >= 14) {
+ struct fuse_init_in *arg = (struct fuse_init_in *)inarg;
+ struct fuse_init_out outarg;
+ struct fuse_session *se = req->se;
+ size_t bufsize = se->bufsize;
+ size_t outargsize = sizeof(outarg);
+
+ (void)nodeid;
+ if (se->debug) {
+ fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
+ if (arg->major == 7 && arg->minor >= 6) {
+ fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
+ fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
+ arg->max_readahead);
+ }
+ }
+ se->conn.proto_major = arg->major;
+ se->conn.proto_minor = arg->minor;
+ se->conn.capable = 0;
+ se->conn.want = 0;
+
+ memset(&outarg, 0, sizeof(outarg));
+ outarg.major = FUSE_KERNEL_VERSION;
+ outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+
+ if (arg->major < 7) {
+ fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
+ arg->major, arg->minor);
+ fuse_reply_err(req, EPROTO);
+ return;
+ }
+
+ if (arg->major > 7) {
+ /* Wait for a second INIT request with a 7.X version */
+ send_reply_ok(req, &outarg, sizeof(outarg));
+ return;
+ }
+
+ if (arg->minor >= 6) {
+ if (arg->max_readahead < se->conn.max_readahead) {
+ se->conn.max_readahead = arg->max_readahead;
+ }
+ if (arg->flags & FUSE_ASYNC_READ) {
+ se->conn.capable |= FUSE_CAP_ASYNC_READ;
+ }
+ if (arg->flags & FUSE_POSIX_LOCKS) {
+ se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
+ }
+ if (arg->flags & FUSE_ATOMIC_O_TRUNC) {
+ se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
+ }
+ if (arg->flags & FUSE_EXPORT_SUPPORT) {
+ se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
+ }
+ if (arg->flags & FUSE_DONT_MASK) {
+ se->conn.capable |= FUSE_CAP_DONT_MASK;
+ }
+ if (arg->flags & FUSE_FLOCK_LOCKS) {
+ se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
+ }
+ if (arg->flags & FUSE_AUTO_INVAL_DATA) {
+ se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
+ }
+ if (arg->flags & FUSE_DO_READDIRPLUS) {
+ se->conn.capable |= FUSE_CAP_READDIRPLUS;
+ }
+ if (arg->flags & FUSE_READDIRPLUS_AUTO) {
+ se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
+ }
+ if (arg->flags & FUSE_ASYNC_DIO) {
+ se->conn.capable |= FUSE_CAP_ASYNC_DIO;
+ }
+ if (arg->flags & FUSE_WRITEBACK_CACHE) {
+ se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
+ }
+ if (arg->flags & FUSE_NO_OPEN_SUPPORT) {
+ se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
+ }
+ if (arg->flags & FUSE_PARALLEL_DIROPS) {
+ se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
+ }
+ if (arg->flags & FUSE_POSIX_ACL) {
+ se->conn.capable |= FUSE_CAP_POSIX_ACL;
+ }
+ if (arg->flags & FUSE_HANDLE_KILLPRIV) {
+ se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
+ }
+ if (arg->flags & FUSE_NO_OPENDIR_SUPPORT) {
+ se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
+ }
+ if (!(arg->flags & FUSE_MAX_PAGES)) {
+ size_t max_bufsize =
+ FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() +
+ FUSE_BUFFER_HEADER_SIZE;
+ if (bufsize > max_bufsize) {
+ bufsize = max_bufsize;
+ }
+ }
+ } else {
+ se->conn.max_readahead = 0;
+ }
+
+ if (se->conn.proto_minor >= 14) {
#ifdef HAVE_SPLICE
#ifdef HAVE_VMSPLICE
- se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
+ se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
#endif
- se->conn.capable |= FUSE_CAP_SPLICE_READ;
+ se->conn.capable |= FUSE_CAP_SPLICE_READ;
#endif
- }
- if (se->conn.proto_minor >= 18)
- se->conn.capable |= FUSE_CAP_IOCTL_DIR;
-
- /* Default settings for modern filesystems.
- *
- * Most of these capabilities were disabled by default in
- * libfuse2 for backwards compatibility reasons. In libfuse3,
- * we can finally enable them by default (as long as they're
- * supported by the kernel).
- */
-#define LL_SET_DEFAULT(cond, cap) \
- if ((cond) && (se->conn.capable & (cap))) \
- se->conn.want |= (cap)
- LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
- LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
- LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
- LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
- LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
- LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
- LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
- LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
- LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
- FUSE_CAP_POSIX_LOCKS);
- LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
- LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
- LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
- FUSE_CAP_READDIRPLUS_AUTO);
- se->conn.time_gran = 1;
-
- if (bufsize < FUSE_MIN_READ_BUFFER) {
- fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
- bufsize);
- bufsize = FUSE_MIN_READ_BUFFER;
- }
- se->bufsize = bufsize;
-
- if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
- se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
-
- se->got_init = 1;
- if (se->op.init)
- se->op.init(se->userdata, &se->conn);
-
- if (se->conn.want & (~se->conn.capable)) {
- fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities "
- "0x%x that are not supported by kernel, aborting.\n",
- se->conn.want & (~se->conn.capable));
- fuse_reply_err(req, EPROTO);
- se->error = -EPROTO;
- fuse_session_exit(se);
- return;
- }
-
- if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
- se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
- }
- if (arg->flags & FUSE_MAX_PAGES) {
- outarg.flags |= FUSE_MAX_PAGES;
- outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
- }
-
- /* Always enable big writes, this is superseded
- by the max_write option */
- outarg.flags |= FUSE_BIG_WRITES;
-
- if (se->conn.want & FUSE_CAP_ASYNC_READ)
- outarg.flags |= FUSE_ASYNC_READ;
- if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
- outarg.flags |= FUSE_POSIX_LOCKS;
- if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
- outarg.flags |= FUSE_ATOMIC_O_TRUNC;
- if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
- outarg.flags |= FUSE_EXPORT_SUPPORT;
- if (se->conn.want & FUSE_CAP_DONT_MASK)
- outarg.flags |= FUSE_DONT_MASK;
- if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
- outarg.flags |= FUSE_FLOCK_LOCKS;
- if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
- outarg.flags |= FUSE_AUTO_INVAL_DATA;
- if (se->conn.want & FUSE_CAP_READDIRPLUS)
- outarg.flags |= FUSE_DO_READDIRPLUS;
- if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
- outarg.flags |= FUSE_READDIRPLUS_AUTO;
- if (se->conn.want & FUSE_CAP_ASYNC_DIO)
- outarg.flags |= FUSE_ASYNC_DIO;
- if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
- outarg.flags |= FUSE_WRITEBACK_CACHE;
- if (se->conn.want & FUSE_CAP_POSIX_ACL)
- outarg.flags |= FUSE_POSIX_ACL;
- outarg.max_readahead = se->conn.max_readahead;
- outarg.max_write = se->conn.max_write;
- if (se->conn.proto_minor >= 13) {
- if (se->conn.max_background >= (1 << 16))
- se->conn.max_background = (1 << 16) - 1;
- if (se->conn.congestion_threshold > se->conn.max_background)
- se->conn.congestion_threshold = se->conn.max_background;
- if (!se->conn.congestion_threshold) {
- se->conn.congestion_threshold =
- se->conn.max_background * 3 / 4;
- }
-
- outarg.max_background = se->conn.max_background;
- outarg.congestion_threshold = se->conn.congestion_threshold;
- }
- if (se->conn.proto_minor >= 23)
- outarg.time_gran = se->conn.time_gran;
-
- if (se->debug) {
- fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor);
- fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
- fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n",
- outarg.max_readahead);
- fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
- fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n",
- outarg.max_background);
- fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n",
- outarg.congestion_threshold);
- fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n",
- outarg.time_gran);
- }
- if (arg->minor < 5)
- outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
- else if (arg->minor < 23)
- outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
-
- send_reply_ok(req, &outarg, outargsize);
+ }
+ if (se->conn.proto_minor >= 18) {
+ se->conn.capable |= FUSE_CAP_IOCTL_DIR;
+ }
+
+ /*
+ * Default settings for modern filesystems.
+ *
+ * Most of these capabilities were disabled by default in
+ * libfuse2 for backwards compatibility reasons. In libfuse3,
+ * we can finally enable them by default (as long as they're
+ * supported by the kernel).
+ */
+#define LL_SET_DEFAULT(cond, cap) \
+ if ((cond) && (se->conn.capable & (cap))) \
+ se->conn.want |= (cap)
+ LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
+ LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
+ LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
+ LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
+ LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
+ LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
+ LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
+ LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
+ LL_SET_DEFAULT(se->op.getlk && se->op.setlk, FUSE_CAP_POSIX_LOCKS);
+ LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
+ LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
+ LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
+ FUSE_CAP_READDIRPLUS_AUTO);
+ se->conn.time_gran = 1;
+
+ if (bufsize < FUSE_MIN_READ_BUFFER) {
+ fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
+ bufsize);
+ bufsize = FUSE_MIN_READ_BUFFER;
+ }
+ se->bufsize = bufsize;
+
+ if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE) {
+ se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
+ }
+
+ se->got_init = 1;
+ if (se->op.init) {
+ se->op.init(se->userdata, &se->conn);
+ }
+
+ if (se->conn.want & (~se->conn.capable)) {
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: error: filesystem requested capabilities "
+ "0x%x that are not supported by kernel, aborting.\n",
+ se->conn.want & (~se->conn.capable));
+ fuse_reply_err(req, EPROTO);
+ se->error = -EPROTO;
+ fuse_session_exit(se);
+ return;
+ }
+
+ if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
+ se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
+ }
+ if (arg->flags & FUSE_MAX_PAGES) {
+ outarg.flags |= FUSE_MAX_PAGES;
+ outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
+ }
+
+ /*
+ * Always enable big writes, this is superseded
+ * by the max_write option
+ */
+ outarg.flags |= FUSE_BIG_WRITES;
+
+ if (se->conn.want & FUSE_CAP_ASYNC_READ) {
+ outarg.flags |= FUSE_ASYNC_READ;
+ }
+ if (se->conn.want & FUSE_CAP_POSIX_LOCKS) {
+ outarg.flags |= FUSE_POSIX_LOCKS;
+ }
+ if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) {
+ outarg.flags |= FUSE_ATOMIC_O_TRUNC;
+ }
+ if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT) {
+ outarg.flags |= FUSE_EXPORT_SUPPORT;
+ }
+ if (se->conn.want & FUSE_CAP_DONT_MASK) {
+ outarg.flags |= FUSE_DONT_MASK;
+ }
+ if (se->conn.want & FUSE_CAP_FLOCK_LOCKS) {
+ outarg.flags |= FUSE_FLOCK_LOCKS;
+ }
+ if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA) {
+ outarg.flags |= FUSE_AUTO_INVAL_DATA;
+ }
+ if (se->conn.want & FUSE_CAP_READDIRPLUS) {
+ outarg.flags |= FUSE_DO_READDIRPLUS;
+ }
+ if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO) {
+ outarg.flags |= FUSE_READDIRPLUS_AUTO;
+ }
+ if (se->conn.want & FUSE_CAP_ASYNC_DIO) {
+ outarg.flags |= FUSE_ASYNC_DIO;
+ }
+ if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE) {
+ outarg.flags |= FUSE_WRITEBACK_CACHE;
+ }
+ if (se->conn.want & FUSE_CAP_POSIX_ACL) {
+ outarg.flags |= FUSE_POSIX_ACL;
+ }
+ outarg.max_readahead = se->conn.max_readahead;
+ outarg.max_write = se->conn.max_write;
+ if (se->conn.proto_minor >= 13) {
+ if (se->conn.max_background >= (1 << 16)) {
+ se->conn.max_background = (1 << 16) - 1;
+ }
+ if (se->conn.congestion_threshold > se->conn.max_background) {
+ se->conn.congestion_threshold = se->conn.max_background;
+ }
+ if (!se->conn.congestion_threshold) {
+ se->conn.congestion_threshold = se->conn.max_background * 3 / 4;
+ }
+
+ outarg.max_background = se->conn.max_background;
+ outarg.congestion_threshold = se->conn.congestion_threshold;
+ }
+ if (se->conn.proto_minor >= 23) {
+ outarg.time_gran = se->conn.time_gran;
+ }
+
+ if (se->debug) {
+ fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major,
+ outarg.minor);
+ fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
+ fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n",
+ outarg.max_readahead);
+ fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
+ fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n",
+ outarg.max_background);
+ fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n",
+ outarg.congestion_threshold);
+ fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n", outarg.time_gran);
+ }
+ if (arg->minor < 5) {
+ outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
+ } else if (arg->minor < 23) {
+ outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
+ }
+
+ send_reply_ok(req, &outarg, outargsize);
}
static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
- struct fuse_session *se = req->se;
+ struct fuse_session *se = req->se;
- (void) nodeid;
- (void) inarg;
+ (void)nodeid;
+ (void)inarg;
- se->got_destroy = 1;
- if (se->op.destroy)
- se->op.destroy(se->userdata);
+ se->got_destroy = 1;
+ if (se->op.destroy) {
+ se->op.destroy(se->userdata);
+ }
- send_reply_ok(req, NULL, 0);
+ send_reply_ok(req, NULL, 0);
}
static void list_del_nreq(struct fuse_notify_req *nreq)
{
- struct fuse_notify_req *prev = nreq->prev;
- struct fuse_notify_req *next = nreq->next;
- prev->next = next;
- next->prev = prev;
+ struct fuse_notify_req *prev = nreq->prev;
+ struct fuse_notify_req *next = nreq->next;
+ prev->next = next;
+ next->prev = prev;
}
static void list_add_nreq(struct fuse_notify_req *nreq,
- struct fuse_notify_req *next)
+ struct fuse_notify_req *next)
{
- struct fuse_notify_req *prev = next->prev;
- nreq->next = next;
- nreq->prev = prev;
- prev->next = nreq;
- next->prev = nreq;
+ struct fuse_notify_req *prev = next->prev;
+ nreq->next = next;
+ nreq->prev = prev;
+ prev->next = nreq;
+ next->prev = nreq;
}
static void list_init_nreq(struct fuse_notify_req *nreq)
{
- nreq->next = nreq;
- nreq->prev = nreq;
+ nreq->next = nreq;
+ nreq->prev = nreq;
}
static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
- const void *inarg, const struct fuse_buf *buf)
+ const void *inarg, const struct fuse_buf *buf)
{
- struct fuse_session *se = req->se;
- struct fuse_notify_req *nreq;
- struct fuse_notify_req *head;
+ struct fuse_session *se = req->se;
+ struct fuse_notify_req *nreq;
+ struct fuse_notify_req *head;
- pthread_mutex_lock(&se->lock);
- head = &se->notify_list;
- for (nreq = head->next; nreq != head; nreq = nreq->next) {
- if (nreq->unique == req->unique) {
- list_del_nreq(nreq);
- break;
- }
- }
- pthread_mutex_unlock(&se->lock);
+ pthread_mutex_lock(&se->lock);
+ head = &se->notify_list;
+ for (nreq = head->next; nreq != head; nreq = nreq->next) {
+ if (nreq->unique == req->unique) {
+ list_del_nreq(nreq);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&se->lock);
- if (nreq != head)
- nreq->reply(nreq, req, nodeid, inarg, buf);
+ if (nreq != head) {
+ nreq->reply(nreq, req, nodeid, inarg, buf);
+ }
}
static int send_notify_iov(struct fuse_session *se, int notify_code,
- struct iovec *iov, int count)
+ struct iovec *iov, int count)
{
- struct fuse_out_header out;
+ struct fuse_out_header out;
- if (!se->got_init)
- return -ENOTCONN;
+ if (!se->got_init) {
+ return -ENOTCONN;
+ }
- out.unique = 0;
- out.error = notify_code;
- iov[0].iov_base = &out;
- iov[0].iov_len = sizeof(struct fuse_out_header);
+ out.unique = 0;
+ out.error = notify_code;
+ iov[0].iov_base = &out;
+ iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(se, NULL, iov, count);
+ return fuse_send_msg(se, NULL, iov, count);
}
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
{
- if (ph != NULL) {
- struct fuse_notify_poll_wakeup_out outarg;
- struct iovec iov[2];
+ if (ph != NULL) {
+ struct fuse_notify_poll_wakeup_out outarg;
+ struct iovec iov[2];
- outarg.kh = ph->kh;
+ outarg.kh = ph->kh;
- iov[1].iov_base = &outarg;
- iov[1].iov_len = sizeof(outarg);
+ iov[1].iov_base = &outarg;
+ iov[1].iov_len = sizeof(outarg);
- return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
- } else {
- return 0;
- }
+ return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
+ } else {
+ return 0;
+ }
}
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
- off_t off, off_t len)
+ off_t off, off_t len)
{
- struct fuse_notify_inval_inode_out outarg;
- struct iovec iov[2];
+ struct fuse_notify_inval_inode_out outarg;
+ struct iovec iov[2];
+
+ if (!se) {
+ return -EINVAL;
+ }
- if (!se)
- return -EINVAL;
+ if (se->conn.proto_major < 6 || se->conn.proto_minor < 12) {
+ return -ENOSYS;
+ }
- if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
- return -ENOSYS;
-
- outarg.ino = ino;
- outarg.off = off;
- outarg.len = len;
+ outarg.ino = ino;
+ outarg.off = off;
+ outarg.len = len;
- iov[1].iov_base = &outarg;
- iov[1].iov_len = sizeof(outarg);
+ iov[1].iov_base = &outarg;
+ iov[1].iov_len = sizeof(outarg);
- return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
+ return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
}
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
- const char *name, size_t namelen)
+ const char *name, size_t namelen)
{
- struct fuse_notify_inval_entry_out outarg;
- struct iovec iov[3];
+ struct fuse_notify_inval_entry_out outarg;
+ struct iovec iov[3];
+
+ if (!se) {
+ return -EINVAL;
+ }
- if (!se)
- return -EINVAL;
-
- if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
- return -ENOSYS;
+ if (se->conn.proto_major < 6 || se->conn.proto_minor < 12) {
+ return -ENOSYS;
+ }
- outarg.parent = parent;
- outarg.namelen = namelen;
- outarg.padding = 0;
+ outarg.parent = parent;
+ outarg.namelen = namelen;
+ outarg.padding = 0;
- iov[1].iov_base = &outarg;
- iov[1].iov_len = sizeof(outarg);
- iov[2].iov_base = (void *)name;
- iov[2].iov_len = namelen + 1;
+ iov[1].iov_base = &outarg;
+ iov[1].iov_len = sizeof(outarg);
+ iov[2].iov_base = (void *)name;
+ iov[2].iov_len = namelen + 1;
- return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
+ return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
}
-int fuse_lowlevel_notify_delete(struct fuse_session *se,
- fuse_ino_t parent, fuse_ino_t child,
- const char *name, size_t namelen)
+int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+ fuse_ino_t child, const char *name,
+ size_t namelen)
{
- struct fuse_notify_delete_out outarg;
- struct iovec iov[3];
+ struct fuse_notify_delete_out outarg;
+ struct iovec iov[3];
- if (!se)
- return -EINVAL;
+ if (!se) {
+ return -EINVAL;
+ }
- if (se->conn.proto_major < 6 || se->conn.proto_minor < 18)
- return -ENOSYS;
+ if (se->conn.proto_major < 6 || se->conn.proto_minor < 18) {
+ return -ENOSYS;
+ }
- outarg.parent = parent;
- outarg.child = child;
- outarg.namelen = namelen;
- outarg.padding = 0;
+ outarg.parent = parent;
+ outarg.child = child;
+ outarg.namelen = namelen;
+ outarg.padding = 0;
- iov[1].iov_base = &outarg;
- iov[1].iov_len = sizeof(outarg);
- iov[2].iov_base = (void *)name;
- iov[2].iov_len = namelen + 1;
+ iov[1].iov_base = &outarg;
+ iov[1].iov_len = sizeof(outarg);
+ iov[2].iov_base = (void *)name;
+ iov[2].iov_len = namelen + 1;
- return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
+ return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
}
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
- off_t offset, struct fuse_bufvec *bufv,
- enum fuse_buf_copy_flags flags)
+ off_t offset, struct fuse_bufvec *bufv,
+ enum fuse_buf_copy_flags flags)
{
- struct fuse_out_header out;
- struct fuse_notify_store_out outarg;
- struct iovec iov[3];
- size_t size = fuse_buf_size(bufv);
- int res;
+ struct fuse_out_header out;
+ struct fuse_notify_store_out outarg;
+ struct iovec iov[3];
+ size_t size = fuse_buf_size(bufv);
+ int res;
- if (!se)
- return -EINVAL;
+ if (!se) {
+ return -EINVAL;
+ }
- if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
- return -ENOSYS;
+ if (se->conn.proto_major < 6 || se->conn.proto_minor < 15) {
+ return -ENOSYS;
+ }
- out.unique = 0;
- out.error = FUSE_NOTIFY_STORE;
+ out.unique = 0;
+ out.error = FUSE_NOTIFY_STORE;
- outarg.nodeid = ino;
- outarg.offset = offset;
- outarg.size = size;
- outarg.padding = 0;
+ outarg.nodeid = ino;
+ outarg.offset = offset;
+ outarg.size = size;
+ outarg.padding = 0;
- iov[0].iov_base = &out;
- iov[0].iov_len = sizeof(out);
- iov[1].iov_base = &outarg;
- iov[1].iov_len = sizeof(outarg);
+ iov[0].iov_base = &out;
+ iov[0].iov_len = sizeof(out);
+ iov[1].iov_base = &outarg;
+ iov[1].iov_len = sizeof(outarg);
- res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
- if (res > 0)
- res = -res;
+ res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
+ if (res > 0) {
+ res = -res;
+ }
- return res;
+ return res;
}
struct fuse_retrieve_req {
- struct fuse_notify_req nreq;
- void *cookie;
+ struct fuse_notify_req nreq;
+ void *cookie;
};
-static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
- fuse_req_t req, fuse_ino_t ino,
- const void *inarg,
- const struct fuse_buf *ibuf)
-{
- struct fuse_session *se = req->se;
- struct fuse_retrieve_req *rreq =
- container_of(nreq, struct fuse_retrieve_req, nreq);
- const struct fuse_notify_retrieve_in *arg = inarg;
- struct fuse_bufvec bufv = {
- .buf[0] = *ibuf,
- .count = 1,
- };
-
- if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
- bufv.buf[0].mem = PARAM(arg);
-
- bufv.buf[0].size -= sizeof(struct fuse_in_header) +
- sizeof(struct fuse_notify_retrieve_in);
-
- if (bufv.buf[0].size < arg->size) {
- fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
- fuse_reply_none(req);
- goto out;
- }
- bufv.buf[0].size = arg->size;
-
- if (se->op.retrieve_reply) {
- se->op.retrieve_reply(req, rreq->cookie, ino,
- arg->offset, &bufv);
- } else {
- fuse_reply_none(req);
- }
+static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, fuse_req_t req,
+ fuse_ino_t ino, const void *inarg,
+ const struct fuse_buf *ibuf)
+{
+ struct fuse_session *se = req->se;
+ struct fuse_retrieve_req *rreq =
+ container_of(nreq, struct fuse_retrieve_req, nreq);
+ const struct fuse_notify_retrieve_in *arg = inarg;
+ struct fuse_bufvec bufv = {
+ .buf[0] = *ibuf,
+ .count = 1,
+ };
+
+ if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
+ bufv.buf[0].mem = PARAM(arg);
+ }
+
+ bufv.buf[0].size -=
+ sizeof(struct fuse_in_header) + sizeof(struct fuse_notify_retrieve_in);
+
+ if (bufv.buf[0].size < arg->size) {
+ fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
+ fuse_reply_none(req);
+ goto out;
+ }
+ bufv.buf[0].size = arg->size;
+
+ if (se->op.retrieve_reply) {
+ se->op.retrieve_reply(req, rreq->cookie, ino, arg->offset, &bufv);
+ } else {
+ fuse_reply_none(req);
+ }
out:
- free(rreq);
+ free(rreq);
}
int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
- size_t size, off_t offset, void *cookie)
+ size_t size, off_t offset, void *cookie)
{
- struct fuse_notify_retrieve_out outarg;
- struct iovec iov[2];
- struct fuse_retrieve_req *rreq;
- int err;
+ struct fuse_notify_retrieve_out outarg;
+ struct iovec iov[2];
+ struct fuse_retrieve_req *rreq;
+ int err;
- if (!se)
- return -EINVAL;
+ if (!se) {
+ return -EINVAL;
+ }
- if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
- return -ENOSYS;
+ if (se->conn.proto_major < 6 || se->conn.proto_minor < 15) {
+ return -ENOSYS;
+ }
- rreq = malloc(sizeof(*rreq));
- if (rreq == NULL)
- return -ENOMEM;
+ rreq = malloc(sizeof(*rreq));
+ if (rreq == NULL) {
+ return -ENOMEM;
+ }
- pthread_mutex_lock(&se->lock);
- rreq->cookie = cookie;
- rreq->nreq.unique = se->notify_ctr++;
- rreq->nreq.reply = fuse_ll_retrieve_reply;
- list_add_nreq(&rreq->nreq, &se->notify_list);
- pthread_mutex_unlock(&se->lock);
+ pthread_mutex_lock(&se->lock);
+ rreq->cookie = cookie;
+ rreq->nreq.unique = se->notify_ctr++;
+ rreq->nreq.reply = fuse_ll_retrieve_reply;
+ list_add_nreq(&rreq->nreq, &se->notify_list);
+ pthread_mutex_unlock(&se->lock);
- outarg.notify_unique = rreq->nreq.unique;
- outarg.nodeid = ino;
- outarg.offset = offset;
- outarg.size = size;
- outarg.padding = 0;
+ outarg.notify_unique = rreq->nreq.unique;
+ outarg.nodeid = ino;
+ outarg.offset = offset;
+ outarg.size = size;
+ outarg.padding = 0;
- iov[1].iov_base = &outarg;
- iov[1].iov_len = sizeof(outarg);
+ iov[1].iov_base = &outarg;
+ iov[1].iov_len = sizeof(outarg);
- err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
- if (err) {
- pthread_mutex_lock(&se->lock);
- list_del_nreq(&rreq->nreq);
- pthread_mutex_unlock(&se->lock);
- free(rreq);
- }
+ err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
+ if (err) {
+ pthread_mutex_lock(&se->lock);
+ list_del_nreq(&rreq->nreq);
+ pthread_mutex_unlock(&se->lock);
+ free(rreq);
+ }
- return err;
+ return err;
}
void *fuse_req_userdata(fuse_req_t req)
{
- return req->se->userdata;
+ return req->se->userdata;
}
const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
{
- return &req->ctx;
+ return &req->ctx;
}
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
- void *data)
+ void *data)
{
- pthread_mutex_lock(&req->lock);
- pthread_mutex_lock(&req->se->lock);
- req->u.ni.func = func;
- req->u.ni.data = data;
- pthread_mutex_unlock(&req->se->lock);
- if (req->interrupted && func)
- func(req, data);
- pthread_mutex_unlock(&req->lock);
+ pthread_mutex_lock(&req->lock);
+ pthread_mutex_lock(&req->se->lock);
+ req->u.ni.func = func;
+ req->u.ni.data = data;
+ pthread_mutex_unlock(&req->se->lock);
+ if (req->interrupted && func) {
+ func(req, data);
+ }
+ pthread_mutex_unlock(&req->lock);
}
int fuse_req_interrupted(fuse_req_t req)
{
- int interrupted;
+ int interrupted;
- pthread_mutex_lock(&req->se->lock);
- interrupted = req->interrupted;
- pthread_mutex_unlock(&req->se->lock);
+ pthread_mutex_lock(&req->se->lock);
+ interrupted = req->interrupted;
+ pthread_mutex_unlock(&req->se->lock);
- return interrupted;
+ return interrupted;
}
static struct {
- void (*func)(fuse_req_t, fuse_ino_t, const void *);
- const char *name;
+ void (*func)(fuse_req_t, fuse_ino_t, const void *);
+ const char *name;
} fuse_ll_ops[] = {
- [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
- [FUSE_FORGET] = { do_forget, "FORGET" },
- [FUSE_GETATTR] = { do_getattr, "GETATTR" },
- [FUSE_SETATTR] = { do_setattr, "SETATTR" },
- [FUSE_READLINK] = { do_readlink, "READLINK" },
- [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
- [FUSE_MKNOD] = { do_mknod, "MKNOD" },
- [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
- [FUSE_UNLINK] = { do_unlink, "UNLINK" },
- [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
- [FUSE_RENAME] = { do_rename, "RENAME" },
- [FUSE_LINK] = { do_link, "LINK" },
- [FUSE_OPEN] = { do_open, "OPEN" },
- [FUSE_READ] = { do_read, "READ" },
- [FUSE_WRITE] = { do_write, "WRITE" },
- [FUSE_STATFS] = { do_statfs, "STATFS" },
- [FUSE_RELEASE] = { do_release, "RELEASE" },
- [FUSE_FSYNC] = { do_fsync, "FSYNC" },
- [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
- [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
- [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
- [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
- [FUSE_FLUSH] = { do_flush, "FLUSH" },
- [FUSE_INIT] = { do_init, "INIT" },
- [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
- [FUSE_READDIR] = { do_readdir, "READDIR" },
- [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
- [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
- [FUSE_GETLK] = { do_getlk, "GETLK" },
- [FUSE_SETLK] = { do_setlk, "SETLK" },
- [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
- [FUSE_ACCESS] = { do_access, "ACCESS" },
- [FUSE_CREATE] = { do_create, "CREATE" },
- [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
- [FUSE_BMAP] = { do_bmap, "BMAP" },
- [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
- [FUSE_POLL] = { do_poll, "POLL" },
- [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
- [FUSE_DESTROY] = { do_destroy, "DESTROY" },
- [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
- [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
- [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
- [FUSE_RENAME2] = { do_rename2, "RENAME2" },
- [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
- [FUSE_LSEEK] = { do_lseek, "LSEEK" },
+ [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
+ [FUSE_FORGET] = { do_forget, "FORGET" },
+ [FUSE_GETATTR] = { do_getattr, "GETATTR" },
+ [FUSE_SETATTR] = { do_setattr, "SETATTR" },
+ [FUSE_READLINK] = { do_readlink, "READLINK" },
+ [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
+ [FUSE_MKNOD] = { do_mknod, "MKNOD" },
+ [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
+ [FUSE_UNLINK] = { do_unlink, "UNLINK" },
+ [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
+ [FUSE_RENAME] = { do_rename, "RENAME" },
+ [FUSE_LINK] = { do_link, "LINK" },
+ [FUSE_OPEN] = { do_open, "OPEN" },
+ [FUSE_READ] = { do_read, "READ" },
+ [FUSE_WRITE] = { do_write, "WRITE" },
+ [FUSE_STATFS] = { do_statfs, "STATFS" },
+ [FUSE_RELEASE] = { do_release, "RELEASE" },
+ [FUSE_FSYNC] = { do_fsync, "FSYNC" },
+ [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
+ [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
+ [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
+ [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
+ [FUSE_FLUSH] = { do_flush, "FLUSH" },
+ [FUSE_INIT] = { do_init, "INIT" },
+ [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
+ [FUSE_READDIR] = { do_readdir, "READDIR" },
+ [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
+ [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
+ [FUSE_GETLK] = { do_getlk, "GETLK" },
+ [FUSE_SETLK] = { do_setlk, "SETLK" },
+ [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
+ [FUSE_ACCESS] = { do_access, "ACCESS" },
+ [FUSE_CREATE] = { do_create, "CREATE" },
+ [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
+ [FUSE_BMAP] = { do_bmap, "BMAP" },
+ [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
+ [FUSE_POLL] = { do_poll, "POLL" },
+ [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
+ [FUSE_DESTROY] = { do_destroy, "DESTROY" },
+ [FUSE_NOTIFY_REPLY] = { (void *)1, "NOTIFY_REPLY" },
+ [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
+ [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS" },
+ [FUSE_RENAME2] = { do_rename2, "RENAME2" },
+ [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
+ [FUSE_LSEEK] = { do_lseek, "LSEEK" },
};
#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
static const char *opname(enum fuse_opcode opcode)
{
- if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
- return "???";
- else
- return fuse_ll_ops[opcode].name;
+ if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) {
+ return "???";
+ } else {
+ return fuse_ll_ops[opcode].name;
+ }
}
void fuse_session_process_buf(struct fuse_session *se,
- const struct fuse_buf *buf)
+ const struct fuse_buf *buf)
{
- fuse_session_process_buf_int(se, buf, NULL);
+ fuse_session_process_buf_int(se, buf, NULL);
}
void fuse_session_process_buf_int(struct fuse_session *se,
- const struct fuse_buf *buf, struct fuse_chan *ch)
-{
- struct fuse_in_header *in;
- const void *inarg;
- struct fuse_req *req;
- int err;
-
- in = buf->mem;
-
- if (se->debug) {
- fuse_log(FUSE_LOG_DEBUG,
- "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
- (unsigned long long) in->unique,
- opname((enum fuse_opcode) in->opcode), in->opcode,
- (unsigned long long) in->nodeid, buf->size, in->pid);
- }
-
- req = fuse_ll_alloc_req(se);
- if (req == NULL) {
- struct fuse_out_header out = {
- .unique = in->unique,
- .error = -ENOMEM,
- };
- struct iovec iov = {
- .iov_base = &out,
- .iov_len = sizeof(struct fuse_out_header),
- };
-
- fuse_send_msg(se, ch, &iov, 1);
- return;
- }
-
- req->unique = in->unique;
- req->ctx.uid = in->uid;
- req->ctx.gid = in->gid;
- req->ctx.pid = in->pid;
- req->ch = ch;
-
- err = EIO;
- if (!se->got_init) {
- enum fuse_opcode expected;
-
- expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
- if (in->opcode != expected)
- goto reply_err;
- } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
- goto reply_err;
-
- err = EACCES;
- /* Implement -o allow_root */
- if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
- in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
- in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
- in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
- in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
- in->opcode != FUSE_NOTIFY_REPLY &&
- in->opcode != FUSE_READDIRPLUS)
- goto reply_err;
-
- err = ENOSYS;
- if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
- goto reply_err;
- if (in->opcode != FUSE_INTERRUPT) {
- struct fuse_req *intr;
- pthread_mutex_lock(&se->lock);
- intr = check_interrupt(se, req);
- list_add_req(req, &se->list);
- pthread_mutex_unlock(&se->lock);
- if (intr)
- fuse_reply_err(intr, EAGAIN);
- }
-
- inarg = (void *) &in[1];
- if (in->opcode == FUSE_WRITE && se->op.write_buf)
- do_write_buf(req, in->nodeid, inarg, buf);
- else if (in->opcode == FUSE_NOTIFY_REPLY)
- do_notify_reply(req, in->nodeid, inarg, buf);
- else
- fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
-
- return;
+ const struct fuse_buf *buf,
+ struct fuse_chan *ch)
+{
+ struct fuse_in_header *in;
+ const void *inarg;
+ struct fuse_req *req;
+ int err;
+
+ in = buf->mem;
+
+ if (se->debug) {
+ fuse_log(FUSE_LOG_DEBUG,
+ "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, "
+ "pid: %u\n",
+ (unsigned long long)in->unique,
+ opname((enum fuse_opcode)in->opcode), in->opcode,
+ (unsigned long long)in->nodeid, buf->size, in->pid);
+ }
+
+ req = fuse_ll_alloc_req(se);
+ if (req == NULL) {
+ struct fuse_out_header out = {
+ .unique = in->unique,
+ .error = -ENOMEM,
+ };
+ struct iovec iov = {
+ .iov_base = &out,
+ .iov_len = sizeof(struct fuse_out_header),
+ };
+
+ fuse_send_msg(se, ch, &iov, 1);
+ return;
+ }
+
+ req->unique = in->unique;
+ req->ctx.uid = in->uid;
+ req->ctx.gid = in->gid;
+ req->ctx.pid = in->pid;
+ req->ch = ch;
+
+ err = EIO;
+ if (!se->got_init) {
+ enum fuse_opcode expected;
+
+ expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
+ if (in->opcode != expected) {
+ goto reply_err;
+ }
+ } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) {
+ goto reply_err;
+ }
+
+ err = EACCES;
+ /* Implement -o allow_root */
+ if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
+ in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
+ in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
+ in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
+ in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
+ in->opcode != FUSE_NOTIFY_REPLY && in->opcode != FUSE_READDIRPLUS) {
+ goto reply_err;
+ }
+
+ err = ENOSYS;
+ if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) {
+ goto reply_err;
+ }
+ if (in->opcode != FUSE_INTERRUPT) {
+ struct fuse_req *intr;
+ pthread_mutex_lock(&se->lock);
+ intr = check_interrupt(se, req);
+ list_add_req(req, &se->list);
+ pthread_mutex_unlock(&se->lock);
+ if (intr) {
+ fuse_reply_err(intr, EAGAIN);
+ }
+ }
+
+ inarg = (void *)&in[1];
+ if (in->opcode == FUSE_WRITE && se->op.write_buf) {
+ do_write_buf(req, in->nodeid, inarg, buf);
+ } else if (in->opcode == FUSE_NOTIFY_REPLY) {
+ do_notify_reply(req, in->nodeid, inarg, buf);
+ } else {
+ fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
+ }
+
+ return;
reply_err:
- fuse_reply_err(req, err);
+ fuse_reply_err(req, err);
}
-#define LL_OPTION(n,o,v) \
- { n, offsetof(struct fuse_session, o), v }
+#define LL_OPTION(n, o, v) \
+ { \
+ n, offsetof(struct fuse_session, o), v \
+ }
static const struct fuse_opt fuse_ll_opts[] = {
- LL_OPTION("debug", debug, 1),
- LL_OPTION("-d", debug, 1),
- LL_OPTION("--debug", debug, 1),
- LL_OPTION("allow_root", deny_others, 1),
- FUSE_OPT_END
+ LL_OPTION("debug", debug, 1), LL_OPTION("-d", debug, 1),
+ LL_OPTION("--debug", debug, 1), LL_OPTION("allow_root", deny_others, 1),
+ FUSE_OPT_END
};
void fuse_lowlevel_version(void)
{
- printf("using FUSE kernel interface version %i.%i\n",
- FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
+ printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION,
+ FUSE_KERNEL_MINOR_VERSION);
}
void fuse_lowlevel_help(void)
{
- /* These are not all options, but the ones that are
- potentially of interest to an end-user */
- printf(
-" -o allow_root allow access by root\n"
-);
+ /*
+ * These are not all options, but the ones that are
+ * potentially of interest to an end-user
+ */
+ printf(" -o allow_root allow access by root\n");
}
void fuse_session_destroy(struct fuse_session *se)
{
- if (se->got_init && !se->got_destroy) {
- if (se->op.destroy)
- se->op.destroy(se->userdata);
- }
- pthread_mutex_destroy(&se->lock);
- free(se->cuse_data);
- if (se->fd != -1)
- close(se->fd);
- free(se);
+ if (se->got_init && !se->got_destroy) {
+ if (se->op.destroy) {
+ se->op.destroy(se->userdata);
+ }
+ }
+ pthread_mutex_destroy(&se->lock);
+ free(se->cuse_data);
+ if (se->fd != -1) {
+ close(se->fd);
+ }
+ free(se);
}
struct fuse_session *fuse_session_new(struct fuse_args *args,
- const struct fuse_lowlevel_ops *op,
- size_t op_size, void *userdata)
-{
- struct fuse_session *se;
-
- if (sizeof(struct fuse_lowlevel_ops) < op_size) {
- fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
- op_size = sizeof(struct fuse_lowlevel_ops);
- }
-
- if (args->argc == 0) {
- fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
- return NULL;
- }
-
- se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
- if (se == NULL) {
- fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
- goto out1;
- }
- se->fd = -1;
- se->conn.max_write = UINT_MAX;
- se->conn.max_readahead = UINT_MAX;
-
- /* Parse options */
- if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
- goto out2;
- if(args->argc == 1 &&
- args->argv[0][0] == '-') {
- fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
- "will be ignored\n");
- } else if (args->argc != 1) {
- int i;
- fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
- for(i = 1; i < args->argc-1; i++)
- fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
- fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
- goto out4;
- }
-
- se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
- FUSE_BUFFER_HEADER_SIZE;
-
- list_init_req(&se->list);
- list_init_req(&se->interrupts);
- list_init_nreq(&se->notify_list);
- se->notify_ctr = 1;
- fuse_mutex_init(&se->lock);
-
- memcpy(&se->op, op, op_size);
- se->owner = getuid();
- se->userdata = userdata;
-
- return se;
+ const struct fuse_lowlevel_ops *op,
+ size_t op_size, void *userdata)
+{
+ struct fuse_session *se;
+
+ if (sizeof(struct fuse_lowlevel_ops) < op_size) {
+ fuse_log(
+ FUSE_LOG_ERR,
+ "fuse: warning: library too old, some operations may not work\n");
+ op_size = sizeof(struct fuse_lowlevel_ops);
+ }
+
+ if (args->argc == 0) {
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: empty argv passed to fuse_session_new().\n");
+ return NULL;
+ }
+
+ se = (struct fuse_session *)calloc(1, sizeof(struct fuse_session));
+ if (se == NULL) {
+ fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
+ goto out1;
+ }
+ se->fd = -1;
+ se->conn.max_write = UINT_MAX;
+ se->conn.max_readahead = UINT_MAX;
+
+ /* Parse options */
+ if (fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1) {
+ goto out2;
+ }
+ if (args->argc == 1 && args->argv[0][0] == '-') {
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: warning: argv[0] looks like an option, but "
+ "will be ignored\n");
+ } else if (args->argc != 1) {
+ int i;
+ fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
+ for (i = 1; i < args->argc - 1; i++) {
+ fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
+ }
+ fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
+ goto out4;
+ }
+
+ se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
+
+ list_init_req(&se->list);
+ list_init_req(&se->interrupts);
+ list_init_nreq(&se->notify_list);
+ se->notify_ctr = 1;
+ fuse_mutex_init(&se->lock);
+
+ memcpy(&se->op, op, op_size);
+ se->owner = getuid();
+ se->userdata = userdata;
+
+ return se;
out4:
- fuse_opt_free_args(args);
+ fuse_opt_free_args(args);
out2:
- free(se);
+ free(se);
out1:
- return NULL;
+ return NULL;
}
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
{
- int fd;
-
- /*
- * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
- * would ensue.
- */
- do {
- fd = open("/dev/null", O_RDWR);
- if (fd > 2)
- close(fd);
- } while (fd >= 0 && fd <= 2);
-
- /*
- * To allow FUSE daemons to run without privileges, the caller may open
- * /dev/fuse before launching the file system and pass on the file
- * descriptor by specifying /dev/fd/N as the mount point. Note that the
- * parent process takes care of performing the mount in this case.
- */
- fd = fuse_mnt_parse_fuse_fd(mountpoint);
- if (fd != -1) {
- if (fcntl(fd, F_GETFD) == -1) {
- fuse_log(FUSE_LOG_ERR,
- "fuse: Invalid file descriptor /dev/fd/%u\n",
- fd);
- return -1;
- }
- se->fd = fd;
- return 0;
- }
-
- /* Open channel */
- fd = fuse_kern_mount(mountpoint, se->mo);
- if (fd == -1)
- return -1;
- se->fd = fd;
-
- /* Save mountpoint */
- se->mountpoint = strdup(mountpoint);
- if (se->mountpoint == NULL)
- goto error_out;
-
- return 0;
+ int fd;
+
+ /*
+ * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
+ * would ensue.
+ */
+ do {
+ fd = open("/dev/null", O_RDWR);
+ if (fd > 2) {
+ close(fd);
+ }
+ } while (fd >= 0 && fd <= 2);
+
+ /*
+ * To allow FUSE daemons to run without privileges, the caller may open
+ * /dev/fuse before launching the file system and pass on the file
+ * descriptor by specifying /dev/fd/N as the mount point. Note that the
+ * parent process takes care of performing the mount in this case.
+ */
+ fd = fuse_mnt_parse_fuse_fd(mountpoint);
+ if (fd != -1) {
+ if (fcntl(fd, F_GETFD) == -1) {
+ fuse_log(FUSE_LOG_ERR, "fuse: Invalid file descriptor /dev/fd/%u\n",
+ fd);
+ return -1;
+ }
+ se->fd = fd;
+ return 0;
+ }
+
+ /* Open channel */
+ fd = fuse_kern_mount(mountpoint, se->mo);
+ if (fd == -1) {
+ return -1;
+ }
+ se->fd = fd;
+
+ /* Save mountpoint */
+ se->mountpoint = strdup(mountpoint);
+ if (se->mountpoint == NULL) {
+ goto error_out;
+ }
+
+ return 0;
error_out:
- fuse_kern_unmount(mountpoint, fd);
- return -1;
+ fuse_kern_unmount(mountpoint, fd);
+ return -1;
}
int fuse_session_fd(struct fuse_session *se)
{
- return se->fd;
+ return se->fd;
}
void fuse_session_unmount(struct fuse_session *se)
@@ -2384,61 +2519,66 @@ void fuse_session_unmount(struct fuse_session *se)
#ifdef linux
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
{
- char *buf;
- size_t bufsize = 1024;
- char path[128];
- int ret;
- int fd;
- unsigned long pid = req->ctx.pid;
- char *s;
+ char *buf;
+ size_t bufsize = 1024;
+ char path[128];
+ int ret;
+ int fd;
+ unsigned long pid = req->ctx.pid;
+ char *s;
- sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
+ sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
retry:
- buf = malloc(bufsize);
- if (buf == NULL)
- return -ENOMEM;
-
- ret = -EIO;
- fd = open(path, O_RDONLY);
- if (fd == -1)
- goto out_free;
-
- ret = read(fd, buf, bufsize);
- close(fd);
- if (ret < 0) {
- ret = -EIO;
- goto out_free;
- }
-
- if ((size_t)ret == bufsize) {
- free(buf);
- bufsize *= 4;
- goto retry;
- }
-
- ret = -EIO;
- s = strstr(buf, "\nGroups:");
- if (s == NULL)
- goto out_free;
-
- s += 8;
- ret = 0;
- while (1) {
- char *end;
- unsigned long val = strtoul(s, &end, 0);
- if (end == s)
- break;
-
- s = end;
- if (ret < size)
- list[ret] = val;
- ret++;
- }
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ return -ENOMEM;
+ }
+
+ ret = -EIO;
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ goto out_free;
+ }
+
+ ret = read(fd, buf, bufsize);
+ close(fd);
+ if (ret < 0) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ if ((size_t)ret == bufsize) {
+ free(buf);
+ bufsize *= 4;
+ goto retry;
+ }
+
+ ret = -EIO;
+ s = strstr(buf, "\nGroups:");
+ if (s == NULL) {
+ goto out_free;
+ }
+
+ s += 8;
+ ret = 0;
+ while (1) {
+ char *end;
+ unsigned long val = strtoul(s, &end, 0);
+ if (end == s) {
+ break;
+ }
+
+ s = end;
+ if (ret < size) {
+ list[ret] = val;
+ }
+ ret++;
+ }
out_free:
- free(buf);
- return ret;
+ free(buf);
+ return ret;
}
#else /* linux */
/*
@@ -2446,23 +2586,25 @@ out_free:
*/
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
{
- (void) req; (void) size; (void) list;
- return -ENOSYS;
+ (void)req;
+ (void)size;
+ (void)list;
+ return -ENOSYS;
}
#endif
void fuse_session_exit(struct fuse_session *se)
{
- se->exited = 1;
+ se->exited = 1;
}
void fuse_session_reset(struct fuse_session *se)
{
- se->exited = 0;
- se->error = 0;
+ se->exited = 0;
+ se->error = 0;
}
int fuse_session_exited(struct fuse_session *se)
{
- return se->exited;
+ return se->exited;
}
diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
index 6b1adfcfd1..adb9054bb1 100644
--- a/tools/virtiofsd/fuse_lowlevel.h
+++ b/tools/virtiofsd/fuse_lowlevel.h
@@ -1,15 +1,16 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB.
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB.
+ */
#ifndef FUSE_LOWLEVEL_H_
#define FUSE_LOWLEVEL_H_
-/** @file
+/**
+ * @file
*
* Low level API
*
@@ -24,16 +25,16 @@
#include "fuse_common.h"
-#include <utime.h>
#include <fcntl.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
+#include <sys/types.h>
#include <sys/uio.h>
+#include <utime.h>
-/* ----------------------------------------------------------- *
- * Miscellaneous definitions *
- * ----------------------------------------------------------- */
+/*
+ * Miscellaneous definitions
+ */
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -53,47 +54,54 @@ struct fuse_session;
/** Directory entry parameters supplied to fuse_reply_entry() */
struct fuse_entry_param {
- /** Unique inode number
- *
- * In lookup, zero means negative entry (from version 2.5)
- * Returning ENOENT also means negative entry, but by setting zero
- * ino the kernel may cache negative entries for entry_timeout
- * seconds.
- */
- fuse_ino_t ino;
-
- /** Generation number for this entry.
- *
- * If the file system will be exported over NFS, the
- * ino/generation pairs need to be unique over the file
- * system's lifetime (rather than just the mount time). So if
- * the file system reuses an inode after it has been deleted,
- * it must assign a new, previously unused generation number
- * to the inode at the same time.
- *
- */
- uint64_t generation;
-
- /** Inode attributes.
- *
- * Even if attr_timeout == 0, attr must be correct. For example,
- * for open(), FUSE uses attr.st_size from lookup() to determine
- * how many bytes to request. If this value is not correct,
- * incorrect data will be returned.
- */
- struct stat attr;
-
- /** Validity timeout (in seconds) for inode attributes. If
- attributes only change as a result of requests that come
- through the kernel, this should be set to a very large
- value. */
- double attr_timeout;
-
- /** Validity timeout (in seconds) for the name. If directory
- entries are changed/deleted only as a result of requests
- that come through the kernel, this should be set to a very
- large value. */
- double entry_timeout;
+ /**
+ * Unique inode number
+ *
+ * In lookup, zero means negative entry (from version 2.5)
+ * Returning ENOENT also means negative entry, but by setting zero
+ * ino the kernel may cache negative entries for entry_timeout
+ * seconds.
+ */
+ fuse_ino_t ino;
+
+ /**
+ * Generation number for this entry.
+ *
+ * If the file system will be exported over NFS, the
+ * ino/generation pairs need to be unique over the file
+ * system's lifetime (rather than just the mount time). So if
+ * the file system reuses an inode after it has been deleted,
+ * it must assign a new, previously unused generation number
+ * to the inode at the same time.
+ *
+ */
+ uint64_t generation;
+
+ /**
+ * Inode attributes.
+ *
+ * Even if attr_timeout == 0, attr must be correct. For example,
+ * for open(), FUSE uses attr.st_size from lookup() to determine
+ * how many bytes to request. If this value is not correct,
+ * incorrect data will be returned.
+ */
+ struct stat attr;
+
+ /**
+ * Validity timeout (in seconds) for inode attributes. If
+ * attributes only change as a result of requests that come
+ * through the kernel, this should be set to a very large
+ * value.
+ */
+ double attr_timeout;
+
+ /**
+ * Validity timeout (in seconds) for the name. If directory
+ * entries are changed/deleted only as a result of requests
+ * that come through the kernel, this should be set to a very
+ * large value.
+ */
+ double entry_timeout;
};
/**
@@ -105,38 +113,38 @@ struct fuse_entry_param {
* there is no valid uid/pid/gid that could be reported.
*/
struct fuse_ctx {
- /** User ID of the calling process */
- uid_t uid;
+ /** User ID of the calling process */
+ uid_t uid;
- /** Group ID of the calling process */
- gid_t gid;
+ /** Group ID of the calling process */
+ gid_t gid;
- /** Thread ID of the calling process */
- pid_t pid;
+ /** Thread ID of the calling process */
+ pid_t pid;
- /** Umask of the calling process */
- mode_t umask;
+ /** Umask of the calling process */
+ mode_t umask;
};
struct fuse_forget_data {
- fuse_ino_t ino;
- uint64_t nlookup;
+ fuse_ino_t ino;
+ uint64_t nlookup;
};
/* 'to_set' flags in setattr */
-#define FUSE_SET_ATTR_MODE (1 << 0)
-#define FUSE_SET_ATTR_UID (1 << 1)
-#define FUSE_SET_ATTR_GID (1 << 2)
-#define FUSE_SET_ATTR_SIZE (1 << 3)
-#define FUSE_SET_ATTR_ATIME (1 << 4)
-#define FUSE_SET_ATTR_MTIME (1 << 5)
-#define FUSE_SET_ATTR_ATIME_NOW (1 << 7)
-#define FUSE_SET_ATTR_MTIME_NOW (1 << 8)
-#define FUSE_SET_ATTR_CTIME (1 << 10)
-
-/* ----------------------------------------------------------- *
- * Request methods and replies *
- * ----------------------------------------------------------- */
+#define FUSE_SET_ATTR_MODE (1 << 0)
+#define FUSE_SET_ATTR_UID (1 << 1)
+#define FUSE_SET_ATTR_GID (1 << 2)
+#define FUSE_SET_ATTR_SIZE (1 << 3)
+#define FUSE_SET_ATTR_ATIME (1 << 4)
+#define FUSE_SET_ATTR_MTIME (1 << 5)
+#define FUSE_SET_ATTR_ATIME_NOW (1 << 7)
+#define FUSE_SET_ATTR_MTIME_NOW (1 << 8)
+#define FUSE_SET_ATTR_CTIME (1 << 10)
+
+/*
+ * Request methods and replies
+ */
/**
* Low level filesystem operations
@@ -166,1075 +174,1069 @@ struct fuse_forget_data {
* this file will not be called.
*/
struct fuse_lowlevel_ops {
- /**
- * Initialize filesystem
- *
- * This function is called when libfuse establishes
- * communication with the FUSE kernel module. The file system
- * should use this module to inspect and/or modify the
- * connection parameters provided in the `conn` structure.
- *
- * Note that some parameters may be overwritten by options
- * passed to fuse_session_new() which take precedence over the
- * values set in this handler.
- *
- * There's no reply to this function
- *
- * @param userdata the user data passed to fuse_session_new()
- */
- void (*init) (void *userdata, struct fuse_conn_info *conn);
-
- /**
- * Clean up filesystem.
- *
- * Called on filesystem exit. When this method is called, the
- * connection to the kernel may be gone already, so that eg. calls
- * to fuse_lowlevel_notify_* will fail.
- *
- * There's no reply to this function
- *
- * @param userdata the user data passed to fuse_session_new()
- */
- void (*destroy) (void *userdata);
-
- /**
- * Look up a directory entry by name and get its attributes.
- *
- * Valid replies:
- * fuse_reply_entry
- * fuse_reply_err
- *
- * @param req request handle
- * @param parent inode number of the parent directory
- * @param name the name to look up
- */
- void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
-
- /**
- * Forget about an inode
- *
- * This function is called when the kernel removes an inode
- * from its internal caches.
- *
- * The inode's lookup count increases by one for every call to
- * fuse_reply_entry and fuse_reply_create. The nlookup parameter
- * indicates by how much the lookup count should be decreased.
- *
- * Inodes with a non-zero lookup count may receive request from
- * the kernel even after calls to unlink, rmdir or (when
- * overwriting an existing file) rename. Filesystems must handle
- * such requests properly and it is recommended to defer removal
- * of the inode until the lookup count reaches zero. Calls to
- * unlink, rmdir or rename will be followed closely by forget
- * unless the file or directory is open, in which case the
- * kernel issues forget only after the release or releasedir
- * calls.
- *
- * Note that if a file system will be exported over NFS the
- * inodes lifetime must extend even beyond forget. See the
- * generation field in struct fuse_entry_param above.
- *
- * On unmount the lookup count for all inodes implicitly drops
- * to zero. It is not guaranteed that the file system will
- * receive corresponding forget messages for the affected
- * inodes.
- *
- * Valid replies:
- * fuse_reply_none
- *
- * @param req request handle
- * @param ino the inode number
- * @param nlookup the number of lookups to forget
- */
- void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup);
-
- /**
- * Get file attributes.
- *
- * If writeback caching is enabled, the kernel may have a
- * better idea of a file's length than the FUSE file system
- * (eg if there has been a write that extended the file size,
- * but that has not yet been passed to the filesystem.n
- *
- * In this case, the st_size value provided by the file system
- * will be ignored.
- *
- * Valid replies:
- * fuse_reply_attr
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi for future use, currently always NULL
- */
- void (*getattr) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi);
-
- /**
- * Set file attributes
- *
- * In the 'attr' argument only members indicated by the 'to_set'
- * bitmask contain valid values. Other members contain undefined
- * values.
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits if the file
- * size or owner is being changed.
- *
- * If the setattr was invoked from the ftruncate() system call
- * under Linux kernel versions 2.6.15 or later, the fi->fh will
- * contain the value set by the open method or will be undefined
- * if the open method didn't set any value. Otherwise (not
- * ftruncate call, or kernel version earlier than 2.6.15) the fi
- * parameter will be NULL.
- *
- * Valid replies:
- * fuse_reply_attr
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param attr the attributes
- * @param to_set bit mask of attributes which should be set
- * @param fi file information, or NULL
- */
- void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
- int to_set, struct fuse_file_info *fi);
-
- /**
- * Read symbolic link
- *
- * Valid replies:
- * fuse_reply_readlink
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- */
- void (*readlink) (fuse_req_t req, fuse_ino_t ino);
-
- /**
- * Create file node
- *
- * Create a regular file, character device, block device, fifo or
- * socket node.
- *
- * Valid replies:
- * fuse_reply_entry
- * fuse_reply_err
- *
- * @param req request handle
- * @param parent inode number of the parent directory
- * @param name to create
- * @param mode file type and mode with which to create the new file
- * @param rdev the device number (only valid if created file is a device)
- */
- void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
- mode_t mode, dev_t rdev);
-
- /**
- * Create a directory
- *
- * Valid replies:
- * fuse_reply_entry
- * fuse_reply_err
- *
- * @param req request handle
- * @param parent inode number of the parent directory
- * @param name to create
- * @param mode with which to create the new file
- */
- void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
- mode_t mode);
-
- /**
- * Remove a file
- *
- * If the file's inode's lookup count is non-zero, the file
- * system is expected to postpone any removal of the inode
- * until the lookup count reaches zero (see description of the
- * forget function).
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param parent inode number of the parent directory
- * @param name to remove
- */
- void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
-
- /**
- * Remove a directory
- *
- * If the directory's inode's lookup count is non-zero, the
- * file system is expected to postpone any removal of the
- * inode until the lookup count reaches zero (see description
- * of the forget function).
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param parent inode number of the parent directory
- * @param name to remove
- */
- void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
-
- /**
- * Create a symbolic link
- *
- * Valid replies:
- * fuse_reply_entry
- * fuse_reply_err
- *
- * @param req request handle
- * @param link the contents of the symbolic link
- * @param parent inode number of the parent directory
- * @param name to create
- */
- void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
- const char *name);
-
- /** Rename a file
- *
- * If the target exists it should be atomically replaced. If
- * the target's inode's lookup count is non-zero, the file
- * system is expected to postpone any removal of the inode
- * until the lookup count reaches zero (see description of the
- * forget function).
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure with error code EINVAL, i.e. all
- * future bmap requests will fail with EINVAL without being
- * send to the filesystem process.
- *
- * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
- * RENAME_NOREPLACE is specified, the filesystem must not
- * overwrite *newname* if it exists and return an error
- * instead. If `RENAME_EXCHANGE` is specified, the filesystem
- * must atomically exchange the two files, i.e. both must
- * exist and neither may be deleted.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param parent inode number of the old parent directory
- * @param name old name
- * @param newparent inode number of the new parent directory
- * @param newname new name
- */
- void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
- fuse_ino_t newparent, const char *newname,
- unsigned int flags);
-
- /**
- * Create a hard link
- *
- * Valid replies:
- * fuse_reply_entry
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the old inode number
- * @param newparent inode number of the new parent directory
- * @param newname new name to create
- */
- void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
- const char *newname);
-
- /**
- * Open a file
- *
- * Open flags are available in fi->flags. The following rules
- * apply.
- *
- * - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
- * filtered out / handled by the kernel.
- *
- * - Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used
- * by the filesystem to check if the operation is
- * permitted. If the ``-o default_permissions`` mount
- * option is given, this check is already done by the
- * kernel before calling open() and may thus be omitted by
- * the filesystem.
- *
- * - When writeback caching is enabled, the kernel may send
- * read requests even for files opened with O_WRONLY. The
- * filesystem should be prepared to handle this.
- *
- * - When writeback caching is disabled, the filesystem is
- * expected to properly handle the O_APPEND flag and ensure
- * that each write is appending to the end of the file.
- *
- * - When writeback caching is enabled, the kernel will
- * handle O_APPEND. However, unless all changes to the file
- * come through the kernel this will not work reliably. The
- * filesystem should thus either ignore the O_APPEND flag
- * (and let the kernel handle it), or return an error
- * (indicating that reliably O_APPEND is not available).
- *
- * Filesystem may store an arbitrary file handle (pointer,
- * index, etc) in fi->fh, and use this in other all other file
- * operations (read, write, flush, release, fsync).
- *
- * Filesystem may also implement stateless file I/O and not store
- * anything in fi->fh.
- *
- * There are also some flags (direct_io, keep_cache) which the
- * filesystem may set in fi, to change the way the file is opened.
- * See fuse_file_info structure in <fuse_common.h> for more details.
- *
- * If this request is answered with an error code of ENOSYS
- * and FUSE_CAP_NO_OPEN_SUPPORT is set in
- * `fuse_conn_info.capable`, this is treated as success and
- * future calls to open and release will also succeed without being
- * sent to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_open
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- */
- void (*open) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi);
-
- /**
- * Read data
- *
- * Read should send exactly the number of bytes requested except
- * on EOF or error, otherwise the rest of the data will be
- * substituted with zeroes. An exception to this is when the file
- * has been opened in 'direct_io' mode, in which case the return
- * value of the read system call will reflect the return value of
- * this operation.
- *
- * fi->fh will contain the value set by the open method, or will
- * be undefined if the open method didn't set any value.
- *
- * Valid replies:
- * fuse_reply_buf
- * fuse_reply_iov
- * fuse_reply_data
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param size number of bytes to read
- * @param off offset to read from
- * @param fi file information
- */
- void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
- struct fuse_file_info *fi);
-
- /**
- * Write data
- *
- * Write should return exactly the number of bytes requested
- * except on error. An exception to this is when the file has
- * been opened in 'direct_io' mode, in which case the return value
- * of the write system call will reflect the return value of this
- * operation.
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits.
- *
- * fi->fh will contain the value set by the open method, or will
- * be undefined if the open method didn't set any value.
- *
- * Valid replies:
- * fuse_reply_write
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param buf data to write
- * @param size number of bytes to write
- * @param off offset to write to
- * @param fi file information
- */
- void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
- size_t size, off_t off, struct fuse_file_info *fi);
-
- /**
- * Flush method
- *
- * This is called on each close() of the opened file.
- *
- * Since file descriptors can be duplicated (dup, dup2, fork), for
- * one open call there may be many flush calls.
- *
- * Filesystems shouldn't assume that flush will always be called
- * after some writes, or that if will be called at all.
- *
- * fi->fh will contain the value set by the open method, or will
- * be undefined if the open method didn't set any value.
- *
- * NOTE: the name of the method is misleading, since (unlike
- * fsync) the filesystem is not forced to flush pending writes.
- * One reason to flush data is if the filesystem wants to return
- * write errors during close. However, such use is non-portable
- * because POSIX does not require [close] to wait for delayed I/O to
- * complete.
- *
- * If the filesystem supports file locking operations (setlk,
- * getlk) it should remove all locks belonging to 'fi->owner'.
- *
- * If this request is answered with an error code of ENOSYS,
- * this is treated as success and future calls to flush() will
- * succeed automatically without being send to the filesystem
- * process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- *
- * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
- */
- void (*flush) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi);
-
- /**
- * Release an open file
- *
- * Release is called when there are no more references to an open
- * file: all file descriptors are closed and all memory mappings
- * are unmapped.
- *
- * For every open call there will be exactly one release call (unless
- * the filesystem is force-unmounted).
- *
- * The filesystem may reply with an error, but error values are
- * not returned to close() or munmap() which triggered the
- * release.
- *
- * fi->fh will contain the value set by the open method, or will
- * be undefined if the open method didn't set any value.
- * fi->flags will contain the same flags as for open.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- */
- void (*release) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi);
-
- /**
- * Synchronize file contents
- *
- * If the datasync parameter is non-zero, then only the user data
- * should be flushed, not the meta data.
- *
- * If this request is answered with an error code of ENOSYS,
- * this is treated as success and future calls to fsync() will
- * succeed automatically without being send to the filesystem
- * process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param datasync flag indicating if only data should be flushed
- * @param fi file information
- */
- void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
- struct fuse_file_info *fi);
-
- /**
- * Open a directory
- *
- * Filesystem may store an arbitrary file handle (pointer, index,
- * etc) in fi->fh, and use this in other all other directory
- * stream operations (readdir, releasedir, fsyncdir).
- *
- * If this request is answered with an error code of ENOSYS and
- * FUSE_CAP_NO_OPENDIR_SUPPORT is set in `fuse_conn_info.capable`,
- * this is treated as success and future calls to opendir and
- * releasedir will also succeed without being sent to the filesystem
- * process. In addition, the kernel will cache readdir results
- * as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR.
- *
- * Valid replies:
- * fuse_reply_open
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- */
- void (*opendir) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi);
-
- /**
- * Read directory
- *
- * Send a buffer filled using fuse_add_direntry(), with size not
- * exceeding the requested size. Send an empty buffer on end of
- * stream.
- *
- * fi->fh will contain the value set by the opendir method, or
- * will be undefined if the opendir method didn't set any value.
- *
- * Returning a directory entry from readdir() does not affect
- * its lookup count.
- *
- * If off_t is non-zero, then it will correspond to one of the off_t
- * values that was previously returned by readdir() for the same
- * directory handle. In this case, readdir() should skip over entries
- * coming before the position defined by the off_t value. If entries
- * are added or removed while the directory handle is open, they filesystem
- * may still include the entries that have been removed, and may not
- * report the entries that have been created. However, addition or
- * removal of entries must never cause readdir() to skip over unrelated
- * entries or to report them more than once. This means
- * that off_t can not be a simple index that enumerates the entries
- * that have been returned but must contain sufficient information to
- * uniquely determine the next directory entry to return even when the
- * set of entries is changing.
- *
- * The function does not have to report the '.' and '..'
- * entries, but is allowed to do so. Note that, if readdir does
- * not return '.' or '..', they will not be implicitly returned,
- * and this behavior is observable by the caller.
- *
- * Valid replies:
- * fuse_reply_buf
- * fuse_reply_data
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param size maximum number of bytes to send
- * @param off offset to continue reading the directory stream
- * @param fi file information
- */
- void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
- struct fuse_file_info *fi);
-
- /**
- * Release an open directory
- *
- * For every opendir call there will be exactly one releasedir
- * call (unless the filesystem is force-unmounted).
- *
- * fi->fh will contain the value set by the opendir method, or
- * will be undefined if the opendir method didn't set any value.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- */
- void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi);
-
- /**
- * Synchronize directory contents
- *
- * If the datasync parameter is non-zero, then only the directory
- * contents should be flushed, not the meta data.
- *
- * fi->fh will contain the value set by the opendir method, or
- * will be undefined if the opendir method didn't set any value.
- *
- * If this request is answered with an error code of ENOSYS,
- * this is treated as success and future calls to fsyncdir() will
- * succeed automatically without being send to the filesystem
- * process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param datasync flag indicating if only data should be flushed
- * @param fi file information
- */
- void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
- struct fuse_file_info *fi);
-
- /**
- * Get file system statistics
- *
- * Valid replies:
- * fuse_reply_statfs
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number, zero means "undefined"
- */
- void (*statfs) (fuse_req_t req, fuse_ino_t ino);
-
- /**
- * Set an extended attribute
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
- * future setxattr() requests will fail with EOPNOTSUPP without being
- * send to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_err
- */
- void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
- const char *value, size_t size, int flags);
-
- /**
- * Get an extended attribute
- *
- * If size is zero, the size of the value should be sent with
- * fuse_reply_xattr.
- *
- * If the size is non-zero, and the value fits in the buffer, the
- * value should be sent with fuse_reply_buf.
- *
- * If the size is too small for the value, the ERANGE error should
- * be sent.
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
- * future getxattr() requests will fail with EOPNOTSUPP without being
- * send to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_buf
- * fuse_reply_data
- * fuse_reply_xattr
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param name of the extended attribute
- * @param size maximum size of the value to send
- */
- void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
- size_t size);
-
- /**
- * List extended attribute names
- *
- * If size is zero, the total size of the attribute list should be
- * sent with fuse_reply_xattr.
- *
- * If the size is non-zero, and the null character separated
- * attribute list fits in the buffer, the list should be sent with
- * fuse_reply_buf.
- *
- * If the size is too small for the list, the ERANGE error should
- * be sent.
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
- * future listxattr() requests will fail with EOPNOTSUPP without being
- * send to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_buf
- * fuse_reply_data
- * fuse_reply_xattr
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param size maximum size of the list to send
- */
- void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
-
- /**
- * Remove an extended attribute
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
- * future removexattr() requests will fail with EOPNOTSUPP without being
- * send to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param name of the extended attribute
- */
- void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
-
- /**
- * Check file access permissions
- *
- * This will be called for the access() and chdir() system
- * calls. If the 'default_permissions' mount option is given,
- * this method is not called.
- *
- * This method is not called under Linux kernel versions 2.4.x
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent success, i.e. this and all future access()
- * requests will succeed without being send to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param mask requested access mode
- */
- void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
-
- /**
- * Create and open a file
- *
- * If the file does not exist, first create it with the specified
- * mode, and then open it.
- *
- * See the description of the open handler for more
- * information.
- *
- * If this method is not implemented or under Linux kernel
- * versions earlier than 2.6.15, the mknod() and open() methods
- * will be called instead.
- *
- * If this request is answered with an error code of ENOSYS, the handler
- * is treated as not implemented (i.e., for this and future requests the
- * mknod() and open() handlers will be called instead).
- *
- * Valid replies:
- * fuse_reply_create
- * fuse_reply_err
- *
- * @param req request handle
- * @param parent inode number of the parent directory
- * @param name to create
- * @param mode file type and mode with which to create the new file
- * @param fi file information
- */
- void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
- mode_t mode, struct fuse_file_info *fi);
-
- /**
- * Test for a POSIX file lock
- *
- * Valid replies:
- * fuse_reply_lock
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- * @param lock the region/type to test
- */
- void (*getlk) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi, struct flock *lock);
-
- /**
- * Acquire, modify or release a POSIX file lock
- *
- * For POSIX threads (NPTL) there's a 1-1 relation between pid and
- * owner, but otherwise this is not always the case. For checking
- * lock ownership, 'fi->owner' must be used. The l_pid field in
- * 'struct flock' should only be used to fill in this field in
- * getlk().
- *
- * Note: if the locking methods are not implemented, the kernel
- * will still allow file locking to work locally. Hence these are
- * only interesting for network filesystems and similar.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- * @param lock the region/type to set
- * @param sleep locking operation may sleep
- */
- void (*setlk) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi,
- struct flock *lock, int sleep);
-
- /**
- * Map block index within file to block index within device
- *
- * Note: This makes sense only for block device backed filesystems
- * mounted with the 'blkdev' option
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure, i.e. all future bmap() requests will
- * fail with the same error code without being send to the filesystem
- * process.
- *
- * Valid replies:
- * fuse_reply_bmap
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param blocksize unit of block index
- * @param idx block index within file
- */
- void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
- uint64_t idx);
-
- /**
- * Ioctl
- *
- * Note: For unrestricted ioctls (not allowed for FUSE
- * servers), data in and out areas can be discovered by giving
- * iovs and setting FUSE_IOCTL_RETRY in *flags*. For
- * restricted ioctls, kernel prepares in/out data area
- * according to the information encoded in cmd.
- *
- * Valid replies:
- * fuse_reply_ioctl_retry
- * fuse_reply_ioctl
- * fuse_reply_ioctl_iov
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param cmd ioctl command
- * @param arg ioctl argument
- * @param fi file information
- * @param flags for FUSE_IOCTL_* flags
- * @param in_buf data fetched from the caller
- * @param in_bufsz number of fetched bytes
- * @param out_bufsz maximum size of output data
- *
- * Note : the unsigned long request submitted by the application
- * is truncated to 32 bits.
- */
- void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
- void *arg, struct fuse_file_info *fi, unsigned flags,
- const void *in_buf, size_t in_bufsz, size_t out_bufsz);
-
- /**
- * Poll for IO readiness
- *
- * Note: If ph is non-NULL, the client should notify
- * when IO readiness events occur by calling
- * fuse_lowlevel_notify_poll() with the specified ph.
- *
- * Regardless of the number of times poll with a non-NULL ph
- * is received, single notification is enough to clear all.
- * Notifying more times incurs overhead but doesn't harm
- * correctness.
- *
- * The callee is responsible for destroying ph with
- * fuse_pollhandle_destroy() when no longer in use.
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as success (with a kernel-defined default poll-mask) and
- * future calls to pull() will succeed the same way without being send
- * to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_poll
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- * @param ph poll handle to be used for notification
- */
- void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
- struct fuse_pollhandle *ph);
-
- /**
- * Write data made available in a buffer
- *
- * This is a more generic version of the ->write() method. If
- * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the
- * kernel supports splicing from the fuse device, then the
- * data will be made available in pipe for supporting zero
- * copy data transfer.
- *
- * buf->count is guaranteed to be one (and thus buf->idx is
- * always zero). The write_buf handler must ensure that
- * bufv->off is correctly updated (reflecting the number of
- * bytes read from bufv->buf[0]).
- *
- * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
- * expected to reset the setuid and setgid bits.
- *
- * Valid replies:
- * fuse_reply_write
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param bufv buffer containing the data
- * @param off offset to write to
- * @param fi file information
- */
- void (*write_buf) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_bufvec *bufv, off_t off,
- struct fuse_file_info *fi);
-
- /**
- * Callback function for the retrieve request
- *
- * Valid replies:
- * fuse_reply_none
- *
- * @param req request handle
- * @param cookie user data supplied to fuse_lowlevel_notify_retrieve()
- * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve()
- * @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
- * @param bufv the buffer containing the returned data
- */
- void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino,
- off_t offset, struct fuse_bufvec *bufv);
-
- /**
- * Forget about multiple inodes
- *
- * See description of the forget function for more
- * information.
- *
- * Valid replies:
- * fuse_reply_none
- *
- * @param req request handle
- */
- void (*forget_multi) (fuse_req_t req, size_t count,
- struct fuse_forget_data *forgets);
-
- /**
- * Acquire, modify or release a BSD file lock
- *
- * Note: if the locking methods are not implemented, the kernel
- * will still allow file locking to work locally. Hence these are
- * only interesting for network filesystems and similar.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param fi file information
- * @param op the locking operation, see flock(2)
- */
- void (*flock) (fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi, int op);
-
- /**
- * Allocate requested space. If this function returns success then
- * subsequent writes to the specified range shall not fail due to the lack
- * of free space on the file system storage media.
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
- * future fallocate() requests will fail with EOPNOTSUPP without being
- * send to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param offset starting point for allocated region
- * @param length size of allocated region
- * @param mode determines the operation to be performed on the given range,
- * see fallocate(2)
- */
- void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode,
- off_t offset, off_t length, struct fuse_file_info *fi);
-
- /**
- * Read directory with attributes
- *
- * Send a buffer filled using fuse_add_direntry_plus(), with size not
- * exceeding the requested size. Send an empty buffer on end of
- * stream.
- *
- * fi->fh will contain the value set by the opendir method, or
- * will be undefined if the opendir method didn't set any value.
- *
- * In contrast to readdir() (which does not affect the lookup counts),
- * the lookup count of every entry returned by readdirplus(), except "."
- * and "..", is incremented by one.
- *
- * Valid replies:
- * fuse_reply_buf
- * fuse_reply_data
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param size maximum number of bytes to send
- * @param off offset to continue reading the directory stream
- * @param fi file information
- */
- void (*readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
- struct fuse_file_info *fi);
-
- /**
- * Copy a range of data from one file to another
- *
- * Performs an optimized copy between two file descriptors without the
- * additional cost of transferring data through the FUSE kernel module
- * to user space (glibc) and then back into the FUSE filesystem again.
- *
- * In case this method is not implemented, glibc falls back to reading
- * data from the source and writing to the destination. Effectively
- * doing an inefficient copy of the data.
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
- * future copy_file_range() requests will fail with EOPNOTSUPP without
- * being send to the filesystem process.
- *
- * Valid replies:
- * fuse_reply_write
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino_in the inode number or the source file
- * @param off_in starting point from were the data should be read
- * @param fi_in file information of the source file
- * @param ino_out the inode number or the destination file
- * @param off_out starting point where the data should be written
- * @param fi_out file information of the destination file
- * @param len maximum size of the data to copy
- * @param flags passed along with the copy_file_range() syscall
- */
- void (*copy_file_range) (fuse_req_t req, fuse_ino_t ino_in,
- off_t off_in, struct fuse_file_info *fi_in,
- fuse_ino_t ino_out, off_t off_out,
- struct fuse_file_info *fi_out, size_t len,
- int flags);
-
- /**
- * Find next data or hole after the specified offset
- *
- * If this request is answered with an error code of ENOSYS, this is
- * treated as a permanent failure, i.e. all future lseek() requests will
- * fail with the same error code without being send to the filesystem
- * process.
- *
- * Valid replies:
- * fuse_reply_lseek
- * fuse_reply_err
- *
- * @param req request handle
- * @param ino the inode number
- * @param off offset to start search from
- * @param whence either SEEK_DATA or SEEK_HOLE
- * @param fi file information
- */
- void (*lseek) (fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
- struct fuse_file_info *fi);
+ /**
+ * Initialize filesystem
+ *
+ * This function is called when libfuse establishes
+ * communication with the FUSE kernel module. The file system
+ * should use this module to inspect and/or modify the
+ * connection parameters provided in the `conn` structure.
+ *
+ * Note that some parameters may be overwritten by options
+ * passed to fuse_session_new() which take precedence over the
+ * values set in this handler.
+ *
+ * There's no reply to this function
+ *
+ * @param userdata the user data passed to fuse_session_new()
+ */
+ void (*init)(void *userdata, struct fuse_conn_info *conn);
+
+ /**
+ * Clean up filesystem.
+ *
+ * Called on filesystem exit. When this method is called, the
+ * connection to the kernel may be gone already, so that eg. calls
+ * to fuse_lowlevel_notify_* will fail.
+ *
+ * There's no reply to this function
+ *
+ * @param userdata the user data passed to fuse_session_new()
+ */
+ void (*destroy)(void *userdata);
+
+ /**
+ * Look up a directory entry by name and get its attributes.
+ *
+ * Valid replies:
+ * fuse_reply_entry
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param parent inode number of the parent directory
+ * @param name the name to look up
+ */
+ void (*lookup)(fuse_req_t req, fuse_ino_t parent, const char *name);
+
+ /**
+ * Forget about an inode
+ *
+ * This function is called when the kernel removes an inode
+ * from its internal caches.
+ *
+ * The inode's lookup count increases by one for every call to
+ * fuse_reply_entry and fuse_reply_create. The nlookup parameter
+ * indicates by how much the lookup count should be decreased.
+ *
+ * Inodes with a non-zero lookup count may receive request from
+ * the kernel even after calls to unlink, rmdir or (when
+ * overwriting an existing file) rename. Filesystems must handle
+ * such requests properly and it is recommended to defer removal
+ * of the inode until the lookup count reaches zero. Calls to
+ * unlink, rmdir or rename will be followed closely by forget
+ * unless the file or directory is open, in which case the
+ * kernel issues forget only after the release or releasedir
+ * calls.
+ *
+ * Note that if a file system will be exported over NFS the
+ * inodes lifetime must extend even beyond forget. See the
+ * generation field in struct fuse_entry_param above.
+ *
+ * On unmount the lookup count for all inodes implicitly drops
+ * to zero. It is not guaranteed that the file system will
+ * receive corresponding forget messages for the affected
+ * inodes.
+ *
+ * Valid replies:
+ * fuse_reply_none
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param nlookup the number of lookups to forget
+ */
+ void (*forget)(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup);
+
+ /**
+ * Get file attributes.
+ *
+ * If writeback caching is enabled, the kernel may have a
+ * better idea of a file's length than the FUSE file system
+ * (eg if there has been a write that extended the file size,
+ * but that has not yet been passed to the filesystem.n
+ *
+ * In this case, the st_size value provided by the file system
+ * will be ignored.
+ *
+ * Valid replies:
+ * fuse_reply_attr
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi for future use, currently always NULL
+ */
+ void (*getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+
+ /**
+ * Set file attributes
+ *
+ * In the 'attr' argument only members indicated by the 'to_set'
+ * bitmask contain valid values. Other members contain undefined
+ * values.
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits if the file
+ * size or owner is being changed.
+ *
+ * If the setattr was invoked from the ftruncate() system call
+ * under Linux kernel versions 2.6.15 or later, the fi->fh will
+ * contain the value set by the open method or will be undefined
+ * if the open method didn't set any value. Otherwise (not
+ * ftruncate call, or kernel version earlier than 2.6.15) the fi
+ * parameter will be NULL.
+ *
+ * Valid replies:
+ * fuse_reply_attr
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param attr the attributes
+ * @param to_set bit mask of attributes which should be set
+ * @param fi file information, or NULL
+ */
+ void (*setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+ int to_set, struct fuse_file_info *fi);
+
+ /**
+ * Read symbolic link
+ *
+ * Valid replies:
+ * fuse_reply_readlink
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ */
+ void (*readlink)(fuse_req_t req, fuse_ino_t ino);
+
+ /**
+ * Create file node
+ *
+ * Create a regular file, character device, block device, fifo or
+ * socket node.
+ *
+ * Valid replies:
+ * fuse_reply_entry
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param parent inode number of the parent directory
+ * @param name to create
+ * @param mode file type and mode with which to create the new file
+ * @param rdev the device number (only valid if created file is a device)
+ */
+ void (*mknod)(fuse_req_t req, fuse_ino_t parent, const char *name,
+ mode_t mode, dev_t rdev);
+
+ /**
+ * Create a directory
+ *
+ * Valid replies:
+ * fuse_reply_entry
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param parent inode number of the parent directory
+ * @param name to create
+ * @param mode with which to create the new file
+ */
+ void (*mkdir)(fuse_req_t req, fuse_ino_t parent, const char *name,
+ mode_t mode);
+
+ /**
+ * Remove a file
+ *
+ * If the file's inode's lookup count is non-zero, the file
+ * system is expected to postpone any removal of the inode
+ * until the lookup count reaches zero (see description of the
+ * forget function).
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param parent inode number of the parent directory
+ * @param name to remove
+ */
+ void (*unlink)(fuse_req_t req, fuse_ino_t parent, const char *name);
+
+ /**
+ * Remove a directory
+ *
+ * If the directory's inode's lookup count is non-zero, the
+ * file system is expected to postpone any removal of the
+ * inode until the lookup count reaches zero (see description
+ * of the forget function).
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param parent inode number of the parent directory
+ * @param name to remove
+ */
+ void (*rmdir)(fuse_req_t req, fuse_ino_t parent, const char *name);
+
+ /**
+ * Create a symbolic link
+ *
+ * Valid replies:
+ * fuse_reply_entry
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param link the contents of the symbolic link
+ * @param parent inode number of the parent directory
+ * @param name to create
+ */
+ void (*symlink)(fuse_req_t req, const char *link, fuse_ino_t parent,
+ const char *name);
+
+ /**
+ * Rename a file
+ *
+ * If the target exists it should be atomically replaced. If
+ * the target's inode's lookup count is non-zero, the file
+ * system is expected to postpone any removal of the inode
+ * until the lookup count reaches zero (see description of the
+ * forget function).
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure with error code EINVAL, i.e. all
+ * future bmap requests will fail with EINVAL without being
+ * send to the filesystem process.
+ *
+ * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
+ * RENAME_NOREPLACE is specified, the filesystem must not
+ * overwrite *newname* if it exists and return an error
+ * instead. If `RENAME_EXCHANGE` is specified, the filesystem
+ * must atomically exchange the two files, i.e. both must
+ * exist and neither may be deleted.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param parent inode number of the old parent directory
+ * @param name old name
+ * @param newparent inode number of the new parent directory
+ * @param newname new name
+ */
+ void (*rename)(fuse_req_t req, fuse_ino_t parent, const char *name,
+ fuse_ino_t newparent, const char *newname,
+ unsigned int flags);
+
+ /**
+ * Create a hard link
+ *
+ * Valid replies:
+ * fuse_reply_entry
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the old inode number
+ * @param newparent inode number of the new parent directory
+ * @param newname new name to create
+ */
+ void (*link)(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+ const char *newname);
+
+ /**
+ * Open a file
+ *
+ * Open flags are available in fi->flags. The following rules
+ * apply.
+ *
+ * - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
+ * filtered out / handled by the kernel.
+ *
+ * - Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used
+ * by the filesystem to check if the operation is
+ * permitted. If the ``-o default_permissions`` mount
+ * option is given, this check is already done by the
+ * kernel before calling open() and may thus be omitted by
+ * the filesystem.
+ *
+ * - When writeback caching is enabled, the kernel may send
+ * read requests even for files opened with O_WRONLY. The
+ * filesystem should be prepared to handle this.
+ *
+ * - When writeback caching is disabled, the filesystem is
+ * expected to properly handle the O_APPEND flag and ensure
+ * that each write is appending to the end of the file.
+ *
+ * - When writeback caching is enabled, the kernel will
+ * handle O_APPEND. However, unless all changes to the file
+ * come through the kernel this will not work reliably. The
+ * filesystem should thus either ignore the O_APPEND flag
+ * (and let the kernel handle it), or return an error
+ * (indicating that reliably O_APPEND is not available).
+ *
+ * Filesystem may store an arbitrary file handle (pointer,
+ * index, etc) in fi->fh, and use this in other all other file
+ * operations (read, write, flush, release, fsync).
+ *
+ * Filesystem may also implement stateless file I/O and not store
+ * anything in fi->fh.
+ *
+ * There are also some flags (direct_io, keep_cache) which the
+ * filesystem may set in fi, to change the way the file is opened.
+ * See fuse_file_info structure in <fuse_common.h> for more details.
+ *
+ * If this request is answered with an error code of ENOSYS
+ * and FUSE_CAP_NO_OPEN_SUPPORT is set in
+ * `fuse_conn_info.capable`, this is treated as success and
+ * future calls to open and release will also succeed without being
+ * sent to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_open
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ */
+ void (*open)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+
+ /**
+ * Read data
+ *
+ * Read should send exactly the number of bytes requested except
+ * on EOF or error, otherwise the rest of the data will be
+ * substituted with zeroes. An exception to this is when the file
+ * has been opened in 'direct_io' mode, in which case the return
+ * value of the read system call will reflect the return value of
+ * this operation.
+ *
+ * fi->fh will contain the value set by the open method, or will
+ * be undefined if the open method didn't set any value.
+ *
+ * Valid replies:
+ * fuse_reply_buf
+ * fuse_reply_iov
+ * fuse_reply_data
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param size number of bytes to read
+ * @param off offset to read from
+ * @param fi file information
+ */
+ void (*read)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+ struct fuse_file_info *fi);
+
+ /**
+ * Write data
+ *
+ * Write should return exactly the number of bytes requested
+ * except on error. An exception to this is when the file has
+ * been opened in 'direct_io' mode, in which case the return value
+ * of the write system call will reflect the return value of this
+ * operation.
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits.
+ *
+ * fi->fh will contain the value set by the open method, or will
+ * be undefined if the open method didn't set any value.
+ *
+ * Valid replies:
+ * fuse_reply_write
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param buf data to write
+ * @param size number of bytes to write
+ * @param off offset to write to
+ * @param fi file information
+ */
+ void (*write)(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size,
+ off_t off, struct fuse_file_info *fi);
+
+ /**
+ * Flush method
+ *
+ * This is called on each close() of the opened file.
+ *
+ * Since file descriptors can be duplicated (dup, dup2, fork), for
+ * one open call there may be many flush calls.
+ *
+ * Filesystems shouldn't assume that flush will always be called
+ * after some writes, or that if will be called at all.
+ *
+ * fi->fh will contain the value set by the open method, or will
+ * be undefined if the open method didn't set any value.
+ *
+ * NOTE: the name of the method is misleading, since (unlike
+ * fsync) the filesystem is not forced to flush pending writes.
+ * One reason to flush data is if the filesystem wants to return
+ * write errors during close. However, such use is non-portable
+ * because POSIX does not require [close] to wait for delayed I/O to
+ * complete.
+ *
+ * If the filesystem supports file locking operations (setlk,
+ * getlk) it should remove all locks belonging to 'fi->owner'.
+ *
+ * If this request is answered with an error code of ENOSYS,
+ * this is treated as success and future calls to flush() will
+ * succeed automatically without being send to the filesystem
+ * process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ *
+ * [close]:
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
+ */
+ void (*flush)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+
+ /**
+ * Release an open file
+ *
+ * Release is called when there are no more references to an open
+ * file: all file descriptors are closed and all memory mappings
+ * are unmapped.
+ *
+ * For every open call there will be exactly one release call (unless
+ * the filesystem is force-unmounted).
+ *
+ * The filesystem may reply with an error, but error values are
+ * not returned to close() or munmap() which triggered the
+ * release.
+ *
+ * fi->fh will contain the value set by the open method, or will
+ * be undefined if the open method didn't set any value.
+ * fi->flags will contain the same flags as for open.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ */
+ void (*release)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+
+ /**
+ * Synchronize file contents
+ *
+ * If the datasync parameter is non-zero, then only the user data
+ * should be flushed, not the meta data.
+ *
+ * If this request is answered with an error code of ENOSYS,
+ * this is treated as success and future calls to fsync() will
+ * succeed automatically without being send to the filesystem
+ * process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param datasync flag indicating if only data should be flushed
+ * @param fi file information
+ */
+ void (*fsync)(fuse_req_t req, fuse_ino_t ino, int datasync,
+ struct fuse_file_info *fi);
+
+ /**
+ * Open a directory
+ *
+ * Filesystem may store an arbitrary file handle (pointer, index,
+ * etc) in fi->fh, and use this in other all other directory
+ * stream operations (readdir, releasedir, fsyncdir).
+ *
+ * If this request is answered with an error code of ENOSYS and
+ * FUSE_CAP_NO_OPENDIR_SUPPORT is set in `fuse_conn_info.capable`,
+ * this is treated as success and future calls to opendir and
+ * releasedir will also succeed without being sent to the filesystem
+ * process. In addition, the kernel will cache readdir results
+ * as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR.
+ *
+ * Valid replies:
+ * fuse_reply_open
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ */
+ void (*opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
+
+ /**
+ * Read directory
+ *
+ * Send a buffer filled using fuse_add_direntry(), with size not
+ * exceeding the requested size. Send an empty buffer on end of
+ * stream.
+ *
+ * fi->fh will contain the value set by the opendir method, or
+ * will be undefined if the opendir method didn't set any value.
+ *
+ * Returning a directory entry from readdir() does not affect
+ * its lookup count.
+ *
+ * If off_t is non-zero, then it will correspond to one of the off_t
+ * values that was previously returned by readdir() for the same
+ * directory handle. In this case, readdir() should skip over entries
+ * coming before the position defined by the off_t value. If entries
+ * are added or removed while the directory handle is open, they filesystem
+ * may still include the entries that have been removed, and may not
+ * report the entries that have been created. However, addition or
+ * removal of entries must never cause readdir() to skip over unrelated
+ * entries or to report them more than once. This means
+ * that off_t can not be a simple index that enumerates the entries
+ * that have been returned but must contain sufficient information to
+ * uniquely determine the next directory entry to return even when the
+ * set of entries is changing.
+ *
+ * The function does not have to report the '.' and '..'
+ * entries, but is allowed to do so. Note that, if readdir does
+ * not return '.' or '..', they will not be implicitly returned,
+ * and this behavior is observable by the caller.
+ *
+ * Valid replies:
+ * fuse_reply_buf
+ * fuse_reply_data
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param size maximum number of bytes to send
+ * @param off offset to continue reading the directory stream
+ * @param fi file information
+ */
+ void (*readdir)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+ struct fuse_file_info *fi);
+
+ /**
+ * Release an open directory
+ *
+ * For every opendir call there will be exactly one releasedir
+ * call (unless the filesystem is force-unmounted).
+ *
+ * fi->fh will contain the value set by the opendir method, or
+ * will be undefined if the opendir method didn't set any value.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ */
+ void (*releasedir)(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi);
+
+ /**
+ * Synchronize directory contents
+ *
+ * If the datasync parameter is non-zero, then only the directory
+ * contents should be flushed, not the meta data.
+ *
+ * fi->fh will contain the value set by the opendir method, or
+ * will be undefined if the opendir method didn't set any value.
+ *
+ * If this request is answered with an error code of ENOSYS,
+ * this is treated as success and future calls to fsyncdir() will
+ * succeed automatically without being send to the filesystem
+ * process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param datasync flag indicating if only data should be flushed
+ * @param fi file information
+ */
+ void (*fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync,
+ struct fuse_file_info *fi);
+
+ /**
+ * Get file system statistics
+ *
+ * Valid replies:
+ * fuse_reply_statfs
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number, zero means "undefined"
+ */
+ void (*statfs)(fuse_req_t req, fuse_ino_t ino);
+
+ /**
+ * Set an extended attribute
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+ * future setxattr() requests will fail with EOPNOTSUPP without being
+ * send to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ */
+ void (*setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name,
+ const char *value, size_t size, int flags);
+
+ /**
+ * Get an extended attribute
+ *
+ * If size is zero, the size of the value should be sent with
+ * fuse_reply_xattr.
+ *
+ * If the size is non-zero, and the value fits in the buffer, the
+ * value should be sent with fuse_reply_buf.
+ *
+ * If the size is too small for the value, the ERANGE error should
+ * be sent.
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+ * future getxattr() requests will fail with EOPNOTSUPP without being
+ * send to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_buf
+ * fuse_reply_data
+ * fuse_reply_xattr
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param name of the extended attribute
+ * @param size maximum size of the value to send
+ */
+ void (*getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name,
+ size_t size);
+
+ /**
+ * List extended attribute names
+ *
+ * If size is zero, the total size of the attribute list should be
+ * sent with fuse_reply_xattr.
+ *
+ * If the size is non-zero, and the null character separated
+ * attribute list fits in the buffer, the list should be sent with
+ * fuse_reply_buf.
+ *
+ * If the size is too small for the list, the ERANGE error should
+ * be sent.
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+ * future listxattr() requests will fail with EOPNOTSUPP without being
+ * send to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_buf
+ * fuse_reply_data
+ * fuse_reply_xattr
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param size maximum size of the list to send
+ */
+ void (*listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size);
+
+ /**
+ * Remove an extended attribute
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+ * future removexattr() requests will fail with EOPNOTSUPP without being
+ * send to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param name of the extended attribute
+ */
+ void (*removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name);
+
+ /**
+ * Check file access permissions
+ *
+ * This will be called for the access() and chdir() system
+ * calls. If the 'default_permissions' mount option is given,
+ * this method is not called.
+ *
+ * This method is not called under Linux kernel versions 2.4.x
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent success, i.e. this and all future access()
+ * requests will succeed without being send to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param mask requested access mode
+ */
+ void (*access)(fuse_req_t req, fuse_ino_t ino, int mask);
+
+ /**
+ * Create and open a file
+ *
+ * If the file does not exist, first create it with the specified
+ * mode, and then open it.
+ *
+ * See the description of the open handler for more
+ * information.
+ *
+ * If this method is not implemented or under Linux kernel
+ * versions earlier than 2.6.15, the mknod() and open() methods
+ * will be called instead.
+ *
+ * If this request is answered with an error code of ENOSYS, the handler
+ * is treated as not implemented (i.e., for this and future requests the
+ * mknod() and open() handlers will be called instead).
+ *
+ * Valid replies:
+ * fuse_reply_create
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param parent inode number of the parent directory
+ * @param name to create
+ * @param mode file type and mode with which to create the new file
+ * @param fi file information
+ */
+ void (*create)(fuse_req_t req, fuse_ino_t parent, const char *name,
+ mode_t mode, struct fuse_file_info *fi);
+
+ /**
+ * Test for a POSIX file lock
+ *
+ * Valid replies:
+ * fuse_reply_lock
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ * @param lock the region/type to test
+ */
+ void (*getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+ struct flock *lock);
+
+ /**
+ * Acquire, modify or release a POSIX file lock
+ *
+ * For POSIX threads (NPTL) there's a 1-1 relation between pid and
+ * owner, but otherwise this is not always the case. For checking
+ * lock ownership, 'fi->owner' must be used. The l_pid field in
+ * 'struct flock' should only be used to fill in this field in
+ * getlk().
+ *
+ * Note: if the locking methods are not implemented, the kernel
+ * will still allow file locking to work locally. Hence these are
+ * only interesting for network filesystems and similar.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ * @param lock the region/type to set
+ * @param sleep locking operation may sleep
+ */
+ void (*setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+ struct flock *lock, int sleep);
+
+ /**
+ * Map block index within file to block index within device
+ *
+ * Note: This makes sense only for block device backed filesystems
+ * mounted with the 'blkdev' option
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure, i.e. all future bmap() requests will
+ * fail with the same error code without being send to the filesystem
+ * process.
+ *
+ * Valid replies:
+ * fuse_reply_bmap
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param blocksize unit of block index
+ * @param idx block index within file
+ */
+ void (*bmap)(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
+ uint64_t idx);
+
+ /**
+ * Ioctl
+ *
+ * Note: For unrestricted ioctls (not allowed for FUSE
+ * servers), data in and out areas can be discovered by giving
+ * iovs and setting FUSE_IOCTL_RETRY in *flags*. For
+ * restricted ioctls, kernel prepares in/out data area
+ * according to the information encoded in cmd.
+ *
+ * Valid replies:
+ * fuse_reply_ioctl_retry
+ * fuse_reply_ioctl
+ * fuse_reply_ioctl_iov
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param cmd ioctl command
+ * @param arg ioctl argument
+ * @param fi file information
+ * @param flags for FUSE_IOCTL_* flags
+ * @param in_buf data fetched from the caller
+ * @param in_bufsz number of fetched bytes
+ * @param out_bufsz maximum size of output data
+ *
+ * Note : the unsigned long request submitted by the application
+ * is truncated to 32 bits.
+ */
+ void (*ioctl)(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
+ struct fuse_file_info *fi, unsigned flags, const void *in_buf,
+ size_t in_bufsz, size_t out_bufsz);
+
+ /**
+ * Poll for IO readiness
+ *
+ * Note: If ph is non-NULL, the client should notify
+ * when IO readiness events occur by calling
+ * fuse_lowlevel_notify_poll() with the specified ph.
+ *
+ * Regardless of the number of times poll with a non-NULL ph
+ * is received, single notification is enough to clear all.
+ * Notifying more times incurs overhead but doesn't harm
+ * correctness.
+ *
+ * The callee is responsible for destroying ph with
+ * fuse_pollhandle_destroy() when no longer in use.
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as success (with a kernel-defined default poll-mask) and
+ * future calls to pull() will succeed the same way without being send
+ * to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_poll
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ * @param ph poll handle to be used for notification
+ */
+ void (*poll)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+ struct fuse_pollhandle *ph);
+
+ /**
+ * Write data made available in a buffer
+ *
+ * This is a more generic version of the ->write() method. If
+ * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the
+ * kernel supports splicing from the fuse device, then the
+ * data will be made available in pipe for supporting zero
+ * copy data transfer.
+ *
+ * buf->count is guaranteed to be one (and thus buf->idx is
+ * always zero). The write_buf handler must ensure that
+ * bufv->off is correctly updated (reflecting the number of
+ * bytes read from bufv->buf[0]).
+ *
+ * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+ * expected to reset the setuid and setgid bits.
+ *
+ * Valid replies:
+ * fuse_reply_write
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param bufv buffer containing the data
+ * @param off offset to write to
+ * @param fi file information
+ */
+ void (*write_buf)(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv,
+ off_t off, struct fuse_file_info *fi);
+
+ /**
+ * Callback function for the retrieve request
+ *
+ * Valid replies:
+ * fuse_reply_none
+ *
+ * @param req request handle
+ * @param cookie user data supplied to fuse_lowlevel_notify_retrieve()
+ * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve()
+ * @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
+ * @param bufv the buffer containing the returned data
+ */
+ void (*retrieve_reply)(fuse_req_t req, void *cookie, fuse_ino_t ino,
+ off_t offset, struct fuse_bufvec *bufv);
+
+ /**
+ * Forget about multiple inodes
+ *
+ * See description of the forget function for more
+ * information.
+ *
+ * Valid replies:
+ * fuse_reply_none
+ *
+ * @param req request handle
+ */
+ void (*forget_multi)(fuse_req_t req, size_t count,
+ struct fuse_forget_data *forgets);
+
+ /**
+ * Acquire, modify or release a BSD file lock
+ *
+ * Note: if the locking methods are not implemented, the kernel
+ * will still allow file locking to work locally. Hence these are
+ * only interesting for network filesystems and similar.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param fi file information
+ * @param op the locking operation, see flock(2)
+ */
+ void (*flock)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+ int op);
+
+ /**
+ * Allocate requested space. If this function returns success then
+ * subsequent writes to the specified range shall not fail due to the lack
+ * of free space on the file system storage media.
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+ * future fallocate() requests will fail with EOPNOTSUPP without being
+ * send to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param offset starting point for allocated region
+ * @param length size of allocated region
+ * @param mode determines the operation to be performed on the given range,
+ * see fallocate(2)
+ */
+ void (*fallocate)(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset,
+ off_t length, struct fuse_file_info *fi);
+
+ /**
+ * Read directory with attributes
+ *
+ * Send a buffer filled using fuse_add_direntry_plus(), with size not
+ * exceeding the requested size. Send an empty buffer on end of
+ * stream.
+ *
+ * fi->fh will contain the value set by the opendir method, or
+ * will be undefined if the opendir method didn't set any value.
+ *
+ * In contrast to readdir() (which does not affect the lookup counts),
+ * the lookup count of every entry returned by readdirplus(), except "."
+ * and "..", is incremented by one.
+ *
+ * Valid replies:
+ * fuse_reply_buf
+ * fuse_reply_data
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param size maximum number of bytes to send
+ * @param off offset to continue reading the directory stream
+ * @param fi file information
+ */
+ void (*readdirplus)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+ struct fuse_file_info *fi);
+
+ /**
+ * Copy a range of data from one file to another
+ *
+ * Performs an optimized copy between two file descriptors without the
+ * additional cost of transferring data through the FUSE kernel module
+ * to user space (glibc) and then back into the FUSE filesystem again.
+ *
+ * In case this method is not implemented, glibc falls back to reading
+ * data from the source and writing to the destination. Effectively
+ * doing an inefficient copy of the data.
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+ * future copy_file_range() requests will fail with EOPNOTSUPP without
+ * being send to the filesystem process.
+ *
+ * Valid replies:
+ * fuse_reply_write
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino_in the inode number or the source file
+ * @param off_in starting point from were the data should be read
+ * @param fi_in file information of the source file
+ * @param ino_out the inode number or the destination file
+ * @param off_out starting point where the data should be written
+ * @param fi_out file information of the destination file
+ * @param len maximum size of the data to copy
+ * @param flags passed along with the copy_file_range() syscall
+ */
+ void (*copy_file_range)(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
+ struct fuse_file_info *fi_in, fuse_ino_t ino_out,
+ off_t off_out, struct fuse_file_info *fi_out,
+ size_t len, int flags);
+
+ /**
+ * Find next data or hole after the specified offset
+ *
+ * If this request is answered with an error code of ENOSYS, this is
+ * treated as a permanent failure, i.e. all future lseek() requests will
+ * fail with the same error code without being send to the filesystem
+ * process.
+ *
+ * Valid replies:
+ * fuse_reply_lseek
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param off offset to start search from
+ * @param whence either SEEK_DATA or SEEK_HOLE
+ * @param fi file information
+ */
+ void (*lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+ struct fuse_file_info *fi);
};
/**
@@ -1305,7 +1307,7 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
* @return zero for success, -errno for failure to send reply
*/
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
- const struct fuse_file_info *fi);
+ const struct fuse_file_info *fi);
/**
* Reply with attributes
@@ -1315,11 +1317,11 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
*
* @param req request handle
* @param attr the attributes
- * @param attr_timeout validity timeout (in seconds) for the attributes
+ * @param attr_timeout validity timeout (in seconds) for the attributes
* @return zero for success, -errno for failure to send reply
*/
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
- double attr_timeout);
+ double attr_timeout);
/**
* Reply with the contents of a symbolic link
@@ -1417,7 +1419,7 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
* @return zero for success, -errno for failure to send reply
*/
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
- enum fuse_buf_copy_flags flags);
+ enum fuse_buf_copy_flags flags);
/**
* Reply with data vector
@@ -1480,9 +1482,9 @@ int fuse_reply_lock(fuse_req_t req, const struct flock *lock);
*/
int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
-/* ----------------------------------------------------------- *
- * Filling a buffer in readdir *
- * ----------------------------------------------------------- */
+/*
+ * Filling a buffer in readdir
+ */
/**
* Add a directory entry to the buffer
@@ -1512,8 +1514,7 @@ int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
* @return the space needed for the entry
*/
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
- const char *name, const struct stat *stbuf,
- off_t off);
+ const char *name, const struct stat *stbuf, off_t off);
/**
* Add a directory entry to the buffer with the attributes
@@ -1529,8 +1530,8 @@ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
* @return the space needed for the entry
*/
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
- const char *name,
- const struct fuse_entry_param *e, off_t off);
+ const char *name,
+ const struct fuse_entry_param *e, off_t off);
/**
* Reply to ask for data fetch and output buffer preparation. ioctl
@@ -1547,9 +1548,9 @@ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
* @param out_count number of entries in out_iov
* @return zero for success, -errno for failure to send reply
*/
-int fuse_reply_ioctl_retry(fuse_req_t req,
- const struct iovec *in_iov, size_t in_count,
- const struct iovec *out_iov, size_t out_count);
+int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov,
+ size_t in_count, const struct iovec *out_iov,
+ size_t out_count);
/**
* Reply to finish ioctl
@@ -1576,7 +1577,7 @@ int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
* @param count the size of vector
*/
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
- int count);
+ int count);
/**
* Reply with poll result event mask
@@ -1598,9 +1599,9 @@ int fuse_reply_poll(fuse_req_t req, unsigned revents);
*/
int fuse_reply_lseek(fuse_req_t req, off_t off);
-/* ----------------------------------------------------------- *
- * Notification *
- * ----------------------------------------------------------- */
+/*
+ * Notification
+ */
/**
* Notify IO readiness event
@@ -1635,7 +1636,7 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
* @return zero for success, -errno for failure
*/
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
- off_t off, off_t len);
+ off_t off, off_t len);
/**
* Notify to invalidate parent attributes and the dentry matching
@@ -1663,7 +1664,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
* @return zero for success, -errno for failure
*/
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
- const char *name, size_t namelen);
+ const char *name, size_t namelen);
/**
* This function behaves like fuse_lowlevel_notify_inval_entry() with
@@ -1693,9 +1694,9 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
* @param namelen strlen() of file name
* @return zero for success, -errno for failure
*/
-int fuse_lowlevel_notify_delete(struct fuse_session *se,
- fuse_ino_t parent, fuse_ino_t child,
- const char *name, size_t namelen);
+int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+ fuse_ino_t child, const char *name,
+ size_t namelen);
/**
* Store data to the kernel buffers
@@ -1723,8 +1724,8 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se,
* @return zero for success, -errno for failure
*/
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
- off_t offset, struct fuse_bufvec *bufv,
- enum fuse_buf_copy_flags flags);
+ off_t offset, struct fuse_bufvec *bufv,
+ enum fuse_buf_copy_flags flags);
/**
* Retrieve data from the kernel buffers
*
@@ -1755,12 +1756,12 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
* @return zero for success, -errno for failure
*/
int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
- size_t size, off_t offset, void *cookie);
+ size_t size, off_t offset, void *cookie);
-/* ----------------------------------------------------------- *
- * Utility functions *
- * ----------------------------------------------------------- */
+/*
+ * Utility functions
+ */
/**
* Get the userdata from the request
@@ -1822,7 +1823,7 @@ typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data);
* @param data user data passed to the callback function
*/
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
- void *data);
+ void *data);
/**
* Check if a request has already been interrupted
@@ -1833,9 +1834,9 @@ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
int fuse_req_interrupted(fuse_req_t req);
-/* ----------------------------------------------------------- *
- * Inquiry functions *
- * ----------------------------------------------------------- */
+/*
+ * Inquiry functions
+ */
/**
* Print low-level version information to stdout.
@@ -1854,18 +1855,18 @@ void fuse_lowlevel_help(void);
*/
void fuse_cmdline_help(void);
-/* ----------------------------------------------------------- *
- * Filesystem setup & teardown *
- * ----------------------------------------------------------- */
+/*
+ * Filesystem setup & teardown
+ */
struct fuse_cmdline_opts {
- int foreground;
- int debug;
- int nodefault_subtype;
- char *mountpoint;
- int show_version;
- int show_help;
- unsigned int max_idle_threads;
+ int foreground;
+ int debug;
+ int nodefault_subtype;
+ char *mountpoint;
+ int show_version;
+ int show_help;
+ unsigned int max_idle_threads;
};
/**
@@ -1886,8 +1887,7 @@ struct fuse_cmdline_opts {
* @param opts output argument for parsed options
* @return 0 on success, -1 on failure
*/
-int fuse_parse_cmdline(struct fuse_args *args,
- struct fuse_cmdline_opts *opts);
+int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts);
/**
* Create a low level session.
@@ -1918,8 +1918,8 @@ int fuse_parse_cmdline(struct fuse_args *args,
* @return the fuse session on success, NULL on failure
**/
struct fuse_session *fuse_session_new(struct fuse_args *args,
- const struct fuse_lowlevel_ops *op,
- size_t op_size, void *userdata);
+ const struct fuse_lowlevel_ops *op,
+ size_t op_size, void *userdata);
/**
* Mount a FUSE file system.
@@ -2014,9 +2014,9 @@ void fuse_session_unmount(struct fuse_session *se);
*/
void fuse_session_destroy(struct fuse_session *se);
-/* ----------------------------------------------------------- *
- * Custom event loop support *
- * ----------------------------------------------------------- */
+/*
+ * Custom event loop support
+ */
/**
* Return file descriptor for communication with kernel.
@@ -2043,7 +2043,7 @@ int fuse_session_fd(struct fuse_session *se);
* @param buf the fuse_buf containing the request
*/
void fuse_session_process_buf(struct fuse_session *se,
- const struct fuse_buf *buf);
+ const struct fuse_buf *buf);
/**
* Read a raw request from the kernel into the supplied buffer.
diff --git a/tools/virtiofsd/fuse_misc.h b/tools/virtiofsd/fuse_misc.h
index 2f6663ed7d..f252baa752 100644
--- a/tools/virtiofsd/fuse_misc.h
+++ b/tools/virtiofsd/fuse_misc.h
@@ -1,18 +1,18 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB
+ */
#include <pthread.h>
/*
- Versioned symbols cannot be used in some cases because it
- - confuse the dynamic linker in uClibc
- - not supported on MacOSX (in MachO binary format)
-*/
+ * Versioned symbols cannot be used in some cases because it
+ * - confuse the dynamic linker in uClibc
+ * - not supported on MacOSX (in MachO binary format)
+ */
#if (!defined(__UCLIBC__) && !defined(__APPLE__))
#define FUSE_SYMVER(x) __asm__(x)
#else
@@ -25,11 +25,11 @@
/* Is this hack still needed? */
static inline void fuse_mutex_init(pthread_mutex_t *mut)
{
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
- pthread_mutex_init(mut, &attr);
- pthread_mutexattr_destroy(&attr);
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+ pthread_mutex_init(mut, &attr);
+ pthread_mutexattr_destroy(&attr);
}
#endif
diff --git a/tools/virtiofsd/fuse_opt.c b/tools/virtiofsd/fuse_opt.c
index 93066b926e..edd36f4a3b 100644
--- a/tools/virtiofsd/fuse_opt.c
+++ b/tools/virtiofsd/fuse_opt.c
@@ -1,423 +1,450 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- Implementation of option parsing routines (dealing with `struct
- fuse_args`).
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * Implementation of option parsing routines (dealing with `struct
+ * fuse_args`).
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB
+ */
+#include "fuse_opt.h"
#include "config.h"
#include "fuse_i.h"
-#include "fuse_opt.h"
#include "fuse_misc.h"
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
struct fuse_opt_context {
- void *data;
- const struct fuse_opt *opt;
- fuse_opt_proc_t proc;
- int argctr;
- int argc;
- char **argv;
- struct fuse_args outargs;
- char *opts;
- int nonopt;
+ void *data;
+ const struct fuse_opt *opt;
+ fuse_opt_proc_t proc;
+ int argctr;
+ int argc;
+ char **argv;
+ struct fuse_args outargs;
+ char *opts;
+ int nonopt;
};
void fuse_opt_free_args(struct fuse_args *args)
{
- if (args) {
- if (args->argv && args->allocated) {
- int i;
- for (i = 0; i < args->argc; i++)
- free(args->argv[i]);
- free(args->argv);
- }
- args->argc = 0;
- args->argv = NULL;
- args->allocated = 0;
- }
+ if (args) {
+ if (args->argv && args->allocated) {
+ int i;
+ for (i = 0; i < args->argc; i++) {
+ free(args->argv[i]);
+ }
+ free(args->argv);
+ }
+ args->argc = 0;
+ args->argv = NULL;
+ args->allocated = 0;
+ }
}
static int alloc_failed(void)
{
- fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
- return -1;
+ fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
+ return -1;
}
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
{
- char **newargv;
- char *newarg;
-
- assert(!args->argv || args->allocated);
-
- newarg = strdup(arg);
- if (!newarg)
- return alloc_failed();
-
- newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
- if (!newargv) {
- free(newarg);
- return alloc_failed();
- }
-
- args->argv = newargv;
- args->allocated = 1;
- args->argv[args->argc++] = newarg;
- args->argv[args->argc] = NULL;
- return 0;
+ char **newargv;
+ char *newarg;
+
+ assert(!args->argv || args->allocated);
+
+ newarg = strdup(arg);
+ if (!newarg) {
+ return alloc_failed();
+ }
+
+ newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
+ if (!newargv) {
+ free(newarg);
+ return alloc_failed();
+ }
+
+ args->argv = newargv;
+ args->allocated = 1;
+ args->argv[args->argc++] = newarg;
+ args->argv[args->argc] = NULL;
+ return 0;
}
static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
- const char *arg)
+ const char *arg)
{
- assert(pos <= args->argc);
- if (fuse_opt_add_arg(args, arg) == -1)
- return -1;
-
- if (pos != args->argc - 1) {
- char *newarg = args->argv[args->argc - 1];
- memmove(&args->argv[pos + 1], &args->argv[pos],
- sizeof(char *) * (args->argc - pos - 1));
- args->argv[pos] = newarg;
- }
- return 0;
+ assert(pos <= args->argc);
+ if (fuse_opt_add_arg(args, arg) == -1) {
+ return -1;
+ }
+
+ if (pos != args->argc - 1) {
+ char *newarg = args->argv[args->argc - 1];
+ memmove(&args->argv[pos + 1], &args->argv[pos],
+ sizeof(char *) * (args->argc - pos - 1));
+ args->argv[pos] = newarg;
+ }
+ return 0;
}
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
{
- return fuse_opt_insert_arg_common(args, pos, arg);
+ return fuse_opt_insert_arg_common(args, pos, arg);
}
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
{
- if (ctx->argctr + 1 >= ctx->argc) {
- fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt);
- return -1;
- }
- ctx->argctr++;
- return 0;
+ if (ctx->argctr + 1 >= ctx->argc) {
+ fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt);
+ return -1;
+ }
+ ctx->argctr++;
+ return 0;
}
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
{
- return fuse_opt_add_arg(&ctx->outargs, arg);
+ return fuse_opt_add_arg(&ctx->outargs, arg);
}
static int add_opt_common(char **opts, const char *opt, int esc)
{
- unsigned oldlen = *opts ? strlen(*opts) : 0;
- char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
-
- if (!d)
- return alloc_failed();
-
- *opts = d;
- if (oldlen) {
- d += oldlen;
- *d++ = ',';
- }
-
- for (; *opt; opt++) {
- if (esc && (*opt == ',' || *opt == '\\'))
- *d++ = '\\';
- *d++ = *opt;
- }
- *d = '\0';
-
- return 0;
+ unsigned oldlen = *opts ? strlen(*opts) : 0;
+ char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
+
+ if (!d) {
+ return alloc_failed();
+ }
+
+ *opts = d;
+ if (oldlen) {
+ d += oldlen;
+ *d++ = ',';
+ }
+
+ for (; *opt; opt++) {
+ if (esc && (*opt == ',' || *opt == '\\')) {
+ *d++ = '\\';
+ }
+ *d++ = *opt;
+ }
+ *d = '\0';
+
+ return 0;
}
int fuse_opt_add_opt(char **opts, const char *opt)
{
- return add_opt_common(opts, opt, 0);
+ return add_opt_common(opts, opt, 0);
}
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
{
- return add_opt_common(opts, opt, 1);
+ return add_opt_common(opts, opt, 1);
}
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
{
- return add_opt_common(&ctx->opts, opt, 1);
+ return add_opt_common(&ctx->opts, opt, 1);
}
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
- int iso)
+ int iso)
{
- if (key == FUSE_OPT_KEY_DISCARD)
- return 0;
-
- if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
- int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
- if (res == -1 || !res)
- return res;
- }
- if (iso)
- return add_opt(ctx, arg);
- else
- return add_arg(ctx, arg);
+ if (key == FUSE_OPT_KEY_DISCARD) {
+ return 0;
+ }
+
+ if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
+ int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
+ if (res == -1 || !res) {
+ return res;
+ }
+ }
+ if (iso) {
+ return add_opt(ctx, arg);
+ } else {
+ return add_arg(ctx, arg);
+ }
}
static int match_template(const char *t, const char *arg, unsigned *sepp)
{
- int arglen = strlen(arg);
- const char *sep = strchr(t, '=');
- sep = sep ? sep : strchr(t, ' ');
- if (sep && (!sep[1] || sep[1] == '%')) {
- int tlen = sep - t;
- if (sep[0] == '=')
- tlen ++;
- if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
- *sepp = sep - t;
- return 1;
- }
- }
- if (strcmp(t, arg) == 0) {
- *sepp = 0;
- return 1;
- }
- return 0;
+ int arglen = strlen(arg);
+ const char *sep = strchr(t, '=');
+ sep = sep ? sep : strchr(t, ' ');
+ if (sep && (!sep[1] || sep[1] == '%')) {
+ int tlen = sep - t;
+ if (sep[0] == '=') {
+ tlen++;
+ }
+ if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
+ *sepp = sep - t;
+ return 1;
+ }
+ }
+ if (strcmp(t, arg) == 0) {
+ *sepp = 0;
+ return 1;
+ }
+ return 0;
}
static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
- const char *arg, unsigned *sepp)
+ const char *arg, unsigned *sepp)
{
- for (; opt && opt->templ; opt++)
- if (match_template(opt->templ, arg, sepp))
- return opt;
- return NULL;
+ for (; opt && opt->templ; opt++) {
+ if (match_template(opt->templ, arg, sepp)) {
+ return opt;
+ }
+ }
+ return NULL;
}
int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
{
- unsigned dummy;
- return find_opt(opts, opt, &dummy) ? 1 : 0;
+ unsigned dummy;
+ return find_opt(opts, opt, &dummy) ? 1 : 0;
}
static int process_opt_param(void *var, const char *format, const char *param,
- const char *arg)
+ const char *arg)
{
- assert(format[0] == '%');
- if (format[1] == 's') {
- char **s = var;
- char *copy = strdup(param);
- if (!copy)
- return alloc_failed();
-
- free(*s);
- *s = copy;
- } else {
- if (sscanf(param, format, var) != 1) {
- fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n", arg);
- return -1;
- }
- }
- return 0;
+ assert(format[0] == '%');
+ if (format[1] == 's') {
+ char **s = var;
+ char *copy = strdup(param);
+ if (!copy) {
+ return alloc_failed();
+ }
+
+ free(*s);
+ *s = copy;
+ } else {
+ if (sscanf(param, format, var) != 1) {
+ fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n",
+ arg);
+ return -1;
+ }
+ }
+ return 0;
}
-static int process_opt(struct fuse_opt_context *ctx,
- const struct fuse_opt *opt, unsigned sep,
- const char *arg, int iso)
+static int process_opt(struct fuse_opt_context *ctx, const struct fuse_opt *opt,
+ unsigned sep, const char *arg, int iso)
{
- if (opt->offset == -1U) {
- if (call_proc(ctx, arg, opt->value, iso) == -1)
- return -1;
- } else {
- void *var = (char *)ctx->data + opt->offset;
- if (sep && opt->templ[sep + 1]) {
- const char *param = arg + sep;
- if (opt->templ[sep] == '=')
- param ++;
- if (process_opt_param(var, opt->templ + sep + 1,
- param, arg) == -1)
- return -1;
- } else
- *(int *)var = opt->value;
- }
- return 0;
+ if (opt->offset == -1U) {
+ if (call_proc(ctx, arg, opt->value, iso) == -1) {
+ return -1;
+ }
+ } else {
+ void *var = (char *)ctx->data + opt->offset;
+ if (sep && opt->templ[sep + 1]) {
+ const char *param = arg + sep;
+ if (opt->templ[sep] == '=') {
+ param++;
+ }
+ if (process_opt_param(var, opt->templ + sep + 1, param, arg) ==
+ -1) {
+ return -1;
+ }
+ } else {
+ *(int *)var = opt->value;
+ }
+ }
+ return 0;
}
static int process_opt_sep_arg(struct fuse_opt_context *ctx,
- const struct fuse_opt *opt, unsigned sep,
- const char *arg, int iso)
+ const struct fuse_opt *opt, unsigned sep,
+ const char *arg, int iso)
{
- int res;
- char *newarg;
- char *param;
-
- if (next_arg(ctx, arg) == -1)
- return -1;
-
- param = ctx->argv[ctx->argctr];
- newarg = malloc(sep + strlen(param) + 1);
- if (!newarg)
- return alloc_failed();
-
- memcpy(newarg, arg, sep);
- strcpy(newarg + sep, param);
- res = process_opt(ctx, opt, sep, newarg, iso);
- free(newarg);
-
- return res;
+ int res;
+ char *newarg;
+ char *param;
+
+ if (next_arg(ctx, arg) == -1) {
+ return -1;
+ }
+
+ param = ctx->argv[ctx->argctr];
+ newarg = malloc(sep + strlen(param) + 1);
+ if (!newarg) {
+ return alloc_failed();
+ }
+
+ memcpy(newarg, arg, sep);
+ strcpy(newarg + sep, param);
+ res = process_opt(ctx, opt, sep, newarg, iso);
+ free(newarg);
+
+ return res;
}
static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
{
- unsigned sep;
- const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
- if (opt) {
- for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
- int res;
- if (sep && opt->templ[sep] == ' ' && !arg[sep])
- res = process_opt_sep_arg(ctx, opt, sep, arg,
- iso);
- else
- res = process_opt(ctx, opt, sep, arg, iso);
- if (res == -1)
- return -1;
- }
- return 0;
- } else
- return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
+ unsigned sep;
+ const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
+ if (opt) {
+ for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
+ int res;
+ if (sep && opt->templ[sep] == ' ' && !arg[sep]) {
+ res = process_opt_sep_arg(ctx, opt, sep, arg, iso);
+ } else {
+ res = process_opt(ctx, opt, sep, arg, iso);
+ }
+ if (res == -1) {
+ return -1;
+ }
+ }
+ return 0;
+ } else {
+ return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
+ }
}
static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
{
- char *s = opts;
- char *d = s;
- int end = 0;
-
- while (!end) {
- if (*s == '\0')
- end = 1;
- if (*s == ',' || end) {
- int res;
-
- *d = '\0';
- res = process_gopt(ctx, opts, 1);
- if (res == -1)
- return -1;
- d = opts;
- } else {
- if (s[0] == '\\' && s[1] != '\0') {
- s++;
- if (s[0] >= '0' && s[0] <= '3' &&
- s[1] >= '0' && s[1] <= '7' &&
- s[2] >= '0' && s[2] <= '7') {
- *d++ = (s[0] - '0') * 0100 +
- (s[1] - '0') * 0010 +
- (s[2] - '0');
- s += 2;
- } else {
- *d++ = *s;
- }
- } else {
- *d++ = *s;
- }
- }
- s++;
- }
-
- return 0;
+ char *s = opts;
+ char *d = s;
+ int end = 0;
+
+ while (!end) {
+ if (*s == '\0') {
+ end = 1;
+ }
+ if (*s == ',' || end) {
+ int res;
+
+ *d = '\0';
+ res = process_gopt(ctx, opts, 1);
+ if (res == -1) {
+ return -1;
+ }
+ d = opts;
+ } else {
+ if (s[0] == '\\' && s[1] != '\0') {
+ s++;
+ if (s[0] >= '0' && s[0] <= '3' && s[1] >= '0' && s[1] <= '7' &&
+ s[2] >= '0' && s[2] <= '7') {
+ *d++ = (s[0] - '0') * 0100 + (s[1] - '0') * 0010 +
+ (s[2] - '0');
+ s += 2;
+ } else {
+ *d++ = *s;
+ }
+ } else {
+ *d++ = *s;
+ }
+ }
+ s++;
+ }
+
+ return 0;
}
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
{
- int res;
- char *copy = strdup(opts);
-
- if (!copy) {
- fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
- return -1;
- }
- res = process_real_option_group(ctx, copy);
- free(copy);
- return res;
+ int res;
+ char *copy = strdup(opts);
+
+ if (!copy) {
+ fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
+ return -1;
+ }
+ res = process_real_option_group(ctx, copy);
+ free(copy);
+ return res;
}
static int process_one(struct fuse_opt_context *ctx, const char *arg)
{
- if (ctx->nonopt || arg[0] != '-')
- return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
- else if (arg[1] == 'o') {
- if (arg[2])
- return process_option_group(ctx, arg + 2);
- else {
- if (next_arg(ctx, arg) == -1)
- return -1;
-
- return process_option_group(ctx,
- ctx->argv[ctx->argctr]);
- }
- } else if (arg[1] == '-' && !arg[2]) {
- if (add_arg(ctx, arg) == -1)
- return -1;
- ctx->nonopt = ctx->outargs.argc;
- return 0;
- } else
- return process_gopt(ctx, arg, 0);
+ if (ctx->nonopt || arg[0] != '-') {
+ return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
+ } else if (arg[1] == 'o') {
+ if (arg[2]) {
+ return process_option_group(ctx, arg + 2);
+ } else {
+ if (next_arg(ctx, arg) == -1) {
+ return -1;
+ }
+
+ return process_option_group(ctx, ctx->argv[ctx->argctr]);
+ }
+ } else if (arg[1] == '-' && !arg[2]) {
+ if (add_arg(ctx, arg) == -1) {
+ return -1;
+ }
+ ctx->nonopt = ctx->outargs.argc;
+ return 0;
+ } else {
+ return process_gopt(ctx, arg, 0);
+ }
}
static int opt_parse(struct fuse_opt_context *ctx)
{
- if (ctx->argc) {
- if (add_arg(ctx, ctx->argv[0]) == -1)
- return -1;
- }
-
- for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
- if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
- return -1;
-
- if (ctx->opts) {
- if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
- fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
- return -1;
- }
-
- /* If option separator ("--") is the last argument, remove it */
- if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
- strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
- free(ctx->outargs.argv[ctx->outargs.argc - 1]);
- ctx->outargs.argv[--ctx->outargs.argc] = NULL;
- }
-
- return 0;
+ if (ctx->argc) {
+ if (add_arg(ctx, ctx->argv[0]) == -1) {
+ return -1;
+ }
+ }
+
+ for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) {
+ if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) {
+ return -1;
+ }
+ }
+
+ if (ctx->opts) {
+ if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
+ fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) {
+ return -1;
+ }
+ }
+
+ /* If option separator ("--") is the last argument, remove it */
+ if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
+ strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
+ free(ctx->outargs.argv[ctx->outargs.argc - 1]);
+ ctx->outargs.argv[--ctx->outargs.argc] = NULL;
+ }
+
+ return 0;
}
int fuse_opt_parse(struct fuse_args *args, void *data,
- const struct fuse_opt opts[], fuse_opt_proc_t proc)
+ const struct fuse_opt opts[], fuse_opt_proc_t proc)
{
- int res;
- struct fuse_opt_context ctx = {
- .data = data,
- .opt = opts,
- .proc = proc,
- };
-
- if (!args || !args->argv || !args->argc)
- return 0;
-
- ctx.argc = args->argc;
- ctx.argv = args->argv;
-
- res = opt_parse(&ctx);
- if (res != -1) {
- struct fuse_args tmp = *args;
- *args = ctx.outargs;
- ctx.outargs = tmp;
- }
- free(ctx.opts);
- fuse_opt_free_args(&ctx.outargs);
- return res;
+ int res;
+ struct fuse_opt_context ctx = {
+ .data = data,
+ .opt = opts,
+ .proc = proc,
+ };
+
+ if (!args || !args->argv || !args->argc) {
+ return 0;
+ }
+
+ ctx.argc = args->argc;
+ ctx.argv = args->argv;
+
+ res = opt_parse(&ctx);
+ if (res != -1) {
+ struct fuse_args tmp = *args;
+ *args = ctx.outargs;
+ ctx.outargs = tmp;
+ }
+ free(ctx.opts);
+ fuse_opt_free_args(&ctx.outargs);
+ return res;
}
diff --git a/tools/virtiofsd/fuse_opt.h b/tools/virtiofsd/fuse_opt.h
index 69102555be..8f59b4d301 100644
--- a/tools/virtiofsd/fuse_opt.h
+++ b/tools/virtiofsd/fuse_opt.h
@@ -1,10 +1,10 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB.
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB.
+ */
#ifndef FUSE_OPT_H_
#define FUSE_OPT_H_
@@ -37,7 +37,7 @@
*
* - 'offsetof(struct foo, member)' actions i) and iii)
*
- * - -1 action ii)
+ * - -1 action ii)
*
* The 'offsetof()' macro is defined in the <stddef.h> header.
*
@@ -48,7 +48,7 @@
*
* The types of templates are:
*
- * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
+ * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
* themselves. Invalid values are "--" and anything beginning
* with "-o"
*
@@ -71,58 +71,67 @@
* freed.
*/
struct fuse_opt {
- /** Matching template and optional parameter formatting */
- const char *templ;
+ /** Matching template and optional parameter formatting */
+ const char *templ;
- /**
- * Offset of variable within 'data' parameter of fuse_opt_parse()
- * or -1
- */
- unsigned long offset;
+ /**
+ * Offset of variable within 'data' parameter of fuse_opt_parse()
+ * or -1
+ */
+ unsigned long offset;
- /**
- * Value to set the variable to, or to be passed as 'key' to the
- * processing function. Ignored if template has a format
- */
- int value;
+ /**
+ * Value to set the variable to, or to be passed as 'key' to the
+ * processing function. Ignored if template has a format
+ */
+ int value;
};
/**
- * Key option. In case of a match, the processing function will be
+ * Key option. In case of a match, the processing function will be
* called with the specified key.
*/
-#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
+#define FUSE_OPT_KEY(templ, key) \
+ { \
+ templ, -1U, key \
+ }
/**
- * Last option. An array of 'struct fuse_opt' must end with a NULL
+ * Last option. An array of 'struct fuse_opt' must end with a NULL
* template value
*/
-#define FUSE_OPT_END { NULL, 0, 0 }
+#define FUSE_OPT_END \
+ { \
+ NULL, 0, 0 \
+ }
/**
* Argument list
*/
struct fuse_args {
- /** Argument count */
- int argc;
+ /** Argument count */
+ int argc;
- /** Argument vector. NULL terminated */
- char **argv;
+ /** Argument vector. NULL terminated */
+ char **argv;
- /** Is 'argv' allocated? */
- int allocated;
+ /** Is 'argv' allocated? */
+ int allocated;
};
/**
* Initializer for 'struct fuse_args'
*/
-#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
+#define FUSE_ARGS_INIT(argc, argv) \
+ { \
+ argc, argv, 0 \
+ }
/**
* Key value passed to the processing function if an option did not
* match any template
*/
-#define FUSE_OPT_KEY_OPT -1
+#define FUSE_OPT_KEY_OPT -1
/**
* Key value passed to the processing function for all non-options
@@ -130,7 +139,7 @@ struct fuse_args {
* Non-options are the arguments beginning with a character other than
* '-' or all arguments after the special '--' option
*/
-#define FUSE_OPT_KEY_NONOPT -2
+#define FUSE_OPT_KEY_NONOPT -2
/**
* Special key value for options to keep
@@ -174,7 +183,7 @@ struct fuse_args {
* @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
*/
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
- struct fuse_args *outargs);
+ struct fuse_args *outargs);
/**
* Option parsing function
@@ -197,7 +206,7 @@ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
* @return -1 on error, 0 on success
*/
int fuse_opt_parse(struct fuse_args *args, void *data,
- const struct fuse_opt opts[], fuse_opt_proc_t proc);
+ const struct fuse_opt opts[], fuse_opt_proc_t proc);
/**
* Add an option to a comma separated option list
diff --git a/tools/virtiofsd/fuse_signals.c b/tools/virtiofsd/fuse_signals.c
index 4271947bd4..19d6791cb9 100644
--- a/tools/virtiofsd/fuse_signals.c
+++ b/tools/virtiofsd/fuse_signals.c
@@ -1,91 +1,95 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- Utility functions for setting signal handlers.
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * Utility functions for setting signal handlers.
+ *
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB
+ */
#include "config.h"
-#include "fuse_lowlevel.h"
#include "fuse_i.h"
+#include "fuse_lowlevel.h"
-#include <stdio.h>
-#include <string.h>
#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
static struct fuse_session *fuse_instance;
static void exit_handler(int sig)
{
- if (fuse_instance) {
- fuse_session_exit(fuse_instance);
- if(sig <= 0) {
- fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
- abort();
- }
- fuse_instance->error = sig;
- }
+ if (fuse_instance) {
+ fuse_session_exit(fuse_instance);
+ if (sig <= 0) {
+ fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
+ abort();
+ }
+ fuse_instance->error = sig;
+ }
}
static void do_nothing(int sig)
{
- (void) sig;
+ (void)sig;
}
static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
{
- struct sigaction sa;
- struct sigaction old_sa;
+ struct sigaction sa;
+ struct sigaction old_sa;
- memset(&sa, 0, sizeof(struct sigaction));
- sa.sa_handler = remove ? SIG_DFL : handler;
- sigemptyset(&(sa.sa_mask));
- sa.sa_flags = 0;
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_handler = remove ? SIG_DFL : handler;
+ sigemptyset(&(sa.sa_mask));
+ sa.sa_flags = 0;
- if (sigaction(sig, NULL, &old_sa) == -1) {
- perror("fuse: cannot get old signal handler");
- return -1;
- }
+ if (sigaction(sig, NULL, &old_sa) == -1) {
+ perror("fuse: cannot get old signal handler");
+ return -1;
+ }
- if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
- sigaction(sig, &sa, NULL) == -1) {
- perror("fuse: cannot set signal handler");
- return -1;
- }
- return 0;
+ if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
+ sigaction(sig, &sa, NULL) == -1) {
+ perror("fuse: cannot set signal handler");
+ return -1;
+ }
+ return 0;
}
int fuse_set_signal_handlers(struct fuse_session *se)
{
- /* If we used SIG_IGN instead of the do_nothing function,
- then we would be unable to tell if we set SIG_IGN (and
- thus should reset to SIG_DFL in fuse_remove_signal_handlers)
- or if it was already set to SIG_IGN (and should be left
- untouched. */
- if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
- set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
- set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
- set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1)
- return -1;
+ /*
+ * If we used SIG_IGN instead of the do_nothing function,
+ * then we would be unable to tell if we set SIG_IGN (and
+ * thus should reset to SIG_DFL in fuse_remove_signal_handlers)
+ * or if it was already set to SIG_IGN (and should be left
+ * untouched.
+ */
+ if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
+ set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
+ set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
+ set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1) {
+ return -1;
+ }
- fuse_instance = se;
- return 0;
+ fuse_instance = se;
+ return 0;
}
void fuse_remove_signal_handlers(struct fuse_session *se)
{
- if (fuse_instance != se)
- fuse_log(FUSE_LOG_ERR,
- "fuse: fuse_remove_signal_handlers: unknown session\n");
- else
- fuse_instance = NULL;
+ if (fuse_instance != se) {
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: fuse_remove_signal_handlers: unknown session\n");
+ } else {
+ fuse_instance = NULL;
+ }
- set_one_signal_handler(SIGHUP, exit_handler, 1);
- set_one_signal_handler(SIGINT, exit_handler, 1);
- set_one_signal_handler(SIGTERM, exit_handler, 1);
- set_one_signal_handler(SIGPIPE, do_nothing, 1);
+ set_one_signal_handler(SIGHUP, exit_handler, 1);
+ set_one_signal_handler(SIGINT, exit_handler, 1);
+ set_one_signal_handler(SIGTERM, exit_handler, 1);
+ set_one_signal_handler(SIGPIPE, do_nothing, 1);
}
diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
index 5a2e64c6d0..5711dd2660 100644
--- a/tools/virtiofsd/helper.c
+++ b/tools/virtiofsd/helper.c
@@ -1,297 +1,309 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * Helper functions to create (simple) standalone programs. With the
+ * aid of these functions it should be possible to create full FUSE
+ * file system by implementing nothing but the request handlers.
- Helper functions to create (simple) standalone programs. With the
- aid of these functions it should be possible to create full FUSE
- file system by implementing nothing but the request handlers.
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB.
-*/
+ * This program can be distributed under the terms of the GNU LGPLv2.
+ * See the file COPYING.LIB.
+ */
#include "config.h"
#include "fuse_i.h"
+#include "fuse_lowlevel.h"
#include "fuse_misc.h"
#include "fuse_opt.h"
-#include "fuse_lowlevel.h"
#include "mount_util.h"
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
#include <string.h>
-#include <limits.h>
-#include <errno.h>
#include <sys/param.h>
+#include <unistd.h>
-#define FUSE_HELPER_OPT(t, p) \
- { t, offsetof(struct fuse_cmdline_opts, p), 1 }
+#define FUSE_HELPER_OPT(t, p) \
+ { \
+ t, offsetof(struct fuse_cmdline_opts, p), 1 \
+ }
static const struct fuse_opt fuse_helper_opts[] = {
- FUSE_HELPER_OPT("-h", show_help),
- FUSE_HELPER_OPT("--help", show_help),
- FUSE_HELPER_OPT("-V", show_version),
- FUSE_HELPER_OPT("--version", show_version),
- FUSE_HELPER_OPT("-d", debug),
- FUSE_HELPER_OPT("debug", debug),
- FUSE_HELPER_OPT("-d", foreground),
- FUSE_HELPER_OPT("debug", foreground),
- FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
- FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
- FUSE_HELPER_OPT("-f", foreground),
- FUSE_HELPER_OPT("fsname=", nodefault_subtype),
- FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
- FUSE_HELPER_OPT("subtype=", nodefault_subtype),
- FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
- FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
- FUSE_OPT_END
+ FUSE_HELPER_OPT("-h", show_help),
+ FUSE_HELPER_OPT("--help", show_help),
+ FUSE_HELPER_OPT("-V", show_version),
+ FUSE_HELPER_OPT("--version", show_version),
+ FUSE_HELPER_OPT("-d", debug),
+ FUSE_HELPER_OPT("debug", debug),
+ FUSE_HELPER_OPT("-d", foreground),
+ FUSE_HELPER_OPT("debug", foreground),
+ FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
+ FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
+ FUSE_HELPER_OPT("-f", foreground),
+ FUSE_HELPER_OPT("fsname=", nodefault_subtype),
+ FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
+ FUSE_HELPER_OPT("subtype=", nodefault_subtype),
+ FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
+ FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
+ FUSE_OPT_END
};
struct fuse_conn_info_opts {
- int atomic_o_trunc;
- int no_remote_posix_lock;
- int no_remote_flock;
- int splice_write;
- int splice_move;
- int splice_read;
- int no_splice_write;
- int no_splice_move;
- int no_splice_read;
- int auto_inval_data;
- int no_auto_inval_data;
- int no_readdirplus;
- int no_readdirplus_auto;
- int async_dio;
- int no_async_dio;
- int writeback_cache;
- int no_writeback_cache;
- int async_read;
- int sync_read;
- unsigned max_write;
- unsigned max_readahead;
- unsigned max_background;
- unsigned congestion_threshold;
- unsigned time_gran;
- int set_max_write;
- int set_max_readahead;
- int set_max_background;
- int set_congestion_threshold;
- int set_time_gran;
+ int atomic_o_trunc;
+ int no_remote_posix_lock;
+ int no_remote_flock;
+ int splice_write;
+ int splice_move;
+ int splice_read;
+ int no_splice_write;
+ int no_splice_move;
+ int no_splice_read;
+ int auto_inval_data;
+ int no_auto_inval_data;
+ int no_readdirplus;
+ int no_readdirplus_auto;
+ int async_dio;
+ int no_async_dio;
+ int writeback_cache;
+ int no_writeback_cache;
+ int async_read;
+ int sync_read;
+ unsigned max_write;
+ unsigned max_readahead;
+ unsigned max_background;
+ unsigned congestion_threshold;
+ unsigned time_gran;
+ int set_max_write;
+ int set_max_readahead;
+ int set_max_background;
+ int set_congestion_threshold;
+ int set_time_gran;
};
-#define CONN_OPTION(t, p, v) \
- { t, offsetof(struct fuse_conn_info_opts, p), v }
+#define CONN_OPTION(t, p, v) \
+ { \
+ t, offsetof(struct fuse_conn_info_opts, p), v \
+ }
static const struct fuse_opt conn_info_opt_spec[] = {
- CONN_OPTION("max_write=%u", max_write, 0),
- CONN_OPTION("max_write=", set_max_write, 1),
- CONN_OPTION("max_readahead=%u", max_readahead, 0),
- CONN_OPTION("max_readahead=", set_max_readahead, 1),
- CONN_OPTION("max_background=%u", max_background, 0),
- CONN_OPTION("max_background=", set_max_background, 1),
- CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
- CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
- CONN_OPTION("sync_read", sync_read, 1),
- CONN_OPTION("async_read", async_read, 1),
- CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
- CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
- CONN_OPTION("no_remote_lock", no_remote_flock, 1),
- CONN_OPTION("no_remote_flock", no_remote_flock, 1),
- CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
- CONN_OPTION("splice_write", splice_write, 1),
- CONN_OPTION("no_splice_write", no_splice_write, 1),
- CONN_OPTION("splice_move", splice_move, 1),
- CONN_OPTION("no_splice_move", no_splice_move, 1),
- CONN_OPTION("splice_read", splice_read, 1),
- CONN_OPTION("no_splice_read", no_splice_read, 1),
- CONN_OPTION("auto_inval_data", auto_inval_data, 1),
- CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
- CONN_OPTION("readdirplus=no", no_readdirplus, 1),
- CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
- CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
- CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
- CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
- CONN_OPTION("async_dio", async_dio, 1),
- CONN_OPTION("no_async_dio", no_async_dio, 1),
- CONN_OPTION("writeback_cache", writeback_cache, 1),
- CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
- CONN_OPTION("time_gran=%u", time_gran, 0),
- CONN_OPTION("time_gran=", set_time_gran, 1),
- FUSE_OPT_END
+ CONN_OPTION("max_write=%u", max_write, 0),
+ CONN_OPTION("max_write=", set_max_write, 1),
+ CONN_OPTION("max_readahead=%u", max_readahead, 0),
+ CONN_OPTION("max_readahead=", set_max_readahead, 1),
+ CONN_OPTION("max_background=%u", max_background, 0),
+ CONN_OPTION("max_background=", set_max_background, 1),
+ CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
+ CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
+ CONN_OPTION("sync_read", sync_read, 1),
+ CONN_OPTION("async_read", async_read, 1),
+ CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
+ CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
+ CONN_OPTION("no_remote_lock", no_remote_flock, 1),
+ CONN_OPTION("no_remote_flock", no_remote_flock, 1),
+ CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
+ CONN_OPTION("splice_write", splice_write, 1),
+ CONN_OPTION("no_splice_write", no_splice_write, 1),
+ CONN_OPTION("splice_move", splice_move, 1),
+ CONN_OPTION("no_splice_move", no_splice_move, 1),
+ CONN_OPTION("splice_read", splice_read, 1),
+ CONN_OPTION("no_splice_read", no_splice_read, 1),
+ CONN_OPTION("auto_inval_data", auto_inval_data, 1),
+ CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
+ CONN_OPTION("readdirplus=no", no_readdirplus, 1),
+ CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
+ CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
+ CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
+ CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
+ CONN_OPTION("async_dio", async_dio, 1),
+ CONN_OPTION("no_async_dio", no_async_dio, 1),
+ CONN_OPTION("writeback_cache", writeback_cache, 1),
+ CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
+ CONN_OPTION("time_gran=%u", time_gran, 0),
+ CONN_OPTION("time_gran=", set_time_gran, 1),
+ FUSE_OPT_END
};
void fuse_cmdline_help(void)
{
- printf(" -h --help print help\n"
- " -V --version print version\n"
- " -d -o debug enable debug output (implies -f)\n"
- " -f foreground operation\n"
- " -o max_idle_threads the maximum number of idle worker threads\n"
- " allowed (default: 10)\n");
+ printf(
+ " -h --help print help\n"
+ " -V --version print version\n"
+ " -d -o debug enable debug output (implies -f)\n"
+ " -f foreground operation\n"
+ " -o max_idle_threads the maximum number of idle worker threads\n"
+ " allowed (default: 10)\n");
}
static int fuse_helper_opt_proc(void *data, const char *arg, int key,
- struct fuse_args *outargs)
+ struct fuse_args *outargs)
{
- (void) outargs;
- struct fuse_cmdline_opts *opts = data;
-
- switch (key) {
- case FUSE_OPT_KEY_NONOPT:
- if (!opts->mountpoint) {
- if (fuse_mnt_parse_fuse_fd(arg) != -1) {
- return fuse_opt_add_opt(&opts->mountpoint, arg);
- }
-
- char mountpoint[PATH_MAX] = "";
- if (realpath(arg, mountpoint) == NULL) {
- fuse_log(FUSE_LOG_ERR,
- "fuse: bad mount point `%s': %s\n",
- arg, strerror(errno));
- return -1;
- }
- return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
- } else {
- fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
- return -1;
- }
-
- default:
- /* Pass through unknown options */
- return 1;
- }
+ (void)outargs;
+ struct fuse_cmdline_opts *opts = data;
+
+ switch (key) {
+ case FUSE_OPT_KEY_NONOPT:
+ if (!opts->mountpoint) {
+ if (fuse_mnt_parse_fuse_fd(arg) != -1) {
+ return fuse_opt_add_opt(&opts->mountpoint, arg);
+ }
+
+ char mountpoint[PATH_MAX] = "";
+ if (realpath(arg, mountpoint) == NULL) {
+ fuse_log(FUSE_LOG_ERR, "fuse: bad mount point `%s': %s\n", arg,
+ strerror(errno));
+ return -1;
+ }
+ return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
+ } else {
+ fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
+ return -1;
+ }
+
+ default:
+ /* Pass through unknown options */
+ return 1;
+ }
}
-int fuse_parse_cmdline(struct fuse_args *args,
- struct fuse_cmdline_opts *opts)
+int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
{
- memset(opts, 0, sizeof(struct fuse_cmdline_opts));
+ memset(opts, 0, sizeof(struct fuse_cmdline_opts));
- opts->max_idle_threads = 10;
+ opts->max_idle_threads = 10;
- if (fuse_opt_parse(args, opts, fuse_helper_opts,
- fuse_helper_opt_proc) == -1)
- return -1;
+ if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) ==
+ -1) {
+ return -1;
+ }
- return 0;
+ return 0;
}
int fuse_daemonize(int foreground)
{
- if (!foreground) {
- int nullfd;
- int waiter[2];
- char completed;
-
- if (pipe(waiter)) {
- perror("fuse_daemonize: pipe");
- return -1;
- }
-
- /*
- * demonize current process by forking it and killing the
- * parent. This makes current process as a child of 'init'.
- */
- switch(fork()) {
- case -1:
- perror("fuse_daemonize: fork");
- return -1;
- case 0:
- break;
- default:
- (void) read(waiter[0], &completed, sizeof(completed));
- _exit(0);
- }
-
- if (setsid() == -1) {
- perror("fuse_daemonize: setsid");
- return -1;
- }
-
- (void) chdir("/");
-
- nullfd = open("/dev/null", O_RDWR, 0);
- if (nullfd != -1) {
- (void) dup2(nullfd, 0);
- (void) dup2(nullfd, 1);
- (void) dup2(nullfd, 2);
- if (nullfd > 2)
- close(nullfd);
- }
-
- /* Propagate completion of daemon initialization */
- completed = 1;
- (void) write(waiter[1], &completed, sizeof(completed));
- close(waiter[0]);
- close(waiter[1]);
- } else {
- (void) chdir("/");
- }
- return 0;
+ if (!foreground) {
+ int nullfd;
+ int waiter[2];
+ char completed;
+
+ if (pipe(waiter)) {
+ perror("fuse_daemonize: pipe");
+ return -1;
+ }
+
+ /*
+ * demonize current process by forking it and killing the
+ * parent. This makes current process as a child of 'init'.
+ */
+ switch (fork()) {
+ case -1:
+ perror("fuse_daemonize: fork");
+ return -1;
+ case 0:
+ break;
+ default:
+ (void)read(waiter[0], &completed, sizeof(completed));
+ _exit(0);
+ }
+
+ if (setsid() == -1) {
+ perror("fuse_daemonize: setsid");
+ return -1;
+ }
+
+ (void)chdir("/");
+
+ nullfd = open("/dev/null", O_RDWR, 0);
+ if (nullfd != -1) {
+ (void)dup2(nullfd, 0);
+ (void)dup2(nullfd, 1);
+ (void)dup2(nullfd, 2);
+ if (nullfd > 2) {
+ close(nullfd);
+ }
+ }
+
+ /* Propagate completion of daemon initialization */
+ completed = 1;
+ (void)write(waiter[1], &completed, sizeof(completed));
+ close(waiter[0]);
+ close(waiter[1]);
+ } else {
+ (void)chdir("/");
+ }
+ return 0;
}
void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
- struct fuse_conn_info *conn)
+ struct fuse_conn_info *conn)
{
- if(opts->set_max_write)
- conn->max_write = opts->max_write;
- if(opts->set_max_background)
- conn->max_background = opts->max_background;
- if(opts->set_congestion_threshold)
- conn->congestion_threshold = opts->congestion_threshold;
- if(opts->set_time_gran)
- conn->time_gran = opts->time_gran;
- if(opts->set_max_readahead)
- conn->max_readahead = opts->max_readahead;
-
-#define LL_ENABLE(cond,cap) \
- if (cond) conn->want |= (cap)
-#define LL_DISABLE(cond,cap) \
- if (cond) conn->want &= ~(cap)
-
- LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
- LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
-
- LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
- LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
-
- LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
- LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
-
- LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
- LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
-
- LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
- LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
-
- LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
- LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
-
- LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
- LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
-
- LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
- LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
-
- LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
- LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
+ if (opts->set_max_write) {
+ conn->max_write = opts->max_write;
+ }
+ if (opts->set_max_background) {
+ conn->max_background = opts->max_background;
+ }
+ if (opts->set_congestion_threshold) {
+ conn->congestion_threshold = opts->congestion_threshold;
+ }
+ if (opts->set_time_gran) {
+ conn->time_gran = opts->time_gran;
+ }
+ if (opts->set_max_readahead) {
+ conn->max_readahead = opts->max_readahead;
+ }
+
+#define LL_ENABLE(cond, cap) \
+ if (cond) \
+ conn->want |= (cap)
+#define LL_DISABLE(cond, cap) \
+ if (cond) \
+ conn->want &= ~(cap)
+
+ LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
+ LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
+
+ LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
+ LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
+
+ LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
+ LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
+
+ LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
+ LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
+
+ LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
+ LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
+
+ LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
+ LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
+
+ LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
+ LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
+
+ LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
+ LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
+
+ LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
+ LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
}
-struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args)
+struct fuse_conn_info_opts *fuse_parse_conn_info_opts(struct fuse_args *args)
{
- struct fuse_conn_info_opts *opts;
-
- opts = calloc(1, sizeof(struct fuse_conn_info_opts));
- if(opts == NULL) {
- fuse_log(FUSE_LOG_ERR, "calloc failed\n");
- return NULL;
- }
- if(fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
- free(opts);
- return NULL;
- }
- return opts;
+ struct fuse_conn_info_opts *opts;
+
+ opts = calloc(1, sizeof(struct fuse_conn_info_opts));
+ if (opts == NULL) {
+ fuse_log(FUSE_LOG_ERR, "calloc failed\n");
+ return NULL;
+ }
+ if (fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
+ free(opts);
+ return NULL;
+ }
+ return opts;
}
diff --git a/tools/virtiofsd/passthrough_helpers.h b/tools/virtiofsd/passthrough_helpers.h
index 7c5f561fbc..0b98275ed5 100644
--- a/tools/virtiofsd/passthrough_helpers.h
+++ b/tools/virtiofsd/passthrough_helpers.h
@@ -28,23 +28,24 @@
* operation
*/
static int mknod_wrapper(int dirfd, const char *path, const char *link,
- int mode, dev_t rdev)
+ int mode, dev_t rdev)
{
- int res;
+ int res;
- if (S_ISREG(mode)) {
- res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
- if (res >= 0)
- res = close(res);
- } else if (S_ISDIR(mode)) {
- res = mkdirat(dirfd, path, mode);
- } else if (S_ISLNK(mode) && link != NULL) {
- res = symlinkat(link, dirfd, path);
- } else if (S_ISFIFO(mode)) {
- res = mkfifoat(dirfd, path, mode);
- } else {
- res = mknodat(dirfd, path, mode, rdev);
- }
+ if (S_ISREG(mode)) {
+ res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
+ if (res >= 0) {
+ res = close(res);
+ }
+ } else if (S_ISDIR(mode)) {
+ res = mkdirat(dirfd, path, mode);
+ } else if (S_ISLNK(mode) && link != NULL) {
+ res = symlinkat(link, dirfd, path);
+ } else if (S_ISFIFO(mode)) {
+ res = mkfifoat(dirfd, path, mode);
+ } else {
+ res = mknodat(dirfd, path, mode, rdev);
+ }
- return res;
+ return res;
}
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index e5f7115bc1..c5850ef803 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -1,12 +1,12 @@
/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU GPLv2.
- See the file COPYING.
-*/
+ * FUSE: Filesystem in Userspace
+ * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ *
+ * This program can be distributed under the terms of the GNU GPLv2.
+ * See the file COPYING.
+ */
-/** @file
+/*
*
* This file system mirrors the existing file system hierarchy of the
* system, starting at the root file system. This is implemented by
@@ -28,7 +28,8 @@
*
* Compile with:
*
- * gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll
+ * gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o
+ * passthrough_ll
*
* ## Source code ##
* \include passthrough_ll.c
@@ -39,1299 +40,1365 @@
#include "config.h"
-#include <fuse_lowlevel.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <string.h>
-#include <limits.h>
-#include <dirent.h>
#include <assert.h>
+#include <dirent.h>
#include <errno.h>
+#include <fuse_lowlevel.h>
#include <inttypes.h>
+#include <limits.h>
#include <pthread.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/file.h>
#include <sys/xattr.h>
+#include <unistd.h>
#include "passthrough_helpers.h"
-/* We are re-using pointers to our `struct lo_inode` and `struct
- lo_dirp` elements as inodes. This means that we must be able to
- store uintptr_t values in a fuse_ino_t variable. The following
- incantation checks this condition at compile time. */
-#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
+/*
+ * We are re-using pointers to our `struct lo_inode` and `struct
+ * lo_dirp` elements as inodes. This means that we must be able to
+ * store uintptr_t values in a fuse_ino_t variable. The following
+ * incantation checks this condition at compile time.
+ */
+#if defined(__GNUC__) && \
+ (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
+ !defined __cplusplus
_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
- "fuse_ino_t too small to hold uintptr_t values!");
+ "fuse_ino_t too small to hold uintptr_t values!");
#else
-struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
- { unsigned _uintptr_to_must_hold_fuse_ino_t:
- ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
+struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
+ unsigned _uintptr_to_must_hold_fuse_ino_t
+ : ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1);
+};
#endif
struct lo_inode {
- struct lo_inode *next; /* protected by lo->mutex */
- struct lo_inode *prev; /* protected by lo->mutex */
- int fd;
- bool is_symlink;
- ino_t ino;
- dev_t dev;
- uint64_t refcount; /* protected by lo->mutex */
+ struct lo_inode *next; /* protected by lo->mutex */
+ struct lo_inode *prev; /* protected by lo->mutex */
+ int fd;
+ bool is_symlink;
+ ino_t ino;
+ dev_t dev;
+ uint64_t refcount; /* protected by lo->mutex */
};
enum {
- CACHE_NEVER,
- CACHE_NORMAL,
- CACHE_ALWAYS,
+ CACHE_NEVER,
+ CACHE_NORMAL,
+ CACHE_ALWAYS,
};
struct lo_data {
- pthread_mutex_t mutex;
- int debug;
- int writeback;
- int flock;
- int xattr;
- const char *source;
- double timeout;
- int cache;
- int timeout_set;
- struct lo_inode root; /* protected by lo->mutex */
+ pthread_mutex_t mutex;
+ int debug;
+ int writeback;
+ int flock;
+ int xattr;
+ const char *source;
+ double timeout;
+ int cache;
+ int timeout_set;
+ struct lo_inode root; /* protected by lo->mutex */
};
static const struct fuse_opt lo_opts[] = {
- { "writeback",
- offsetof(struct lo_data, writeback), 1 },
- { "no_writeback",
- offsetof(struct lo_data, writeback), 0 },
- { "source=%s",
- offsetof(struct lo_data, source), 0 },
- { "flock",
- offsetof(struct lo_data, flock), 1 },
- { "no_flock",
- offsetof(struct lo_data, flock), 0 },
- { "xattr",
- offsetof(struct lo_data, xattr), 1 },
- { "no_xattr",
- offsetof(struct lo_data, xattr), 0 },
- { "timeout=%lf",
- offsetof(struct lo_data, timeout), 0 },
- { "timeout=",
- offsetof(struct lo_data, timeout_set), 1 },
- { "cache=never",
- offsetof(struct lo_data, cache), CACHE_NEVER },
- { "cache=auto",
- offsetof(struct lo_data, cache), CACHE_NORMAL },
- { "cache=always",
- offsetof(struct lo_data, cache), CACHE_ALWAYS },
-
- FUSE_OPT_END
+ { "writeback", offsetof(struct lo_data, writeback), 1 },
+ { "no_writeback", offsetof(struct lo_data, writeback), 0 },
+ { "source=%s", offsetof(struct lo_data, source), 0 },
+ { "flock", offsetof(struct lo_data, flock), 1 },
+ { "no_flock", offsetof(struct lo_data, flock), 0 },
+ { "xattr", offsetof(struct lo_data, xattr), 1 },
+ { "no_xattr", offsetof(struct lo_data, xattr), 0 },
+ { "timeout=%lf", offsetof(struct lo_data, timeout), 0 },
+ { "timeout=", offsetof(struct lo_data, timeout_set), 1 },
+ { "cache=never", offsetof(struct lo_data, cache), CACHE_NEVER },
+ { "cache=auto", offsetof(struct lo_data, cache), CACHE_NORMAL },
+ { "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS },
+
+ FUSE_OPT_END
};
static struct lo_data *lo_data(fuse_req_t req)
{
- return (struct lo_data *) fuse_req_userdata(req);
+ return (struct lo_data *)fuse_req_userdata(req);
}
static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
{
- if (ino == FUSE_ROOT_ID)
- return &lo_data(req)->root;
- else
- return (struct lo_inode *) (uintptr_t) ino;
+ if (ino == FUSE_ROOT_ID) {
+ return &lo_data(req)->root;
+ } else {
+ return (struct lo_inode *)(uintptr_t)ino;
+ }
}
static int lo_fd(fuse_req_t req, fuse_ino_t ino)
{
- return lo_inode(req, ino)->fd;
+ return lo_inode(req, ino)->fd;
}
static bool lo_debug(fuse_req_t req)
{
- return lo_data(req)->debug != 0;
+ return lo_data(req)->debug != 0;
}
-static void lo_init(void *userdata,
- struct fuse_conn_info *conn)
+static void lo_init(void *userdata, struct fuse_conn_info *conn)
{
- struct lo_data *lo = (struct lo_data*) userdata;
-
- if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
- conn->want |= FUSE_CAP_EXPORT_SUPPORT;
-
- if (lo->writeback &&
- conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
- if (lo->debug)
- fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
- conn->want |= FUSE_CAP_WRITEBACK_CACHE;
- }
- if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
- if (lo->debug)
- fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
- conn->want |= FUSE_CAP_FLOCK_LOCKS;
- }
+ struct lo_data *lo = (struct lo_data *)userdata;
+
+ if (conn->capable & FUSE_CAP_EXPORT_SUPPORT) {
+ conn->want |= FUSE_CAP_EXPORT_SUPPORT;
+ }
+
+ if (lo->writeback && conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
+ if (lo->debug) {
+ fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
+ }
+ conn->want |= FUSE_CAP_WRITEBACK_CACHE;
+ }
+ if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
+ if (lo->debug) {
+ fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+ }
+ conn->want |= FUSE_CAP_FLOCK_LOCKS;
+ }
}
static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
- struct fuse_file_info *fi)
+ struct fuse_file_info *fi)
{
- int res;
- struct stat buf;
- struct lo_data *lo = lo_data(req);
+ int res;
+ struct stat buf;
+ struct lo_data *lo = lo_data(req);
- (void) fi;
+ (void)fi;
- res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
- if (res == -1)
- return (void) fuse_reply_err(req, errno);
+ res =
+ fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+ if (res == -1) {
+ return (void)fuse_reply_err(req, errno);
+ }
- fuse_reply_attr(req, &buf, lo->timeout);
+ fuse_reply_attr(req, &buf, lo->timeout);
}
static int utimensat_empty_nofollow(struct lo_inode *inode,
- const struct timespec *tv)
+ const struct timespec *tv)
{
- int res;
- char procname[64];
-
- if (inode->is_symlink) {
- res = utimensat(inode->fd, "", tv,
- AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
- if (res == -1 && errno == EINVAL) {
- /* Sorry, no race free way to set times on symlink. */
- errno = EPERM;
- }
- return res;
- }
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
-
- return utimensat(AT_FDCWD, procname, tv, 0);
+ int res;
+ char procname[64];
+
+ if (inode->is_symlink) {
+ res = utimensat(inode->fd, "", tv, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+ if (res == -1 && errno == EINVAL) {
+ /* Sorry, no race free way to set times on symlink. */
+ errno = EPERM;
+ }
+ return res;
+ }
+ sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+ return utimensat(AT_FDCWD, procname, tv, 0);
}
static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
- int valid, struct fuse_file_info *fi)
+ int valid, struct fuse_file_info *fi)
{
- int saverr;
- char procname[64];
- struct lo_inode *inode = lo_inode(req, ino);
- int ifd = inode->fd;
- int res;
-
- if (valid & FUSE_SET_ATTR_MODE) {
- if (fi) {
- res = fchmod(fi->fh, attr->st_mode);
- } else {
- sprintf(procname, "/proc/self/fd/%i", ifd);
- res = chmod(procname, attr->st_mode);
- }
- if (res == -1)
- goto out_err;
- }
- if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
- uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
- attr->st_uid : (uid_t) -1;
- gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
- attr->st_gid : (gid_t) -1;
-
- res = fchownat(ifd, "", uid, gid,
- AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
- if (res == -1)
- goto out_err;
- }
- if (valid & FUSE_SET_ATTR_SIZE) {
- if (fi) {
- res = ftruncate(fi->fh, attr->st_size);
- } else {
- sprintf(procname, "/proc/self/fd/%i", ifd);
- res = truncate(procname, attr->st_size);
- }
- if (res == -1)
- goto out_err;
- }
- if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
- struct timespec tv[2];
-
- tv[0].tv_sec = 0;
- tv[1].tv_sec = 0;
- tv[0].tv_nsec = UTIME_OMIT;
- tv[1].tv_nsec = UTIME_OMIT;
-
- if (valid & FUSE_SET_ATTR_ATIME_NOW)
- tv[0].tv_nsec = UTIME_NOW;
- else if (valid & FUSE_SET_ATTR_ATIME)
- tv[0] = attr->st_atim;
-
- if (valid & FUSE_SET_ATTR_MTIME_NOW)
- tv[1].tv_nsec = UTIME_NOW;
- else if (valid & FUSE_SET_ATTR_MTIME)
- tv[1] = attr->st_mtim;
-
- if (fi)
- res = futimens(fi->fh, tv);
- else
- res = utimensat_empty_nofollow(inode, tv);
- if (res == -1)
- goto out_err;
- }
-
- return lo_getattr(req, ino, fi);
+ int saverr;
+ char procname[64];
+ struct lo_inode *inode = lo_inode(req, ino);
+ int ifd = inode->fd;
+ int res;
+
+ if (valid & FUSE_SET_ATTR_MODE) {
+ if (fi) {
+ res = fchmod(fi->fh, attr->st_mode);
+ } else {
+ sprintf(procname, "/proc/self/fd/%i", ifd);
+ res = chmod(procname, attr->st_mode);
+ }
+ if (res == -1) {
+ goto out_err;
+ }
+ }
+ if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
+ uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t)-1;
+ gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t)-1;
+
+ res = fchownat(ifd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+ if (res == -1) {
+ goto out_err;
+ }
+ }
+ if (valid & FUSE_SET_ATTR_SIZE) {
+ if (fi) {
+ res = ftruncate(fi->fh, attr->st_size);
+ } else {
+ sprintf(procname, "/proc/self/fd/%i", ifd);
+ res = truncate(procname, attr->st_size);
+ }
+ if (res == -1) {
+ goto out_err;
+ }
+ }
+ if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
+ struct timespec tv[2];
+
+ tv[0].tv_sec = 0;
+ tv[1].tv_sec = 0;
+ tv[0].tv_nsec = UTIME_OMIT;
+ tv[1].tv_nsec = UTIME_OMIT;
+
+ if (valid & FUSE_SET_ATTR_ATIME_NOW) {
+ tv[0].tv_nsec = UTIME_NOW;
+ } else if (valid & FUSE_SET_ATTR_ATIME) {
+ tv[0] = attr->st_atim;
+ }
+
+ if (valid & FUSE_SET_ATTR_MTIME_NOW) {
+ tv[1].tv_nsec = UTIME_NOW;
+ } else if (valid & FUSE_SET_ATTR_MTIME) {
+ tv[1] = attr->st_mtim;
+ }
+
+ if (fi) {
+ res = futimens(fi->fh, tv);
+ } else {
+ res = utimensat_empty_nofollow(inode, tv);
+ }
+ if (res == -1) {
+ goto out_err;
+ }
+ }
+
+ return lo_getattr(req, ino, fi);
out_err:
- saverr = errno;
- fuse_reply_err(req, saverr);
+ saverr = errno;
+ fuse_reply_err(req, saverr);
}
static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
{
- struct lo_inode *p;
- struct lo_inode *ret = NULL;
-
- pthread_mutex_lock(&lo->mutex);
- for (p = lo->root.next; p != &lo->root; p = p->next) {
- if (p->ino == st->st_ino && p->dev == st->st_dev) {
- assert(p->refcount > 0);
- ret = p;
- ret->refcount++;
- break;
- }
- }
- pthread_mutex_unlock(&lo->mutex);
- return ret;
+ struct lo_inode *p;
+ struct lo_inode *ret = NULL;
+
+ pthread_mutex_lock(&lo->mutex);
+ for (p = lo->root.next; p != &lo->root; p = p->next) {
+ if (p->ino == st->st_ino && p->dev == st->st_dev) {
+ assert(p->refcount > 0);
+ ret = p;
+ ret->refcount++;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&lo->mutex);
+ return ret;
}
static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
- struct fuse_entry_param *e)
+ struct fuse_entry_param *e)
{
- int newfd;
- int res;
- int saverr;
- struct lo_data *lo = lo_data(req);
- struct lo_inode *inode;
-
- memset(e, 0, sizeof(*e));
- e->attr_timeout = lo->timeout;
- e->entry_timeout = lo->timeout;
-
- newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
- if (newfd == -1)
- goto out_err;
-
- res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
- if (res == -1)
- goto out_err;
-
- inode = lo_find(lo_data(req), &e->attr);
- if (inode) {
- close(newfd);
- newfd = -1;
- } else {
- struct lo_inode *prev, *next;
-
- saverr = ENOMEM;
- inode = calloc(1, sizeof(struct lo_inode));
- if (!inode)
- goto out_err;
-
- inode->is_symlink = S_ISLNK(e->attr.st_mode);
- inode->refcount = 1;
- inode->fd = newfd;
- inode->ino = e->attr.st_ino;
- inode->dev = e->attr.st_dev;
-
- pthread_mutex_lock(&lo->mutex);
- prev = &lo->root;
- next = prev->next;
- next->prev = inode;
- inode->next = next;
- inode->prev = prev;
- prev->next = inode;
- pthread_mutex_unlock(&lo->mutex);
- }
- e->ino = (uintptr_t) inode;
-
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
- (unsigned long long) parent, name, (unsigned long long) e->ino);
-
- return 0;
+ int newfd;
+ int res;
+ int saverr;
+ struct lo_data *lo = lo_data(req);
+ struct lo_inode *inode;
+
+ memset(e, 0, sizeof(*e));
+ e->attr_timeout = lo->timeout;
+ e->entry_timeout = lo->timeout;
+
+ newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
+ if (newfd == -1) {
+ goto out_err;
+ }
+
+ res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+ if (res == -1) {
+ goto out_err;
+ }
+
+ inode = lo_find(lo_data(req), &e->attr);
+ if (inode) {
+ close(newfd);
+ newfd = -1;
+ } else {
+ struct lo_inode *prev, *next;
+
+ saverr = ENOMEM;
+ inode = calloc(1, sizeof(struct lo_inode));
+ if (!inode) {
+ goto out_err;
+ }
+
+ inode->is_symlink = S_ISLNK(e->attr.st_mode);
+ inode->refcount = 1;
+ inode->fd = newfd;
+ inode->ino = e->attr.st_ino;
+ inode->dev = e->attr.st_dev;
+
+ pthread_mutex_lock(&lo->mutex);
+ prev = &lo->root;
+ next = prev->next;
+ next->prev = inode;
+ inode->next = next;
+ inode->prev = prev;
+ prev->next = inode;
+ pthread_mutex_unlock(&lo->mutex);
+ }
+ e->ino = (uintptr_t)inode;
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
+ (unsigned long long)parent, name, (unsigned long long)e->ino);
+ }
+
+ return 0;
out_err:
- saverr = errno;
- if (newfd != -1)
- close(newfd);
- return saverr;
+ saverr = errno;
+ if (newfd != -1) {
+ close(newfd);
+ }
+ return saverr;
}
static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
- struct fuse_entry_param e;
- int err;
-
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
- parent, name);
-
- err = lo_do_lookup(req, parent, name, &e);
- if (err)
- fuse_reply_err(req, err);
- else
- fuse_reply_entry(req, &e);
+ struct fuse_entry_param e;
+ int err;
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
+ parent, name);
+ }
+
+ err = lo_do_lookup(req, parent, name, &e);
+ if (err) {
+ fuse_reply_err(req, err);
+ } else {
+ fuse_reply_entry(req, &e);
+ }
}
static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
- const char *name, mode_t mode, dev_t rdev,
- const char *link)
+ const char *name, mode_t mode, dev_t rdev,
+ const char *link)
{
- int res;
- int saverr;
- struct lo_inode *dir = lo_inode(req, parent);
- struct fuse_entry_param e;
+ int res;
+ int saverr;
+ struct lo_inode *dir = lo_inode(req, parent);
+ struct fuse_entry_param e;
- saverr = ENOMEM;
+ saverr = ENOMEM;
- res = mknod_wrapper(dir->fd, name, link, mode, rdev);
+ res = mknod_wrapper(dir->fd, name, link, mode, rdev);
- saverr = errno;
- if (res == -1)
- goto out;
+ saverr = errno;
+ if (res == -1) {
+ goto out;
+ }
- saverr = lo_do_lookup(req, parent, name, &e);
- if (saverr)
- goto out;
+ saverr = lo_do_lookup(req, parent, name, &e);
+ if (saverr) {
+ goto out;
+ }
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
- (unsigned long long) parent, name, (unsigned long long) e.ino);
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
+ (unsigned long long)parent, name, (unsigned long long)e.ino);
+ }
- fuse_reply_entry(req, &e);
- return;
+ fuse_reply_entry(req, &e);
+ return;
out:
- fuse_reply_err(req, saverr);
+ fuse_reply_err(req, saverr);
}
-static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
- const char *name, mode_t mode, dev_t rdev)
+static void lo_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
+ mode_t mode, dev_t rdev)
{
- lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
+ lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
}
static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
- mode_t mode)
+ mode_t mode)
{
- lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
+ lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
}
-static void lo_symlink(fuse_req_t req, const char *link,
- fuse_ino_t parent, const char *name)
+static void lo_symlink(fuse_req_t req, const char *link, fuse_ino_t parent,
+ const char *name)
{
- lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
+ lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
}
static int linkat_empty_nofollow(struct lo_inode *inode, int dfd,
- const char *name)
+ const char *name)
{
- int res;
- char procname[64];
+ int res;
+ char procname[64];
- if (inode->is_symlink) {
- res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
- if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
- /* Sorry, no race free way to hard-link a symlink. */
- errno = EPERM;
- }
- return res;
- }
+ if (inode->is_symlink) {
+ res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
+ if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
+ /* Sorry, no race free way to hard-link a symlink. */
+ errno = EPERM;
+ }
+ return res;
+ }
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
+ sprintf(procname, "/proc/self/fd/%i", inode->fd);
- return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
+ return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
}
static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
- const char *name)
+ const char *name)
{
- int res;
- struct lo_data *lo = lo_data(req);
- struct lo_inode *inode = lo_inode(req, ino);
- struct fuse_entry_param e;
- int saverr;
-
- memset(&e, 0, sizeof(struct fuse_entry_param));
- e.attr_timeout = lo->timeout;
- e.entry_timeout = lo->timeout;
-
- res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
- if (res == -1)
- goto out_err;
-
- res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
- if (res == -1)
- goto out_err;
-
- pthread_mutex_lock(&lo->mutex);
- inode->refcount++;
- pthread_mutex_unlock(&lo->mutex);
- e.ino = (uintptr_t) inode;
-
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
- (unsigned long long) parent, name,
- (unsigned long long) e.ino);
-
- fuse_reply_entry(req, &e);
- return;
+ int res;
+ struct lo_data *lo = lo_data(req);
+ struct lo_inode *inode = lo_inode(req, ino);
+ struct fuse_entry_param e;
+ int saverr;
+
+ memset(&e, 0, sizeof(struct fuse_entry_param));
+ e.attr_timeout = lo->timeout;
+ e.entry_timeout = lo->timeout;
+
+ res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
+ if (res == -1) {
+ goto out_err;
+ }
+
+ res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+ if (res == -1) {
+ goto out_err;
+ }
+
+ pthread_mutex_lock(&lo->mutex);
+ inode->refcount++;
+ pthread_mutex_unlock(&lo->mutex);
+ e.ino = (uintptr_t)inode;
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
+ (unsigned long long)parent, name, (unsigned long long)e.ino);
+ }
+
+ fuse_reply_entry(req, &e);
+ return;
out_err:
- saverr = errno;
- fuse_reply_err(req, saverr);
+ saverr = errno;
+ fuse_reply_err(req, saverr);
}
static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
{
- int res;
+ int res;
- res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
+ res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
- fuse_reply_err(req, res == -1 ? errno : 0);
+ fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
- fuse_ino_t newparent, const char *newname,
- unsigned int flags)
+ fuse_ino_t newparent, const char *newname,
+ unsigned int flags)
{
- int res;
+ int res;
- if (flags) {
- fuse_reply_err(req, EINVAL);
- return;
- }
+ if (flags) {
+ fuse_reply_err(req, EINVAL);
+ return;
+ }
- res = renameat(lo_fd(req, parent), name,
- lo_fd(req, newparent), newname);
+ res = renameat(lo_fd(req, parent), name, lo_fd(req, newparent), newname);
- fuse_reply_err(req, res == -1 ? errno : 0);
+ fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
{
- int res;
+ int res;
- res = unlinkat(lo_fd(req, parent), name, 0);
+ res = unlinkat(lo_fd(req, parent), name, 0);
- fuse_reply_err(req, res == -1 ? errno : 0);
+ fuse_reply_err(req, res == -1 ? errno : 0);
}
static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
{
- if (!inode)
- return;
-
- pthread_mutex_lock(&lo->mutex);
- assert(inode->refcount >= n);
- inode->refcount -= n;
- if (!inode->refcount) {
- struct lo_inode *prev, *next;
-
- prev = inode->prev;
- next = inode->next;
- next->prev = prev;
- prev->next = next;
-
- pthread_mutex_unlock(&lo->mutex);
- close(inode->fd);
- free(inode);
-
- } else {
- pthread_mutex_unlock(&lo->mutex);
- }
+ if (!inode) {
+ return;
+ }
+
+ pthread_mutex_lock(&lo->mutex);
+ assert(inode->refcount >= n);
+ inode->refcount -= n;
+ if (!inode->refcount) {
+ struct lo_inode *prev, *next;
+
+ prev = inode->prev;
+ next = inode->next;
+ next->prev = prev;
+ prev->next = next;
+
+ pthread_mutex_unlock(&lo->mutex);
+ close(inode->fd);
+ free(inode);
+
+ } else {
+ pthread_mutex_unlock(&lo->mutex);
+ }
}
static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
{
- struct lo_data *lo = lo_data(req);
- struct lo_inode *inode = lo_inode(req, ino);
+ struct lo_data *lo = lo_data(req);
+ struct lo_inode *inode = lo_inode(req, ino);
- if (lo_debug(req)) {
- fuse_log(FUSE_LOG_DEBUG, " forget %lli %lli -%lli\n",
- (unsigned long long) ino,
- (unsigned long long) inode->refcount,
- (unsigned long long) nlookup);
- }
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, " forget %lli %lli -%lli\n",
+ (unsigned long long)ino, (unsigned long long)inode->refcount,
+ (unsigned long long)nlookup);
+ }
- unref_inode(lo, inode, nlookup);
+ unref_inode(lo, inode, nlookup);
}
static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
{
- lo_forget_one(req, ino, nlookup);
- fuse_reply_none(req);
+ lo_forget_one(req, ino, nlookup);
+ fuse_reply_none(req);
}
static void lo_forget_multi(fuse_req_t req, size_t count,
- struct fuse_forget_data *forgets)
+ struct fuse_forget_data *forgets)
{
- int i;
+ int i;
- for (i = 0; i < count; i++)
- lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
- fuse_reply_none(req);
+ for (i = 0; i < count; i++) {
+ lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
+ }
+ fuse_reply_none(req);
}
static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
{
- char buf[PATH_MAX + 1];
- int res;
+ char buf[PATH_MAX + 1];
+ int res;
- res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
- if (res == -1)
- return (void) fuse_reply_err(req, errno);
+ res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
+ if (res == -1) {
+ return (void)fuse_reply_err(req, errno);
+ }
- if (res == sizeof(buf))
- return (void) fuse_reply_err(req, ENAMETOOLONG);
+ if (res == sizeof(buf)) {
+ return (void)fuse_reply_err(req, ENAMETOOLONG);
+ }
- buf[res] = '\0';
+ buf[res] = '\0';
- fuse_reply_readlink(req, buf);
+ fuse_reply_readlink(req, buf);
}
struct lo_dirp {
- DIR *dp;
- struct dirent *entry;
- off_t offset;
+ DIR *dp;
+ struct dirent *entry;
+ off_t offset;
};
static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
{
- return (struct lo_dirp *) (uintptr_t) fi->fh;
+ return (struct lo_dirp *)(uintptr_t)fi->fh;
}
-static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- int error = ENOMEM;
- struct lo_data *lo = lo_data(req);
- struct lo_dirp *d;
- int fd;
-
- d = calloc(1, sizeof(struct lo_dirp));
- if (d == NULL)
- goto out_err;
-
- fd = openat(lo_fd(req, ino), ".", O_RDONLY);
- if (fd == -1)
- goto out_errno;
-
- d->dp = fdopendir(fd);
- if (d->dp == NULL)
- goto out_errno;
-
- d->offset = 0;
- d->entry = NULL;
-
- fi->fh = (uintptr_t) d;
- if (lo->cache == CACHE_ALWAYS)
- fi->keep_cache = 1;
- fuse_reply_open(req, fi);
- return;
+ int error = ENOMEM;
+ struct lo_data *lo = lo_data(req);
+ struct lo_dirp *d;
+ int fd;
+
+ d = calloc(1, sizeof(struct lo_dirp));
+ if (d == NULL) {
+ goto out_err;
+ }
+
+ fd = openat(lo_fd(req, ino), ".", O_RDONLY);
+ if (fd == -1) {
+ goto out_errno;
+ }
+
+ d->dp = fdopendir(fd);
+ if (d->dp == NULL) {
+ goto out_errno;
+ }
+
+ d->offset = 0;
+ d->entry = NULL;
+
+ fi->fh = (uintptr_t)d;
+ if (lo->cache == CACHE_ALWAYS) {
+ fi->keep_cache = 1;
+ }
+ fuse_reply_open(req, fi);
+ return;
out_errno:
- error = errno;
+ error = errno;
out_err:
- if (d) {
- if (fd != -1)
- close(fd);
- free(d);
- }
- fuse_reply_err(req, error);
+ if (d) {
+ if (fd != -1) {
+ close(fd);
+ }
+ free(d);
+ }
+ fuse_reply_err(req, error);
}
static int is_dot_or_dotdot(const char *name)
{
- return name[0] == '.' && (name[1] == '\0' ||
- (name[1] == '.' && name[2] == '\0'));
+ return name[0] == '.' &&
+ (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
}
static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
- off_t offset, struct fuse_file_info *fi, int plus)
+ off_t offset, struct fuse_file_info *fi, int plus)
{
- struct lo_dirp *d = lo_dirp(fi);
- char *buf;
- char *p;
- size_t rem = size;
- int err;
-
- (void) ino;
-
- buf = calloc(1, size);
- if (!buf) {
- err = ENOMEM;
- goto error;
- }
- p = buf;
-
- if (offset != d->offset) {
- seekdir(d->dp, offset);
- d->entry = NULL;
- d->offset = offset;
- }
- while (1) {
- size_t entsize;
- off_t nextoff;
- const char *name;
-
- if (!d->entry) {
- errno = 0;
- d->entry = readdir(d->dp);
- if (!d->entry) {
- if (errno) { // Error
- err = errno;
- goto error;
- } else { // End of stream
- break;
- }
- }
- }
- nextoff = d->entry->d_off;
- name = d->entry->d_name;
- fuse_ino_t entry_ino = 0;
- if (plus) {
- struct fuse_entry_param e;
- if (is_dot_or_dotdot(name)) {
- e = (struct fuse_entry_param) {
- .attr.st_ino = d->entry->d_ino,
- .attr.st_mode = d->entry->d_type << 12,
- };
- } else {
- err = lo_do_lookup(req, ino, name, &e);
- if (err)
- goto error;
- entry_ino = e.ino;
- }
-
- entsize = fuse_add_direntry_plus(req, p, rem, name,
- &e, nextoff);
- } else {
- struct stat st = {
- .st_ino = d->entry->d_ino,
- .st_mode = d->entry->d_type << 12,
- };
- entsize = fuse_add_direntry(req, p, rem, name,
- &st, nextoff);
- }
- if (entsize > rem) {
- if (entry_ino != 0)
- lo_forget_one(req, entry_ino, 1);
- break;
- }
-
- p += entsize;
- rem -= entsize;
-
- d->entry = NULL;
- d->offset = nextoff;
- }
+ struct lo_dirp *d = lo_dirp(fi);
+ char *buf;
+ char *p;
+ size_t rem = size;
+ int err;
+
+ (void)ino;
+
+ buf = calloc(1, size);
+ if (!buf) {
+ err = ENOMEM;
+ goto error;
+ }
+ p = buf;
+
+ if (offset != d->offset) {
+ seekdir(d->dp, offset);
+ d->entry = NULL;
+ d->offset = offset;
+ }
+ while (1) {
+ size_t entsize;
+ off_t nextoff;
+ const char *name;
+
+ if (!d->entry) {
+ errno = 0;
+ d->entry = readdir(d->dp);
+ if (!d->entry) {
+ if (errno) { /* Error */
+ err = errno;
+ goto error;
+ } else { /* End of stream */
+ break;
+ }
+ }
+ }
+ nextoff = d->entry->d_off;
+ name = d->entry->d_name;
+ fuse_ino_t entry_ino = 0;
+ if (plus) {
+ struct fuse_entry_param e;
+ if (is_dot_or_dotdot(name)) {
+ e = (struct fuse_entry_param){
+ .attr.st_ino = d->entry->d_ino,
+ .attr.st_mode = d->entry->d_type << 12,
+ };
+ } else {
+ err = lo_do_lookup(req, ino, name, &e);
+ if (err) {
+ goto error;
+ }
+ entry_ino = e.ino;
+ }
+
+ entsize = fuse_add_direntry_plus(req, p, rem, name, &e, nextoff);
+ } else {
+ struct stat st = {
+ .st_ino = d->entry->d_ino,
+ .st_mode = d->entry->d_type << 12,
+ };
+ entsize = fuse_add_direntry(req, p, rem, name, &st, nextoff);
+ }
+ if (entsize > rem) {
+ if (entry_ino != 0) {
+ lo_forget_one(req, entry_ino, 1);
+ }
+ break;
+ }
+
+ p += entsize;
+ rem -= entsize;
+
+ d->entry = NULL;
+ d->offset = nextoff;
+ }
err = 0;
error:
- // If there's an error, we can only signal it if we haven't stored
- // any entries yet - otherwise we'd end up with wrong lookup
- // counts for the entries that are already in the buffer. So we
- // return what we've collected until that point.
- if (err && rem == size)
- fuse_reply_err(req, err);
- else
- fuse_reply_buf(req, buf, size - rem);
+ /*
+ * If there's an error, we can only signal it if we haven't stored
+ * any entries yet - otherwise we'd end up with wrong lookup
+ * counts for the entries that are already in the buffer. So we
+ * return what we've collected until that point.
+ */
+ if (err && rem == size) {
+ fuse_reply_err(req, err);
+ } else {
+ fuse_reply_buf(req, buf, size - rem);
+ }
free(buf);
}
static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
- off_t offset, struct fuse_file_info *fi)
+ off_t offset, struct fuse_file_info *fi)
{
- lo_do_readdir(req, ino, size, offset, fi, 0);
+ lo_do_readdir(req, ino, size, offset, fi, 0);
}
static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
- off_t offset, struct fuse_file_info *fi)
+ off_t offset, struct fuse_file_info *fi)
{
- lo_do_readdir(req, ino, size, offset, fi, 1);
+ lo_do_readdir(req, ino, size, offset, fi, 1);
}
-static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+static void lo_releasedir(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- struct lo_dirp *d = lo_dirp(fi);
- (void) ino;
- closedir(d->dp);
- free(d);
- fuse_reply_err(req, 0);
+ struct lo_dirp *d = lo_dirp(fi);
+ (void)ino;
+ closedir(d->dp);
+ free(d);
+ fuse_reply_err(req, 0);
}
static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
- mode_t mode, struct fuse_file_info *fi)
+ mode_t mode, struct fuse_file_info *fi)
{
- int fd;
- struct lo_data *lo = lo_data(req);
- struct fuse_entry_param e;
- int err;
-
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
- parent, name);
-
- fd = openat(lo_fd(req, parent), name,
- (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
- if (fd == -1)
- return (void) fuse_reply_err(req, errno);
-
- fi->fh = fd;
- if (lo->cache == CACHE_NEVER)
- fi->direct_io = 1;
- else if (lo->cache == CACHE_ALWAYS)
- fi->keep_cache = 1;
-
- err = lo_do_lookup(req, parent, name, &e);
- if (err)
- fuse_reply_err(req, err);
- else
- fuse_reply_create(req, &e, fi);
+ int fd;
+ struct lo_data *lo = lo_data(req);
+ struct fuse_entry_param e;
+ int err;
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
+ parent, name);
+ }
+
+ fd = openat(lo_fd(req, parent), name, (fi->flags | O_CREAT) & ~O_NOFOLLOW,
+ mode);
+ if (fd == -1) {
+ return (void)fuse_reply_err(req, errno);
+ }
+
+ fi->fh = fd;
+ if (lo->cache == CACHE_NEVER) {
+ fi->direct_io = 1;
+ } else if (lo->cache == CACHE_ALWAYS) {
+ fi->keep_cache = 1;
+ }
+
+ err = lo_do_lookup(req, parent, name, &e);
+ if (err) {
+ fuse_reply_err(req, err);
+ } else {
+ fuse_reply_create(req, &e, fi);
+ }
}
static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
- struct fuse_file_info *fi)
+ struct fuse_file_info *fi)
{
- int res;
- int fd = dirfd(lo_dirp(fi)->dp);
- (void) ino;
- if (datasync)
- res = fdatasync(fd);
- else
- res = fsync(fd);
- fuse_reply_err(req, res == -1 ? errno : 0);
+ int res;
+ int fd = dirfd(lo_dirp(fi)->dp);
+ (void)ino;
+ if (datasync) {
+ res = fdatasync(fd);
+ } else {
+ res = fsync(fd);
+ }
+ fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
- int fd;
- char buf[64];
- struct lo_data *lo = lo_data(req);
-
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
- ino, fi->flags);
-
- /* With writeback cache, kernel may send read requests even
- when userspace opened write-only */
- if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
- fi->flags &= ~O_ACCMODE;
- fi->flags |= O_RDWR;
- }
-
- /* With writeback cache, O_APPEND is handled by the kernel.
- This breaks atomicity (since the file may change in the
- underlying filesystem, so that the kernel's idea of the
- end of the file isn't accurate anymore). In this example,
- we just accept that. A more rigorous filesystem may want
- to return an error here */
- if (lo->writeback && (fi->flags & O_APPEND))
- fi->flags &= ~O_APPEND;
-
- sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
- fd = open(buf, fi->flags & ~O_NOFOLLOW);
- if (fd == -1)
- return (void) fuse_reply_err(req, errno);
-
- fi->fh = fd;
- if (lo->cache == CACHE_NEVER)
- fi->direct_io = 1;
- else if (lo->cache == CACHE_ALWAYS)
- fi->keep_cache = 1;
- fuse_reply_open(req, fi);
+ int fd;
+ char buf[64];
+ struct lo_data *lo = lo_data(req);
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n", ino,
+ fi->flags);
+ }
+
+ /*
+ * With writeback cache, kernel may send read requests even
+ * when userspace opened write-only
+ */
+ if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
+ fi->flags &= ~O_ACCMODE;
+ fi->flags |= O_RDWR;
+ }
+
+ /*
+ * With writeback cache, O_APPEND is handled by the kernel.
+ * This breaks atomicity (since the file may change in the
+ * underlying filesystem, so that the kernel's idea of the
+ * end of the file isn't accurate anymore). In this example,
+ * we just accept that. A more rigorous filesystem may want
+ * to return an error here
+ */
+ if (lo->writeback && (fi->flags & O_APPEND)) {
+ fi->flags &= ~O_APPEND;
+ }
+
+ sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
+ fd = open(buf, fi->flags & ~O_NOFOLLOW);
+ if (fd == -1) {
+ return (void)fuse_reply_err(req, errno);
+ }
+
+ fi->fh = fd;
+ if (lo->cache == CACHE_NEVER) {
+ fi->direct_io = 1;
+ } else if (lo->cache == CACHE_ALWAYS) {
+ fi->keep_cache = 1;
+ }
+ fuse_reply_open(req, fi);
}
-static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+static void lo_release(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- (void) ino;
+ (void)ino;
- close(fi->fh);
- fuse_reply_err(req, 0);
+ close(fi->fh);
+ fuse_reply_err(req, 0);
}
static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
- int res;
- (void) ino;
- res = close(dup(fi->fh));
- fuse_reply_err(req, res == -1 ? errno : 0);
+ int res;
+ (void)ino;
+ res = close(dup(fi->fh));
+ fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
- struct fuse_file_info *fi)
+ struct fuse_file_info *fi)
{
- int res;
- (void) ino;
- if (datasync)
- res = fdatasync(fi->fh);
- else
- res = fsync(fi->fh);
- fuse_reply_err(req, res == -1 ? errno : 0);
+ int res;
+ (void)ino;
+ if (datasync) {
+ res = fdatasync(fi->fh);
+ } else {
+ res = fsync(fi->fh);
+ }
+ fuse_reply_err(req, res == -1 ? errno : 0);
}
-static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
- off_t offset, struct fuse_file_info *fi)
+static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset,
+ struct fuse_file_info *fi)
{
- struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
+ struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
- "off=%lu)\n", ino, size, (unsigned long) offset);
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_read(ino=%" PRIu64 ", size=%zd, "
+ "off=%lu)\n",
+ ino, size, (unsigned long)offset);
+ }
- buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
- buf.buf[0].fd = fi->fh;
- buf.buf[0].pos = offset;
+ buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+ buf.buf[0].fd = fi->fh;
+ buf.buf[0].pos = offset;
- fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
+ fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
}
static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
- struct fuse_bufvec *in_buf, off_t off,
- struct fuse_file_info *fi)
+ struct fuse_bufvec *in_buf, off_t off,
+ struct fuse_file_info *fi)
{
- (void) ino;
- ssize_t res;
- struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
-
- out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
- out_buf.buf[0].fd = fi->fh;
- out_buf.buf[0].pos = off;
-
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
- ino, out_buf.buf[0].size, (unsigned long) off);
-
- res = fuse_buf_copy(&out_buf, in_buf, 0);
- if(res < 0)
- fuse_reply_err(req, -res);
- else
- fuse_reply_write(req, (size_t) res);
+ (void)ino;
+ ssize_t res;
+ struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
+
+ out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+ out_buf.buf[0].fd = fi->fh;
+ out_buf.buf[0].pos = off;
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n", ino,
+ out_buf.buf[0].size, (unsigned long)off);
+ }
+
+ res = fuse_buf_copy(&out_buf, in_buf, 0);
+ if (res < 0) {
+ fuse_reply_err(req, -res);
+ } else {
+ fuse_reply_write(req, (size_t)res);
+ }
}
static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
{
- int res;
- struct statvfs stbuf;
-
- res = fstatvfs(lo_fd(req, ino), &stbuf);
- if (res == -1)
- fuse_reply_err(req, errno);
- else
- fuse_reply_statfs(req, &stbuf);
+ int res;
+ struct statvfs stbuf;
+
+ res = fstatvfs(lo_fd(req, ino), &stbuf);
+ if (res == -1) {
+ fuse_reply_err(req, errno);
+ } else {
+ fuse_reply_statfs(req, &stbuf);
+ }
}
-static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
- off_t offset, off_t length, struct fuse_file_info *fi)
+static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset,
+ off_t length, struct fuse_file_info *fi)
{
- int err = EOPNOTSUPP;
- (void) ino;
+ int err = EOPNOTSUPP;
+ (void)ino;
#ifdef HAVE_FALLOCATE
- err = fallocate(fi->fh, mode, offset, length);
- if (err < 0)
- err = errno;
+ err = fallocate(fi->fh, mode, offset, length);
+ if (err < 0) {
+ err = errno;
+ }
#elif defined(HAVE_POSIX_FALLOCATE)
- if (mode) {
- fuse_reply_err(req, EOPNOTSUPP);
- return;
- }
+ if (mode) {
+ fuse_reply_err(req, EOPNOTSUPP);
+ return;
+ }
- err = posix_fallocate(fi->fh, offset, length);
+ err = posix_fallocate(fi->fh, offset, length);
#endif
- fuse_reply_err(req, err);
+ fuse_reply_err(req, err);
}
static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
- int op)
+ int op)
{
- int res;
- (void) ino;
+ int res;
+ (void)ino;
- res = flock(fi->fh, op);
+ res = flock(fi->fh, op);
- fuse_reply_err(req, res == -1 ? errno : 0);
+ fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
- size_t size)
+ size_t size)
{
- char *value = NULL;
- char procname[64];
- struct lo_inode *inode = lo_inode(req, ino);
- ssize_t ret;
- int saverr;
-
- saverr = ENOSYS;
- if (!lo_data(req)->xattr)
- goto out;
-
- if (lo_debug(req)) {
- fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
- ino, name, size);
- }
-
- if (inode->is_symlink) {
- /* Sorry, no race free way to getxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
-
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
-
- if (size) {
- value = malloc(size);
- if (!value)
- goto out_err;
-
- ret = getxattr(procname, name, value, size);
- if (ret == -1)
- goto out_err;
- saverr = 0;
- if (ret == 0)
- goto out;
-
- fuse_reply_buf(req, value, ret);
- } else {
- ret = getxattr(procname, name, NULL, 0);
- if (ret == -1)
- goto out_err;
-
- fuse_reply_xattr(req, ret);
- }
+ char *value = NULL;
+ char procname[64];
+ struct lo_inode *inode = lo_inode(req, ino);
+ ssize_t ret;
+ int saverr;
+
+ saverr = ENOSYS;
+ if (!lo_data(req)->xattr) {
+ goto out;
+ }
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n", ino, name,
+ size);
+ }
+
+ if (inode->is_symlink) {
+ /* Sorry, no race free way to getxattr on symlink. */
+ saverr = EPERM;
+ goto out;
+ }
+
+ sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+ if (size) {
+ value = malloc(size);
+ if (!value) {
+ goto out_err;
+ }
+
+ ret = getxattr(procname, name, value, size);
+ if (ret == -1) {
+ goto out_err;
+ }
+ saverr = 0;
+ if (ret == 0) {
+ goto out;
+ }
+
+ fuse_reply_buf(req, value, ret);
+ } else {
+ ret = getxattr(procname, name, NULL, 0);
+ if (ret == -1) {
+ goto out_err;
+ }
+
+ fuse_reply_xattr(req, ret);
+ }
out_free:
- free(value);
- return;
+ free(value);
+ return;
out_err:
- saverr = errno;
+ saverr = errno;
out:
- fuse_reply_err(req, saverr);
- goto out_free;
+ fuse_reply_err(req, saverr);
+ goto out_free;
}
static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
{
- char *value = NULL;
- char procname[64];
- struct lo_inode *inode = lo_inode(req, ino);
- ssize_t ret;
- int saverr;
-
- saverr = ENOSYS;
- if (!lo_data(req)->xattr)
- goto out;
-
- if (lo_debug(req)) {
- fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
- ino, size);
- }
-
- if (inode->is_symlink) {
- /* Sorry, no race free way to listxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
-
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
-
- if (size) {
- value = malloc(size);
- if (!value)
- goto out_err;
-
- ret = listxattr(procname, value, size);
- if (ret == -1)
- goto out_err;
- saverr = 0;
- if (ret == 0)
- goto out;
-
- fuse_reply_buf(req, value, ret);
- } else {
- ret = listxattr(procname, NULL, 0);
- if (ret == -1)
- goto out_err;
-
- fuse_reply_xattr(req, ret);
- }
+ char *value = NULL;
+ char procname[64];
+ struct lo_inode *inode = lo_inode(req, ino);
+ ssize_t ret;
+ int saverr;
+
+ saverr = ENOSYS;
+ if (!lo_data(req)->xattr) {
+ goto out;
+ }
+
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
+ ino, size);
+ }
+
+ if (inode->is_symlink) {
+ /* Sorry, no race free way to listxattr on symlink. */
+ saverr = EPERM;
+ goto out;
+ }
+
+ sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+ if (size) {
+ value = malloc(size);
+ if (!value) {
+ goto out_err;
+ }
+
+ ret = listxattr(procname, value, size);
+ if (ret == -1) {
+ goto out_err;
+ }
+ saverr = 0;
+ if (ret == 0) {
+ goto out;
+ }
+
+ fuse_reply_buf(req, value, ret);
+ } else {
+ ret = listxattr(procname, NULL, 0);
+ if (ret == -1) {
+ goto out_err;
+ }
+
+ fuse_reply_xattr(req, ret);
+ }
out_free:
- free(value);
- return;
+ free(value);
+ return;
out_err:
- saverr = errno;
+ saverr = errno;
out:
- fuse_reply_err(req, saverr);
- goto out_free;
+ fuse_reply_err(req, saverr);
+ goto out_free;
}
static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
- const char *value, size_t size, int flags)
+ const char *value, size_t size, int flags)
{
- char procname[64];
- struct lo_inode *inode = lo_inode(req, ino);
- ssize_t ret;
- int saverr;
+ char procname[64];
+ struct lo_inode *inode = lo_inode(req, ino);
+ ssize_t ret;
+ int saverr;
- saverr = ENOSYS;
- if (!lo_data(req)->xattr)
- goto out;
+ saverr = ENOSYS;
+ if (!lo_data(req)->xattr) {
+ goto out;
+ }
- if (lo_debug(req)) {
- fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
- ino, name, value, size);
- }
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
+ ino, name, value, size);
+ }
- if (inode->is_symlink) {
- /* Sorry, no race free way to setxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
+ if (inode->is_symlink) {
+ /* Sorry, no race free way to setxattr on symlink. */
+ saverr = EPERM;
+ goto out;
+ }
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
+ sprintf(procname, "/proc/self/fd/%i", inode->fd);
- ret = setxattr(procname, name, value, size, flags);
- saverr = ret == -1 ? errno : 0;
+ ret = setxattr(procname, name, value, size, flags);
+ saverr = ret == -1 ? errno : 0;
out:
- fuse_reply_err(req, saverr);
+ fuse_reply_err(req, saverr);
}
static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
{
- char procname[64];
- struct lo_inode *inode = lo_inode(req, ino);
- ssize_t ret;
- int saverr;
+ char procname[64];
+ struct lo_inode *inode = lo_inode(req, ino);
+ ssize_t ret;
+ int saverr;
- saverr = ENOSYS;
- if (!lo_data(req)->xattr)
- goto out;
+ saverr = ENOSYS;
+ if (!lo_data(req)->xattr) {
+ goto out;
+ }
- if (lo_debug(req)) {
- fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
- ino, name);
- }
+ if (lo_debug(req)) {
+ fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
+ ino, name);
+ }
- if (inode->is_symlink) {
- /* Sorry, no race free way to setxattr on symlink. */
- saverr = EPERM;
- goto out;
- }
+ if (inode->is_symlink) {
+ /* Sorry, no race free way to setxattr on symlink. */
+ saverr = EPERM;
+ goto out;
+ }
- sprintf(procname, "/proc/self/fd/%i", inode->fd);
+ sprintf(procname, "/proc/self/fd/%i", inode->fd);
- ret = removexattr(procname, name);
- saverr = ret == -1 ? errno : 0;
+ ret = removexattr(procname, name);
+ saverr = ret == -1 ? errno : 0;
out:
- fuse_reply_err(req, saverr);
+ fuse_reply_err(req, saverr);
}
#ifdef HAVE_COPY_FILE_RANGE
static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
- struct fuse_file_info *fi_in,
- fuse_ino_t ino_out, off_t off_out,
- struct fuse_file_info *fi_out, size_t len,
- int flags)
+ struct fuse_file_info *fi_in, fuse_ino_t ino_out,
+ off_t off_out, struct fuse_file_info *fi_out,
+ size_t len, int flags)
{
- ssize_t res;
-
- if (lo_debug(req))
- fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
- "off=%lu, ino=%" PRIu64 "/fd=%lu, "
- "off=%lu, size=%zd, flags=0x%x)\n",
- ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
- len, flags);
-
- res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
- flags);
- if (res < 0)
- fuse_reply_err(req, -errno);
- else
- fuse_reply_write(req, res);
+ ssize_t res;
+
+ if (lo_debug(req))
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
+ "off=%lu, ino=%" PRIu64 "/fd=%lu, "
+ "off=%lu, size=%zd, flags=0x%x)\n",
+ ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out, len,
+ flags);
+
+ res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len, flags);
+ if (res < 0) {
+ fuse_reply_err(req, -errno);
+ } else {
+ fuse_reply_write(req, res);
+ }
}
#endif
static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
- struct fuse_file_info *fi)
+ struct fuse_file_info *fi)
{
- off_t res;
-
- (void)ino;
- res = lseek(fi->fh, off, whence);
- if (res != -1)
- fuse_reply_lseek(req, res);
- else
- fuse_reply_err(req, errno);
+ off_t res;
+
+ (void)ino;
+ res = lseek(fi->fh, off, whence);
+ if (res != -1) {
+ fuse_reply_lseek(req, res);
+ } else {
+ fuse_reply_err(req, errno);
+ }
}
static struct fuse_lowlevel_ops lo_oper = {
- .init = lo_init,
- .lookup = lo_lookup,
- .mkdir = lo_mkdir,
- .mknod = lo_mknod,
- .symlink = lo_symlink,
- .link = lo_link,
- .unlink = lo_unlink,
- .rmdir = lo_rmdir,
- .rename = lo_rename,
- .forget = lo_forget,
- .forget_multi = lo_forget_multi,
- .getattr = lo_getattr,
- .setattr = lo_setattr,
- .readlink = lo_readlink,
- .opendir = lo_opendir,
- .readdir = lo_readdir,
- .readdirplus = lo_readdirplus,
- .releasedir = lo_releasedir,
- .fsyncdir = lo_fsyncdir,
- .create = lo_create,
- .open = lo_open,
- .release = lo_release,
- .flush = lo_flush,
- .fsync = lo_fsync,
- .read = lo_read,
- .write_buf = lo_write_buf,
- .statfs = lo_statfs,
- .fallocate = lo_fallocate,
- .flock = lo_flock,
- .getxattr = lo_getxattr,
- .listxattr = lo_listxattr,
- .setxattr = lo_setxattr,
- .removexattr = lo_removexattr,
+ .init = lo_init,
+ .lookup = lo_lookup,
+ .mkdir = lo_mkdir,
+ .mknod = lo_mknod,
+ .symlink = lo_symlink,
+ .link = lo_link,
+ .unlink = lo_unlink,
+ .rmdir = lo_rmdir,
+ .rename = lo_rename,
+ .forget = lo_forget,
+ .forget_multi = lo_forget_multi,
+ .getattr = lo_getattr,
+ .setattr = lo_setattr,
+ .readlink = lo_readlink,
+ .opendir = lo_opendir,
+ .readdir = lo_readdir,
+ .readdirplus = lo_readdirplus,
+ .releasedir = lo_releasedir,
+ .fsyncdir = lo_fsyncdir,
+ .create = lo_create,
+ .open = lo_open,
+ .release = lo_release,
+ .flush = lo_flush,
+ .fsync = lo_fsync,
+ .read = lo_read,
+ .write_buf = lo_write_buf,
+ .statfs = lo_statfs,
+ .fallocate = lo_fallocate,
+ .flock = lo_flock,
+ .getxattr = lo_getxattr,
+ .listxattr = lo_listxattr,
+ .setxattr = lo_setxattr,
+ .removexattr = lo_removexattr,
#ifdef HAVE_COPY_FILE_RANGE
- .copy_file_range = lo_copy_file_range,
+ .copy_file_range = lo_copy_file_range,
#endif
- .lseek = lo_lseek,
+ .lseek = lo_lseek,
};
int main(int argc, char *argv[])
{
- struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
- struct fuse_session *se;
- struct fuse_cmdline_opts opts;
- struct lo_data lo = { .debug = 0,
- .writeback = 0 };
- int ret = -1;
-
- /* Don't mask creation mode, kernel already did that */
- umask(0);
-
- pthread_mutex_init(&lo.mutex, NULL);
- lo.root.next = lo.root.prev = &lo.root;
- lo.root.fd = -1;
- lo.cache = CACHE_NORMAL;
-
- if (fuse_parse_cmdline(&args, &opts) != 0)
- return 1;
- if (opts.show_help) {
- printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
- fuse_cmdline_help();
- fuse_lowlevel_help();
- ret = 0;
- goto err_out1;
- } else if (opts.show_version) {
- fuse_lowlevel_version();
- ret = 0;
- goto err_out1;
- }
-
- if(opts.mountpoint == NULL) {
- printf("usage: %s [options] <mountpoint>\n", argv[0]);
- printf(" %s --help\n", argv[0]);
- ret = 1;
- goto err_out1;
- }
-
- if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
- return 1;
-
- lo.debug = opts.debug;
- lo.root.refcount = 2;
- if (lo.source) {
- struct stat stat;
- int res;
-
- res = lstat(lo.source, &stat);
- if (res == -1) {
- fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
- lo.source);
- exit(1);
- }
- if (!S_ISDIR(stat.st_mode)) {
- fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
- exit(1);
- }
-
- } else {
- lo.source = "/";
- }
- lo.root.is_symlink = false;
- if (!lo.timeout_set) {
- switch (lo.cache) {
- case CACHE_NEVER:
- lo.timeout = 0.0;
- break;
-
- case CACHE_NORMAL:
- lo.timeout = 1.0;
- break;
-
- case CACHE_ALWAYS:
- lo.timeout = 86400.0;
- break;
- }
- } else if (lo.timeout < 0) {
- fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
- lo.timeout);
- exit(1);
- }
-
- lo.root.fd = open(lo.source, O_PATH);
- if (lo.root.fd == -1) {
- fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
- lo.source);
- exit(1);
- }
-
- se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
- if (se == NULL)
- goto err_out1;
-
- if (fuse_set_signal_handlers(se) != 0)
- goto err_out2;
-
- if (fuse_session_mount(se, opts.mountpoint) != 0)
- goto err_out3;
-
- fuse_daemonize(opts.foreground);
-
- /* Block until ctrl+c or fusermount -u */
- if (opts.singlethread)
- ret = fuse_session_loop(se);
- else
- ret = fuse_session_loop_mt(se, opts.clone_fd);
-
- fuse_session_unmount(se);
+ struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+ struct fuse_session *se;
+ struct fuse_cmdline_opts opts;
+ struct lo_data lo = { .debug = 0, .writeback = 0 };
+ int ret = -1;
+
+ /* Don't mask creation mode, kernel already did that */
+ umask(0);
+
+ pthread_mutex_init(&lo.mutex, NULL);
+ lo.root.next = lo.root.prev = &lo.root;
+ lo.root.fd = -1;
+ lo.cache = CACHE_NORMAL;
+
+ if (fuse_parse_cmdline(&args, &opts) != 0) {
+ return 1;
+ }
+ if (opts.show_help) {
+ printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
+ fuse_cmdline_help();
+ fuse_lowlevel_help();
+ ret = 0;
+ goto err_out1;
+ } else if (opts.show_version) {
+ fuse_lowlevel_version();
+ ret = 0;
+ goto err_out1;
+ }
+
+ if (opts.mountpoint == NULL) {
+ printf("usage: %s [options] <mountpoint>\n", argv[0]);
+ printf(" %s --help\n", argv[0]);
+ ret = 1;
+ goto err_out1;
+ }
+
+ if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1) {
+ return 1;
+ }
+
+ lo.debug = opts.debug;
+ lo.root.refcount = 2;
+ if (lo.source) {
+ struct stat stat;
+ int res;
+
+ res = lstat(lo.source, &stat);
+ if (res == -1) {
+ fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
+ lo.source);
+ exit(1);
+ }
+ if (!S_ISDIR(stat.st_mode)) {
+ fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
+ exit(1);
+ }
+
+ } else {
+ lo.source = "/";
+ }
+ lo.root.is_symlink = false;
+ if (!lo.timeout_set) {
+ switch (lo.cache) {
+ case CACHE_NEVER:
+ lo.timeout = 0.0;
+ break;
+
+ case CACHE_NORMAL:
+ lo.timeout = 1.0;
+ break;
+
+ case CACHE_ALWAYS:
+ lo.timeout = 86400.0;
+ break;
+ }
+ } else if (lo.timeout < 0) {
+ fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n", lo.timeout);
+ exit(1);
+ }
+
+ lo.root.fd = open(lo.source, O_PATH);
+ if (lo.root.fd == -1) {
+ fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", lo.source);
+ exit(1);
+ }
+
+ se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
+ if (se == NULL) {
+ goto err_out1;
+ }
+
+ if (fuse_set_signal_handlers(se) != 0) {
+ goto err_out2;
+ }
+
+ if (fuse_session_mount(se, opts.mountpoint) != 0) {
+ goto err_out3;
+ }
+
+ fuse_daemonize(opts.foreground);
+
+ /* Block until ctrl+c or fusermount -u */
+ if (opts.singlethread) {
+ ret = fuse_session_loop(se);
+ } else {
+ ret = fuse_session_loop_mt(se, opts.clone_fd);
+ }
+
+ fuse_session_unmount(se);
err_out3:
- fuse_remove_signal_handlers(se);
+ fuse_remove_signal_handlers(se);
err_out2:
- fuse_session_destroy(se);
+ fuse_session_destroy(se);
err_out1:
- free(opts.mountpoint);
- fuse_opt_free_args(&args);
+ free(opts.mountpoint);
+ fuse_opt_free_args(&args);
- if (lo.root.fd >= 0)
- close(lo.root.fd);
+ if (lo.root.fd >= 0) {
+ close(lo.root.fd);
+ }
- return ret ? 1 : 0;
+ return ret ? 1 : 0;
}