From f9b831eb1ae81783dfde85bb486303321109de51 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Fri, 31 Jul 2020 23:50:47 -0400 Subject: [PATCH 1/6] libfuse cleanup: reindent --- libfuse/include/cuse_lowlevel.h | 102 +- libfuse/include/fuse.h | 1793 ++++----- libfuse/include/fuse_common.h | 836 ++-- libfuse/include/fuse_common_compat.h | 13 +- libfuse/include/fuse_compat.h | 241 +- libfuse/include/fuse_dirents.h | 20 +- libfuse/include/fuse_lowlevel.h | 3450 ++++++++-------- libfuse/include/fuse_lowlevel_compat.h | 226 +- libfuse/include/fuse_opt.h | 434 +-- libfuse/include/fuse_timeouts.h | 10 + libfuse/lib/buffer.c | 476 +-- libfuse/lib/cuse_lowlevel.c | 508 +-- libfuse/lib/fuse.c | 4961 ++++++++++++------------ libfuse/lib/fuse_i.h | 140 +- libfuse/lib/fuse_kern_chan.c | 106 +- libfuse/lib/fuse_loop.c | 58 +- libfuse/lib/fuse_loop_mt.c | 308 +- libfuse/lib/fuse_lowlevel.c | 3966 +++++++++---------- libfuse/lib/fuse_misc.h | 14 +- libfuse/lib/fuse_mt.c | 143 +- libfuse/lib/fuse_opt.c | 593 +-- libfuse/lib/fuse_session.c | 204 +- libfuse/lib/fuse_signals.c | 71 +- libfuse/lib/helper.c | 478 +-- libfuse/lib/mount_bsd.c | 590 +-- libfuse/lib/mount_generic.c | 992 ++--- libfuse/lib/mount_util.c | 554 +-- libfuse/lib/ulockmgr.c | 694 ++-- 28 files changed, 10990 insertions(+), 10991 deletions(-) create mode 100644 libfuse/include/fuse_timeouts.h diff --git a/libfuse/include/cuse_lowlevel.h b/libfuse/include/cuse_lowlevel.h index e147fa26..e80a9c3d 100644 --- a/libfuse/include/cuse_lowlevel.h +++ b/libfuse/include/cuse_lowlevel.h @@ -28,57 +28,57 @@ extern "C" { #define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */ -struct fuse_session; - -struct cuse_info { - unsigned dev_major; - unsigned dev_minor; - unsigned dev_info_argc; - const char **dev_info_argv; - unsigned flags; -}; - -/* - * Most ops behave almost identically to the matching fuse_lowlevel - * ops except that they don't take @ino. - * - * init_done : called after initialization is complete - * read/write : always direct IO, simultaneous operations allowed - * ioctl : might be in unrestricted mode depending on ci->flags - */ -struct cuse_lowlevel_ops { - void (*init) (void *userdata, struct fuse_conn_info *conn); - void (*init_done) (void *userdata); - void (*destroy) (void *userdata); - void (*open) (fuse_req_t req, struct fuse_file_info *fi); - void (*read) (fuse_req_t req, size_t size, off_t off, - struct fuse_file_info *fi); - void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off, - struct fuse_file_info *fi); - void (*flush) (fuse_req_t req, struct fuse_file_info *fi); - void (*release) (fuse_req_t req, struct fuse_file_info *fi); - void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi); - void (*ioctl) (fuse_req_t req, int cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz); - void (*poll) (fuse_req_t req, struct fuse_file_info *fi, - struct fuse_pollhandle *ph); -}; - -struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - void *userdata); - -struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - int *multithreaded, void *userdata); - -void cuse_lowlevel_teardown(struct fuse_session *se); - -int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, void *userdata); + struct fuse_session; + + struct cuse_info { + unsigned dev_major; + unsigned dev_minor; + unsigned dev_info_argc; + const char **dev_info_argv; + unsigned flags; + }; + + /* + * Most ops behave almost identically to the matching fuse_lowlevel + * ops except that they don't take @ino. + * + * init_done : called after initialization is complete + * read/write : always direct IO, simultaneous operations allowed + * ioctl : might be in unrestricted mode depending on ci->flags + */ + struct cuse_lowlevel_ops { + void (*init) (void *userdata, struct fuse_conn_info *conn); + void (*init_done) (void *userdata); + void (*destroy) (void *userdata); + void (*open) (fuse_req_t req, struct fuse_file_info *fi); + void (*read) (fuse_req_t req, size_t size, off_t off, + struct fuse_file_info *fi); + void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off, + struct fuse_file_info *fi); + void (*flush) (fuse_req_t req, struct fuse_file_info *fi); + void (*release) (fuse_req_t req, struct fuse_file_info *fi); + void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi); + void (*ioctl) (fuse_req_t req, int cmd, void *arg, + struct fuse_file_info *fi, unsigned int flags, + const void *in_buf, size_t in_bufsz, size_t out_bufsz); + void (*poll) (fuse_req_t req, struct fuse_file_info *fi, + struct fuse_pollhandle *ph); + }; + + struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, + const struct cuse_info *ci, + const struct cuse_lowlevel_ops *clop, + void *userdata); + + struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], + const struct cuse_info *ci, + const struct cuse_lowlevel_ops *clop, + int *multithreaded, void *userdata); + + void cuse_lowlevel_teardown(struct fuse_session *se); + + int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, + const struct cuse_lowlevel_ops *clop, void *userdata); #ifdef __cplusplus } diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index 0717fe0d..9d5f0f43 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -38,1005 +38,914 @@ extern "C" { #endif -/* ----------------------------------------------------------- * - * Basic FUSE API * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Basic FUSE API * + * ----------------------------------------------------------- */ -/** Handle for a FUSE filesystem */ -struct fuse; + /** Handle for a FUSE filesystem */ + struct fuse; -/** Structure containing a raw command */ -struct fuse_cmd; - -/** - * The file system operations: - * - * Most of these should work very similarly to the well known UNIX - * file system operations. A major exception is that instead of - * returning an error in 'errno', the operation should return the - * negated error value (-errno) directly. - * - * All methods are optional, but some are essential for a useful - * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, - * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock, - * init and destroy are special purpose methods, without which a full - * featured filesystem can still be implemented. - * - * Almost all operations take a path which can be of any length. - * - * Changed in fuse 2.8.0 (regardless of API version) - * Previously, paths were limited to a length of PATH_MAX. - * - * See http://fuse.sourceforge.net/wiki/ for more information. There - * is also a snapshot of the relevant wiki pages in the doc/ folder. - */ -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. - */ - int (*getattr) (const char *, struct stat *, fuse_timeouts_t *); - - /** 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); - - /** Hide files unlinked / renamed over - * - * Allows storing of a file handle when a file is unlinked - * while open. Helps manage the fact the kernel usually does - * not send fh with getattr requests. - */ - int (*prepare_hide)(const char *name_, uint64_t *fh_); - int (*free_hide)(const uint64_t fh_); - - /** 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 */ - int (*rename) (const char *, const char *); - - /** Create a hard link to a file */ - int (*link) (const char *, const char *); - - /** Change the permission bits of a file */ - int (*chmod) (const char *, mode_t); - int (*fchmod)(const struct fuse_file_info *, const mode_t); - - /** Change the owner and group of a file */ - int (*chown) (const char *, uid_t, gid_t); - int (*fchown)(const struct fuse_file_info *, const uid_t, const gid_t); - - /** Change the size of a file */ - int (*truncate) (const char *, off_t); - - /** Change the access and/or modification times of a file - * - * Deprecated, use utimens() instead. - */ - int (*utime) (const char *, struct utimbuf *); - - /** File open operation - * - * No creation (O_CREAT, O_EXCL) and by default also no - * truncation (O_TRUNC) flags will be passed to open(). If an - * application specifies O_TRUNC, fuse first calls truncate() - * and then open(). Only if 'atomic_o_trunc' has been - * specified and kernel version is 2.6.24 or later, O_TRUNC is - * passed on to open. - * - * Unless the 'default_permissions' mount option is given, - * open should check if the operation is permitted for the - * given flags. Optionally open may also return an arbitrary - * filehandle in the fuse_file_info structure, which will be - * passed to all file operations. - * - * Changed in version 2.2 - */ - 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. - * - * Changed in version 2.2 - */ - int (*read) (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). - * - * Changed in version 2.2 - */ - int (*write) (const char *, size_t, off_t, - struct fuse_file_info *); - - /** Get file system statistics - * - * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored - * - * Replaced 'struct statfs' parameter with 'struct statvfs' in - * version 2.5 - */ - 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. So if a - * filesystem wants to return write errors in close() and the file - * has cached dirty data, this is a good place to write back data - * and return any errors. Since many applications ignore close() - * errors this is not always useful. - * - * NOTE: The flush() method may be called more than once for each - * open(). This happens if more than one file descriptor refers - * to an opened file 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 always be called - * after some writes, or that if will be called at all. - * - * Changed in version 2.2 - */ - int (*flush) (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 descriptor. 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. - * - * Changed in version 2.2 - */ - int (*release) (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. - * - * Changed in version 2.2 - */ - int (*fsync) (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, closedir and fsyncdir. - * - * Introduced in version 2.3 - */ - int (*opendir) (const char *, struct fuse_file_info *); - - /** Read directory - * - * This supersedes the old getdir() interface. New applications - * should use this. - * - * 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. This - * works just like the old getdir() method. - * - * 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'. - * - * Introduced in version 2.3 - */ - int (*readdir)(struct fuse_file_info *, - fuse_dirents_t *); - - int (*readdir_plus)(struct fuse_file_info *, - fuse_dirents_t *); - - - /** Release directory - * - * Introduced in version 2.3 - */ - int (*releasedir) (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 - * - * Introduced in version 2.3 - */ - int (*fsyncdir) (int, struct fuse_file_info *); - - /** - * Initialize filesystem - * - * The return value will passed in the private_data field of - * fuse_context to all file operations and as a parameter to the - * destroy() method. - * - * Introduced in version 2.3 - * Changed in version 2.6 - */ - void *(*init) (struct fuse_conn_info *conn); - - /** - * Clean up filesystem - * - * Called on filesystem exit. - * - * Introduced in version 2.3 - */ - void (*destroy) (void *); - - /** - * 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 - * - * Introduced in version 2.5 - */ - 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. - * - * Introduced in version 2.5 - */ - int (*create) (const char *, mode_t, struct fuse_file_info *); - - /** - * Change the size of an open file - * - * This method is called instead of the truncate() method if the - * truncation was invoked from an ftruncate() system call. - * - * If this method is not implemented or under Linux kernel - * versions earlier than 2.6.15, the truncate() method will be - * called instead. - * - * Introduced in version 2.5 - */ - int (*ftruncate) (off_t, struct fuse_file_info *); - - /** - * Get attributes from an open file - * - * This method is called instead of the getattr() method if the - * file information is available. - * - * Currently this is only called after the create() method if that - * is implemented (see above). Later it may be called for - * invocations of fstat() too. - * - * Introduced in version 2.5 - */ - int (*fgetattr) (struct stat *, struct fuse_file_info *, fuse_timeouts_t *); - - /** - * 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. - * - * Introduced in version 2.6 - */ - int (*lock) (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. - * - * See the utimensat(2) man page for details. - * - * Introduced in version 2.6 - */ - int (*utimens)(const char *, const struct timespec tv[2]); - int (*futimens)(const struct fuse_file_info *ffi_, const struct timespec tv_[2]); - - /** - * 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 - * - * Introduced in version 2.6 - */ - 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. - * - * Introduced in version 2.8 - */ - int (*ioctl) (unsigned long cmd, - void *arg, - struct fuse_file_info *ffi, - unsigned int flags, - void *data, - uint32_t *out_bufsz); - - /** - * 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. - * - * Introduced in version 2.8 - */ - int (*poll) (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. - * - * Introduced in version 2.9 - */ - int (*write_buf) (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. - * - * Introduced in version 2.9 - */ - int (*read_buf) (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. - * - * Introduced in version 2.9 - */ - int (*flock) (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. - * - * Introduced in version 2.9.1 - */ - int (*fallocate) (int, off_t, off_t,struct fuse_file_info *); + /** Structure containing a raw command */ + struct fuse_cmd; /** - * Copy a range of data from one file to another + * The file system operations: + * + * Most of these should work very similarly to the well known UNIX + * file system operations. A major exception is that instead of + * returning an error in 'errno', the operation should return the + * negated error value (-errno) directly. + * + * All methods are optional, but some are essential for a useful + * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, + * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock, + * init and destroy are special purpose methods, without which a full + * featured filesystem can still be implemented. * - * 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. + * Almost all operations take a path which can be of any length. * - * 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. + * Changed in fuse 2.8.0 (regardless of API version) + * Previously, paths were limited to a length of PATH_MAX. + * + * See http://fuse.sourceforge.net/wiki/ for more information. There + * is also a snapshot of the relevant wiki pages in the doc/ folder. */ - ssize_t (*copy_file_range)(struct fuse_file_info *fi_in, - off_t offset_in, - struct fuse_file_info *fi_out, - off_t offset_out, - size_t size, - int flags); -}; - -/** 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; - - /** User ID of the calling process */ - uid_t uid; + 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. + */ + int (*getattr) (const char *, struct stat *, fuse_timeouts_t *); + + /** 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); + + /** Hide files unlinked / renamed over + * + * Allows storing of a file handle when a file is unlinked + * while open. Helps manage the fact the kernel usually does + * not send fh with getattr requests. + */ + int (*prepare_hide)(const char *name_, uint64_t *fh_); + int (*free_hide)(const uint64_t fh_); + + /** 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 */ + int (*rename) (const char *, const char *); + + /** Create a hard link to a file */ + int (*link) (const char *, const char *); + + /** Change the permission bits of a file */ + int (*chmod) (const char *, mode_t); + int (*fchmod)(const struct fuse_file_info *, const mode_t); + + /** Change the owner and group of a file */ + int (*chown) (const char *, uid_t, gid_t); + int (*fchown)(const struct fuse_file_info *, const uid_t, const gid_t); + + /** Change the size of a file */ + int (*truncate) (const char *, off_t); + + /** Change the access and/or modification times of a file + * + * Deprecated, use utimens() instead. + */ + int (*utime) (const char *, struct utimbuf *); + + /** File open operation + * + * No creation (O_CREAT, O_EXCL) and by default also no + * truncation (O_TRUNC) flags will be passed to open(). If an + * application specifies O_TRUNC, fuse first calls truncate() + * and then open(). Only if 'atomic_o_trunc' has been + * specified and kernel version is 2.6.24 or later, O_TRUNC is + * passed on to open. + * + * Unless the 'default_permissions' mount option is given, + * open should check if the operation is permitted for the + * given flags. Optionally open may also return an arbitrary + * filehandle in the fuse_file_info structure, which will be + * passed to all file operations. + * + * Changed in version 2.2 + */ + 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. + * + * Changed in version 2.2 + */ + int (*read) (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). + * + * Changed in version 2.2 + */ + int (*write) (const char *, size_t, off_t, + struct fuse_file_info *); + + /** Get file system statistics + * + * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored + * + * Replaced 'struct statfs' parameter with 'struct statvfs' in + * version 2.5 + */ + 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. So if a + * filesystem wants to return write errors in close() and the file + * has cached dirty data, this is a good place to write back data + * and return any errors. Since many applications ignore close() + * errors this is not always useful. + * + * NOTE: The flush() method may be called more than once for each + * open(). This happens if more than one file descriptor refers + * to an opened file 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 always be called + * after some writes, or that if will be called at all. + * + * Changed in version 2.2 + */ + int (*flush) (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 descriptor. 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. + * + * Changed in version 2.2 + */ + int (*release) (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. + * + * Changed in version 2.2 + */ + int (*fsync) (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, closedir and fsyncdir. + * + * Introduced in version 2.3 + */ + int (*opendir) (const char *, struct fuse_file_info *); + + /** Read directory + * + * This supersedes the old getdir() interface. New applications + * should use this. + * + * 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. This + * works just like the old getdir() method. + * + * 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'. + * + * Introduced in version 2.3 + */ + int (*readdir)(struct fuse_file_info *, + fuse_dirents_t *); + + int (*readdir_plus)(struct fuse_file_info *, + fuse_dirents_t *); + + + /** Release directory + * + * Introduced in version 2.3 + */ + int (*releasedir) (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 + * + * Introduced in version 2.3 + */ + int (*fsyncdir) (int, struct fuse_file_info *); + + /** + * Initialize filesystem + * + * The return value will passed in the private_data field of + * fuse_context to all file operations and as a parameter to the + * destroy() method. + * + * Introduced in version 2.3 + * Changed in version 2.6 + */ + void *(*init) (struct fuse_conn_info *conn); + + /** + * Clean up filesystem + * + * Called on filesystem exit. + * + * Introduced in version 2.3 + */ + void (*destroy) (void *); + + /** + * 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 + * + * Introduced in version 2.5 + */ + 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. + * + * Introduced in version 2.5 + */ + int (*create) (const char *, mode_t, struct fuse_file_info *); + + /** + * Change the size of an open file + * + * This method is called instead of the truncate() method if the + * truncation was invoked from an ftruncate() system call. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the truncate() method will be + * called instead. + * + * Introduced in version 2.5 + */ + int (*ftruncate) (off_t, struct fuse_file_info *); + + /** + * Get attributes from an open file + * + * This method is called instead of the getattr() method if the + * file information is available. + * + * Currently this is only called after the create() method if that + * is implemented (see above). Later it may be called for + * invocations of fstat() too. + * + * Introduced in version 2.5 + */ + int (*fgetattr) (struct stat *, struct fuse_file_info *, fuse_timeouts_t *); + + /** + * 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. + * + * Introduced in version 2.6 + */ + int (*lock) (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. + * + * See the utimensat(2) man page for details. + * + * Introduced in version 2.6 + */ + int (*utimens)(const char *, const struct timespec tv[2]); + int (*futimens)(const struct fuse_file_info *ffi_, const struct timespec tv_[2]); + + /** + * 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 + * + * Introduced in version 2.6 + */ + 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. + * + * Introduced in version 2.8 + */ + int (*ioctl) (unsigned long cmd, + void *arg, + struct fuse_file_info *ffi, + unsigned int flags, + void *data, + uint32_t *out_bufsz); + + /** + * 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. + * + * Introduced in version 2.8 + */ + int (*poll) (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. + * + * Introduced in version 2.9 + */ + int (*write_buf) (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. + * + * Introduced in version 2.9 + */ + int (*read_buf) (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. + * + * Introduced in version 2.9 + */ + int (*flock) (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. + * + * Introduced in version 2.9.1 + */ + int (*fallocate) (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)(struct fuse_file_info *fi_in, + off_t offset_in, + struct fuse_file_info *fi_out, + off_t offset_out, + size_t size, + int flags); + }; + + /** 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; - /** Group ID of the calling process */ - gid_t gid; + /** User ID of the calling process */ + uid_t uid; - /** Thread ID of the calling process */ - pid_t pid; + /** Group ID of the calling process */ + gid_t gid; - /** Private filesystem data */ - void *private_data; + /** Thread ID of the calling process */ + pid_t pid; - /** Umask of the calling process (introduced in version 2.8) */ - mode_t umask; -}; + /** Private filesystem data */ + void *private_data; -/** - * Main function of FUSE. - * - * This is for the lazy. This is all that has to be called from the - * main() function. - * - * This function does the following: - * - parses command line options (-d -s and -h) - * - passes relevant mount options to the fuse_mount() - * - installs signal handlers for INT, HUP, TERM and PIPE - * - registers an exit handler to unmount the filesystem on program exit - * - creates a fuse handle - * - registers the operations - * - calls either the single-threaded or the multi-threaded event loop - * - * Note: this is currently implemented as a macro. - * - * @param argc the argument counter passed to the main() function - * @param argv the argument vector passed to the main() function - * @param op the file system operation - * @param user_data user data supplied in the context during the init() method - * @return 0 on success, nonzero on failure - */ -/* - int fuse_main(int argc, char *argv[], const struct fuse_operations *op, - void *user_data); -*/ -#define fuse_main(argc, argv, op, user_data) \ - fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) + /** Umask of the calling process (introduced in version 2.8) */ + mode_t umask; + }; -/* ----------------------------------------------------------- * - * More detailed API * - * ----------------------------------------------------------- */ + /** + * Main function of FUSE. + * + * This is for the lazy. This is all that has to be called from the + * main() function. + * + * This function does the following: + * - parses command line options (-d -s and -h) + * - passes relevant mount options to the fuse_mount() + * - installs signal handlers for INT, HUP, TERM and PIPE + * - registers an exit handler to unmount the filesystem on program exit + * - creates a fuse handle + * - registers the operations + * - calls either the single-threaded or the multi-threaded event loop + * + * Note: this is currently implemented as a macro. + * + * @param argc the argument counter passed to the main() function + * @param argv the argument vector passed to the main() function + * @param op the file system operation + * @param user_data user data supplied in the context during the init() method + * @return 0 on success, nonzero on failure + */ + /* + int fuse_main(int argc, char *argv[], const struct fuse_operations *op, + void *user_data); + */ +#define fuse_main(argc, argv, op, user_data) \ + fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) -/** - * Create a new FUSE filesystem. - * - * @param ch the communication channel - * @param args argument vector - * @param op the filesystem operations - * @param op_size the size of the fuse_operations structure - * @param user_data user data supplied in the context during the init() method - * @return the created FUSE handle - */ -struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, size_t op_size, - void *user_data); + /* ----------------------------------------------------------- * + * More detailed API * + * ----------------------------------------------------------- */ -/** - * Destroy the FUSE handle. - * - * The communication channel attached to the handle is also destroyed. - * - * NOTE: This function does not unmount the filesystem. If this is - * needed, call fuse_unmount() before calling this function. - * - * @param f the FUSE handle - */ -void fuse_destroy(struct fuse *f); + /** + * Create a new FUSE filesystem. + * + * @param ch the communication channel + * @param args argument vector + * @param op the filesystem operations + * @param op_size the size of the fuse_operations structure + * @param user_data user data supplied in the context during the init() method + * @return the created FUSE handle + */ + struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, + const struct fuse_operations *op, size_t op_size, + void *user_data); -/** - * FUSE event loop. - * - * Requests from the kernel are processed, and the appropriate - * operations are called. - * - * @param f the FUSE handle - * @return 0 if no error occurred, -1 otherwise - */ -int fuse_loop(struct fuse *f); + /** + * Destroy the FUSE handle. + * + * The communication channel attached to the handle is also destroyed. + * + * NOTE: This function does not unmount the filesystem. If this is + * needed, call fuse_unmount() before calling this function. + * + * @param f the FUSE handle + */ + void fuse_destroy(struct fuse *f); -/** - * Exit from event loop - * - * @param f the FUSE handle - */ -void fuse_exit(struct fuse *f); - -void fuse_config_set_entry_timeout(struct fuse *fuse_, - const double entry_timeout_); -void fuse_config_set_negative_entry_timeout(struct fuse *fuse_, - const double entry_timeout_); -void fuse_config_set_attr_timeout(struct fuse *fuse_, - const double attr_timeout_); - -int fuse_config_num_threads(const struct fuse *fuse_); -double fuse_config_get_entry_timeout(const struct fuse *fuse_); -double fuse_config_get_negative_entry_timeout(const struct fuse *fuse_); -double fuse_config_get_attr_timeout(const struct fuse *fuse_); - -/** - * FUSE event loop with multiple threads - * - * Requests from the kernel are processed, and the appropriate - * operations are called. Request are processed in parallel by - * distributing them between multiple threads. - * - * Calling this function requires the pthreads library to be linked to - * the application. - * - * @param f the FUSE handle - * @return 0 if no error occurred, -1 otherwise - */ -int fuse_loop_mt(struct fuse *f); + /** + * FUSE event loop. + * + * Requests from the kernel are processed, and the appropriate + * operations are called. + * + * @param f the FUSE handle + * @return 0 if no error occurred, -1 otherwise + */ + int fuse_loop(struct fuse *f); -/** - * Get the current context - * - * The context is only valid for the duration of a filesystem - * operation, and thus must not be stored and used later. - * - * @return the context - */ -struct fuse_context *fuse_get_context(void); + /** + * Exit from event loop + * + * @param f the FUSE handle + */ + void fuse_exit(struct fuse *f); -/** - * Get the current supplementary group IDs for the current request - * - * Similar to the getgroups(2) system call, except the return value is - * always the total number of group IDs, even if it is larger than the - * specified size. - * - * The current fuse kernel module in linux (as of 2.6.30) doesn't pass - * the group list to userspace, hence this function needs to parse - * "/proc/$TID/task/$TID/status" to get the group IDs. - * - * This feature may not be supported on all operating systems. In - * such a case this function will return -ENOSYS. - * - * @param size size of given array - * @param list array of group IDs to be filled in - * @return the total number of supplementary group IDs or -errno on failure - */ -int fuse_getgroups(int size, gid_t list[]); + int fuse_config_num_threads(const struct fuse *fuse_); -/** - * Check if the current request has already been interrupted - * - * @return 1 if the request has been interrupted, 0 otherwise - */ -int fuse_interrupted(void); + /** + * FUSE event loop with multiple threads + * + * Requests from the kernel are processed, and the appropriate + * operations are called. Request are processed in parallel by + * distributing them between multiple threads. + * + * Calling this function requires the pthreads library to be linked to + * the application. + * + * @param f the FUSE handle + * @return 0 if no error occurred, -1 otherwise + */ + int fuse_loop_mt(struct fuse *f); -/** - * Obsolete, doesn't do anything - * - * @return -EINVAL - */ -int fuse_invalidate(struct fuse *f, const char *path); + /** + * Get the current context + * + * The context is only valid for the duration of a filesystem + * operation, and thus must not be stored and used later. + * + * @return the context + */ + struct fuse_context *fuse_get_context(void); -/* Deprecated, don't use */ -int fuse_is_lib_option(const char *opt); + /** + * Check if the current request has already been interrupted + * + * @return 1 if the request has been interrupted, 0 otherwise + */ + int fuse_interrupted(void); -/** - * The real main function - * - * 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 *user_data); + /** + * Obsolete, doesn't do anything + * + * @return -EINVAL + */ + int fuse_invalidate(struct fuse *f, const char *path); -/** - * Start the cleanup thread when using option "remember". - * - * This is done automatically by fuse_loop_mt() - * @param fuse struct fuse pointer for fuse instance - * @return 0 on success and -1 on error - */ -int fuse_start_cleanup_thread(struct fuse *fuse); + /* Deprecated, don't use */ + int fuse_is_lib_option(const char *opt); -/** - * Stop the cleanup thread when using option "remember". - * - * This is done automatically by fuse_loop_mt() - * @param fuse struct fuse pointer for fuse instance - */ -void fuse_stop_cleanup_thread(struct fuse *fuse); + /** + * The real main function + * + * 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 *user_data); -/** - * Iterate over cache removing stale entries - * use in conjunction with "-oremember" - * - * NOTE: This is already done for the standard sessions - * - * @param fuse struct fuse pointer for fuse instance - * @return the number of seconds until the next cleanup - */ -int fuse_clean_cache(struct fuse *fuse); + /** + * Start the cleanup thread when using option "remember". + * + * This is done automatically by fuse_loop_mt() + * @param fuse struct fuse pointer for fuse instance + * @return 0 on success and -1 on error + */ + int fuse_start_cleanup_thread(struct fuse *fuse); -/* - * Stacking API - */ + /** + * Stop the cleanup thread when using option "remember". + * + * This is done automatically by fuse_loop_mt() + * @param fuse struct fuse pointer for fuse instance + */ + void fuse_stop_cleanup_thread(struct fuse *fuse); -/** - * Fuse filesystem object - * - * This is opaque object represents a filesystem layer - */ -struct fuse_fs; + /** + * Iterate over cache removing stale entries + * use in conjunction with "-oremember" + * + * NOTE: This is already done for the standard sessions + * + * @param fuse struct fuse pointer for fuse instance + * @return the number of seconds until the next cleanup + */ + int fuse_clean_cache(struct fuse *fuse); -/* - * These functions call the relevant filesystem operation, and return - * the result. - * - * If the operation is not defined, they return -ENOSYS, with the - * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir, - * fuse_fs_releasedir and fuse_fs_statfs, which return 0. - */ + /* + * Stacking API + */ -int fuse_fs_getattr(struct fuse_fs *fs, - const char *path, - struct stat *buf, - fuse_timeouts_t *timeout); - -int fuse_fs_fgetattr(struct fuse_fs *fs, - struct stat *buf, - struct fuse_file_info *fi, - fuse_timeouts_t *timeout); - -int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, - const char *newpath); -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_link(struct fuse_fs *fs, const char *oldpath, const char *newpath); -int fuse_fs_release(struct fuse_fs *fs, - struct fuse_file_info *fi); -int fuse_fs_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi); -int fuse_fs_read(struct fuse_fs *fs, char *buf, size_t size, - off_t off, struct fuse_file_info *fi); -int fuse_fs_read_buf(struct fuse_fs *fs, - 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 *buf, - size_t size, off_t off, struct fuse_file_info *fi); -int fuse_fs_write_buf(struct fuse_fs *fs, - struct fuse_bufvec *buf, off_t off, - struct fuse_file_info *fi); -int fuse_fs_fsync(struct fuse_fs *fs, int datasync, - struct fuse_file_info *fi); -int fuse_fs_flush(struct fuse_fs *fs, - 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); -int fuse_fs_readdir(struct fuse_fs *fs, - struct fuse_file_info *fi, - fuse_dirents_t *buf); -int fuse_fs_fsyncdir(struct fuse_fs *fs, int datasync, - struct fuse_file_info *fi); -int fuse_fs_releasedir(struct fuse_fs *fs, - struct fuse_file_info *fi); -int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, - struct fuse_file_info *fi); -int fuse_fs_lock(struct fuse_fs *fs, - struct fuse_file_info *fi, int cmd, struct flock *lock); -int fuse_fs_flock(struct fuse_fs *fs, - struct fuse_file_info *fi, int op); -int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode); -int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid); -int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size); -int fuse_fs_ftruncate(struct fuse_fs *fs, off_t size, - struct fuse_file_info *fi); -int fuse_fs_utimens(struct fuse_fs *fs, const char *path, - const struct timespec tv[2]); -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); -int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, - 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); -int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, - 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); -int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, - uint64_t *idx); -int fuse_fs_ioctl(struct fuse_fs *fs, unsigned long cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - void *data, uint32_t *out_bufsz); -int fuse_fs_poll(struct fuse_fs *fs, - struct fuse_file_info *fi, struct fuse_pollhandle *ph, - unsigned *reventsp); -int fuse_fs_fallocate(struct fuse_fs *fs, int mode, - off_t offset, off_t length, struct fuse_file_info *fi); -void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn); -void fuse_fs_destroy(struct fuse_fs *fs); - -int fuse_fs_prepare_hide(struct fuse_fs *fs, const char *path, uint64_t *fh); -int fuse_fs_free_hide(struct fuse_fs *fs, uint64_t fh); -ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, - struct fuse_file_info *fi_in, off_t off_in, - struct fuse_file_info *fi_out, off_t off_out, - size_t len, int flags); - -int fuse_notify_poll(struct fuse_pollhandle *ph); - -/** - * Create a new fuse filesystem object - * - * This is usually called from the factory of a fuse module to create - * a new instance of a filesystem. - * - * @param op the filesystem operations - * @param op_size the size of the fuse_operations structure - * @param user_data user data supplied in the context during the init() method - * @return a new filesystem object - */ -struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, - void *user_data); + /** + * Fuse filesystem object + * + * This is opaque object represents a filesystem layer + */ + struct fuse_fs; -/** - * Filesystem module - * - * Filesystem modules are registered with the FUSE_REGISTER_MODULE() - * macro. - * - * If the "-omodules=modname:..." option is present, filesystem - * objects are created and pushed onto the stack with the 'factory' - * function. - */ -struct fuse_module { - /** - * Name of filesystem - */ - const char *name; - - /** - * Factory for creating filesystem objects - * - * The function may use and remove options from 'args' that belong - * to this module. - * - * For now the 'fs' vector always contains exactly one filesystem. - * This is the filesystem which will be below the newly created - * filesystem in the stack. - * - * @param args the command line arguments - * @param fs NULL terminated filesystem object vector - * @return the new filesystem object - */ - struct fuse_fs *(*factory)(struct fuse_args *args, - struct fuse_fs *fs[]); - - struct fuse_module *next; - struct fusemod_so *so; - int ctr; -}; - -/** - * Register a filesystem module - * - * This function is used by FUSE_REGISTER_MODULE and there's usually - * no need to call it directly - */ -void fuse_register_module(struct fuse_module *mod); + /* + * These functions call the relevant filesystem operation, and return + * the result. + * + * If the operation is not defined, they return -ENOSYS, with the + * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir, + * fuse_fs_releasedir and fuse_fs_statfs, which return 0. + */ -/** - * Register filesystem module - * - * For the parameters, see description of the fields in 'struct - * fuse_module' - */ -#define FUSE_REGISTER_MODULE(name_, factory_) \ - static __attribute__((constructor)) void name_ ## _register(void) \ - { \ - static struct fuse_module mod = \ - { #name_, factory_, NULL, NULL, 0 }; \ - fuse_register_module(&mod); \ - } + int fuse_fs_getattr(struct fuse_fs *fs, + const char *path, + struct stat *buf, + fuse_timeouts_t *timeout); + + int fuse_fs_fgetattr(struct fuse_fs *fs, + struct stat *buf, + struct fuse_file_info *fi, + fuse_timeouts_t *timeout); + + int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, + const char *newpath); + 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_link(struct fuse_fs *fs, const char *oldpath, const char *newpath); + int fuse_fs_release(struct fuse_fs *fs, + struct fuse_file_info *fi); + int fuse_fs_open(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); + int fuse_fs_read(struct fuse_fs *fs, char *buf, size_t size, + off_t off, struct fuse_file_info *fi); + int fuse_fs_read_buf(struct fuse_fs *fs, + 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 *buf, + size_t size, off_t off, struct fuse_file_info *fi); + int fuse_fs_write_buf(struct fuse_fs *fs, + struct fuse_bufvec *buf, off_t off, + struct fuse_file_info *fi); + int fuse_fs_fsync(struct fuse_fs *fs, int datasync, + struct fuse_file_info *fi); + int fuse_fs_flush(struct fuse_fs *fs, + 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); + int fuse_fs_readdir(struct fuse_fs *fs, + struct fuse_file_info *fi, + fuse_dirents_t *buf); + int fuse_fs_fsyncdir(struct fuse_fs *fs, int datasync, + struct fuse_file_info *fi); + int fuse_fs_releasedir(struct fuse_fs *fs, + struct fuse_file_info *fi); + int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, + struct fuse_file_info *fi); + int fuse_fs_lock(struct fuse_fs *fs, + struct fuse_file_info *fi, int cmd, struct flock *lock); + int fuse_fs_flock(struct fuse_fs *fs, + struct fuse_file_info *fi, int op); + int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode); + int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid); + int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size); + int fuse_fs_ftruncate(struct fuse_fs *fs, off_t size, + struct fuse_file_info *fi); + int fuse_fs_utimens(struct fuse_fs *fs, const char *path, + const struct timespec tv[2]); + 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); + int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, + 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); + int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, + 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); + int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, + uint64_t *idx); + int fuse_fs_ioctl(struct fuse_fs *fs, unsigned long cmd, void *arg, + struct fuse_file_info *fi, unsigned int flags, + void *data, uint32_t *out_bufsz); + int fuse_fs_poll(struct fuse_fs *fs, + struct fuse_file_info *fi, struct fuse_pollhandle *ph, + unsigned *reventsp); + int fuse_fs_fallocate(struct fuse_fs *fs, int mode, + off_t offset, off_t length, struct fuse_file_info *fi); + void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn); + void fuse_fs_destroy(struct fuse_fs *fs); + + int fuse_fs_prepare_hide(struct fuse_fs *fs, const char *path, uint64_t *fh); + int fuse_fs_free_hide(struct fuse_fs *fs, uint64_t fh); + ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, + struct fuse_file_info *fi_in, off_t off_in, + struct fuse_file_info *fi_out, off_t off_out, + size_t len, int flags); + + int fuse_notify_poll(struct fuse_pollhandle *ph); + /** + * Create a new fuse filesystem object + * + * This is usually called from the factory of a fuse module to create + * a new instance of a filesystem. + * + * @param op the filesystem operations + * @param op_size the size of the fuse_operations structure + * @param user_data user data supplied in the context during the init() method + * @return a new filesystem object + */ + struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, + void *user_data); -/* ----------------------------------------------------------- * - * Advanced API for event handling, don't worry about this... * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Advanced API for event handling, don't worry about this... * + * ----------------------------------------------------------- */ -/* NOTE: the following functions are deprecated, and will be removed - from the 3.0 API. Use the lowlevel session functions instead */ + /* NOTE: the following functions are deprecated, and will be removed + from the 3.0 API. Use the lowlevel session functions instead */ -/** Function type used to process commands */ -typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); + /** Function type used to process commands */ + typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); -/** This is the part of fuse_main() before the event loop */ -struct fuse *fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - char **mountpoint, int *multithreaded, - void *user_data); + /** This is the part of fuse_main() before the event loop */ + struct fuse *fuse_setup(int argc, char *argv[], + const struct fuse_operations *op, size_t op_size, + char **mountpoint, int *multithreaded, + void *user_data); -/** This is the part of fuse_main() after the event loop */ -void fuse_teardown(struct fuse *fuse, char *mountpoint); + /** This is the part of fuse_main() after the event loop */ + void fuse_teardown(struct fuse *fuse, char *mountpoint); -/** Read a single command. If none are read, return NULL */ -struct fuse_cmd *fuse_read_cmd(struct fuse *f); + /** Read a single command. If none are read, return NULL */ + struct fuse_cmd *fuse_read_cmd(struct fuse *f); -/** Process a single command */ -void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd); + /** Process a single command */ + void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd); -/** Multi threaded event loop, which calls the custom command - processor function */ -int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data); + /** Multi threaded event loop, which calls the custom command + processor function */ + int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data); -/** Return the exited flag, which indicates if fuse_exit() has been - called */ -int fuse_exited(struct fuse *f); + /** Return the exited flag, which indicates if fuse_exit() has been + called */ + int fuse_exited(struct fuse *f); -/** This function is obsolete and implemented as a no-op */ -void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); + /** This function is obsolete and implemented as a no-op */ + void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); -/** Get session from fuse object */ -struct fuse_session *fuse_get_session(struct fuse *f); + /** Get session from fuse object */ + struct fuse_session *fuse_get_session(struct fuse *f); -/* ----------------------------------------------------------- * - * Compatibility stuff * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Compatibility stuff * + * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # include "fuse_compat.h" # undef fuse_main # if FUSE_USE_VERSION == 25 # define fuse_main(argc, argv, op) \ - fuse_main_real_compat25(argc, argv, op, sizeof(*(op))) + fuse_main_real_compat25(argc, argv, op, sizeof(*(op))) # define fuse_new fuse_new_compat25 # define fuse_setup fuse_setup_compat25 # define fuse_teardown fuse_teardown_compat22 # define fuse_operations fuse_operations_compat25 # elif FUSE_USE_VERSION == 22 # define fuse_main(argc, argv, op) \ - fuse_main_real_compat22(argc, argv, op, sizeof(*(op))) + fuse_main_real_compat22(argc, argv, op, sizeof(*(op))) # define fuse_new fuse_new_compat22 # define fuse_setup fuse_setup_compat22 # define fuse_teardown fuse_teardown_compat22 diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index e78b57c1..79feb44e 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -16,6 +16,7 @@ #define _FUSE_COMMON_H_ #include "fuse_opt.h" +#include "fuse_timeouts.h" #include #include @@ -40,79 +41,72 @@ extern "C" { #endif -typedef struct fuse_timeouts_s fuse_timeouts_t; -struct fuse_timeouts_s -{ - uint64_t entry; - uint64_t attr; -}; - -/** - * Information about open files - * - * Changed in version 2.5 - */ -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 - writepage */ - uint32_t writepage : 1; - - /** Can be filled in by open, to use direct I/O on this file. - Introduced in version 2.4 */ - uint32_t direct_io : 1; - - /** Can be filled in by open, to indicate, that cached file data - need not be invalidated. Introduced in version 2.4 */ - uint32_t keep_cache : 1; - - /** Indicates a flush operation. Set in flush operation, also - maybe set in highlevel lock operation and lowlevel release - operation. Introduced in version 2.6 */ - uint32_t flush : 1; - - /** Can be filled in by open, to indicate that the file is not - seekable. Introduced in version 2.8 */ - uint32_t 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(). Introduced in version - 2.9 */ - uint32_t flock_release : 1; - - /* Requests the kernel to cache entries returned by readdir */ - uint32_t cache_readdir : 1; - - uint32_t auto_cache : 1; - - /** File handle. May be filled in by filesystem in open(). - Available in all other file operations */ - uint64_t fh; - - /** Lock owner id. Available in locking operations and flush */ - uint64_t lock_owner; -}; - -/** - * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' - * - * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests - * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking - * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag - * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." - * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB - * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations - * FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device - * FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice() - * FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device - * FUSE_CAP_IOCTL_DIR: ioctl support on directories - * FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses - */ + /** + * Information about open files + * + * Changed in version 2.5 + */ + 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 + writepage */ + uint32_t writepage : 1; + + /** Can be filled in by open, to use direct I/O on this file. + Introduced in version 2.4 */ + uint32_t direct_io : 1; + + /** Can be filled in by open, to indicate, that cached file data + need not be invalidated. Introduced in version 2.4 */ + uint32_t keep_cache : 1; + + /** Indicates a flush operation. Set in flush operation, also + maybe set in highlevel lock operation and lowlevel release + operation. Introduced in version 2.6 */ + uint32_t flush : 1; + + /** Can be filled in by open, to indicate that the file is not + seekable. Introduced in version 2.8 */ + uint32_t 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(). Introduced in version + 2.9 */ + uint32_t flock_release : 1; + + /* Requests the kernel to cache entries returned by readdir */ + uint32_t cache_readdir : 1; + + uint32_t auto_cache : 1; + + /** File handle. May be filled in by filesystem in open(). + Available in all other file operations */ + uint64_t fh; + + /** Lock owner id. Available in locking operations and flush */ + uint64_t lock_owner; + }; + + /** + * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' + * + * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests + * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking + * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag + * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." + * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB + * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations + * FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device + * FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice() + * FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device + * FUSE_CAP_IOCTL_DIR: ioctl support on directories + * FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses + */ #define FUSE_CAP_ASYNC_READ (1 << 0) #define FUSE_CAP_POSIX_LOCKS (1 << 1) #define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3) @@ -133,16 +127,16 @@ fuse_file_info #define FUSE_CAP_CACHE_SYMLINKS (1 << 20) #define FUSE_CAP_MAX_PAGES (1 << 21) -/** - * Ioctl flags - * - * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine - * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed - * FUSE_IOCTL_RETRY: retry with new iovecs - * FUSE_IOCTL_DIR: is a directory - * - * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs - */ + /** + * Ioctl flags + * + * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine + * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed + * FUSE_IOCTL_RETRY: retry with new iovecs + * FUSE_IOCTL_DIR: is a directory + * + * 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) @@ -150,344 +144,344 @@ fuse_file_info #define FUSE_IOCTL_MAX_IOV 256 -/** - * Connection information, passed to the ->init() method - * - * Some of the elements are read-write, these can be changed to - * indicate the value requested by the filesystem. The requested - * 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 readahead - */ - unsigned max_readahead; - - /** - * Capability flags, that the kernel supports - */ - unsigned capable; - - /** - * Capability flags, that the filesystem wants to enable - */ - unsigned want; - - /** - * Maximum number of backgrounded requests - */ - unsigned max_background; - - /** - * Kernel congestion threshold parameter - */ - unsigned congestion_threshold; - - /** - * Max pages - */ - uint16_t max_pages; - - /** - * For future use. - */ - unsigned reserved[22]; -}; - -struct fuse_session; -struct fuse_chan; -struct fuse_pollhandle; - -/** - * Create a FUSE mountpoint - * - * Returns a control file descriptor suitable for passing to - * fuse_new() - * - * @param mountpoint the mount point path - * @param args argument vector - * @return the communication channel on success, NULL on failure - */ -struct fuse_chan *fuse_mount(const char *mountpoint, - struct fuse_args *args); - -/** - * Umount a FUSE mountpoint - * - * @param mountpoint the mount point path - * @param ch the communication channel - */ -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); - -/** - * Parse common options - * - * The following options are parsed: - * - * '-f' foreground - * '-d' '-odebug' foreground, but keep the debug option - * '-s' single threaded - * '-h' '--help' help - * '-ho' help without header - * '-ofsname=..' file system name, if not present, then set to the program - * name - * - * All parameters may be NULL - * - * @param args argument vector - * @param mountpoint the returned mountpoint, should be freed after use - * @param multithreaded set to 1 unless the '-s' option is present - * @param foreground set to 1 if one of the relevant options is present - * @return 0 on success, -1 on failure - */ -int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground); - -/** - * Go into the background - * - * @param foreground if true, stay in the foreground - * @return 0 on success, -1 on failure - */ -int fuse_daemonize(int foreground); - -/** - * Get the version of the library - * - * @return the version - */ -int fuse_version(void); - -/** - * Destroy poll handle - * - * @param ph the poll handle - */ -void fuse_pollhandle_destroy(struct fuse_pollhandle *ph); - -/* ----------------------------------------------------------- * - * 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 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), -}; - -/** - * Single data buffer - * - * Generic data buffer for I/O, extended attributes, etc... Data may - * 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; -}; - -/** - * Data buffer vector - * - * An array of data buffers, each containing a memory pointer or a - * file descriptor. - * - * 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]; -}; - -/* 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, \ - } } \ - } ) - -/** - * Get total size of data in a fuse buffer vector - * - * @param bufv buffer vector - * @return size of data - */ -size_t fuse_buf_size(const struct fuse_bufvec *bufv); - -/** - * Copy data from one buffer vector to another - * - * @param dst destination buffer vector - * @param src source buffer vector - * @param flags flags controlling the copy - * @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); - -/* ----------------------------------------------------------- * - * 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 - * process until fuse_remove_signal_handlers() is called. - * - * @param se the session to exit - * @return 0 on success, -1 on failure - */ -int fuse_set_signal_handlers(struct fuse_session *se); - -/** - * Restore default signal handlers - * - * Resets global session. After this fuse_set_signal_handlers() may - * be called again. - * - * @param se the same session as given in fuse_set_signal_handlers() - */ -void fuse_remove_signal_handlers(struct fuse_session *se); - -/* ----------------------------------------------------------- * - * Compatibility stuff * - * ----------------------------------------------------------- */ + /** + * Connection information, passed to the ->init() method + * + * Some of the elements are read-write, these can be changed to + * indicate the value requested by the filesystem. The requested + * 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 readahead + */ + unsigned max_readahead; + + /** + * Capability flags, that the kernel supports + */ + unsigned capable; + + /** + * Capability flags, that the filesystem wants to enable + */ + unsigned want; + + /** + * Maximum number of backgrounded requests + */ + unsigned max_background; + + /** + * Kernel congestion threshold parameter + */ + unsigned congestion_threshold; + + /** + * Max pages + */ + uint16_t max_pages; + + /** + * For future use. + */ + unsigned reserved[22]; + }; + + struct fuse_session; + struct fuse_chan; + struct fuse_pollhandle; + + /** + * Create a FUSE mountpoint + * + * Returns a control file descriptor suitable for passing to + * fuse_new() + * + * @param mountpoint the mount point path + * @param args argument vector + * @return the communication channel on success, NULL on failure + */ + struct fuse_chan *fuse_mount(const char *mountpoint, + struct fuse_args *args); + + /** + * Umount a FUSE mountpoint + * + * @param mountpoint the mount point path + * @param ch the communication channel + */ + void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); + + /** + * Parse common options + * + * The following options are parsed: + * + * '-f' foreground + * '-d' '-odebug' foreground, but keep the debug option + * '-s' single threaded + * '-h' '--help' help + * '-ho' help without header + * '-ofsname=..' file system name, if not present, then set to the program + * name + * + * All parameters may be NULL + * + * @param args argument vector + * @param mountpoint the returned mountpoint, should be freed after use + * @param multithreaded set to 1 unless the '-s' option is present + * @param foreground set to 1 if one of the relevant options is present + * @return 0 on success, -1 on failure + */ + int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, + int *multithreaded, int *foreground); + + /** + * Go into the background + * + * @param foreground if true, stay in the foreground + * @return 0 on success, -1 on failure + */ + int fuse_daemonize(int foreground); + + /** + * Get the version of the library + * + * @return the version + */ + int fuse_version(void); + + /** + * Destroy poll handle + * + * @param ph the poll handle + */ + void fuse_pollhandle_destroy(struct fuse_pollhandle *ph); + + /* ----------------------------------------------------------- * + * 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 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), + }; + + /** + * Single data buffer + * + * Generic data buffer for I/O, extended attributes, etc... Data may + * 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; + }; + + /** + * Data buffer vector + * + * An array of data buffers, each containing a memory pointer or a + * file descriptor. + * + * 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]; + }; + + /* 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, \ + } } \ + } ) + + /** + * Get total size of data in a fuse buffer vector + * + * @param bufv buffer vector + * @return size of data + */ + size_t fuse_buf_size(const struct fuse_bufvec *bufv); + + /** + * Copy data from one buffer vector to another + * + * @param dst destination buffer vector + * @param src source buffer vector + * @param flags flags controlling the copy + * @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); + + /* ----------------------------------------------------------- * + * 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 + * process until fuse_remove_signal_handlers() is called. + * + * @param se the session to exit + * @return 0 on success, -1 on failure + */ + int fuse_set_signal_handlers(struct fuse_session *se); + + /** + * Restore default signal handlers + * + * Resets global session. After this fuse_set_signal_handlers() may + * be called again. + * + * @param se the same session as given in fuse_set_signal_handlers() + */ + void fuse_remove_signal_handlers(struct fuse_session *se); + + /* ----------------------------------------------------------- * + * Compatibility stuff * + * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # ifdef __FreeBSD__ diff --git a/libfuse/include/fuse_common_compat.h b/libfuse/include/fuse_common_compat.h index 34440ff7..dea34468 100644 --- a/libfuse/include/fuse_common_compat.h +++ b/libfuse/include/fuse_common_compat.h @@ -9,12 +9,13 @@ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ -struct fuse_file_info_compat { - int flags; - unsigned long fh; - int writepage; - unsigned int direct_io : 1; - unsigned int keep_cache : 1; +struct fuse_file_info_compat +{ + int flags; + unsigned long fh; + int writepage; + unsigned int direct_io : 1; + unsigned int keep_cache : 1; }; int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args); diff --git a/libfuse/include/fuse_compat.h b/libfuse/include/fuse_compat.h index 509f6896..a2147a62 100644 --- a/libfuse/include/fuse_compat.h +++ b/libfuse/include/fuse_compat.h @@ -9,44 +9,45 @@ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ -struct fuse_operations_compat25 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info *); - int (*read) (const char *, char *, size_t, off_t, - struct fuse_file_info *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info *); - int (*statfs) (const char *, struct statvfs *); - int (*flush) (const char *, struct fuse_file_info *); - int (*release) (const char *, struct fuse_file_info *); - int (*fsync) (const char *, int, struct fuse_file_info *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info *); - int (*readdir) (const char *, void *, off_t, - struct fuse_file_info *); - int (*releasedir) (const char *, struct fuse_file_info *); - int (*fsyncdir) (const char *, int, struct fuse_file_info *); - void *(*init) (void); - void (*destroy) (void *); - int (*access) (const char *, int); - int (*create) (const char *, mode_t, struct fuse_file_info *); - int (*ftruncate) (const char *, off_t, struct fuse_file_info *); - int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); +struct fuse_operations_compat25 +{ + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, struct fuse_file_info *); + int (*read) (const char *, char *, size_t, off_t, + struct fuse_file_info *); + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info *); + int (*statfs) (const char *, struct statvfs *); + int (*flush) (const char *, struct fuse_file_info *); + int (*release) (const char *, struct fuse_file_info *); + int (*fsync) (const char *, int, struct fuse_file_info *); + int (*setxattr) (const char *, const char *, const char *, size_t, int); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); + int (*opendir) (const char *, struct fuse_file_info *); + int (*readdir) (const char *, void *, off_t, + struct fuse_file_info *); + int (*releasedir) (const char *, struct fuse_file_info *); + int (*fsyncdir) (const char *, int, struct fuse_file_info *); + void *(*init) (void); + void (*destroy) (void *); + int (*access) (const char *, int); + int (*create) (const char *, mode_t, struct fuse_file_info *); + int (*ftruncate) (const char *, off_t, struct fuse_file_info *); + int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); }; struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, @@ -68,39 +69,39 @@ void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint); #include struct fuse_operations_compat22 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info_compat *); - int (*read) (const char *, char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *, struct fuse_file_info_compat *); - int (*release) (const char *, struct fuse_file_info_compat *); - int (*fsync) (const char *, int, struct fuse_file_info_compat *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info_compat *); - int (*readdir) (const char *, void *, off_t, - struct fuse_file_info_compat *); - int (*releasedir) (const char *, struct fuse_file_info_compat *); - int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *); - void *(*init) (void); - void (*destroy) (void *); + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, struct fuse_file_info_compat *); + int (*read) (const char *, char *, size_t, off_t, + struct fuse_file_info_compat *); + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info_compat *); + int (*statfs) (const char *, struct statfs *); + int (*flush) (const char *, struct fuse_file_info_compat *); + int (*release) (const char *, struct fuse_file_info_compat *); + int (*fsync) (const char *, int, struct fuse_file_info_compat *); + int (*setxattr) (const char *, const char *, const char *, size_t, int); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); + int (*opendir) (const char *, struct fuse_file_info_compat *); + int (*readdir) (const char *, void *, off_t, + struct fuse_file_info_compat *); + int (*releasedir) (const char *, struct fuse_file_info_compat *); + int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *); + void *(*init) (void); + void (*destroy) (void *); }; struct fuse *fuse_new_compat22(int fd, const char *opts, @@ -117,31 +118,31 @@ int fuse_main_real_compat22(int argc, char *argv[], size_t op_size); struct fuse_operations_compat2 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); - int (*setxattr) (const char *, const char *, const char *, + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, int); + int (*read) (const char *, char *, size_t, off_t); + int (*write) (const char *, const char *, size_t, off_t); + int (*statfs) (const char *, struct statfs *); + int (*flush) (const char *); + int (*release) (const char *, int); + int (*fsync) (const char *, int); + int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); }; int fuse_main_compat2(int argc, char *argv[], @@ -155,34 +156,34 @@ struct fuse *fuse_setup_compat2(int argc, char *argv[], char **mountpoint, int *multithreaded, int *fd); struct fuse_statfs_compat1 { - long block_size; - long blocks; - long blocks_free; - long files; - long files_free; - long namelen; + long block_size; + long blocks; + long blocks_free; + long files; + long files_free; + long namelen; }; struct fuse_operations_compat1 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (struct fuse_statfs_compat1 *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, int); + int (*read) (const char *, char *, size_t, off_t); + int (*write) (const char *, const char *, size_t, off_t); + int (*statfs) (struct fuse_statfs_compat1 *); + int (*release) (const char *, int); + int (*fsync) (const char *, int); }; #define FUSE_DEBUG_COMPAT1 (1 << 1) diff --git a/libfuse/include/fuse_dirents.h b/libfuse/include/fuse_dirents.h index b26bc12d..92920141 100644 --- a/libfuse/include/fuse_dirents.h +++ b/libfuse/include/fuse_dirents.h @@ -18,9 +18,9 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif +#include "extern_c.h" + +EXTERN_C_BEGIN #include "kvec.h" #include "fuse_dirent.h" @@ -36,11 +36,11 @@ extern "C" { #include enum fuse_dirents_type_e - { - UNSET = 0, - NORMAL, - PLUS - }; +{ + UNSET = 0, + NORMAL, + PLUS +}; typedef enum fuse_dirents_type_e fuse_dirents_type_t; typedef struct fuse_dirents_s fuse_dirents_t; @@ -79,6 +79,4 @@ void *fuse_dirents_find(fuse_dirents_t *d, int fuse_dirents_convert_plus2normal(fuse_dirents_t *d); -#ifdef __cplusplus -} -#endif +EXTERN_C_END diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index ff4b1c1d..8054b149 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -37,1800 +37,1806 @@ extern "C" { #endif -/* ----------------------------------------------------------- * - * Miscellaneous definitions * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Miscellaneous definitions * + * ----------------------------------------------------------- */ -/** The node ID of the root inode */ + /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 -/** Inode number type */ -typedef uint64_t fuse_ino_t; + /** Inode number type */ + typedef uint64_t fuse_ino_t; -/** Request pointer type */ -typedef struct fuse_req *fuse_req_t; + /** Request pointer type */ + typedef struct fuse_req *fuse_req_t; -/** - * Session - * - * This provides hooks for processing requests, and exiting - */ -struct fuse_session; + /** + * Session + * + * This provides hooks for processing requests, and exiting + */ + struct fuse_session; -/** - * Channel - * - * A communication channel, providing hooks for sending and receiving - * messages - */ -struct fuse_chan; - -/** 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. - * - * The generation must be non-zero, otherwise FUSE will treat - * it as an error. - * - */ - 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; - - fuse_timeouts_t timeout; -}; - -/** Additional context associated with requests */ -struct fuse_ctx { - /** User ID of the calling process */ - uid_t uid; - - /** Group ID of the calling process */ - gid_t gid; - - /** Thread ID of the calling process */ - pid_t pid; - - /** Umask of the calling process (introduced in version 2.8) */ - mode_t umask; -}; - -struct fuse_forget_data { - fuse_ino_t ino; - uint64_t nlookup; -}; - -/* ----------------------------------------------------------- * - * Request methods and replies * - * ----------------------------------------------------------- */ - -/** - * Low level filesystem operations - * - * Most of the methods (with the exception of init and destroy) - * receive a request handle (fuse_req_t) as their first argument. - * This handle must be passed to one of the specified reply functions. - * - * This may be done inside the method invocation, or after the call - * has returned. The request handle is valid until one of the reply - * functions is called. - * - * Other pointer arguments (name, fuse_file_info, etc) are not valid - * after the call has returned, so if they are needed later, their - * contents have to be copied. - * - * The filesystem sometimes needs to handle a return value of -ENOENT - * from the reply function, which means, that the request was - * interrupted, and the reply discarded. For example if - * fuse_reply_open() return -ENOENT means, that the release method for - * this file will not be called. - */ -struct fuse_lowlevel_ops { - /** - * Initialize filesystem - * - * Called before any other filesystem method - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_new() - */ - void (*init) (void *userdata, struct fuse_conn_info *conn); - - /** - * Clean up filesystem - * - * Called on filesystem exit - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_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, remdir 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 - * - * 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. - * - * 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 - * - * Changed in version 2.5: - * file information filled in for ftruncate - */ - 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). - * - * 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); - - /** - * 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 (with the exception of O_CREAT, O_EXCL, O_NOCTTY and - * O_TRUNC) are available in fi->flags. - * - * 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 for more details. - * - * 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. - * - * 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. - * - * If the filesystem supports file locking operations (setlk, - * getlk) it should remove all locks belonging to 'fi->owner'. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - 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. - * - * 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. - * - * 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). - * - * Filesystem may also implement stateless directory I/O and not - * store anything in fi->fh, though that makes it impossible to - * implement standard conforming directory stream operations in - * case the contents of the directory can change between opendir - * and releasedir. - * - * 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. - * - * 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 *llffi); - - void (*readdir_plus)(fuse_req_t req, fuse_ino_t ino, - size_t size, off_t off, - struct fuse_file_info *ffi); - - /** - * Release an open directory - * - * For every opendir call there will be exactly one releasedir - * call. - * - * 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. - * - * 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 - * - * 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. - * - * 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. - * - * 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 - * - * 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() 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 - * - * Introduced in version 2.5 - * - * 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. - * - * Open flags (with the exception of O_NOCTTY) are available in - * fi->flags. - * - * 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). - * - * 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 for more details. - * - * 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. - * - * Introduced in version 2.5 - * - * 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 - * - * Introduced in version 2.6 - * - * 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. - * - * Introduced in version 2.6 - * - * 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 - * - * Introduced in version 2.6 - * - * 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. - * - * Introduced in version 2.8 - * - * 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 - */ - void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned long cmd, void *arg, - struct fuse_file_info *fi, unsigned flags, - const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz); - - /** - * Poll for IO readiness - * - * Introduced in version 2.8 - * - * Note: If ph is non-NULL, the client should notify - * when IO readiness events occur by calling - * fuse_lowelevel_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. - * - * 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]). - * - * Introduced in version 2.9 - * - * 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 - * - * Introduced in version 2.9 - * - * 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. - * - * Introduced in version 2.9 - * - * 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. - * - * Introduced in version 2.9 - * - * 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. - * - * Introduced in version 2.9 - * - * 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, + /** + * Channel + * + * A communication channel, providing hooks for sending and receiving + * messages + */ + struct fuse_chan; + + /** 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. + * + * The generation must be non-zero, otherwise FUSE will treat + * it as an error. + * + */ + 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; + + fuse_timeouts_t timeout; + }; + + /** Additional context associated with requests */ + struct fuse_ctx + { + /** User ID of the calling process */ + uid_t uid; + + /** Group ID of the calling process */ + gid_t gid; + + /** Thread ID of the calling process */ + pid_t pid; + + /** Umask of the calling process (introduced in version 2.8) */ + mode_t umask; + }; + + struct fuse_forget_data + { + fuse_ino_t ino; + uint64_t nlookup; + }; + + /* ----------------------------------------------------------- * + * Request methods and replies * + * ----------------------------------------------------------- */ + + /** + * Low level filesystem operations + * + * Most of the methods (with the exception of init and destroy) + * receive a request handle (fuse_req_t) as their first argument. + * This handle must be passed to one of the specified reply functions. + * + * This may be done inside the method invocation, or after the call + * has returned. The request handle is valid until one of the reply + * functions is called. + * + * Other pointer arguments (name, fuse_file_info, etc) are not valid + * after the call has returned, so if they are needed later, their + * contents have to be copied. + * + * The filesystem sometimes needs to handle a return value of -ENOENT + * from the reply function, which means, that the request was + * interrupted, and the reply discarded. For example if + * fuse_reply_open() return -ENOENT means, that the release method for + * this file will not be called. + */ + struct fuse_lowlevel_ops + { + /** + * Initialize filesystem + * + * Called before any other filesystem method + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ + void (*init) (void *userdata, struct fuse_conn_info *conn); + + /** + * Clean up filesystem + * + * Called on filesystem exit + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_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, remdir 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 + * + * 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. + * + * 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 + * + * Changed in version 2.5: + * file information filled in for ftruncate + */ + 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). + * + * 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); + + /** + * 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 (with the exception of O_CREAT, O_EXCL, O_NOCTTY and + * O_TRUNC) are available in fi->flags. + * + * 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 for more details. + * + * 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. + * + * 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. + * + * If the filesystem supports file locking operations (setlk, + * getlk) it should remove all locks belonging to 'fi->owner'. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + 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. + * + * 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. + * + * 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). + * + * Filesystem may also implement stateless directory I/O and not + * store anything in fi->fh, though that makes it impossible to + * implement standard conforming directory stream operations in + * case the contents of the directory can change between opendir + * and releasedir. + * + * 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. + * + * 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 *llffi); + + void (*readdir_plus)(fuse_req_t req, fuse_ino_t ino, + size_t size, off_t off, + struct fuse_file_info *ffi); + + /** + * Release an open directory + * + * For every opendir call there will be exactly one releasedir + * call. + * + * 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. + * + * 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 + * + * 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. + * + * 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. + * + * 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 + * + * 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() 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 + * + * Introduced in version 2.5 + * + * 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. + * + * Open flags (with the exception of O_NOCTTY) are available in + * fi->flags. + * + * 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). + * + * 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 for more details. + * + * 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. + * + * Introduced in version 2.5 + * + * 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 + * + * Introduced in version 2.6 + * + * 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. + * + * Introduced in version 2.6 + * + * 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 + * + * Introduced in version 2.6 + * + * 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. + * + * Introduced in version 2.8 + * + * 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 + */ + void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned long cmd, void *arg, + struct fuse_file_info *fi, unsigned flags, + const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz); + + /** + * Poll for IO readiness + * + * Introduced in version 2.8 + * + * Note: If ph is non-NULL, the client should notify + * when IO readiness events occur by calling + * fuse_lowelevel_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. + * + * 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]). + * + * Introduced in version 2.9 + * + * 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 + * + * Introduced in version 2.9 + * + * 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. + * + * Introduced in version 2.9 + * + * 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. + * + * Introduced in version 2.9 + * + * 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. + * + * Introduced in version 2.9 + * + * 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); + /** + * 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 of 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 of 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); + }; + /** - * 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 + * Reply with an error code or success + * + * Possible requests: + * all except forget + * + * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, + * removexattr and setlk may send a zero code * * @param req request handle - * @param ino_in the inode number of 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 of 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 + * @param err the positive error value, or zero for success + * @return zero for success, -errno for failure to send reply */ - 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); -}; - -/** - * Reply with an error code or success - * - * Possible requests: - * all except forget - * - * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, - * removexattr and setlk may send a zero code - * - * @param req request handle - * @param err the positive error value, or zero for success - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_err(fuse_req_t req, int err); + int fuse_reply_err(fuse_req_t req, int err); -/** - * Don't send reply - * - * Possible requests: - * forget - * - * @param req request handle - */ -void fuse_reply_none(fuse_req_t req); + /** + * Don't send reply + * + * Possible requests: + * forget + * + * @param req request handle + */ + void fuse_reply_none(fuse_req_t req); -/** - * Reply with a directory entry - * - * Possible requests: - * lookup, mknod, mkdir, symlink, link - * - * Side effects: - * increments the lookup count on success - * - * @param req request handle - * @param e the entry parameters - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); + /** + * Reply with a directory entry + * + * Possible requests: + * lookup, mknod, mkdir, symlink, link + * + * Side effects: + * increments the lookup count on success + * + * @param req request handle + * @param e the entry parameters + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); -/** - * Reply with a directory entry and open parameters - * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache - * - * Possible requests: - * create - * - * Side effects: - * increments the lookup count on success - * - * @param req request handle - * @param e the entry parameters - * @param fi file information - * @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); + /** + * Reply with a directory entry and open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * create + * + * Side effects: + * increments the lookup count on success + * + * @param req request handle + * @param e the entry parameters + * @param fi file information + * @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); -/** - * Reply with attributes - * - * Possible requests: - * getattr, setattr - * - * @param req request handle - * @param attr 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, - const uint64_t timeout); + /** + * Reply with attributes + * + * Possible requests: + * getattr, setattr + * + * @param req request handle + * @param attr 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, + const uint64_t timeout); -/** - * Reply with the contents of a symbolic link - * - * Possible requests: - * readlink - * - * @param req request handle - * @param link symbolic link contents - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_readlink(fuse_req_t req, const char *link); + /** + * Reply with the contents of a symbolic link + * + * Possible requests: + * readlink + * + * @param req request handle + * @param link symbolic link contents + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_readlink(fuse_req_t req, const char *link); -/** - * Reply with open parameters - * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache - * - * Possible requests: - * open, opendir - * - * @param req request handle - * @param fi file information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); + /** + * Reply with open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * open, opendir + * + * @param req request handle + * @param fi file information + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); -/** - * Reply with number of bytes written - * - * Possible requests: - * write - * - * @param req request handle - * @param count the number of bytes written - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_write(fuse_req_t req, size_t count); + /** + * Reply with number of bytes written + * + * Possible requests: + * write + * + * @param req request handle + * @param count the number of bytes written + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_write(fuse_req_t req, size_t count); -/** - * Reply with data - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param buf buffer containing data - * @param size the size of data in bytes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); + /** + * Reply with data + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param buf buffer containing data + * @param size the size of data in bytes + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); -/** - * Reply with data copied/moved from buffer(s) - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param bufv buffer vector - * @param flags flags controlling the copy - * @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); + /** + * Reply with data copied/moved from buffer(s) + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param bufv buffer vector + * @param flags flags controlling the copy + * @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); -/** - * Reply with data vector - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param iov the vector containing the data - * @param count the size of vector - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); + /** + * Reply with data vector + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param iov the vector containing the data + * @param count the size of vector + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); -/** - * Reply with filesystem statistics - * - * Possible requests: - * statfs - * - * @param req request handle - * @param stbuf filesystem statistics - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); + /** + * Reply with filesystem statistics + * + * Possible requests: + * statfs + * + * @param req request handle + * @param stbuf filesystem statistics + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); -/** - * Reply with needed buffer size - * - * Possible requests: - * getxattr, listxattr - * - * @param req request handle - * @param count the buffer size needed in bytes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_xattr(fuse_req_t req, size_t count); + /** + * Reply with needed buffer size + * + * Possible requests: + * getxattr, listxattr + * + * @param req request handle + * @param count the buffer size needed in bytes + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_xattr(fuse_req_t req, size_t count); -/** - * Reply with file lock information - * - * Possible requests: - * getlk - * - * @param req request handle - * @param lock the lock information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_lock(fuse_req_t req, const struct flock *lock); + /** + * Reply with file lock information + * + * Possible requests: + * getlk + * + * @param req request handle + * @param lock the lock information + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_lock(fuse_req_t req, const struct flock *lock); -/** - * Reply with block index - * - * Possible requests: - * bmap - * - * @param req request handle - * @param idx block index within device - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_bmap(fuse_req_t req, uint64_t idx); + /** + * Reply with block index + * + * Possible requests: + * bmap + * + * @param req request handle + * @param idx block index within device + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_bmap(fuse_req_t req, uint64_t idx); -/** - * Reply to ask for data fetch and output buffer preparation. ioctl - * will be retried with the specified input data fetched and output - * buffer prepared. - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param in_iov iovec specifying data to fetch from the caller - * @param in_count number of entries in in_iov - * @param out_iov iovec specifying addresses to write output to - * @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); + /** + * Reply to ask for data fetch and output buffer preparation. ioctl + * will be retried with the specified input data fetched and output + * buffer prepared. + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param in_iov iovec specifying data to fetch from the caller + * @param in_count number of entries in in_iov + * @param out_iov iovec specifying addresses to write output to + * @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); -/** - * Reply to finish ioctl - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param result result to be passed to the caller - * @param buf buffer containing output data - * @param size length of output data - */ -int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size); + /** + * Reply to finish ioctl + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param result result to be passed to the caller + * @param buf buffer containing output data + * @param size length of output data + */ + int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size); -/** - * Reply to finish ioctl with iov buffer - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param result result to be passed to the caller - * @param iov the vector containing the data - * @param count the size of vector - */ -int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, - int count); + /** + * Reply to finish ioctl with iov buffer + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param result result to be passed to the caller + * @param iov the vector containing the data + * @param count the size of vector + */ + int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, + int count); -/** - * Reply with poll result event mask - * - * @param req request handle - * @param revents poll result event mask - */ -int fuse_reply_poll(fuse_req_t req, unsigned revents); + /** + * Reply with poll result event mask + * + * @param req request handle + * @param revents poll result event mask + */ + int fuse_reply_poll(fuse_req_t req, unsigned revents); -/* ----------------------------------------------------------- * - * Notification * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Notification * + * ----------------------------------------------------------- */ -/** - * Notify IO readiness event - * - * For more information, please read comment for poll operation. - * - * @param ph poll handle to notify IO readiness event for - */ -int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); + /** + * Notify IO readiness event + * + * For more information, please read comment for poll operation. + * + * @param ph poll handle to notify IO readiness event for + */ + int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); -/** - * Notify to invalidate cache for an inode - * - * @param ch the channel through which to send the invalidation - * @param ino the inode number - * @param off the offset in the inode where to start invalidating - * or negative to invalidate attributes only - * @param len the amount of cache to invalidate or 0 for all - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, - off_t off, off_t len); + /** + * Notify to invalidate cache for an inode + * + * @param ch the channel through which to send the invalidation + * @param ino the inode number + * @param off the offset in the inode where to start invalidating + * or negative to invalidate attributes only + * @param len the amount of cache to invalidate or 0 for all + * @return zero for success, -errno for failure + */ + int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, + off_t off, off_t len); -/** - * Notify to invalidate parent attributes and the dentry matching - * parent/name - * - * To avoid a deadlock don't call this function from a filesystem operation and - * don't call it with a lock held that can also be held by a filesystem - * operation. - * - * @param ch the channel through which to send the invalidation - * @param parent inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, - const char *name, size_t namelen); + /** + * Notify to invalidate parent attributes and the dentry matching + * parent/name + * + * To avoid a deadlock don't call this function from a filesystem operation and + * don't call it with a lock held that can also be held by a filesystem + * operation. + * + * @param ch the channel through which to send the invalidation + * @param parent inode number + * @param name file name + * @param namelen strlen() of file name + * @return zero for success, -errno for failure + */ + int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, + const char *name, size_t namelen); -/** - * Notify to invalidate parent attributes and delete the dentry matching - * parent/name if the dentry's inode number matches child (otherwise it - * will invalidate the matching dentry). - * - * To avoid a deadlock don't call this function from a filesystem operation and - * don't call it with a lock held that can also be held by a filesystem - * operation. - * - * @param ch the channel through which to send the notification - * @param parent inode number - * @param child inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_delete(struct fuse_chan *ch, - fuse_ino_t parent, fuse_ino_t child, - const char *name, size_t namelen); + /** + * Notify to invalidate parent attributes and delete the dentry matching + * parent/name if the dentry's inode number matches child (otherwise it + * will invalidate the matching dentry). + * + * To avoid a deadlock don't call this function from a filesystem operation and + * don't call it with a lock held that can also be held by a filesystem + * operation. + * + * @param ch the channel through which to send the notification + * @param parent inode number + * @param child inode number + * @param name file name + * @param namelen strlen() of file name + * @return zero for success, -errno for failure + */ + int fuse_lowlevel_notify_delete(struct fuse_chan *ch, + fuse_ino_t parent, fuse_ino_t child, + const char *name, size_t namelen); -/** - * Store data to the kernel buffers - * - * Synchronously store data in the kernel buffers belonging to the - * given inode. The stored data is marked up-to-date (no read will be - * performed against it, unless it's invalidated or evicted from the - * cache). - * - * If the stored data overflows the current file size, then the size - * is extended, similarly to a write(2) on the filesystem. - * - * If this function returns an error, then the store wasn't fully - * completed, but it may have been partially completed. - * - * @param ch the channel through which to send the invalidation - * @param ino the inode number - * @param offset the starting offset into the file to store to - * @param bufv buffer vector - * @param flags flags controlling the copy - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, - off_t offset, struct fuse_bufvec *bufv, - enum fuse_buf_copy_flags flags); -/** - * Retrieve data from the kernel buffers - * - * Retrieve data in the kernel buffers belonging to the given inode. - * If successful then the retrieve_reply() method will be called with - * the returned data. - * - * Only present pages are returned in the retrieve reply. Retrieving - * stops when it finds a non-present page and only data prior to that is - * returned. - * - * If this function returns an error, then the retrieve will not be - * completed and no reply will be sent. - * - * This function doesn't change the dirty state of pages in the kernel - * buffer. For dirty pages the write() method will be called - * regardless of having been retrieved previously. - * - * @param ch the channel through which to send the invalidation - * @param ino the inode number - * @param size the number of bytes to retrieve - * @param offset the starting offset into the file to retrieve from - * @param cookie user data to supply to the reply callback - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, - size_t size, off_t offset, void *cookie); + /** + * Store data to the kernel buffers + * + * Synchronously store data in the kernel buffers belonging to the + * given inode. The stored data is marked up-to-date (no read will be + * performed against it, unless it's invalidated or evicted from the + * cache). + * + * If the stored data overflows the current file size, then the size + * is extended, similarly to a write(2) on the filesystem. + * + * If this function returns an error, then the store wasn't fully + * completed, but it may have been partially completed. + * + * @param ch the channel through which to send the invalidation + * @param ino the inode number + * @param offset the starting offset into the file to store to + * @param bufv buffer vector + * @param flags flags controlling the copy + * @return zero for success, -errno for failure + */ + int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, + off_t offset, struct fuse_bufvec *bufv, + enum fuse_buf_copy_flags flags); + /** + * Retrieve data from the kernel buffers + * + * Retrieve data in the kernel buffers belonging to the given inode. + * If successful then the retrieve_reply() method will be called with + * the returned data. + * + * Only present pages are returned in the retrieve reply. Retrieving + * stops when it finds a non-present page and only data prior to that is + * returned. + * + * If this function returns an error, then the retrieve will not be + * completed and no reply will be sent. + * + * This function doesn't change the dirty state of pages in the kernel + * buffer. For dirty pages the write() method will be called + * regardless of having been retrieved previously. + * + * @param ch the channel through which to send the invalidation + * @param ino the inode number + * @param size the number of bytes to retrieve + * @param offset the starting offset into the file to retrieve from + * @param cookie user data to supply to the reply callback + * @return zero for success, -errno for failure + */ + int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, + size_t size, off_t offset, void *cookie); -/* ----------------------------------------------------------- * - * Utility functions * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Utility functions * + * ----------------------------------------------------------- */ -/** - * Get the userdata from the request - * - * @param req request handle - * @return the user data passed to fuse_lowlevel_new() - */ -void *fuse_req_userdata(fuse_req_t req); + /** + * Get the userdata from the request + * + * @param req request handle + * @return the user data passed to fuse_lowlevel_new() + */ + void *fuse_req_userdata(fuse_req_t req); -/** - * Get the context from the request - * - * The pointer returned by this function will only be valid for the - * request's lifetime - * - * @param req request handle - * @return the context structure - */ -const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); + /** + * Get the context from the request + * + * The pointer returned by this function will only be valid for the + * request's lifetime + * + * @param req request handle + * @return the context structure + */ + const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); -/** - * Get the current supplementary group IDs for the specified request - * - * Similar to the getgroups(2) system call, except the return value is - * always the total number of group IDs, even if it is larger than the - * specified size. - * - * The current fuse kernel module in linux (as of 2.6.30) doesn't pass - * the group list to userspace, hence this function needs to parse - * "/proc/$TID/task/$TID/status" to get the group IDs. - * - * This feature may not be supported on all operating systems. In - * such a case this function will return -ENOSYS. - * - * @param req request handle - * @param size size of given array - * @param list array of group IDs to be filled in - * @return the total number of supplementary group IDs or -errno on failure - */ -int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]); + /** + * Get the current supplementary group IDs for the specified request + * + * Similar to the getgroups(2) system call, except the return value is + * always the total number of group IDs, even if it is larger than the + * specified size. + * + * The current fuse kernel module in linux (as of 2.6.30) doesn't pass + * the group list to userspace, hence this function needs to parse + * "/proc/$TID/task/$TID/status" to get the group IDs. + * + * This feature may not be supported on all operating systems. In + * such a case this function will return -ENOSYS. + * + * @param req request handle + * @param size size of given array + * @param list array of group IDs to be filled in + * @return the total number of supplementary group IDs or -errno on failure + */ + int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]); -/** - * Callback function for an interrupt - * - * @param req interrupted request - * @param data user data - */ -typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); + /** + * Callback function for an interrupt + * + * @param req interrupted request + * @param data user data + */ + typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); -/** - * Register/unregister callback for an interrupt - * - * If an interrupt has already happened, then the callback function is - * called from within this function, hence it's not possible for - * interrupts to be lost. - * - * @param req request handle - * @param func the callback function or NULL for unregister - * @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); + /** + * Register/unregister callback for an interrupt + * + * If an interrupt has already happened, then the callback function is + * called from within this function, hence it's not possible for + * interrupts to be lost. + * + * @param req request handle + * @param func the callback function or NULL for unregister + * @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); -/** - * Check if a request has already been interrupted - * - * @param req request handle - * @return 1 if the request has been interrupted, 0 otherwise - */ -int fuse_req_interrupted(fuse_req_t req); + /** + * Check if a request has already been interrupted + * + * @param req request handle + * @return 1 if the request has been interrupted, 0 otherwise + */ + int fuse_req_interrupted(fuse_req_t req); -/* ----------------------------------------------------------- * - * Filesystem setup * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Filesystem setup * + * ----------------------------------------------------------- */ -/* Deprecated, don't use */ -int fuse_lowlevel_is_lib_option(const char *opt); + /* Deprecated, don't use */ + int fuse_lowlevel_is_lib_option(const char *opt); -/** - * Create a low level session - * - * @param args argument vector - * @param op the low level filesystem operations - * @param op_size sizeof(struct fuse_lowlevel_ops) - * @param userdata user data - * @return the created session object, or NULL on failure - */ -struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + /** + * Create a low level session + * + * @param args argument vector + * @param op the low level filesystem operations + * @param op_size sizeof(struct fuse_lowlevel_ops) + * @param userdata user data + * @return the created session object, or NULL on failure + */ + struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); -/* ----------------------------------------------------------- * - * Session interface * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Session interface * + * ----------------------------------------------------------- */ -/** - * Session operations - * - * This is used in session creation - */ -struct fuse_session_ops { - /** - * Hook to process a request (mandatory) - * - * @param data user data passed to fuse_session_new() - * @param buf buffer containing the raw request - * @param len request length - * @param ch channel on which the request was received - */ - void (*process) (void *data, const char *buf, size_t len, - struct fuse_chan *ch); - - /** - * Hook for session exit and reset (optional) - * - * @param data user data passed to fuse_session_new() - * @param val exited status (1 - exited, 0 - not exited) - */ - void (*exit) (void *data, int val); - - /** - * Hook for querying the current exited status (optional) - * - * @param data user data passed to fuse_session_new() - * @return 1 if exited, 0 if not exited - */ - int (*exited) (void *data); - - /** - * Hook for cleaning up the channel on destroy (optional) - * - * @param data user data passed to fuse_session_new() - */ - void (*destroy) (void *data); -}; - -/** - * Create a new session - * - * @param op session operations - * @param data user data - * @return new session object, or NULL on failure - */ -struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); + /** + * Session operations + * + * This is used in session creation + */ + struct fuse_session_ops + { + /** + * Hook to process a request (mandatory) + * + * @param data user data passed to fuse_session_new() + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received + */ + void (*process) (void *data, const char *buf, size_t len, + struct fuse_chan *ch); + + /** + * Hook for session exit and reset (optional) + * + * @param data user data passed to fuse_session_new() + * @param val exited status (1 - exited, 0 - not exited) + */ + void (*exit) (void *data, int val); + + /** + * Hook for querying the current exited status (optional) + * + * @param data user data passed to fuse_session_new() + * @return 1 if exited, 0 if not exited + */ + int (*exited) (void *data); + + /** + * Hook for cleaning up the channel on destroy (optional) + * + * @param data user data passed to fuse_session_new() + */ + void (*destroy) (void *data); + }; -/** - * Assign a channel to a session - * - * Note: currently only a single channel may be assigned. This may - * change in the future - * - * If a session is destroyed, the assigned channel is also destroyed - * - * @param se the session - * @param ch the channel - */ -void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); + /** + * Create a new session + * + * @param op session operations + * @param data user data + * @return new session object, or NULL on failure + */ + struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); -/** - * Remove a channel from a session - * - * If the channel is not assigned to a session, then this is a no-op - * - * @param ch the channel to remove - */ -void fuse_session_remove_chan(struct fuse_chan *ch); + /** + * Assign a channel to a session + * + * Note: currently only a single channel may be assigned. This may + * change in the future + * + * If a session is destroyed, the assigned channel is also destroyed + * + * @param se the session + * @param ch the channel + */ + void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); -/** - * Iterate over the channels assigned to a session - * - * The iterating function needs to start with a NULL channel, and - * after that needs to pass the previously returned channel to the - * function. - * - * @param se the session - * @param ch the previous channel, or NULL - * @return the next channel, or NULL if no more channels exist - */ -struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, - struct fuse_chan *ch); + /** + * Remove a channel from a session + * + * If the channel is not assigned to a session, then this is a no-op + * + * @param ch the channel to remove + */ + void fuse_session_remove_chan(struct fuse_chan *ch); -/** - * Process a raw request - * - * @param se the session - * @param buf buffer containing the raw request - * @param len request length - * @param ch channel on which the request was received - */ -void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, - struct fuse_chan *ch); + /** + * Iterate over the channels assigned to a session + * + * The iterating function needs to start with a NULL channel, and + * after that needs to pass the previously returned channel to the + * function. + * + * @param se the session + * @param ch the previous channel, or NULL + * @return the next channel, or NULL if no more channels exist + */ + struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, + struct fuse_chan *ch); -/** - * Process a raw request supplied in a generic buffer - * - * This is a more generic version of fuse_session_process(). The - * fuse_buf may contain a memory buffer or a pipe file descriptor. - * - * @param se the session - * @param buf the fuse_buf containing the request - * @param ch channel on which the request was received - */ -void fuse_session_process_buf(struct fuse_session *se, - const struct fuse_buf *buf, struct fuse_chan *ch); + /** + * Process a raw request + * + * @param se the session + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received + */ + void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, + struct fuse_chan *ch); -/** - * Receive a raw request supplied in a generic buffer - * - * This is a more generic version of fuse_chan_recv(). The fuse_buf - * supplied to this function contains a suitably allocated memory - * buffer. This may be overwritten with a file descriptor buffer. - * - * @param se the session - * @param buf the fuse_buf to store the request in - * @param chp pointer to the channel - * @return the actual size of the raw request, or -errno on error - */ -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp); + /** + * Process a raw request supplied in a generic buffer + * + * This is a more generic version of fuse_session_process(). The + * fuse_buf may contain a memory buffer or a pipe file descriptor. + * + * @param se the session + * @param buf the fuse_buf containing the request + * @param ch channel on which the request was received + */ + void fuse_session_process_buf(struct fuse_session *se, + const struct fuse_buf *buf, struct fuse_chan *ch); -/** - * Destroy a session - * - * @param se the session - */ -void fuse_session_destroy(struct fuse_session *se); + /** + * Receive a raw request supplied in a generic buffer + * + * This is a more generic version of fuse_chan_recv(). The fuse_buf + * supplied to this function contains a suitably allocated memory + * buffer. This may be overwritten with a file descriptor buffer. + * + * @param se the session + * @param buf the fuse_buf to store the request in + * @param chp pointer to the channel + * @return the actual size of the raw request, or -errno on error + */ + int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan **chp); -/** - * Exit a session - * - * @param se the session - */ -void fuse_session_exit(struct fuse_session *se); + /** + * Destroy a session + * + * @param se the session + */ + void fuse_session_destroy(struct fuse_session *se); -/** - * Reset the exited status of a session - * - * @param se the session - */ -void fuse_session_reset(struct fuse_session *se); + /** + * Exit a session + * + * @param se the session + */ + void fuse_session_exit(struct fuse_session *se); -/** - * Query the exited status of a session - * - * @param se the session - * @return 1 if exited, 0 if not exited - */ -int fuse_session_exited(struct fuse_session *se); + /** + * Reset the exited status of a session + * + * @param se the session + */ + void fuse_session_reset(struct fuse_session *se); -/** - * Get the user data provided to the session - * - * @param se the session - * @return the user data - */ -void *fuse_session_data(struct fuse_session *se); + /** + * Query the exited status of a session + * + * @param se the session + * @return 1 if exited, 0 if not exited + */ + int fuse_session_exited(struct fuse_session *se); -/** - * Enter a single threaded event loop - * - * @param se the session - * @return 0 on success, -1 on error - */ -int fuse_session_loop(struct fuse_session *se); + /** + * Get the user data provided to the session + * + * @param se the session + * @return the user data + */ + void *fuse_session_data(struct fuse_session *se); -/** - * Enter a multi-threaded event loop - * - * @param se the session - * @return 0 on success, -1 on error - */ -int fuse_session_loop_mt(struct fuse_session *se, const int threads); + /** + * Enter a single threaded event loop + * + * @param se the session + * @return 0 on success, -1 on error + */ + int fuse_session_loop(struct fuse_session *se); + + /** + * Enter a multi-threaded event loop + * + * @param se the session + * @return 0 on success, -1 on error + */ + int fuse_session_loop_mt(struct fuse_session *se, const int threads); -/* ----------------------------------------------------------- * - * Channel interface * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Channel interface * + * ----------------------------------------------------------- */ -/** - * Channel operations - * - * This is used in channel creation - */ -struct fuse_chan_ops { - /** - * Hook for receiving a raw request - * - * @param ch pointer to the channel - * @param buf the buffer to store the request in - * @param size the size of the buffer - * @return the actual size of the raw request, or -1 on error - */ - int (*receive)(struct fuse_chan **chp, char *buf, size_t size); - - /** - * Hook for sending a raw reply - * - * A return value of -ENOENT means, that the request was - * interrupted, and the reply was discarded - * - * @param ch the channel - * @param iov vector of blocks - * @param count the number of blocks in vector - * @return zero on success, -errno on failure - */ - int (*send)(struct fuse_chan *ch, const struct iovec iov[], - size_t count); - - /** - * Destroy the channel - * - * @param ch the channel - */ - void (*destroy)(struct fuse_chan *ch); -}; - -/** - * Create a new channel - * - * @param op channel operations - * @param fd file descriptor of the channel - * @param bufsize the minimal receive buffer size - * @param data user data - * @return the new channel object, or NULL on failure - */ -struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data); + /** + * Channel operations + * + * This is used in channel creation + */ + struct fuse_chan_ops + { + /** + * Hook for receiving a raw request + * + * @param ch pointer to the channel + * @param buf the buffer to store the request in + * @param size the size of the buffer + * @return the actual size of the raw request, or -1 on error + */ + int (*receive)(struct fuse_chan **chp, char *buf, size_t size); + + /** + * Hook for sending a raw reply + * + * A return value of -ENOENT means, that the request was + * interrupted, and the reply was discarded + * + * @param ch the channel + * @param iov vector of blocks + * @param count the number of blocks in vector + * @return zero on success, -errno on failure + */ + int (*send)(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + + /** + * Destroy the channel + * + * @param ch the channel + */ + void (*destroy)(struct fuse_chan *ch); + }; -/** - * Query the file descriptor of the channel - * - * @param ch the channel - * @return the file descriptor passed to fuse_chan_new() - */ -int fuse_chan_fd(struct fuse_chan *ch); + /** + * Create a new channel + * + * @param op channel operations + * @param fd file descriptor of the channel + * @param bufsize the minimal receive buffer size + * @param data user data + * @return the new channel object, or NULL on failure + */ + struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, + size_t bufsize, void *data); -/** - * Query the minimal receive buffer size - * - * @param ch the channel - * @return the buffer size passed to fuse_chan_new() - */ -size_t fuse_chan_bufsize(struct fuse_chan *ch); + /** + * Query the file descriptor of the channel + * + * @param ch the channel + * @return the file descriptor passed to fuse_chan_new() + */ + int fuse_chan_fd(struct fuse_chan *ch); -/** - * Query the user data - * - * @param ch the channel - * @return the user data passed to fuse_chan_new() - */ -void *fuse_chan_data(struct fuse_chan *ch); + /** + * Query the minimal receive buffer size + * + * @param ch the channel + * @return the buffer size passed to fuse_chan_new() + */ + size_t fuse_chan_bufsize(struct fuse_chan *ch); -/** - * Query the session to which this channel is assigned - * - * @param ch the channel - * @return the session, or NULL if the channel is not assigned - */ -struct fuse_session *fuse_chan_session(struct fuse_chan *ch); + /** + * Query the user data + * + * @param ch the channel + * @return the user data passed to fuse_chan_new() + */ + void *fuse_chan_data(struct fuse_chan *ch); -/** - * Receive a raw request - * - * A return value of -ENODEV means, that the filesystem was unmounted - * - * @param ch pointer to the channel - * @param buf the buffer to store the request in - * @param size the size of the buffer - * @return the actual size of the raw request, or -errno on error - */ -int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); + /** + * Query the session to which this channel is assigned + * + * @param ch the channel + * @return the session, or NULL if the channel is not assigned + */ + struct fuse_session *fuse_chan_session(struct fuse_chan *ch); -/** - * Send a raw reply - * - * A return value of -ENOENT means, that the request was - * interrupted, and the reply was discarded - * - * @param ch the channel - * @param iov vector of blocks - * @param count the number of blocks in vector - * @return zero on success, -errno on failure - */ -int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], - size_t count); + /** + * Receive a raw request + * + * A return value of -ENODEV means, that the filesystem was unmounted + * + * @param ch pointer to the channel + * @param buf the buffer to store the request in + * @param size the size of the buffer + * @return the actual size of the raw request, or -errno on error + */ + int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); -/** - * Destroy a channel - * - * @param ch the channel - */ -void fuse_chan_destroy(struct fuse_chan *ch); + /** + * Send a raw reply + * + * A return value of -ENOENT means, that the request was + * interrupted, and the reply was discarded + * + * @param ch the channel + * @param iov vector of blocks + * @param count the number of blocks in vector + * @return zero on success, -errno on failure + */ + int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + + /** + * Destroy a channel + * + * @param ch the channel + */ + void fuse_chan_destroy(struct fuse_chan *ch); -/* ----------------------------------------------------------- * - * Compatibility stuff * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Compatibility stuff * + * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # include "fuse_lowlevel_compat.h" diff --git a/libfuse/include/fuse_lowlevel_compat.h b/libfuse/include/fuse_lowlevel_compat.h index 8de220b9..5c4649d7 100644 --- a/libfuse/include/fuse_lowlevel_compat.h +++ b/libfuse/include/fuse_lowlevel_compat.h @@ -9,63 +9,64 @@ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ -struct fuse_lowlevel_ops_compat25 { - void (*init) (void *userdata); - void (*destroy) (void *userdata); - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); - void (*getattr) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info *fi); - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - void (*open) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi); - void (*flush) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*release) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - void (*opendir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - void (*statfs) (fuse_req_t req); - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi); +struct fuse_lowlevel_ops_compat25 +{ + void (*init) (void *userdata); + void (*destroy) (void *userdata); + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); + void (*readlink) (fuse_req_t req, fuse_ino_t ino); + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + void (*statfs) (fuse_req_t req); + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi); }; struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata); size_t fuse_dirent_size(size_t namelen); @@ -76,58 +77,59 @@ char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, #include -struct fuse_lowlevel_ops_compat { - void (*init) (void *userdata); - void (*destroy) (void *userdata); - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); - void (*getattr) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info_compat *fi); - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - void (*open) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info_compat *fi); - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info_compat *fi); - void (*flush) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*release) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info_compat *fi); - void (*opendir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info_compat *fi); - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info_compat *fi); - void (*statfs) (fuse_req_t req); - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info_compat *fi); +struct fuse_lowlevel_ops_compat +{ + void (*init) (void *userdata); + void (*destroy) (void *userdata); + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info_compat *fi); + void (*readlink) (fuse_req_t req, fuse_ino_t ino); + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info_compat *fi); + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info_compat *fi); + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info_compat *fi); + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info_compat *fi); + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info_compat *fi); + void (*statfs) (fuse_req_t req); + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info_compat *fi); }; int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf); @@ -136,16 +138,16 @@ int fuse_reply_open_compat(fuse_req_t req, const struct fuse_file_info_compat *fi); struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops_compat *op, + size_t op_size, void *userdata); #endif /* __FreeBSD__ || __NetBSD__ */ struct fuse_chan_ops_compat24 { - int (*receive)(struct fuse_chan *ch, char *buf, size_t size); - int (*send)(struct fuse_chan *ch, const struct iovec iov[], - size_t count); - void (*destroy)(struct fuse_chan *ch); + int (*receive)(struct fuse_chan *ch, char *buf, size_t size); + int (*send)(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + void (*destroy)(struct fuse_chan *ch); }; struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, diff --git a/libfuse/include/fuse_opt.h b/libfuse/include/fuse_opt.h index add0a308..229c3931 100644 --- a/libfuse/include/fuse_opt.h +++ b/libfuse/include/fuse_opt.h @@ -18,250 +18,252 @@ extern "C" { #endif -/** - * Option description - * - * This structure describes a single option, and action associated - * with it, in case it matches. - * - * More than one such match may occur, in which case the action for - * each match is executed. - * - * There are three possible actions in case of a match: - * - * i) An integer (int or unsigned) variable determined by 'offset' is - * set to 'value' - * - * ii) The processing function is called, with 'value' as the key - * - * iii) An integer (any) or string (char *) variable determined by - * 'offset' is set to the value of an option parameter - * - * 'offset' should normally be either set to - * - * - 'offsetof(struct foo, member)' actions i) and iii) - * - * - -1 action ii) - * - * The 'offsetof()' macro is defined in the header. - * - * The template determines which options match, and also have an - * effect on the action. Normally the action is either i) or ii), but - * if a format is present in the template, then action iii) is - * performed. - * - * The types of templates are: - * - * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only - * themselves. Invalid values are "--" and anything beginning - * with "-o" - * - * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or - * the relevant option in a comma separated option list - * - * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) - * which have a parameter - * - * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform - * action iii). - * - * 5) "-x ", etc. Matches either "-xparam" or "-x param" as - * two separate arguments - * - * 6) "-x %s", etc. Combination of 4) and 5) - * - * If the format is "%s", memory is allocated for the string unlike - * with scanf(). - */ -struct fuse_opt { - /** Matching template and optional parameter formatting */ - const char *templ; + /** + * Option description + * + * This structure describes a single option, and action associated + * with it, in case it matches. + * + * More than one such match may occur, in which case the action for + * each match is executed. + * + * There are three possible actions in case of a match: + * + * i) An integer (int or unsigned) variable determined by 'offset' is + * set to 'value' + * + * ii) The processing function is called, with 'value' as the key + * + * iii) An integer (any) or string (char *) variable determined by + * 'offset' is set to the value of an option parameter + * + * 'offset' should normally be either set to + * + * - 'offsetof(struct foo, member)' actions i) and iii) + * + * - -1 action ii) + * + * The 'offsetof()' macro is defined in the header. + * + * The template determines which options match, and also have an + * effect on the action. Normally the action is either i) or ii), but + * if a format is present in the template, then action iii) is + * performed. + * + * The types of templates are: + * + * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only + * themselves. Invalid values are "--" and anything beginning + * with "-o" + * + * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or + * the relevant option in a comma separated option list + * + * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) + * which have a parameter + * + * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform + * action iii). + * + * 5) "-x ", etc. Matches either "-xparam" or "-x param" as + * two separate arguments + * + * 6) "-x %s", etc. Combination of 4) and 5) + * + * If the format is "%s", memory is allocated for the string unlike + * with scanf(). + */ + struct fuse_opt + { + /** 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 - * called with the specified key. - */ + /** + * 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 } -/** - * Last option. An array of 'struct fuse_opt' must end with a NULL - * template value - */ + /** + * Last option. An array of 'struct fuse_opt' must end with a NULL + * template value + */ #define FUSE_OPT_END { NULL, 0, 0 } -/** - * Argument list - */ -struct fuse_args { - /** Argument count */ - int argc; + /** + * Argument list + */ + struct fuse_args + { + /** 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' - */ + /** + * Initializer for 'struct fuse_args' + */ #define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 } -/** - * Key value passed to the processing function if an option did not - * match any template - */ + /** + * Key value passed to the processing function if an option did not + * match any template + */ #define FUSE_OPT_KEY_OPT -1 -/** - * Key value passed to the processing function for all non-options - * - * Non-options are the arguments beginning with a character other than - * '-' or all arguments after the special '--' option - */ + /** + * Key value passed to the processing function for all non-options + * + * Non-options are the arguments beginning with a character other than + * '-' or all arguments after the special '--' option + */ #define FUSE_OPT_KEY_NONOPT -2 -/** - * Special key value for options to keep - * - * Argument is not passed to processing function, but behave as if the - * processing function returned 1 - */ + /** + * Special key value for options to keep + * + * Argument is not passed to processing function, but behave as if the + * processing function returned 1 + */ #define FUSE_OPT_KEY_KEEP -3 -/** - * Special key value for options to discard - * - * Argument is not passed to processing function, but behave as if the - * processing function returned zero - */ + /** + * Special key value for options to discard + * + * Argument is not passed to processing function, but behave as if the + * processing function returned zero + */ #define FUSE_OPT_KEY_DISCARD -4 -/** - * Processing function - * - * This function is called if - * - option did not match any 'struct fuse_opt' - * - argument is a non-option - * - option did match and offset was set to -1 - * - * The 'arg' parameter will always contain the whole argument or - * option including the parameter if exists. A two-argument option - * ("-x foo") is always converted to single argument option of the - * form "-xfoo" before this function is called. - * - * Options of the form '-ofoo' are passed to this function without the - * '-o' prefix. - * - * The return value of this function determines whether this argument - * is to be inserted into the output argument vector, or discarded. - * - * @param data is the user data passed to the fuse_opt_parse() function - * @param arg is the whole argument or option - * @param key determines why the processing function was called - * @param outargs the current output argument list - * @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); + /** + * Processing function + * + * This function is called if + * - option did not match any 'struct fuse_opt' + * - argument is a non-option + * - option did match and offset was set to -1 + * + * The 'arg' parameter will always contain the whole argument or + * option including the parameter if exists. A two-argument option + * ("-x foo") is always converted to single argument option of the + * form "-xfoo" before this function is called. + * + * Options of the form '-ofoo' are passed to this function without the + * '-o' prefix. + * + * The return value of this function determines whether this argument + * is to be inserted into the output argument vector, or discarded. + * + * @param data is the user data passed to the fuse_opt_parse() function + * @param arg is the whole argument or option + * @param key determines why the processing function was called + * @param outargs the current output argument list + * @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); -/** - * Option parsing function - * - * If 'args' was returned from a previous call to fuse_opt_parse() or - * it was constructed from - * - * A NULL 'args' is equivalent to an empty argument vector - * - * A NULL 'opts' is equivalent to an 'opts' array containing a single - * end marker - * - * A NULL 'proc' is equivalent to a processing function always - * returning '1' - * - * @param args is the input and output argument list - * @param data is the user data - * @param opts is the option description array - * @param proc is the processing function - * @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); + /** + * Option parsing function + * + * If 'args' was returned from a previous call to fuse_opt_parse() or + * it was constructed from + * + * A NULL 'args' is equivalent to an empty argument vector + * + * A NULL 'opts' is equivalent to an 'opts' array containing a single + * end marker + * + * A NULL 'proc' is equivalent to a processing function always + * returning '1' + * + * @param args is the input and output argument list + * @param data is the user data + * @param opts is the option description array + * @param proc is the processing function + * @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); -/** - * Add an option to a comma separated option list - * - * @param opts is a pointer to an option list, may point to a NULL value - * @param opt is the option to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_add_opt(char **opts, const char *opt); + /** + * Add an option to a comma separated option list + * + * @param opts is a pointer to an option list, may point to a NULL value + * @param opt is the option to add + * @return -1 on allocation error, 0 on success + */ + int fuse_opt_add_opt(char **opts, const char *opt); -/** - * Add an option, escaping commas, to a comma separated option list - * - * @param opts is a pointer to an option list, may point to a NULL value - * @param opt is the option to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_add_opt_escaped(char **opts, const char *opt); + /** + * Add an option, escaping commas, to a comma separated option list + * + * @param opts is a pointer to an option list, may point to a NULL value + * @param opt is the option to add + * @return -1 on allocation error, 0 on success + */ + int fuse_opt_add_opt_escaped(char **opts, const char *opt); -/** - * Add an argument to a NULL terminated argument vector - * - * @param args is the structure containing the current argument list - * @param arg is the new argument to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_add_arg(struct fuse_args *args, const char *arg); + /** + * Add an argument to a NULL terminated argument vector + * + * @param args is the structure containing the current argument list + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ + int fuse_opt_add_arg(struct fuse_args *args, const char *arg); -/** - * Add an argument at the specified position in a NULL terminated - * argument vector - * - * Adds the argument to the N-th position. This is useful for adding - * options at the beginning of the array which must not come after the - * special '--' option. - * - * @param args is the structure containing the current argument list - * @param pos is the position at which to add the argument - * @param arg is the new argument to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); + /** + * Add an argument at the specified position in a NULL terminated + * argument vector + * + * Adds the argument to the N-th position. This is useful for adding + * options at the beginning of the array which must not come after the + * special '--' option. + * + * @param args is the structure containing the current argument list + * @param pos is the position at which to add the argument + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ + int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); -/** - * Free the contents of argument list - * - * The structure itself is not freed - * - * @param args is the structure containing the argument list - */ -void fuse_opt_free_args(struct fuse_args *args); + /** + * Free the contents of argument list + * + * The structure itself is not freed + * + * @param args is the structure containing the argument list + */ + void fuse_opt_free_args(struct fuse_args *args); -/** - * Check if an option matches - * - * @param opts is the option description array - * @param opt is the option to match - * @return 1 if a match is found, 0 if not - */ -int fuse_opt_match(const struct fuse_opt opts[], const char *opt); + /** + * Check if an option matches + * + * @param opts is the option description array + * @param opt is the option to match + * @return 1 if a match is found, 0 if not + */ + int fuse_opt_match(const struct fuse_opt opts[], const char *opt); #ifdef __cplusplus } diff --git a/libfuse/include/fuse_timeouts.h b/libfuse/include/fuse_timeouts.h new file mode 100644 index 00000000..b2e5505b --- /dev/null +++ b/libfuse/include/fuse_timeouts.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +typedef struct fuse_timeouts_s fuse_timeouts_t; +struct fuse_timeouts_s +{ + uint64_t entry; + uint64_t attr; +}; diff --git a/libfuse/lib/buffer.c b/libfuse/lib/buffer.c index 40e426ec..50ed9e7d 100644 --- a/libfuse/lib/buffer.c +++ b/libfuse/lib/buffer.c @@ -18,140 +18,140 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv) { - size_t i; - size_t size = 0; + 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; - } + 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; + 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) { - ssize_t res = 0; - size_t copied = 0; - - while (len) { - if (dst->flags & FUSE_BUF_FD_SEEK) { - res = pwrite(dst->fd, src->mem + src_off, len, - dst->pos + dst_off); - } else { - res = write(dst->fd, 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, src->mem + src_off, len, + dst->pos + dst_off); + } else { + res = write(dst->fd, 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) { - ssize_t res = 0; - size_t copied = 0; - - while (len) { - if (src->flags & FUSE_BUF_FD_SEEK) { - res = pread(src->fd, dst->mem + dst_off, len, - src->pos + src_off); - } else { - res = read(src->fd, 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, dst->mem + dst_off, len, + src->pos + src_off); + } else { + res = read(src->fd, 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) { - 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; } #ifdef HAVE_SPLICE @@ -159,64 +159,64 @@ static ssize_t fuse_buf_splice(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) { - int splice_flags = 0; - off_t *srcpos = NULL; - off_t *dstpos = NULL; - off_t srcpos_val; - off_t dstpos_val; - ssize_t res; - size_t copied = 0; - - if (flags & FUSE_BUF_SPLICE_MOVE) - splice_flags |= SPLICE_F_MOVE; - if (flags & FUSE_BUF_SPLICE_NONBLOCK) - splice_flags |= SPLICE_F_NONBLOCK; - - if (src->flags & FUSE_BUF_FD_SEEK) { - srcpos_val = src->pos + src_off; - srcpos = &srcpos_val; - } - if (dst->flags & FUSE_BUF_FD_SEEK) { - dstpos_val = dst->pos + dst_off; - dstpos = &dstpos_val; - } - - while (len) { - res = splice(src->fd, srcpos, dst->fd, dstpos, len, - splice_flags); - if (res == -1) { - if (copied) - break; - - if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE)) - return -errno; - - /* Maybe splice is not supported for this combination */ - return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, - len); - } - if (res == 0) - break; - - copied += res; - if (!(src->flags & FUSE_BUF_FD_RETRY) && - !(dst->flags & FUSE_BUF_FD_RETRY)) { - break; - } - - len -= res; - } - - return copied; + int splice_flags = 0; + off_t *srcpos = NULL; + off_t *dstpos = NULL; + off_t srcpos_val; + off_t dstpos_val; + ssize_t res; + size_t copied = 0; + + if (flags & FUSE_BUF_SPLICE_MOVE) + splice_flags |= SPLICE_F_MOVE; + if (flags & FUSE_BUF_SPLICE_NONBLOCK) + splice_flags |= SPLICE_F_NONBLOCK; + + if (src->flags & FUSE_BUF_FD_SEEK) { + srcpos_val = src->pos + src_off; + srcpos = &srcpos_val; + } + if (dst->flags & FUSE_BUF_FD_SEEK) { + dstpos_val = dst->pos + dst_off; + dstpos = &dstpos_val; + } + + while (len) { + res = splice(src->fd, srcpos, dst->fd, dstpos, len, + splice_flags); + if (res == -1) { + if (copied) + break; + + if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE)) + return -errno; + + /* Maybe splice is not supported for this combination */ + return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, + len); + } + if (res == 0) + break; + + copied += res; + if (!(src->flags & FUSE_BUF_FD_RETRY) && + !(dst->flags & FUSE_BUF_FD_RETRY)) { + break; + } + + len -= res; + } + + return copied; } #else static ssize_t fuse_buf_splice(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) { - (void) flags; + (void) flags; - return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); + return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); } #endif @@ -225,94 +225,94 @@ 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) { - 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 = dst->mem + dst_off; - char *srcmem = 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 if (flags & FUSE_BUF_NO_SPLICE) { - return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); - } else { - return fuse_buf_splice(dst, dst_off, src, src_off, len, 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 = dst->mem + dst_off; + char *srcmem = 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 if (flags & FUSE_BUF_NO_SPLICE) { + return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); + } else { + return fuse_buf_splice(dst, dst_off, src, src_off, len, flags); + } } 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) { - 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/libfuse/lib/cuse_lowlevel.c b/libfuse/lib/cuse_lowlevel.c index b3a535f1..d42badbd 100644 --- a/libfuse/lib/cuse_lowlevel.c +++ b/libfuse/lib/cuse_lowlevel.c @@ -21,127 +21,127 @@ #include struct cuse_data { - struct cuse_lowlevel_ops clop; - unsigned max_read; - unsigned dev_major; - unsigned dev_minor; - unsigned flags; - unsigned dev_info_len; - char dev_info[]; + struct cuse_lowlevel_ops clop; + unsigned max_read; + unsigned dev_major; + unsigned dev_minor; + unsigned flags; + unsigned dev_info_len; + char dev_info[]; }; static struct cuse_lowlevel_ops *req_clop(fuse_req_t req) { - return &req->f->cuse_data->clop; + return &req->f->cuse_data->clop; } static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - (void)ino; - req_clop(req)->open(req, fi); + (void)ino; + req_clop(req)->open(req, fi); } static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { - (void)ino; - req_clop(req)->read(req, size, off, fi); + (void)ino; + req_clop(req)->read(req, size, off, fi); } static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { - (void)ino; - req_clop(req)->write(req, buf, size, off, fi); + (void)ino; + req_clop(req)->write(req, buf, size, off, fi); } static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - (void)ino; - req_clop(req)->flush(req, fi); + (void)ino; + req_clop(req)->flush(req, fi); } static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - (void)ino; - req_clop(req)->release(req, fi); + (void)ino; + req_clop(req)->release(req, fi); } static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { - (void)ino; - req_clop(req)->fsync(req, datasync, fi); + (void)ino; + req_clop(req)->fsync(req, datasync, fi); } static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz) + struct fuse_file_info *fi, unsigned int flags, + const void *in_buf, size_t in_bufsz, size_t out_bufsz) { - (void)ino; - req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz, - out_bufsz); + (void)ino; + req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz, + out_bufsz); } static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph) { - (void)ino; - req_clop(req)->poll(req, fi, ph); + (void)ino; + req_clop(req)->poll(req, fi, ph); } static size_t cuse_pack_info(int argc, const char **argv, char *buf) { - size_t size = 0; - int i; + size_t size = 0; + int i; - for (i = 0; i < argc; i++) { - size_t len; + for (i = 0; i < argc; i++) { + size_t len; - len = strlen(argv[i]) + 1; - size += len; - if (buf) { - memcpy(buf, argv[i], len); - buf += len; - } - } + len = strlen(argv[i]) + 1; + size += len; + if (buf) { + memcpy(buf, argv[i], len); + buf += len; + } + } - return size; + return size; } static struct cuse_data *cuse_prep_data(const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop) { - struct cuse_data *cd; - size_t dev_info_len; - - dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, - NULL); - - if (dev_info_len > CUSE_INIT_INFO_MAX) { - fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n", - dev_info_len, CUSE_INIT_INFO_MAX); - return NULL; - } - - cd = calloc(1, sizeof(*cd) + dev_info_len); - if (!cd) { - fprintf(stderr, "cuse: failed to allocate cuse_data\n"); - return NULL; - } - - memcpy(&cd->clop, clop, sizeof(cd->clop)); - cd->max_read = 131072; - cd->dev_major = ci->dev_major; - cd->dev_minor = ci->dev_minor; - cd->dev_info_len = dev_info_len; - cd->flags = ci->flags; - cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info); - - return cd; + struct cuse_data *cd; + size_t dev_info_len; + + dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, + NULL); + + if (dev_info_len > CUSE_INIT_INFO_MAX) { + fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n", + dev_info_len, CUSE_INIT_INFO_MAX); + return NULL; + } + + cd = calloc(1, sizeof(*cd) + dev_info_len); + if (!cd) { + fprintf(stderr, "cuse: failed to allocate cuse_data\n"); + return NULL; + } + + memcpy(&cd->clop, clop, sizeof(cd->clop)); + cd->max_read = 131072; + cd->dev_major = ci->dev_major; + cd->dev_minor = ci->dev_minor; + cd->dev_info_len = dev_info_len; + cd->flags = ci->flags; + cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info); + + return cd; } struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, @@ -149,118 +149,118 @@ struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, const struct cuse_lowlevel_ops *clop, void *userdata) { - struct fuse_lowlevel_ops lop; - struct cuse_data *cd; - struct fuse_session *se; - struct fuse_ll *ll; - - cd = cuse_prep_data(ci, clop); - if (!cd) - return NULL; - - memset(&lop, 0, sizeof(lop)); - lop.init = clop->init; - lop.destroy = clop->destroy; - lop.open = clop->open ? cuse_fll_open : NULL; - lop.read = clop->read ? cuse_fll_read : NULL; - lop.write = clop->write ? cuse_fll_write : NULL; - lop.flush = clop->flush ? cuse_fll_flush : NULL; - lop.release = clop->release ? cuse_fll_release : NULL; - lop.fsync = clop->fsync ? cuse_fll_fsync : NULL; - lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL; - lop.poll = clop->poll ? cuse_fll_poll : NULL; - - se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata); - if (!se) { - free(cd); - return NULL; - } - ll = se->data; - ll->cuse_data = cd; - - return se; + struct fuse_lowlevel_ops lop; + struct cuse_data *cd; + struct fuse_session *se; + struct fuse_ll *ll; + + cd = cuse_prep_data(ci, clop); + if (!cd) + return NULL; + + memset(&lop, 0, sizeof(lop)); + lop.init = clop->init; + lop.destroy = clop->destroy; + lop.open = clop->open ? cuse_fll_open : NULL; + lop.read = clop->read ? cuse_fll_read : NULL; + lop.write = clop->write ? cuse_fll_write : NULL; + lop.flush = clop->flush ? cuse_fll_flush : NULL; + lop.release = clop->release ? cuse_fll_release : NULL; + lop.fsync = clop->fsync ? cuse_fll_fsync : NULL; + lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL; + lop.poll = clop->poll ? cuse_fll_poll : NULL; + + se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata); + if (!se) { + free(cd); + return NULL; + } + ll = se->data; + ll->cuse_data = cd; + + return se; } static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg, char *dev_info, unsigned dev_info_len) { - struct iovec iov[3]; + struct iovec iov[3]; - iov[1].iov_base = arg; - iov[1].iov_len = sizeof(struct cuse_init_out); - iov[2].iov_base = dev_info; - iov[2].iov_len = dev_info_len; + iov[1].iov_base = arg; + iov[1].iov_len = sizeof(struct cuse_init_out); + iov[2].iov_base = dev_info; + iov[2].iov_len = dev_info_len; - return fuse_send_reply_iov_nofree(req, 0, iov, 3); + return fuse_send_reply_iov_nofree(req, 0, iov, 3); } void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_init_in *arg = (struct fuse_init_in *) inarg; - struct cuse_init_out outarg; - struct fuse_ll *f = req->f; - struct cuse_data *cd = f->cuse_data; - size_t bufsize = fuse_chan_bufsize(req->ch); - struct cuse_lowlevel_ops *clop = req_clop(req); - - (void) nodeid; - if (f->debug) { - fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor); - fprintf(stderr, "flags=0x%08x\n", arg->flags); - } - f->conn.proto_major = arg->major; - f->conn.proto_minor = arg->minor; - f->conn.capable = 0; - f->conn.want = 0; - - if (arg->major < 7) { - fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); - return; - } - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fprintf(stderr, "cuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - - bufsize -= 4096; - if (bufsize < f->conn.max_write) - f->conn.max_write = bufsize; - - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata, &f->conn); - - memset(&outarg, 0, sizeof(outarg)); - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - outarg.flags = cd->flags; - outarg.max_read = cd->max_read; - outarg.max_write = f->conn.max_write; - outarg.dev_major = cd->dev_major; - outarg.dev_minor = cd->dev_minor; - - if (f->debug) { - fprintf(stderr, " CUSE_INIT: %u.%u\n", - outarg.major, outarg.minor); - fprintf(stderr, " flags=0x%08x\n", outarg.flags); - fprintf(stderr, " max_read=0x%08x\n", outarg.max_read); - fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); - fprintf(stderr, " dev_major=%u\n", outarg.dev_major); - fprintf(stderr, " dev_minor=%u\n", outarg.dev_minor); - fprintf(stderr, " dev_info: %.*s\n", cd->dev_info_len, - cd->dev_info); - } - - cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len); - - if (clop->init_done) - clop->init_done(f->userdata); - - fuse_free_req(req); + struct fuse_init_in *arg = (struct fuse_init_in *) inarg; + struct cuse_init_out outarg; + struct fuse_ll *f = req->f; + struct cuse_data *cd = f->cuse_data; + size_t bufsize = fuse_chan_bufsize(req->ch); + struct cuse_lowlevel_ops *clop = req_clop(req); + + (void) nodeid; + if (f->debug) { + fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor); + fprintf(stderr, "flags=0x%08x\n", arg->flags); + } + f->conn.proto_major = arg->major; + f->conn.proto_minor = arg->minor; + f->conn.capable = 0; + f->conn.want = 0; + + if (arg->major < 7) { + fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n", + arg->major, arg->minor); + fuse_reply_err(req, EPROTO); + return; + } + + if (bufsize < FUSE_MIN_READ_BUFFER) { + fprintf(stderr, "cuse: warning: buffer size too small: %zu\n", + bufsize); + bufsize = FUSE_MIN_READ_BUFFER; + } + + bufsize -= 4096; + if (bufsize < f->conn.max_write) + f->conn.max_write = bufsize; + + f->got_init = 1; + if (f->op.init) + f->op.init(f->userdata, &f->conn); + + memset(&outarg, 0, sizeof(outarg)); + outarg.major = FUSE_KERNEL_VERSION; + outarg.minor = FUSE_KERNEL_MINOR_VERSION; + outarg.flags = cd->flags; + outarg.max_read = cd->max_read; + outarg.max_write = f->conn.max_write; + outarg.dev_major = cd->dev_major; + outarg.dev_minor = cd->dev_minor; + + if (f->debug) { + fprintf(stderr, " CUSE_INIT: %u.%u\n", + outarg.major, outarg.minor); + fprintf(stderr, " flags=0x%08x\n", outarg.flags); + fprintf(stderr, " max_read=0x%08x\n", outarg.max_read); + fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); + fprintf(stderr, " dev_major=%u\n", outarg.dev_major); + fprintf(stderr, " dev_minor=%u\n", outarg.dev_minor); + fprintf(stderr, " dev_info: %.*s\n", cd->dev_info_len, + cd->dev_info); + } + + cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len); + + if (clop->init_done) + clop->init_done(f->userdata); + + fuse_free_req(req); } struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], @@ -268,104 +268,104 @@ struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], const struct cuse_lowlevel_ops *clop, int *multithreaded, void *userdata) { - const char *devname = "/dev/cuse"; - static const struct fuse_opt kill_subtype_opts[] = { - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_END - }; - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_session *se; - struct fuse_chan *ch; - int fd; - int foreground; - int res; - - res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground); - if (res == -1) - goto err_args; - - res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL); - if (res == -1) - goto err_args; - - /* - * 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); - - se = cuse_lowlevel_new(&args, ci, clop, userdata); - fuse_opt_free_args(&args); - if (se == NULL) - goto err_args; - - fd = open(devname, O_RDWR); - if (fd == -1) { - if (errno == ENODEV || errno == ENOENT) - fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n"); - else - fprintf(stderr, "cuse: failed to open %s: %s\n", - devname, strerror(errno)); - goto err_se; - } - - ch = fuse_kern_chan_new(fd); - if (!ch) { - close(fd); - goto err_se; - } - - fuse_session_add_chan(se, ch); - - res = fuse_set_signal_handlers(se); - if (res == -1) - goto err_se; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_sig; - - return se; - -err_sig: - fuse_remove_signal_handlers(se); -err_se: - fuse_session_destroy(se); -err_args: - fuse_opt_free_args(&args); - return NULL; + const char *devname = "/dev/cuse"; + static const struct fuse_opt kill_subtype_opts[] = { + FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_END + }; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse_session *se; + struct fuse_chan *ch; + int fd; + int foreground; + int res; + + res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground); + if (res == -1) + goto err_args; + + res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL); + if (res == -1) + goto err_args; + + /* + * 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); + + se = cuse_lowlevel_new(&args, ci, clop, userdata); + fuse_opt_free_args(&args); + if (se == NULL) + goto err_args; + + fd = open(devname, O_RDWR); + if (fd == -1) { + if (errno == ENODEV || errno == ENOENT) + fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n"); + else + fprintf(stderr, "cuse: failed to open %s: %s\n", + devname, strerror(errno)); + goto err_se; + } + + ch = fuse_kern_chan_new(fd); + if (!ch) { + close(fd); + goto err_se; + } + + fuse_session_add_chan(se, ch); + + res = fuse_set_signal_handlers(se); + if (res == -1) + goto err_se; + + res = fuse_daemonize(foreground); + if (res == -1) + goto err_sig; + + return se; + + err_sig: + fuse_remove_signal_handlers(se); + err_se: + fuse_session_destroy(se); + err_args: + fuse_opt_free_args(&args); + return NULL; } void cuse_lowlevel_teardown(struct fuse_session *se) { - fuse_remove_signal_handlers(se); - fuse_session_destroy(se); + fuse_remove_signal_handlers(se); + fuse_session_destroy(se); } int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata) { - struct fuse_session *se; - int multithreaded; - int res; + struct fuse_session *se; + int multithreaded; + int res; - se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded, - userdata); - if (se == NULL) - return 1; + se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded, + userdata); + if (se == NULL) + return 1; - if (multithreaded) - res = fuse_session_loop_mt(se, 0); - else - res = fuse_session_loop(se); + if (multithreaded) + res = fuse_session_loop_mt(se, 0); + else + res = fuse_session_loop(se); - cuse_lowlevel_teardown(se); - if (res == -1) - return 1; + cuse_lowlevel_teardown(se); + if (res == -1) + return 1; - return 0; + return 0; } diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index 2c3c7392..93d6c278 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -54,69 +54,75 @@ #define NODE_TABLE_MIN_SIZE 8192 -struct fuse_config { - unsigned int uid; - unsigned int gid; - unsigned int umask; - int remember; - int debug; - int use_ino; - int set_mode; - int set_uid; - int set_gid; - int intr; - int intr_signal; - int help; - int threads; +struct fuse_config +{ + unsigned int uid; + unsigned int gid; + unsigned int umask; + int remember; + int debug; + int use_ino; + int set_mode; + int set_uid; + int set_gid; + int intr; + int intr_signal; + int help; + int threads; }; -struct fuse_fs { - struct fuse_operations op; - void *user_data; - int compat; - int debug; +struct fuse_fs +{ + struct fuse_operations op; + void *user_data; + int compat; + int debug; }; -struct lock_queue_element { - struct lock_queue_element *next; - pthread_cond_t cond; - fuse_ino_t nodeid1; - const char *name1; - char **path1; - struct node **wnode1; - fuse_ino_t nodeid2; - const char *name2; - char **path2; - struct node **wnode2; - int err; - bool first_locked : 1; - bool second_locked : 1; - bool done : 1; +struct lock_queue_element +{ + struct lock_queue_element *next; + pthread_cond_t cond; + fuse_ino_t nodeid1; + const char *name1; + char **path1; + struct node **wnode1; + fuse_ino_t nodeid2; + const char *name2; + char **path2; + struct node **wnode2; + int err; + bool first_locked : 1; + bool second_locked : 1; + bool done : 1; }; -struct node_table { - struct node **array; - size_t use; - size_t size; - size_t split; +struct node_table +{ + struct node **array; + size_t use; + size_t size; + size_t split; }; -#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) );}) #define list_entry(ptr, type, member) \ - container_of(ptr, type, member) + container_of(ptr, type, member) -struct list_head { - struct list_head *next; - struct list_head *prev; +struct list_head +{ + struct list_head *next; + struct list_head *prev; }; -struct node_slab { - struct list_head list; /* must be the first member */ - struct list_head freelist; - int used; +struct node_slab +{ + struct list_head list; /* must be the first member */ + struct list_head freelist; + int used; }; struct fuse @@ -139,13 +145,14 @@ struct fuse pthread_t prune_thread; }; -struct lock { - int type; - off_t start; - off_t end; - pid_t pid; - uint64_t owner; - struct lock *next; +struct lock +{ + int type; + off_t start; + off_t end; + pid_t pid; + uint64_t owner; + struct lock *next; }; struct node @@ -171,10 +178,11 @@ struct node #define TREELOCK_WRITE -1 #define TREELOCK_WAIT_OFFSET INT_MIN -struct node_lru { - struct node node; - struct list_head lru; - struct timespec forget_time; +struct node_lru +{ + struct node node; + struct list_head lru; + struct timespec forget_time; }; struct fuse_dh @@ -184,198 +192,250 @@ struct fuse_dh fuse_dirents_t d; }; -struct fuse_context_i { - struct fuse_context ctx; - fuse_req_t req; +struct fuse_context_i +{ + struct fuse_context ctx; + fuse_req_t req; }; static pthread_key_t fuse_context_key; static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; static int fuse_context_ref; -static void init_list_head(struct list_head *list) +static +void +init_list_head(struct list_head *list) { - list->next = list; - list->prev = list; + list->next = list; + list->prev = list; } -static int list_empty(const struct list_head *head) +static +int +list_empty(const struct list_head *head) { - return head->next == head; + return head->next == head; } -static void list_add(struct list_head *new, struct list_head *prev, - struct list_head *next) +static +void +list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } -static inline void list_add_head(struct list_head *new, struct list_head *head) +static +inline +void +list_add_head(struct list_head *new, + struct list_head *head) { - list_add(new, head, head->next); + list_add(new, head, head->next); } -static inline void list_add_tail(struct list_head *new, struct list_head *head) +static +inline +void +list_add_tail(struct list_head *new, + struct list_head *head) { - list_add(new, head->prev, head); + list_add(new, head->prev, head); } -static inline void list_del(struct list_head *entry) +static +inline +void +list_del(struct list_head *entry) { - struct list_head *prev = entry->prev; - struct list_head *next = entry->next; + struct list_head *prev = entry->prev; + struct list_head *next = entry->next; - next->prev = prev; - prev->next = next; + next->prev = prev; + prev->next = next; } -static inline int lru_enabled(struct fuse *f) +static +inline +int +lru_enabled(struct fuse *f) { - return f->conf.remember > 0; + return f->conf.remember > 0; } -static struct node_lru *node_lru(struct node *node) +static +struct +node_lru* +node_lru(struct node *node) { - return (struct node_lru *) node; + return (struct node_lru*)node; } -static size_t get_node_size(struct fuse *f) +static +size_t +get_node_size(struct fuse *f) { - if (lru_enabled(f)) - return sizeof(struct node_lru); - else - return sizeof(struct node); + if (lru_enabled(f)) + return sizeof(struct node_lru); + else + return sizeof(struct node); } #ifdef FUSE_NODE_SLAB -static struct node_slab *list_to_slab(struct list_head *head) +static +struct node_slab* +list_to_slab(struct list_head *head) { - return (struct node_slab *) head; + return (struct node_slab *) head; } -static struct node_slab *node_to_slab(struct fuse *f, struct node *node) +static +struct node_slab* +node_to_slab(struct fuse *f, struct node *node) { - return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); + return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); } -static int alloc_slab(struct fuse *f) +static +int +alloc_slab(struct fuse *f) { - void *mem; - struct node_slab *slab; - char *start; - size_t num; - size_t i; - size_t node_size = get_node_size(f); + void *mem; + struct node_slab *slab; + char *start; + size_t num; + size_t i; + size_t node_size = get_node_size(f); - mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (mem == MAP_FAILED) - return -1; + if (mem == MAP_FAILED) + return -1; - slab = mem; - init_list_head(&slab->freelist); - slab->used = 0; - num = (f->pagesize - sizeof(struct node_slab)) / node_size; + slab = mem; + init_list_head(&slab->freelist); + slab->used = 0; + num = (f->pagesize - sizeof(struct node_slab)) / node_size; - start = (char *) mem + f->pagesize - num * node_size; - for (i = 0; i < num; i++) { - struct list_head *n; + start = (char *) mem + f->pagesize - num * node_size; + for (i = 0; i < num; i++) { + struct list_head *n; - n = (struct list_head *) (start + i * node_size); - list_add_tail(n, &slab->freelist); - } - list_add_tail(&slab->list, &f->partial_slabs); + n = (struct list_head *) (start + i * node_size); + list_add_tail(n, &slab->freelist); + } + list_add_tail(&slab->list, &f->partial_slabs); - return 0; + return 0; } -static struct node *alloc_node(struct fuse *f) +static +struct node* +alloc_node(struct fuse *f) { - struct node_slab *slab; - struct list_head *node; + struct node_slab *slab; + struct list_head *node; - if (list_empty(&f->partial_slabs)) { - int res = alloc_slab(f); - if (res != 0) - return NULL; - } - slab = list_to_slab(f->partial_slabs.next); - slab->used++; - node = slab->freelist.next; - list_del(node); - if (list_empty(&slab->freelist)) { - list_del(&slab->list); - list_add_tail(&slab->list, &f->full_slabs); - } - memset(node, 0, sizeof(struct node)); + if (list_empty(&f->partial_slabs)) { + int res = alloc_slab(f); + if (res != 0) + return NULL; + } + slab = list_to_slab(f->partial_slabs.next); + slab->used++; + node = slab->freelist.next; + list_del(node); + if (list_empty(&slab->freelist)) { + list_del(&slab->list); + list_add_tail(&slab->list, &f->full_slabs); + } + memset(node, 0, sizeof(struct node)); - return (struct node *) node; + return (struct node *) node; } -static void free_slab(struct fuse *f, struct node_slab *slab) +static +void +free_slab(struct fuse *f, + struct node_slab *slab) { - int res; + int res; - list_del(&slab->list); - res = munmap(slab, f->pagesize); - if (res == -1) - fprintf(stderr, "fuse warning: munmap(%p) failed\n", slab); + list_del(&slab->list); + res = munmap(slab, f->pagesize); + if (res == -1) + fprintf(stderr, "fuse warning: munmap(%p) failed\n", slab); } -static void free_node_mem(struct fuse *f, struct node *node) +static +void +free_node_mem(struct fuse *f, + struct node *node) { - struct node_slab *slab = node_to_slab(f, node); - struct list_head *n = (struct list_head *) node; + struct node_slab *slab = node_to_slab(f, node); + struct list_head *n = (struct list_head *) node; - slab->used--; - if (slab->used) { - if (list_empty(&slab->freelist)) { - list_del(&slab->list); - list_add_tail(&slab->list, &f->partial_slabs); - } - list_add_head(n, &slab->freelist); - } else { - free_slab(f, slab); - } + slab->used--; + if (slab->used) { + if (list_empty(&slab->freelist)) { + list_del(&slab->list); + list_add_tail(&slab->list, &f->partial_slabs); + } + list_add_head(n, &slab->freelist); + } else { + free_slab(f, slab); + } } #else -static struct node *alloc_node(struct fuse *f) +static +struct node* +alloc_node(struct fuse *f) { - return (struct node *) calloc(1, get_node_size(f)); + return (struct node *) calloc(1, get_node_size(f)); } -static void free_node_mem(struct fuse *f, struct node *node) +static +void +free_node_mem(struct fuse *f, + struct node *node) { - (void) f; - free(node); + (void) f; + free(node); } #endif -static size_t id_hash(struct fuse *f, fuse_ino_t ino) +static +size_t +id_hash(struct fuse *f, + fuse_ino_t ino) { - uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; - uint64_t oldhash = hash % (f->id_table.size / 2); + uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; + uint64_t oldhash = hash % (f->id_table.size / 2); - if (oldhash >= f->id_table.split) - return oldhash; - else - return hash; + if (oldhash >= f->id_table.split) + return oldhash; + else + return hash; } -static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) +static +struct node* +get_node_nocheck(struct fuse *f, + fuse_ino_t nodeid) { - size_t hash = id_hash(f, nodeid); - struct node *node; + size_t hash = id_hash(f, nodeid); + struct node *node; - for (node = f->id_table.array[hash]; node != NULL; node = node->id_next) - if (node->nodeid == nodeid) - return node; + for (node = f->id_table.array[hash]; node != NULL; node = node->id_next) + if (node->nodeid == nodeid) + return node; - return NULL; + return NULL; } static @@ -397,22 +457,27 @@ get_node(struct fuse *f, static void curr_time(struct timespec *now); static double diff_timespec(const struct timespec *t1, - const struct timespec *t2); + const struct timespec *t2); -static void remove_node_lru(struct node *node) +static +void +remove_node_lru(struct node *node) { - struct node_lru *lnode = node_lru(node); - list_del(&lnode->lru); - init_list_head(&lnode->lru); + struct node_lru *lnode = node_lru(node); + list_del(&lnode->lru); + init_list_head(&lnode->lru); } -static void set_forget_time(struct fuse *f, struct node *node) +static +void +set_forget_time(struct fuse *f, + struct node *node) { - struct node_lru *lnode = node_lru(node); + struct node_lru *lnode = node_lru(node); - list_del(&lnode->lru); - list_add_tail(&lnode->lru, &f->lru_table); - curr_time(&lnode->forget_time); + list_del(&lnode->lru); + list_add_tail(&lnode->lru, &f->lru_table); + curr_time(&lnode->forget_time); } static @@ -429,268 +494,274 @@ free_node(struct fuse *f_, free_node_mem(f_,node_); } -static void node_table_reduce(struct node_table *t) +static +void +node_table_reduce(struct node_table *t) { - size_t newsize = t->size / 2; - void *newarray; + size_t newsize = t->size / 2; + void *newarray; - if (newsize < NODE_TABLE_MIN_SIZE) - return; + if (newsize < NODE_TABLE_MIN_SIZE) + return; - newarray = realloc(t->array, sizeof(struct node *) * newsize); - if (newarray != NULL) - t->array = newarray; + newarray = realloc(t->array, sizeof(struct node *) * newsize); + if (newarray != NULL) + t->array = newarray; - t->size = newsize; - t->split = t->size / 2; + t->size = newsize; + t->split = t->size / 2; } -static void remerge_id(struct fuse *f) +static +void +remerge_id(struct fuse *f) { - struct node_table *t = &f->id_table; - int iter; + struct node_table *t = &f->id_table; + int iter; - if (t->split == 0) - node_table_reduce(t); + if (t->split == 0) + node_table_reduce(t); - for (iter = 8; t->split > 0 && iter; iter--) { - struct node **upper; + for (iter = 8; t->split > 0 && iter; iter--) { + struct node **upper; - t->split--; - upper = &t->array[t->split + t->size / 2]; - if (*upper) { - struct node **nodep; + t->split--; + upper = &t->array[t->split + t->size / 2]; + if (*upper) { + struct node **nodep; - for (nodep = &t->array[t->split]; *nodep; - nodep = &(*nodep)->id_next); + for (nodep = &t->array[t->split]; *nodep; + nodep = &(*nodep)->id_next); - *nodep = *upper; - *upper = NULL; - break; - } - } + *nodep = *upper; + *upper = NULL; + break; + } + } } -static void unhash_id(struct fuse *f, struct node *node) +static +void +unhash_id(struct fuse *f, struct node *node) { - struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; + struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; - for (; *nodep != NULL; nodep = &(*nodep)->id_next) - if (*nodep == node) { - *nodep = node->id_next; - f->id_table.use--; + for (; *nodep != NULL; nodep = &(*nodep)->id_next) + if (*nodep == node) { + *nodep = node->id_next; + f->id_table.use--; - if(f->id_table.use < f->id_table.size / 4) - remerge_id(f); - return; - } + if(f->id_table.use < f->id_table.size / 4) + remerge_id(f); + return; + } } static int node_table_resize(struct node_table *t) { - size_t newsize = t->size * 2; - void *newarray; + size_t newsize = t->size * 2; + void *newarray; - newarray = realloc(t->array, sizeof(struct node *) * newsize); - if (newarray == NULL) - return -1; + newarray = realloc(t->array, sizeof(struct node *) * newsize); + if (newarray == NULL) + return -1; - t->array = newarray; - memset(t->array + t->size, 0, t->size * sizeof(struct node *)); - t->size = newsize; - t->split = 0; + t->array = newarray; + memset(t->array + t->size, 0, t->size * sizeof(struct node *)); + t->size = newsize; + t->split = 0; - return 0; + return 0; } static void rehash_id(struct fuse *f) { - struct node_table *t = &f->id_table; - struct node **nodep; - struct node **next; - size_t hash; - - if (t->split == t->size / 2) - return; - - hash = t->split; - t->split++; - for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { - struct node *node = *nodep; - size_t newhash = id_hash(f, node->nodeid); - - if (newhash != hash) { - next = nodep; - *nodep = node->id_next; - node->id_next = t->array[newhash]; - t->array[newhash] = node; - } else { - next = &node->id_next; - } - } - if (t->split == t->size / 2) - node_table_resize(t); + struct node_table *t = &f->id_table; + struct node **nodep; + struct node **next; + size_t hash; + + if (t->split == t->size / 2) + return; + + hash = t->split; + t->split++; + for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { + struct node *node = *nodep; + size_t newhash = id_hash(f, node->nodeid); + + if (newhash != hash) { + next = nodep; + *nodep = node->id_next; + node->id_next = t->array[newhash]; + t->array[newhash] = node; + } else { + next = &node->id_next; + } + } + if (t->split == t->size / 2) + node_table_resize(t); } static void hash_id(struct fuse *f, struct node *node) { - size_t hash = id_hash(f, node->nodeid); - node->id_next = f->id_table.array[hash]; - f->id_table.array[hash] = node; - f->id_table.use++; + size_t hash = id_hash(f, node->nodeid); + node->id_next = f->id_table.array[hash]; + f->id_table.array[hash] = node; + f->id_table.use++; - if (f->id_table.use >= f->id_table.size / 2) - rehash_id(f); + if (f->id_table.use >= f->id_table.size / 2) + rehash_id(f); } static size_t name_hash(struct fuse *f, fuse_ino_t parent, const char *name) { - uint64_t hash = parent; - uint64_t oldhash; + uint64_t hash = parent; + uint64_t oldhash; - for (; *name; name++) - hash = hash * 31 + (unsigned char) *name; + for (; *name; name++) + hash = hash * 31 + (unsigned char) *name; - hash %= f->name_table.size; - oldhash = hash % (f->name_table.size / 2); - if (oldhash >= f->name_table.split) - return oldhash; - else - return hash; + hash %= f->name_table.size; + oldhash = hash % (f->name_table.size / 2); + if (oldhash >= f->name_table.split) + return oldhash; + else + return hash; } static void unref_node(struct fuse *f, struct node *node); static void remerge_name(struct fuse *f) { - struct node_table *t = &f->name_table; - int iter; + struct node_table *t = &f->name_table; + int iter; - if (t->split == 0) - node_table_reduce(t); + if (t->split == 0) + node_table_reduce(t); - for (iter = 8; t->split > 0 && iter; iter--) { - struct node **upper; + for (iter = 8; t->split > 0 && iter; iter--) { + struct node **upper; - t->split--; - upper = &t->array[t->split + t->size / 2]; - if (*upper) { - struct node **nodep; + t->split--; + upper = &t->array[t->split + t->size / 2]; + if (*upper) { + struct node **nodep; - for (nodep = &t->array[t->split]; *nodep; - nodep = &(*nodep)->name_next); + for (nodep = &t->array[t->split]; *nodep; + nodep = &(*nodep)->name_next); - *nodep = *upper; - *upper = NULL; - break; - } - } + *nodep = *upper; + *upper = NULL; + break; + } + } } static void unhash_name(struct fuse *f, struct node *node) { - if (node->name) { - size_t hash = name_hash(f, node->parent->nodeid, node->name); - struct node **nodep = &f->name_table.array[hash]; - - for (; *nodep != NULL; nodep = &(*nodep)->name_next) - if (*nodep == node) { - *nodep = node->name_next; - node->name_next = NULL; - unref_node(f, node->parent); - if (node->name != node->inline_name) - free(node->name); - node->name = NULL; - node->parent = NULL; - f->name_table.use--; - - if (f->name_table.use < f->name_table.size / 4) - remerge_name(f); - return; - } - fprintf(stderr, - "fuse internal error: unable to unhash node: %llu\n", - (unsigned long long) node->nodeid); - abort(); - } + if (node->name) { + size_t hash = name_hash(f, node->parent->nodeid, node->name); + struct node **nodep = &f->name_table.array[hash]; + + for (; *nodep != NULL; nodep = &(*nodep)->name_next) + if (*nodep == node) { + *nodep = node->name_next; + node->name_next = NULL; + unref_node(f, node->parent); + if (node->name != node->inline_name) + free(node->name); + node->name = NULL; + node->parent = NULL; + f->name_table.use--; + + if (f->name_table.use < f->name_table.size / 4) + remerge_name(f); + return; + } + fprintf(stderr, + "fuse internal error: unable to unhash node: %llu\n", + (unsigned long long) node->nodeid); + abort(); + } } static void rehash_name(struct fuse *f) { - struct node_table *t = &f->name_table; - struct node **nodep; - struct node **next; - size_t hash; - - if (t->split == t->size / 2) - return; - - hash = t->split; - t->split++; - for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { - struct node *node = *nodep; - size_t newhash = name_hash(f, node->parent->nodeid, node->name); - - if (newhash != hash) { - next = nodep; - *nodep = node->name_next; - node->name_next = t->array[newhash]; - t->array[newhash] = node; - } else { - next = &node->name_next; - } - } - if (t->split == t->size / 2) - node_table_resize(t); + struct node_table *t = &f->name_table; + struct node **nodep; + struct node **next; + size_t hash; + + if (t->split == t->size / 2) + return; + + hash = t->split; + t->split++; + for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { + struct node *node = *nodep; + size_t newhash = name_hash(f, node->parent->nodeid, node->name); + + if (newhash != hash) { + next = nodep; + *nodep = node->name_next; + node->name_next = t->array[newhash]; + t->array[newhash] = node; + } else { + next = &node->name_next; + } + } + if (t->split == t->size / 2) + node_table_resize(t); } static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid, const char *name) { - size_t hash = name_hash(f, parentid, name); - struct node *parent = get_node(f, parentid); - if (strlen(name) < sizeof(node->inline_name)) { - strcpy(node->inline_name, name); - node->name = node->inline_name; - } else { - node->name = strdup(name); - if (node->name == NULL) - return -1; - } + size_t hash = name_hash(f, parentid, name); + struct node *parent = get_node(f, parentid); + if (strlen(name) < sizeof(node->inline_name)) { + strcpy(node->inline_name, name); + node->name = node->inline_name; + } else { + node->name = strdup(name); + if (node->name == NULL) + return -1; + } - parent->refctr ++; - node->parent = parent; - node->name_next = f->name_table.array[hash]; - f->name_table.array[hash] = node; - f->name_table.use++; + parent->refctr ++; + node->parent = parent; + node->name_next = f->name_table.array[hash]; + f->name_table.array[hash] = node; + f->name_table.use++; - if (f->name_table.use >= f->name_table.size / 2) - rehash_name(f); + if (f->name_table.use >= f->name_table.size / 2) + rehash_name(f); - return 0; + return 0; } static void delete_node(struct fuse *f, struct node *node) { - if (f->conf.debug) - fprintf(stderr, "DELETE: %llu\n", - (unsigned long long) node->nodeid); + if (f->conf.debug) + fprintf(stderr, "DELETE: %llu\n", + (unsigned long long) node->nodeid); - assert(node->treelock == 0); - unhash_name(f, node); - if (lru_enabled(f)) - remove_node_lru(node); - unhash_id(f, node); - free_node(f, node); + assert(node->treelock == 0); + unhash_name(f, node); + if (lru_enabled(f)) + remove_node_lru(node); + unhash_id(f, node); + free_node(f, node); } static void unref_node(struct fuse *f, struct node *node) { - assert(node->refctr > 0); - node->refctr --; - if (!node->refctr) - delete_node(f, node); + assert(node->refctr > 0); + node->refctr --; + if (!node->refctr) + delete_node(f, node); } static @@ -725,368 +796,368 @@ next_id(struct fuse *f) static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, const char *name) { - size_t hash = name_hash(f, parent, name); - struct node *node; + size_t hash = name_hash(f, parent, name); + struct node *node; - for (node = f->name_table.array[hash]; node != NULL; node = node->name_next) - if (node->parent->nodeid == parent && - strcmp(node->name, name) == 0) - return node; + for (node = f->name_table.array[hash]; node != NULL; node = node->name_next) + if (node->parent->nodeid == parent && + strcmp(node->name, name) == 0) + return node; - return NULL; + return NULL; } static void inc_nlookup(struct node *node) { - if (!node->nlookup) - node->refctr++; - node->nlookup++; + if (!node->nlookup) + node->refctr++; + node->nlookup++; } static struct node *find_node(struct fuse *f, fuse_ino_t parent, const char *name) { - struct node *node; - - pthread_mutex_lock(&f->lock); - if (!name) - node = get_node(f, parent); - else - node = lookup_node(f, parent, name); - if (node == NULL) { - node = alloc_node(f); - if (node == NULL) - goto out_err; - - node->nodeid = next_id(f); - node->generation = f->generation; - if (f->conf.remember) - inc_nlookup(node); - - if (hash_name(f, node, parent, name) == -1) { - free_node(f, node); - node = NULL; - goto out_err; - } - hash_id(f, node); - if (lru_enabled(f)) { - struct node_lru *lnode = node_lru(node); - init_list_head(&lnode->lru); - } - } else if (lru_enabled(f) && node->nlookup == 1) { - remove_node_lru(node); - } - inc_nlookup(node); -out_err: - pthread_mutex_unlock(&f->lock); - return node; + struct node *node; + + pthread_mutex_lock(&f->lock); + if (!name) + node = get_node(f, parent); + else + node = lookup_node(f, parent, name); + if (node == NULL) { + node = alloc_node(f); + if (node == NULL) + goto out_err; + + node->nodeid = next_id(f); + node->generation = f->generation; + if (f->conf.remember) + inc_nlookup(node); + + if (hash_name(f, node, parent, name) == -1) { + free_node(f, node); + node = NULL; + goto out_err; + } + hash_id(f, node); + if (lru_enabled(f)) { + struct node_lru *lnode = node_lru(node); + init_list_head(&lnode->lru); + } + } else if (lru_enabled(f) && node->nlookup == 1) { + remove_node_lru(node); + } + inc_nlookup(node); + out_err: + pthread_mutex_unlock(&f->lock); + return node; } static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name) { - size_t len = strlen(name); + size_t len = strlen(name); - if (s - len <= *buf) { - unsigned pathlen = *bufsize - (s - *buf); - unsigned newbufsize = *bufsize; - char *newbuf; + if (s - len <= *buf) { + unsigned pathlen = *bufsize - (s - *buf); + unsigned newbufsize = *bufsize; + char *newbuf; - while (newbufsize < pathlen + len + 1) { - if (newbufsize >= 0x80000000) - newbufsize = 0xffffffff; - else - newbufsize *= 2; - } + while (newbufsize < pathlen + len + 1) { + if (newbufsize >= 0x80000000) + newbufsize = 0xffffffff; + else + newbufsize *= 2; + } - newbuf = realloc(*buf, newbufsize); - if (newbuf == NULL) - return NULL; + newbuf = realloc(*buf, newbufsize); + if (newbuf == NULL) + return NULL; - *buf = newbuf; - s = newbuf + newbufsize - pathlen; - memmove(s, newbuf + *bufsize - pathlen, pathlen); - *bufsize = newbufsize; - } - s -= len; - strncpy(s, name, len); - s--; - *s = '/'; + *buf = newbuf; + s = newbuf + newbufsize - pathlen; + memmove(s, newbuf + *bufsize - pathlen, pathlen); + *bufsize = newbufsize; + } + s -= len; + strncpy(s, name, len); + s--; + *s = '/'; - return s; + return s; } static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, struct node *end) { - struct node *node; + struct node *node; - if (wnode) { - assert(wnode->treelock == TREELOCK_WRITE); - wnode->treelock = 0; - } + if (wnode) { + assert(wnode->treelock == TREELOCK_WRITE); + wnode->treelock = 0; + } - for (node = get_node(f, nodeid); - node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) { - assert(node->treelock != 0); - assert(node->treelock != TREELOCK_WAIT_OFFSET); - assert(node->treelock != TREELOCK_WRITE); - node->treelock--; - if (node->treelock == TREELOCK_WAIT_OFFSET) - node->treelock = 0; - } + for (node = get_node(f, nodeid); + node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) { + assert(node->treelock != 0); + assert(node->treelock != TREELOCK_WAIT_OFFSET); + assert(node->treelock != TREELOCK_WRITE); + node->treelock--; + if (node->treelock == TREELOCK_WAIT_OFFSET) + node->treelock = 0; + } } static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnodep, bool need_lock) { - unsigned bufsize = 256; - char *buf; - char *s; - struct node *node; - struct node *wnode = NULL; - int err; - - *path = NULL; - - err = -ENOMEM; - buf = malloc(bufsize); - if (buf == NULL) - goto out_err; - - s = buf + bufsize - 1; - *s = '\0'; - - if (name != NULL) { - s = add_name(&buf, &bufsize, s, name); - err = -ENOMEM; - if (s == NULL) - goto out_free; - } - - if (wnodep) { - assert(need_lock); - wnode = lookup_node(f, nodeid, name); - if (wnode) { - if (wnode->treelock != 0) { - if (wnode->treelock > 0) - wnode->treelock += TREELOCK_WAIT_OFFSET; - err = -EAGAIN; - goto out_free; - } - wnode->treelock = TREELOCK_WRITE; - } - } - - for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; - node = node->parent) { - err = -ENOENT; - if (node->name == NULL || node->parent == NULL) - goto out_unlock; - - err = -ENOMEM; - s = add_name(&buf, &bufsize, s, node->name); - if (s == NULL) - goto out_unlock; - - if (need_lock) { - err = -EAGAIN; - if (node->treelock < 0) - goto out_unlock; - - node->treelock++; - } - } - - if (s[0]) - memmove(buf, s, bufsize - (s - buf)); - else - strcpy(buf, "/"); - - *path = buf; - if (wnodep) - *wnodep = wnode; - - return 0; + unsigned bufsize = 256; + char *buf; + char *s; + struct node *node; + struct node *wnode = NULL; + int err; + + *path = NULL; + + err = -ENOMEM; + buf = malloc(bufsize); + if (buf == NULL) + goto out_err; + + s = buf + bufsize - 1; + *s = '\0'; + + if (name != NULL) { + s = add_name(&buf, &bufsize, s, name); + err = -ENOMEM; + if (s == NULL) + goto out_free; + } + + if (wnodep) { + assert(need_lock); + wnode = lookup_node(f, nodeid, name); + if (wnode) { + if (wnode->treelock != 0) { + if (wnode->treelock > 0) + wnode->treelock += TREELOCK_WAIT_OFFSET; + err = -EAGAIN; + goto out_free; + } + wnode->treelock = TREELOCK_WRITE; + } + } + + for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; + node = node->parent) { + err = -ENOENT; + if (node->name == NULL || node->parent == NULL) + goto out_unlock; + + err = -ENOMEM; + s = add_name(&buf, &bufsize, s, node->name); + if (s == NULL) + goto out_unlock; + + if (need_lock) { + err = -EAGAIN; + if (node->treelock < 0) + goto out_unlock; + + node->treelock++; + } + } + + if (s[0]) + memmove(buf, s, bufsize - (s - buf)); + else + strcpy(buf, "/"); + + *path = buf; + if (wnodep) + *wnodep = wnode; + + return 0; out_unlock: - if (need_lock) - unlock_path(f, nodeid, wnode, node); + if (need_lock) + unlock_path(f, nodeid, wnode, node); out_free: - free(buf); + free(buf); out_err: - return err; + return err; } static void queue_element_unlock(struct fuse *f, struct lock_queue_element *qe) { - struct node *wnode; + struct node *wnode; - if (qe->first_locked) { - wnode = qe->wnode1 ? *qe->wnode1 : NULL; - unlock_path(f, qe->nodeid1, wnode, NULL); - qe->first_locked = false; - } - if (qe->second_locked) { - wnode = qe->wnode2 ? *qe->wnode2 : NULL; - unlock_path(f, qe->nodeid2, wnode, NULL); - qe->second_locked = false; - } + if (qe->first_locked) { + wnode = qe->wnode1 ? *qe->wnode1 : NULL; + unlock_path(f, qe->nodeid1, wnode, NULL); + qe->first_locked = false; + } + if (qe->second_locked) { + wnode = qe->wnode2 ? *qe->wnode2 : NULL; + unlock_path(f, qe->nodeid2, wnode, NULL); + qe->second_locked = false; + } } static void queue_element_wakeup(struct fuse *f, struct lock_queue_element *qe) { - int err; - bool first = (qe == f->lockq); - - if (!qe->path1) { - /* Just waiting for it to be unlocked */ - if (get_node(f, qe->nodeid1)->treelock == 0) - pthread_cond_signal(&qe->cond); - - return; - } - - if (!qe->first_locked) { - err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1, - qe->wnode1, true); - if (!err) - qe->first_locked = true; - else if (err != -EAGAIN) - goto err_unlock; - } - if (!qe->second_locked && qe->path2) { - err = try_get_path(f, qe->nodeid2, qe->name2, qe->path2, - qe->wnode2, true); - if (!err) - qe->second_locked = true; - else if (err != -EAGAIN) - goto err_unlock; - } - - if (qe->first_locked && (qe->second_locked || !qe->path2)) { - err = 0; - goto done; - } - - /* - * Only let the first element be partially locked otherwise there could - * be a deadlock. - * - * But do allow the first element to be partially locked to prevent - * starvation. - */ - if (!first) - queue_element_unlock(f, qe); - - /* keep trying */ - return; - -err_unlock: - queue_element_unlock(f, qe); -done: - qe->err = err; - qe->done = true; - pthread_cond_signal(&qe->cond); + int err; + bool first = (qe == f->lockq); + + if (!qe->path1) { + /* Just waiting for it to be unlocked */ + if (get_node(f, qe->nodeid1)->treelock == 0) + pthread_cond_signal(&qe->cond); + + return; + } + + if (!qe->first_locked) { + err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1, + qe->wnode1, true); + if (!err) + qe->first_locked = true; + else if (err != -EAGAIN) + goto err_unlock; + } + if (!qe->second_locked && qe->path2) { + err = try_get_path(f, qe->nodeid2, qe->name2, qe->path2, + qe->wnode2, true); + if (!err) + qe->second_locked = true; + else if (err != -EAGAIN) + goto err_unlock; + } + + if (qe->first_locked && (qe->second_locked || !qe->path2)) { + err = 0; + goto done; + } + + /* + * Only let the first element be partially locked otherwise there could + * be a deadlock. + * + * But do allow the first element to be partially locked to prevent + * starvation. + */ + if (!first) + queue_element_unlock(f, qe); + + /* keep trying */ + return; + + err_unlock: + queue_element_unlock(f, qe); + done: + qe->err = err; + qe->done = true; + pthread_cond_signal(&qe->cond); } static void wake_up_queued(struct fuse *f) { - struct lock_queue_element *qe; + struct lock_queue_element *qe; - for (qe = f->lockq; qe != NULL; qe = qe->next) - queue_element_wakeup(f, qe); + for (qe = f->lockq; qe != NULL; qe = qe->next) + queue_element_wakeup(f, qe); } static void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid, const char *name, bool wr) { - if (f->conf.debug) { - struct node *wnode = NULL; + if (f->conf.debug) { + struct node *wnode = NULL; - if (wr) - wnode = lookup_node(f, nodeid, name); + if (wr) + wnode = lookup_node(f, nodeid, name); - if (wnode) - fprintf(stderr, "%s %li (w)\n", msg, wnode->nodeid); - else - fprintf(stderr, "%s %li\n", msg, nodeid); - } + if (wnode) + fprintf(stderr, "%s %li (w)\n", msg, wnode->nodeid); + else + fprintf(stderr, "%s %li\n", msg, nodeid); + } } static void queue_path(struct fuse *f, struct lock_queue_element *qe) { - struct lock_queue_element **qp; + struct lock_queue_element **qp; - qe->done = false; - qe->first_locked = false; - qe->second_locked = false; - pthread_cond_init(&qe->cond, NULL); - qe->next = NULL; - for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next); - *qp = qe; + qe->done = false; + qe->first_locked = false; + qe->second_locked = false; + pthread_cond_init(&qe->cond, NULL); + qe->next = NULL; + for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next); + *qp = qe; } static void dequeue_path(struct fuse *f, struct lock_queue_element *qe) { - struct lock_queue_element **qp; + struct lock_queue_element **qp; - pthread_cond_destroy(&qe->cond); - for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next); - *qp = qe->next; + pthread_cond_destroy(&qe->cond); + for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next); + *qp = qe->next; } static int wait_path(struct fuse *f, struct lock_queue_element *qe) { - queue_path(f, qe); + queue_path(f, qe); - do { - pthread_cond_wait(&qe->cond, &f->lock); - } while (!qe->done); + do { + pthread_cond_wait(&qe->cond, &f->lock); + } while (!qe->done); - dequeue_path(f, qe); + dequeue_path(f, qe); - return qe->err; + return qe->err; } static int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnode) { - int err; + int err; - pthread_mutex_lock(&f->lock); - err = try_get_path(f, nodeid, name, path, wnode, true); - if (err == -EAGAIN) { - struct lock_queue_element qe = { - .nodeid1 = nodeid, - .name1 = name, - .path1 = path, - .wnode1 = wnode, - }; - debug_path(f, "QUEUE PATH", nodeid, name, !!wnode); - err = wait_path(f, &qe); - debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode); - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + err = try_get_path(f, nodeid, name, path, wnode, true); + if (err == -EAGAIN) { + struct lock_queue_element qe = { + .nodeid1 = nodeid, + .name1 = name, + .path1 = path, + .wnode1 = wnode, + }; + debug_path(f, "QUEUE PATH", nodeid, name, !!wnode); + err = wait_path(f, &qe); + debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode); + } + pthread_mutex_unlock(&f->lock); - return err; + return err; } static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path) { - return get_path_common(f, nodeid, NULL, path, NULL); + return get_path_common(f, nodeid, NULL, path, NULL); } static int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path) { - return get_path_common(f, nodeid, name, path, NULL); + return get_path_common(f, nodeid, name, path, NULL); } static int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnode) { - return get_path_common(f, nodeid, name, path, wnode); + return get_path_common(f, nodeid, name, path, wnode); } static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, @@ -1094,20 +1165,20 @@ static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, char **path1, char **path2, struct node **wnode1, struct node **wnode2) { - int err; + int err; - /* FIXME: locking two paths needs deadlock checking */ - err = try_get_path(f, nodeid1, name1, path1, wnode1, true); - if (!err) { - err = try_get_path(f, nodeid2, name2, path2, wnode2, true); - if (err) { - struct node *wn1 = wnode1 ? *wnode1 : NULL; + /* FIXME: locking two paths needs deadlock checking */ + err = try_get_path(f, nodeid1, name1, path1, wnode1, true); + if (!err) { + err = try_get_path(f, nodeid2, name2, path2, wnode2, true); + if (err) { + struct node *wn1 = wnode1 ? *wnode1 : NULL; - unlock_path(f, nodeid1, wn1, NULL); - free(*path1); - } - } - return err; + unlock_path(f, nodeid1, wn1, NULL); + free(*path1); + } + } + return err; } static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, @@ -1115,62 +1186,62 @@ static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, char **path1, char **path2, struct node **wnode1, struct node **wnode2) { - int err; - - pthread_mutex_lock(&f->lock); - err = try_get_path2(f, nodeid1, name1, nodeid2, name2, - path1, path2, wnode1, wnode2); - if (err == -EAGAIN) { - struct lock_queue_element qe = { - .nodeid1 = nodeid1, - .name1 = name1, - .path1 = path1, - .wnode1 = wnode1, - .nodeid2 = nodeid2, - .name2 = name2, - .path2 = path2, - .wnode2 = wnode2, - }; - - debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1); - debug_path(f, " PATH2", nodeid2, name2, !!wnode2); - err = wait_path(f, &qe); - debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1); - debug_path(f, " PATH2", nodeid2, name2, !!wnode2); - } - pthread_mutex_unlock(&f->lock); - - return err; + int err; + + pthread_mutex_lock(&f->lock); + err = try_get_path2(f, nodeid1, name1, nodeid2, name2, + path1, path2, wnode1, wnode2); + if (err == -EAGAIN) { + struct lock_queue_element qe = { + .nodeid1 = nodeid1, + .name1 = name1, + .path1 = path1, + .wnode1 = wnode1, + .nodeid2 = nodeid2, + .name2 = name2, + .path2 = path2, + .wnode2 = wnode2, + }; + + debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1); + debug_path(f, " PATH2", nodeid2, name2, !!wnode2); + err = wait_path(f, &qe); + debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1); + debug_path(f, " PATH2", nodeid2, name2, !!wnode2); + } + pthread_mutex_unlock(&f->lock); + + return err; } static void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, char *path) { - pthread_mutex_lock(&f->lock); - unlock_path(f, nodeid, wnode, NULL); - if (f->lockq) - wake_up_queued(f); - pthread_mutex_unlock(&f->lock); - free(path); + pthread_mutex_lock(&f->lock); + unlock_path(f, nodeid, wnode, NULL); + if (f->lockq) + wake_up_queued(f); + pthread_mutex_unlock(&f->lock); + free(path); } static void free_path(struct fuse *f, fuse_ino_t nodeid, char *path) { - if (path) - free_path_wrlock(f, nodeid, NULL, path); + if (path) + free_path_wrlock(f, nodeid, NULL, path); } static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2, struct node *wnode1, struct node *wnode2, char *path1, char *path2) { - pthread_mutex_lock(&f->lock); - unlock_path(f, nodeid1, wnode1, NULL); - unlock_path(f, nodeid2, wnode2, NULL); - wake_up_queued(f); - pthread_mutex_unlock(&f->lock); - free(path1); - free(path2); + pthread_mutex_lock(&f->lock); + unlock_path(f, nodeid1, wnode1, NULL); + unlock_path(f, nodeid2, wnode2, NULL); + wake_up_queued(f); + pthread_mutex_unlock(&f->lock); + free(path1); + free(path2); } static @@ -1222,135 +1293,135 @@ forget_node(struct fuse *f, static void unlink_node(struct fuse *f, struct node *node) { - if (f->conf.remember) { - assert(node->nlookup > 1); - node->nlookup--; - } - unhash_name(f, node); + if (f->conf.remember) { + assert(node->nlookup > 1); + node->nlookup--; + } + unhash_name(f, node); } static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name) { - struct node *node; + struct node *node; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, name); - if (node != NULL) - unlink_node(f, node); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node != NULL) + unlink_node(f, node); + pthread_mutex_unlock(&f->lock); } static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, fuse_ino_t newdir, const char *newname) { - struct node *node; - struct node *newnode; - int err = 0; + struct node *node; + struct node *newnode; + int err = 0; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, olddir, oldname); - newnode = lookup_node(f, newdir, newname); - if (node == NULL) - goto out; + pthread_mutex_lock(&f->lock); + node = lookup_node(f, olddir, oldname); + newnode = lookup_node(f, newdir, newname); + if (node == NULL) + goto out; - if (newnode != NULL) - unlink_node(f, newnode); + if (newnode != NULL) + unlink_node(f, newnode); - unhash_name(f, node); - if (hash_name(f, node, newdir, newname) == -1) { - err = -ENOMEM; - goto out; - } + unhash_name(f, node); + if (hash_name(f, node, newdir, newname) == -1) { + err = -ENOMEM; + goto out; + } -out: - pthread_mutex_unlock(&f->lock); - return err; + out: + pthread_mutex_unlock(&f->lock); + return err; } static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf) { - if (!f->conf.use_ino) - stbuf->st_ino = nodeid; - if (f->conf.set_mode) - stbuf->st_mode = (stbuf->st_mode & S_IFMT) | - (0777 & ~f->conf.umask); - if (f->conf.set_uid) - stbuf->st_uid = f->conf.uid; - if (f->conf.set_gid) - stbuf->st_gid = f->conf.gid; + if (!f->conf.use_ino) + stbuf->st_ino = nodeid; + if (f->conf.set_mode) + stbuf->st_mode = (stbuf->st_mode & S_IFMT) | + (0777 & ~f->conf.umask); + if (f->conf.set_uid) + stbuf->st_uid = f->conf.uid; + if (f->conf.set_gid) + stbuf->st_gid = f->conf.gid; } static struct fuse *req_fuse(fuse_req_t req) { - return (struct fuse *) fuse_req_userdata(req); + return (struct fuse *) fuse_req_userdata(req); } static void fuse_intr_sighandler(int sig) { - (void) sig; - /* Nothing to do */ + (void) sig; + /* Nothing to do */ } struct fuse_intr_data { - pthread_t id; - pthread_cond_t cond; - int finished; + pthread_t id; + pthread_cond_t cond; + int finished; }; static void fuse_interrupt(fuse_req_t req, void *d_) { - struct fuse_intr_data *d = d_; - struct fuse *f = req_fuse(req); - - if (d->id == pthread_self()) - return; + struct fuse_intr_data *d = d_; + struct fuse *f = req_fuse(req); - pthread_mutex_lock(&f->lock); - while (!d->finished) { - struct timeval now; - struct timespec timeout; + if (d->id == pthread_self()) + return; - pthread_kill(d->id, f->conf.intr_signal); - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec + 1; - timeout.tv_nsec = now.tv_usec * 1000; - pthread_cond_timedwait(&d->cond, &f->lock, &timeout); - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + while (!d->finished) { + struct timeval now; + struct timespec timeout; + + pthread_kill(d->id, f->conf.intr_signal); + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec + 1; + timeout.tv_nsec = now.tv_usec * 1000; + pthread_cond_timedwait(&d->cond, &f->lock, &timeout); + } + pthread_mutex_unlock(&f->lock); } static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { - pthread_mutex_lock(&f->lock); - d->finished = 1; - pthread_cond_broadcast(&d->cond); - pthread_mutex_unlock(&f->lock); - fuse_req_interrupt_func(req, NULL, NULL); - pthread_cond_destroy(&d->cond); + pthread_mutex_lock(&f->lock); + d->finished = 1; + pthread_cond_broadcast(&d->cond); + pthread_mutex_unlock(&f->lock); + fuse_req_interrupt_func(req, NULL, NULL); + pthread_cond_destroy(&d->cond); } static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d) { - d->id = pthread_self(); - pthread_cond_init(&d->cond, NULL); - d->finished = 0; - fuse_req_interrupt_func(req, fuse_interrupt, d); + d->id = pthread_self(); + pthread_cond_init(&d->cond, NULL); + d->finished = 0; + fuse_req_interrupt_func(req, fuse_interrupt, d); } static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_finish_interrupt(f, req, d); + if (f->conf.intr) + fuse_do_finish_interrupt(f, req, d); } static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_prepare_interrupt(req, d); + if (f->conf.intr) + fuse_do_prepare_interrupt(req, d); } #if !defined(__FreeBSD__) && !defined(__NetBSD__) @@ -1358,93 +1429,93 @@ static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, static int fuse_compat_open(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - int err; - if (!fs->compat || fs->compat >= 25) - err = fs->op.open(path, fi); - else if (fs->compat == 22) { - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op)->open(path,&tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - } else - err = ((struct fuse_operations_compat2 *) &fs->op) - ->open(path, fi->flags); - return err; + int err; + if (!fs->compat || fs->compat >= 25) + err = fs->op.open(path, fi); + else if (fs->compat == 22) { + struct fuse_file_info_compat tmp; + memcpy(&tmp, fi, sizeof(tmp)); + err = ((struct fuse_operations_compat22 *) &fs->op)->open(path,&tmp); + memcpy(fi, &tmp, sizeof(tmp)); + fi->fh = tmp.fh; + } else + err = ((struct fuse_operations_compat2 *) &fs->op) + ->open(path, fi->flags); + return err; } static int fuse_compat_release(struct fuse_fs *fs, struct fuse_file_info *fi) { - if (!fs->compat || fs->compat >= 22) - return fs->op.release(fi); - else - return ((struct fuse_operations_compat2 *) &fs->op) - ->release(NULL, fi->flags); + if (!fs->compat || fs->compat >= 22) + return fs->op.release(fi); + else + return ((struct fuse_operations_compat2 *) &fs->op) + ->release(NULL, fi->flags); } static int fuse_compat_opendir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - if (!fs->compat || fs->compat >= 25) - return fs->op.opendir(path, fi); - else { - int err; - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op) - ->opendir(path, &tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - return err; - } + if (!fs->compat || fs->compat >= 25) + return fs->op.opendir(path, fi); + else { + int err; + struct fuse_file_info_compat tmp; + memcpy(&tmp, fi, sizeof(tmp)); + err = ((struct fuse_operations_compat22 *) &fs->op) + ->opendir(path, &tmp); + memcpy(fi, &tmp, sizeof(tmp)); + fi->fh = tmp.fh; + return err; + } } static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf, struct statvfs *stbuf) { - stbuf->f_bsize = compatbuf->block_size; - stbuf->f_blocks = compatbuf->blocks; - stbuf->f_bfree = compatbuf->blocks_free; - stbuf->f_bavail = compatbuf->blocks_free; - stbuf->f_files = compatbuf->files; - stbuf->f_ffree = compatbuf->files_free; - stbuf->f_namemax = compatbuf->namelen; + stbuf->f_bsize = compatbuf->block_size; + stbuf->f_blocks = compatbuf->blocks; + stbuf->f_bfree = compatbuf->blocks_free; + stbuf->f_bavail = compatbuf->blocks_free; + stbuf->f_files = compatbuf->files; + stbuf->f_ffree = compatbuf->files_free; + stbuf->f_namemax = compatbuf->namelen; } static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf) { - stbuf->f_bsize = oldbuf->f_bsize; - stbuf->f_blocks = oldbuf->f_blocks; - stbuf->f_bfree = oldbuf->f_bfree; - stbuf->f_bavail = oldbuf->f_bavail; - stbuf->f_files = oldbuf->f_files; - stbuf->f_ffree = oldbuf->f_ffree; - stbuf->f_namemax = oldbuf->f_namelen; + stbuf->f_bsize = oldbuf->f_bsize; + stbuf->f_blocks = oldbuf->f_blocks; + stbuf->f_bfree = oldbuf->f_bfree; + stbuf->f_bavail = oldbuf->f_bavail; + stbuf->f_files = oldbuf->f_files; + stbuf->f_ffree = oldbuf->f_ffree; + stbuf->f_namemax = oldbuf->f_namelen; } static int fuse_compat_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) { - int err; - - if (!fs->compat || fs->compat >= 25) { - err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf); - } else if (fs->compat > 11) { - struct statfs oldbuf; - err = ((struct fuse_operations_compat22 *) &fs->op) - ->statfs("/", &oldbuf); - if (!err) - convert_statfs_old(&oldbuf, buf); - } else { - struct fuse_statfs_compat1 compatbuf; - memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); - err = ((struct fuse_operations_compat1 *) &fs->op) - ->statfs(&compatbuf); - if (!err) - convert_statfs_compat(&compatbuf, buf); - } - return err; + int err; + + if (!fs->compat || fs->compat >= 25) { + err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf); + } else if (fs->compat > 11) { + struct statfs oldbuf; + err = ((struct fuse_operations_compat22 *) &fs->op) + ->statfs("/", &oldbuf); + if (!err) + convert_statfs_old(&oldbuf, buf); + } else { + struct fuse_statfs_compat1 compatbuf; + memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); + err = ((struct fuse_operations_compat1 *) &fs->op) + ->statfs(&compatbuf); + if (!err) + convert_statfs_compat(&compatbuf, buf); + } + return err; } #else /* __FreeBSD__ || __NetBSD__ */ @@ -1452,25 +1523,25 @@ static int fuse_compat_statfs(struct fuse_fs *fs, const char *path, static inline int fuse_compat_open(struct fuse_fs *fs, char *path, struct fuse_file_info *fi) { - return fs->op.open(path, fi); + return fs->op.open(path, fi); } static inline int fuse_compat_release(struct fuse_fs *fs, struct fuse_file_info *fi) { - return fs->op.release(fi); + return fs->op.release(fi); } static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - return fs->op.opendir(path, fi); + return fs->op.opendir(path, fi); } static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) { - return fs->op.statfs(fs->compat == 25 ? "/" : path, buf); + return fs->op.statfs(fs->compat == 25 ? "/" : path, buf); } #endif /* __FreeBSD__ || __NetBSD__ */ @@ -1548,349 +1619,349 @@ fuse_fs_free_hide(struct fuse_fs *fs_, int fuse_fs_unlink(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.unlink) { - if (fs->debug) - fprintf(stderr, "unlink %s\n", path); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.unlink) { + if (fs->debug) + fprintf(stderr, "unlink %s\n", path); - return fs->op.unlink(path); - } else { - return -ENOSYS; - } + return fs->op.unlink(path); + } else { + return -ENOSYS; + } } int fuse_fs_rmdir(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.rmdir) { - if (fs->debug) - fprintf(stderr, "rmdir %s\n", path); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rmdir) { + if (fs->debug) + fprintf(stderr, "rmdir %s\n", path); - return fs->op.rmdir(path); - } else { - return -ENOSYS; - } + return fs->op.rmdir(path); + } else { + return -ENOSYS; + } } int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.symlink) { - if (fs->debug) - fprintf(stderr, "symlink %s %s\n", linkname, path); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.symlink) { + if (fs->debug) + fprintf(stderr, "symlink %s %s\n", linkname, path); - return fs->op.symlink(linkname, path); - } else { - return -ENOSYS; - } + return fs->op.symlink(linkname, path); + } else { + return -ENOSYS; + } } int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.link) { - if (fs->debug) - fprintf(stderr, "link %s %s\n", oldpath, newpath); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.link) { + if (fs->debug) + fprintf(stderr, "link %s %s\n", oldpath, newpath); - return fs->op.link(oldpath, newpath); - } else { - return -ENOSYS; - } + return fs->op.link(oldpath, newpath); + } else { + return -ENOSYS; + } } int fuse_fs_release(struct fuse_fs *fs, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.release) { - if (fs->debug) - fprintf(stderr, "release%s[%llu] flags: 0x%x\n", - fi->flush ? "+flush" : "", - (unsigned long long) fi->fh, fi->flags); - - return fuse_compat_release(fs, fi); - } else { - return 0; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.release) { + if (fs->debug) + fprintf(stderr, "release%s[%llu] flags: 0x%x\n", + fi->flush ? "+flush" : "", + (unsigned long long) fi->fh, fi->flags); + + return fuse_compat_release(fs, fi); + } else { + return 0; + } } int fuse_fs_opendir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.opendir) { - int err; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.opendir) { + int err; - if (fs->debug) - fprintf(stderr, "opendir flags: 0x%x %s\n", fi->flags, - path); + if (fs->debug) + fprintf(stderr, "opendir flags: 0x%x %s\n", fi->flags, + path); - err = fuse_compat_opendir(fs, path, fi); + err = fuse_compat_opendir(fs, path, fi); - if (fs->debug && !err) - fprintf(stderr, " opendir[%lli] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); + if (fs->debug && !err) + fprintf(stderr, " opendir[%lli] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); - return err; - } else { - return 0; - } + return err; + } else { + return 0; + } } int fuse_fs_open(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.open) { - int err; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.open) { + int err; - if (fs->debug) - fprintf(stderr, "open flags: 0x%x %s\n", fi->flags, - path); + if (fs->debug) + fprintf(stderr, "open flags: 0x%x %s\n", fi->flags, + path); - err = fuse_compat_open(fs, path, fi); + err = fuse_compat_open(fs, path, fi); - if (fs->debug && !err) - fprintf(stderr, " open[%lli] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); + if (fs->debug && !err) + fprintf(stderr, " open[%lli] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); - return err; - } else { - return 0; - } + return err; + } else { + return 0; + } } static void fuse_free_buf(struct fuse_bufvec *buf) { - if (buf != NULL) { - size_t i; + if (buf != NULL) { + size_t i; - for (i = 0; i < buf->count; i++) - free(buf->buf[i].mem); - free(buf); - } + for (i = 0; i < buf->count; i++) + free(buf->buf[i].mem); + free(buf); + } } int fuse_fs_read_buf(struct fuse_fs *fs, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.read || fs->op.read_buf) { - int res; - - if (fs->debug) - fprintf(stderr, - "read[%llu] %zu bytes from %llu flags: 0x%x\n", - (unsigned long long) fi->fh, - size, (unsigned long long) off, fi->flags); - - if (fs->op.read_buf) { - res = fs->op.read_buf(bufp, size, off, fi); - } else { - struct fuse_bufvec *buf; - void *mem; - - buf = malloc(sizeof(struct fuse_bufvec)); - if (buf == NULL) - return -ENOMEM; - - mem = malloc(size); - if (mem == NULL) { - free(buf); - return -ENOMEM; - } - *buf = FUSE_BUFVEC_INIT(size); - buf->buf[0].mem = mem; - *bufp = buf; - - res = fs->op.read(mem, size, off, fi); - if (res >= 0) - buf->buf[0].size = res; - } - - if (fs->debug && res >= 0) - fprintf(stderr, " read[%llu] %zu bytes from %llu\n", - (unsigned long long) fi->fh, - fuse_buf_size(*bufp), - (unsigned long long) off); - if (res >= 0 && fuse_buf_size(*bufp) > (int) size) - fprintf(stderr, "fuse: read too many bytes\n"); - - if (res < 0) - return res; - - return 0; - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.read || fs->op.read_buf) { + int res; + + if (fs->debug) + fprintf(stderr, + "read[%llu] %zu bytes from %llu flags: 0x%x\n", + (unsigned long long) fi->fh, + size, (unsigned long long) off, fi->flags); + + if (fs->op.read_buf) { + res = fs->op.read_buf(bufp, size, off, fi); + } else { + struct fuse_bufvec *buf; + void *mem; + + buf = malloc(sizeof(struct fuse_bufvec)); + if (buf == NULL) + return -ENOMEM; + + mem = malloc(size); + if (mem == NULL) { + free(buf); + return -ENOMEM; + } + *buf = FUSE_BUFVEC_INIT(size); + buf->buf[0].mem = mem; + *bufp = buf; + + res = fs->op.read(mem, size, off, fi); + if (res >= 0) + buf->buf[0].size = res; + } + + if (fs->debug && res >= 0) + fprintf(stderr, " read[%llu] %zu bytes from %llu\n", + (unsigned long long) fi->fh, + fuse_buf_size(*bufp), + (unsigned long long) off); + if (res >= 0 && fuse_buf_size(*bufp) > (int) size) + fprintf(stderr, "fuse: read too many bytes\n"); + + if (res < 0) + return res; + + return 0; + } else { + return -ENOSYS; + } } int fuse_fs_read(struct fuse_fs *fs, char *mem, size_t size, off_t off, struct fuse_file_info *fi) { - int res; - struct fuse_bufvec *buf = NULL; + int res; + struct fuse_bufvec *buf = NULL; - res = fuse_fs_read_buf(fs, &buf, size, off, fi); - if (res == 0) { - struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size); + res = fuse_fs_read_buf(fs, &buf, size, off, fi); + if (res == 0) { + struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size); - dst.buf[0].mem = mem; - res = fuse_buf_copy(&dst, buf, 0); - } - fuse_free_buf(buf); + dst.buf[0].mem = mem; + res = fuse_buf_copy(&dst, buf, 0); + } + fuse_free_buf(buf); - return res; + return res; } int fuse_fs_write_buf(struct fuse_fs *fs, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.write_buf || fs->op.write) { - int res; - size_t size = fuse_buf_size(buf); - - assert(buf->idx == 0 && buf->off == 0); - if (fs->debug) - fprintf(stderr, - "write%s[%llu] %zu bytes to %llu flags: 0x%x\n", - fi->writepage ? "page" : "", - (unsigned long long) fi->fh, - size, - (unsigned long long) off, - fi->flags); - - if (fs->op.write_buf) { - res = fs->op.write_buf(buf, off, fi); - } else { - void *mem = NULL; - struct fuse_buf *flatbuf; - struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size); - - if (buf->count == 1 && - !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { - flatbuf = &buf->buf[0]; - } else { - res = -ENOMEM; - mem = malloc(size); - if (mem == NULL) - goto out; - - tmp.buf[0].mem = mem; - res = fuse_buf_copy(&tmp, buf, 0); - if (res <= 0) - goto out_free; - - tmp.buf[0].size = res; - flatbuf = &tmp.buf[0]; - } - - res = fs->op.write(flatbuf->mem, flatbuf->size, - off, fi); -out_free: - free(mem); - } -out: - if (fs->debug && res >= 0) - fprintf(stderr, " write%s[%llu] %u bytes to %llu\n", - fi->writepage ? "page" : "", - (unsigned long long) fi->fh, res, - (unsigned long long) off); - if (res > (int) size) - fprintf(stderr, "fuse: wrote too many bytes\n"); - - return res; - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.write_buf || fs->op.write) { + int res; + size_t size = fuse_buf_size(buf); + + assert(buf->idx == 0 && buf->off == 0); + if (fs->debug) + fprintf(stderr, + "write%s[%llu] %zu bytes to %llu flags: 0x%x\n", + fi->writepage ? "page" : "", + (unsigned long long) fi->fh, + size, + (unsigned long long) off, + fi->flags); + + if (fs->op.write_buf) { + res = fs->op.write_buf(buf, off, fi); + } else { + void *mem = NULL; + struct fuse_buf *flatbuf; + struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size); + + if (buf->count == 1 && + !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { + flatbuf = &buf->buf[0]; + } else { + res = -ENOMEM; + mem = malloc(size); + if (mem == NULL) + goto out; + + tmp.buf[0].mem = mem; + res = fuse_buf_copy(&tmp, buf, 0); + if (res <= 0) + goto out_free; + + tmp.buf[0].size = res; + flatbuf = &tmp.buf[0]; + } + + res = fs->op.write(flatbuf->mem, flatbuf->size, + off, fi); + out_free: + free(mem); + } + out: + if (fs->debug && res >= 0) + fprintf(stderr, " write%s[%llu] %u bytes to %llu\n", + fi->writepage ? "page" : "", + (unsigned long long) fi->fh, res, + (unsigned long long) off); + if (res > (int) size) + fprintf(stderr, "fuse: wrote too many bytes\n"); + + return res; + } else { + return -ENOSYS; + } } int fuse_fs_write(struct fuse_fs *fs, const char *mem, size_t size, off_t off, struct fuse_file_info *fi) { - struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size); + struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size); - bufv.buf[0].mem = (void *) mem; + bufv.buf[0].mem = (void *) mem; - return fuse_fs_write_buf(fs, &bufv, off, fi); + return fuse_fs_write_buf(fs, &bufv, off, fi); } int fuse_fs_fsync(struct fuse_fs *fs, int datasync, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsync) { - if (fs->debug) - fprintf(stderr, "fsync[%llu] datasync: %i\n", - (unsigned long long) fi->fh, datasync); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsync) { + if (fs->debug) + fprintf(stderr, "fsync[%llu] datasync: %i\n", + (unsigned long long) fi->fh, datasync); - return fs->op.fsync(datasync, fi); - } else { - return -ENOSYS; - } + return fs->op.fsync(datasync, fi); + } else { + return -ENOSYS; + } } int fuse_fs_fsyncdir(struct fuse_fs *fs, int datasync, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsyncdir) { - if (fs->debug) - fprintf(stderr, "fsyncdir[%llu] datasync: %i\n", - (unsigned long long) fi->fh, datasync); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsyncdir) { + if (fs->debug) + fprintf(stderr, "fsyncdir[%llu] datasync: %i\n", + (unsigned long long) fi->fh, datasync); - return fs->op.fsyncdir(datasync, fi); - } else { - return -ENOSYS; - } + return fs->op.fsyncdir(datasync, fi); + } else { + return -ENOSYS; + } } int fuse_fs_flush(struct fuse_fs *fs, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.flush) { - if (fs->debug) - fprintf(stderr, "flush[%llu]\n", - (unsigned long long) fi->fh); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.flush) { + if (fs->debug) + fprintf(stderr, "flush[%llu]\n", + (unsigned long long) fi->fh); - return fs->op.flush(fi); - } else { - return -ENOSYS; - } + return fs->op.flush(fi); + } else { + return -ENOSYS; + } } int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.statfs) { - if (fs->debug) - fprintf(stderr, "statfs %s\n", path); - - return fuse_compat_statfs(fs, path, buf); - } else { - buf->f_namemax = 255; - buf->f_bsize = 512; - return 0; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.statfs) { + if (fs->debug) + fprintf(stderr, "statfs %s\n", path); + + return fuse_compat_statfs(fs, path, buf); + } else { + buf->f_namemax = 255; + buf->f_bsize = 512; + return 0; + } } int fuse_fs_releasedir(struct fuse_fs *fs, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.releasedir) { - if (fs->debug) - fprintf(stderr, "releasedir[%llu] flags: 0x%x\n", - (unsigned long long) fi->fh, fi->flags); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.releasedir) { + if (fs->debug) + fprintf(stderr, "releasedir[%llu] flags: 0x%x\n", + (unsigned long long) fi->fh, fi->flags); - return fs->op.releasedir(fi); - } else { - return 0; - } + return fs->op.releasedir(fi); + } else { + return 0; + } } int @@ -1922,86 +1993,86 @@ fuse_fs_readdir_plus(struct fuse_fs *fs_, int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.create) { - int err; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.create) { + int err; - if (fs->debug) - fprintf(stderr, - "create flags: 0x%x %s 0%o umask=0%03o\n", - fi->flags, path, mode, - fuse_get_context()->umask); + if (fs->debug) + fprintf(stderr, + "create flags: 0x%x %s 0%o umask=0%03o\n", + fi->flags, path, mode, + fuse_get_context()->umask); - err = fs->op.create(path, mode, fi); + err = fs->op.create(path, mode, fi); - if (fs->debug && !err) - fprintf(stderr, " create[%llu] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); + if (fs->debug && !err) + fprintf(stderr, " create[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); - return err; - } else { - return -ENOSYS; - } + return err; + } else { + return -ENOSYS; + } } int fuse_fs_lock(struct fuse_fs *fs, struct fuse_file_info *fi, int cmd, struct flock *lock) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.lock) { - if (fs->debug) - fprintf(stderr, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n", - (unsigned long long) fi->fh, - (cmd == F_GETLK ? "F_GETLK" : - (cmd == F_SETLK ? "F_SETLK" : - (cmd == F_SETLKW ? "F_SETLKW" : "???"))), - (lock->l_type == F_RDLCK ? "F_RDLCK" : - (lock->l_type == F_WRLCK ? "F_WRLCK" : - (lock->l_type == F_UNLCK ? "F_UNLCK" : - "???"))), - (unsigned long long) lock->l_start, - (unsigned long long) lock->l_len, - (unsigned long long) lock->l_pid); - - return fs->op.lock(fi, cmd, lock); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.lock) { + if (fs->debug) + fprintf(stderr, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n", + (unsigned long long) fi->fh, + (cmd == F_GETLK ? "F_GETLK" : + (cmd == F_SETLK ? "F_SETLK" : + (cmd == F_SETLKW ? "F_SETLKW" : "???"))), + (lock->l_type == F_RDLCK ? "F_RDLCK" : + (lock->l_type == F_WRLCK ? "F_WRLCK" : + (lock->l_type == F_UNLCK ? "F_UNLCK" : + "???"))), + (unsigned long long) lock->l_start, + (unsigned long long) lock->l_len, + (unsigned long long) lock->l_pid); + + return fs->op.lock(fi, cmd, lock); + } else { + return -ENOSYS; + } } int fuse_fs_flock(struct fuse_fs *fs, struct fuse_file_info *fi, int op) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.flock) { - if (fs->debug) { - int xop = op & ~LOCK_NB; - - fprintf(stderr, "lock[%llu] %s%s\n", - (unsigned long long) fi->fh, - xop == LOCK_SH ? "LOCK_SH" : - (xop == LOCK_EX ? "LOCK_EX" : - (xop == LOCK_UN ? "LOCK_UN" : "???")), - (op & LOCK_NB) ? "|LOCK_NB" : ""); - } - return fs->op.flock(fi, op); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.flock) { + if (fs->debug) { + int xop = op & ~LOCK_NB; + + fprintf(stderr, "lock[%llu] %s%s\n", + (unsigned long long) fi->fh, + xop == LOCK_SH ? "LOCK_SH" : + (xop == LOCK_EX ? "LOCK_EX" : + (xop == LOCK_UN ? "LOCK_UN" : "???")), + (op & LOCK_NB) ? "|LOCK_NB" : ""); + } + return fs->op.flock(fi, op); + } else { + return -ENOSYS; + } } int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chown) { - if (fs->debug) - fprintf(stderr, "chown %s %lu %lu\n", path, - (unsigned long) uid, (unsigned long) gid); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chown) { + if (fs->debug) + fprintf(stderr, "chown %s %lu %lu\n", path, + (unsigned long) uid, (unsigned long) gid); - return fs->op.chown(path, uid, gid); - } else { - return -ENOSYS; - } + return fs->op.chown(path, uid, gid); + } else { + return -ENOSYS; + } } int @@ -2020,54 +2091,54 @@ fuse_fs_fchown(struct fuse_fs *fs_, int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.truncate) { - if (fs->debug) - fprintf(stderr, "truncate %s %llu\n", path, - (unsigned long long) size); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.truncate) { + if (fs->debug) + fprintf(stderr, "truncate %s %llu\n", path, + (unsigned long long) size); - return fs->op.truncate(path, size); - } else { - return -ENOSYS; - } + return fs->op.truncate(path, size); + } else { + return -ENOSYS; + } } int fuse_fs_ftruncate(struct fuse_fs *fs, off_t size, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->debug) - fprintf(stderr, "ftruncate[%llu] %llu\n", - (unsigned long long) fi->fh, - (unsigned long long) size); + fuse_get_context()->private_data = fs->user_data; + if (fs->debug) + fprintf(stderr, "ftruncate[%llu] %llu\n", + (unsigned long long) fi->fh, + (unsigned long long) size); - return fs->op.ftruncate(size, fi); + return fs->op.ftruncate(size, fi); } int fuse_fs_utimens(struct fuse_fs *fs, const char *path, const struct timespec tv[2]) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.utimens) { - if (fs->debug) - fprintf(stderr, "utimens %s %li.%09lu %li.%09lu\n", - path, tv[0].tv_sec, tv[0].tv_nsec, - tv[1].tv_sec, tv[1].tv_nsec); - - return fs->op.utimens(path, tv); - } else if(fs->op.utime) { - struct utimbuf buf; - - if (fs->debug) - fprintf(stderr, "utime %s %li %li\n", path, - tv[0].tv_sec, tv[1].tv_sec); - - buf.actime = tv[0].tv_sec; - buf.modtime = tv[1].tv_sec; - return fs->op.utime(path, &buf); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.utimens) { + if (fs->debug) + fprintf(stderr, "utimens %s %li.%09lu %li.%09lu\n", + path, tv[0].tv_sec, tv[0].tv_nsec, + tv[1].tv_sec, tv[1].tv_nsec); + + return fs->op.utimens(path, tv); + } else if(fs->op.utime) { + struct utimbuf buf; + + if (fs->debug) + fprintf(stderr, "utime %s %li %li\n", path, + tv[0].tv_sec, tv[1].tv_sec); + + buf.actime = tv[0].tv_sec; + buf.modtime = tv[1].tv_sec; + return fs->op.utime(path, &buf); + } else { + return -ENOSYS; + } } int @@ -2085,188 +2156,188 @@ fuse_fs_futimens(struct fuse_fs *fs_, int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.access) { - if (fs->debug) - fprintf(stderr, "access %s 0%o\n", path, mask); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.access) { + if (fs->debug) + fprintf(stderr, "access %s 0%o\n", path, mask); - return fs->op.access(path, mask); - } else { - return -ENOSYS; - } + return fs->op.access(path, mask); + } else { + return -ENOSYS; + } } int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, size_t len) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.readlink) { - if (fs->debug) - fprintf(stderr, "readlink %s %lu\n", path, - (unsigned long) len); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readlink) { + if (fs->debug) + fprintf(stderr, "readlink %s %lu\n", path, + (unsigned long) len); - return fs->op.readlink(path, buf, len); - } else { - return -ENOSYS; - } + return fs->op.readlink(path, buf, len); + } else { + return -ENOSYS; + } } int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, dev_t rdev) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mknod) { - if (fs->debug) - fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n", - path, mode, (unsigned long long) rdev, - fuse_get_context()->umask); - - return fs->op.mknod(path, mode, rdev); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mknod) { + if (fs->debug) + fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n", + path, mode, (unsigned long long) rdev, + fuse_get_context()->umask); + + return fs->op.mknod(path, mode, rdev); + } else { + return -ENOSYS; + } } int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mkdir) { - if (fs->debug) - fprintf(stderr, "mkdir %s 0%o umask=0%03o\n", - path, mode, fuse_get_context()->umask); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mkdir) { + if (fs->debug) + fprintf(stderr, "mkdir %s 0%o umask=0%03o\n", + path, mode, fuse_get_context()->umask); - return fs->op.mkdir(path, mode); - } else { - return -ENOSYS; - } + return fs->op.mkdir(path, mode); + } else { + return -ENOSYS; + } } int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, const char *value, size_t size, int flags) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.setxattr) { - if (fs->debug) - fprintf(stderr, "setxattr %s %s %lu 0x%x\n", - path, name, (unsigned long) size, flags); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.setxattr) { + if (fs->debug) + fprintf(stderr, "setxattr %s %s %lu 0x%x\n", + path, name, (unsigned long) size, flags); - return fs->op.setxattr(path, name, value, size, flags); - } else { - return -ENOSYS; - } + return fs->op.setxattr(path, name, value, size, flags); + } else { + return -ENOSYS; + } } int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, char *value, size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.getxattr) { - if (fs->debug) - fprintf(stderr, "getxattr %s %s %lu\n", - path, name, (unsigned long) size); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getxattr) { + if (fs->debug) + fprintf(stderr, "getxattr %s %s %lu\n", + path, name, (unsigned long) size); - return fs->op.getxattr(path, name, value, size); - } else { - return -ENOSYS; - } + return fs->op.getxattr(path, name, value, size); + } else { + return -ENOSYS; + } } int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.listxattr) { - if (fs->debug) - fprintf(stderr, "listxattr %s %lu\n", - path, (unsigned long) size); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.listxattr) { + if (fs->debug) + fprintf(stderr, "listxattr %s %lu\n", + path, (unsigned long) size); - return fs->op.listxattr(path, list, size); - } else { - return -ENOSYS; - } + return fs->op.listxattr(path, list, size); + } else { + return -ENOSYS; + } } int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, uint64_t *idx) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.bmap) { - if (fs->debug) - fprintf(stderr, "bmap %s blocksize: %lu index: %llu\n", - path, (unsigned long) blocksize, - (unsigned long long) *idx); - - return fs->op.bmap(path, blocksize, idx); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.bmap) { + if (fs->debug) + fprintf(stderr, "bmap %s blocksize: %lu index: %llu\n", + path, (unsigned long) blocksize, + (unsigned long long) *idx); + + return fs->op.bmap(path, blocksize, idx); + } else { + return -ENOSYS; + } } int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.removexattr) { - if (fs->debug) - fprintf(stderr, "removexattr %s %s\n", path, name); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.removexattr) { + if (fs->debug) + fprintf(stderr, "removexattr %s %s\n", path, name); - return fs->op.removexattr(path, name); - } else { - return -ENOSYS; - } + return fs->op.removexattr(path, name); + } else { + return -ENOSYS; + } } int fuse_fs_ioctl(struct fuse_fs *fs, unsigned long cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data, uint32_t *out_size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.ioctl) { - if (fs->debug) - fprintf(stderr, "ioctl[%llu] 0x%lx flags: 0x%x\n", - (unsigned long long) fi->fh, cmd, flags); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.ioctl) { + if (fs->debug) + fprintf(stderr, "ioctl[%llu] 0x%lx flags: 0x%x\n", + (unsigned long long) fi->fh, cmd, flags); - return fs->op.ioctl(cmd, arg, fi, flags, data, out_size); - } else - return -ENOSYS; + return fs->op.ioctl(cmd, arg, fi, flags, data, out_size); + } else + return -ENOSYS; } int fuse_fs_poll(struct fuse_fs *fs, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.poll) { - int res; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.poll) { + int res; - if (fs->debug) - fprintf(stderr, "poll[%llu] ph: %p\n", - (unsigned long long) fi->fh, ph); + if (fs->debug) + fprintf(stderr, "poll[%llu] ph: %p\n", + (unsigned long long) fi->fh, ph); - res = fs->op.poll(fi, ph, reventsp); + res = fs->op.poll(fi, ph, reventsp); - if (fs->debug && !res) - fprintf(stderr, " poll[%llu] revents: 0x%x\n", - (unsigned long long) fi->fh, *reventsp); + if (fs->debug && !res) + fprintf(stderr, " poll[%llu] revents: 0x%x\n", + (unsigned long long) fi->fh, *reventsp); - return res; - } else - return -ENOSYS; + return res; + } else + return -ENOSYS; } int fuse_fs_fallocate(struct fuse_fs *fs, int mode, - off_t offset, off_t length, struct fuse_file_info *fi) + off_t offset, off_t length, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fallocate) { - if (fs->debug) - fprintf(stderr, "fallocate mode %x, offset: %llu, length: %llu\n", - mode, - (unsigned long long) offset, - (unsigned long long) length); - - return fs->op.fallocate(mode, offset, length, fi); - } else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fallocate) { + if (fs->debug) + fprintf(stderr, "fallocate mode %x, offset: %llu, length: %llu\n", + mode, + (unsigned long long) offset, + (unsigned long long) length); + + return fs->op.fallocate(mode, offset, length, fi); + } else + return -ENOSYS; } ssize_t @@ -2304,16 +2375,16 @@ node_open(const struct node *node_) static void curr_time(struct timespec *now) { - static clockid_t clockid = CLOCK_MONOTONIC; - int res = clock_gettime(clockid, now); - if (res == -1 && errno == EINVAL) { - clockid = CLOCK_REALTIME; - res = clock_gettime(clockid, now); - } - if (res == -1) { - perror("fuse: clock_gettime"); - abort(); - } + static clockid_t clockid = CLOCK_MONOTONIC; + int res = clock_gettime(clockid, now); + if (res == -1 && errno == EINVAL) { + clockid = CLOCK_REALTIME; + res = clock_gettime(clockid, now); + } + if (res == -1) { + perror("fuse: clock_gettime"); + abort(); + } } static @@ -2384,133 +2455,133 @@ lookup_path(struct fuse *f, static struct fuse_context_i *fuse_get_context_internal(void) { - struct fuse_context_i *c; - - c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); - if (c == NULL) { - c = (struct fuse_context_i *) - calloc(1, sizeof(struct fuse_context_i)); - if (c == NULL) { - /* This is hard to deal with properly, so just - abort. If memory is so low that the - context cannot be allocated, there's not - much hope for the filesystem anyway */ - fprintf(stderr, "fuse: failed to allocate thread specific data\n"); - abort(); - } - pthread_setspecific(fuse_context_key, c); - } - return c; + struct fuse_context_i *c; + + c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); + if (c == NULL) { + c = (struct fuse_context_i *) + calloc(1, sizeof(struct fuse_context_i)); + if (c == NULL) { + /* This is hard to deal with properly, so just + abort. If memory is so low that the + context cannot be allocated, there's not + much hope for the filesystem anyway */ + fprintf(stderr, "fuse: failed to allocate thread specific data\n"); + abort(); + } + pthread_setspecific(fuse_context_key, c); + } + return c; } static void fuse_freecontext(void *data) { - free(data); + free(data); } static int fuse_create_context_key(void) { - int err = 0; - pthread_mutex_lock(&fuse_context_lock); - if (!fuse_context_ref) { - err = pthread_key_create(&fuse_context_key, fuse_freecontext); - if (err) { - fprintf(stderr, "fuse: failed to create thread specific key: %s\n", - strerror(err)); - pthread_mutex_unlock(&fuse_context_lock); - return -1; - } - } - fuse_context_ref++; - pthread_mutex_unlock(&fuse_context_lock); - return 0; + int err = 0; + pthread_mutex_lock(&fuse_context_lock); + if (!fuse_context_ref) { + err = pthread_key_create(&fuse_context_key, fuse_freecontext); + if (err) { + fprintf(stderr, "fuse: failed to create thread specific key: %s\n", + strerror(err)); + pthread_mutex_unlock(&fuse_context_lock); + return -1; + } + } + fuse_context_ref++; + pthread_mutex_unlock(&fuse_context_lock); + return 0; } static void fuse_delete_context_key(void) { - pthread_mutex_lock(&fuse_context_lock); - fuse_context_ref--; - if (!fuse_context_ref) { - free(pthread_getspecific(fuse_context_key)); - pthread_key_delete(fuse_context_key); - } - pthread_mutex_unlock(&fuse_context_lock); + pthread_mutex_lock(&fuse_context_lock); + fuse_context_ref--; + if (!fuse_context_ref) { + free(pthread_getspecific(fuse_context_key)); + pthread_key_delete(fuse_context_key); + } + pthread_mutex_unlock(&fuse_context_lock); } static struct fuse *req_fuse_prepare(fuse_req_t req) { - struct fuse_context_i *c = fuse_get_context_internal(); - const struct fuse_ctx *ctx = fuse_req_ctx(req); - c->req = req; - c->ctx.fuse = req_fuse(req); - c->ctx.uid = ctx->uid; - c->ctx.gid = ctx->gid; - c->ctx.pid = ctx->pid; - c->ctx.umask = ctx->umask; - return c->ctx.fuse; + struct fuse_context_i *c = fuse_get_context_internal(); + const struct fuse_ctx *ctx = fuse_req_ctx(req); + c->req = req; + c->ctx.fuse = req_fuse(req); + c->ctx.uid = ctx->uid; + c->ctx.gid = ctx->gid; + c->ctx.pid = ctx->pid; + c->ctx.umask = ctx->umask; + return c->ctx.fuse; } static inline void reply_err(fuse_req_t req, int err) { - /* fuse_reply_err() uses non-negated errno values */ - fuse_reply_err(req, -err); + /* fuse_reply_err() uses non-negated errno values */ + fuse_reply_err(req, -err); } static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, int err) { - if (!err) { - struct fuse *f = req_fuse(req); - if (fuse_reply_entry(req, e) == -ENOENT) { - /* Skip forget for negative result */ - if (e->ino != 0) - forget_node(f, e->ino, 1); - } - } else - reply_err(req, err); + if (!err) { + struct fuse *f = req_fuse(req); + if (fuse_reply_entry(req, e) == -ENOENT) { + /* Skip forget for negative result */ + if (e->ino != 0) + forget_node(f, e->ino, 1); + } + } else + reply_err(req, err); } void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn) { - fuse_get_context()->private_data = fs->user_data; - if (!fs->op.write_buf) - conn->want &= ~FUSE_CAP_SPLICE_READ; - if (!fs->op.lock) - conn->want &= ~FUSE_CAP_POSIX_LOCKS; - if (!fs->op.flock) - conn->want &= ~FUSE_CAP_FLOCK_LOCKS; - if (fs->op.init) - fs->user_data = fs->op.init(conn); + fuse_get_context()->private_data = fs->user_data; + if (!fs->op.write_buf) + conn->want &= ~FUSE_CAP_SPLICE_READ; + if (!fs->op.lock) + conn->want &= ~FUSE_CAP_POSIX_LOCKS; + if (!fs->op.flock) + conn->want &= ~FUSE_CAP_FLOCK_LOCKS; + if (fs->op.init) + fs->user_data = fs->op.init(conn); } static void fuse_lib_init(void *data, struct fuse_conn_info *conn) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - conn->want |= FUSE_CAP_EXPORT_SUPPORT; - fuse_fs_init(f->fs, conn); + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + conn->want |= FUSE_CAP_EXPORT_SUPPORT; + fuse_fs_init(f->fs, conn); } void fuse_fs_destroy(struct fuse_fs *fs) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.destroy) - fs->op.destroy(fs->user_data); - free(fs); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.destroy) + fs->op.destroy(fs->user_data); + free(fs); } static void fuse_lib_destroy(void *data) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - fuse_fs_destroy(f->fs); - f->fs = NULL; + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_destroy(f->fs); + f->fs = NULL; } static @@ -2599,13 +2670,13 @@ fuse_lib_forget(fuse_req_t req, static void fuse_lib_forget_multi(fuse_req_t req, size_t count, struct fuse_forget_data *forgets) { - struct fuse *f = req_fuse(req); - size_t i; + struct fuse *f = req_fuse(req); + size_t i; - for (i = 0; i < count; i++) - do_forget(f, forgets[i].ino, forgets[i].nlookup); + for (i = 0; i < count; i++) + do_forget(f, forgets[i].ino, forgets[i].nlookup); - fuse_reply_none(req); + fuse_reply_none(req); } @@ -2676,11 +2747,11 @@ fuse_lib_getattr(fuse_req_t req, int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chmod) - return fs->op.chmod(path, mode); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chmod) + return fs->op.chmod(path, mode); + else + return -ENOSYS; } int @@ -2822,102 +2893,102 @@ fuse_lib_setattr(fuse_req_t req, static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_access(f->fs, path, mask); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_access(f->fs, path, mask); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - char linkname[PATH_MAX + 1]; - char *path; - int err; - - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - if (!err) { - linkname[PATH_MAX] = '\0'; - fuse_reply_readlink(req, linkname); - } else - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + char linkname[PATH_MAX + 1]; + char *path; + int err; + + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + if (!err) { + linkname[PATH_MAX] = '\0'; + fuse_reply_readlink(req, linkname); + } else + reply_err(req, err); } static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = get_path_name(f, parent, name, &path); - if (!err) { - struct fuse_intr_data d; - - fuse_prepare_interrupt(f, req, &d); - err = -ENOSYS; - if (S_ISREG(mode)) { - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.flags = O_CREAT | O_EXCL | O_WRONLY; - err = fuse_fs_create(f->fs, path, mode, &fi); - if (!err) { - err = lookup_path(f, parent, name, path, &e, - &fi); - fuse_fs_release(f->fs, &fi); - } - } - if (err == -ENOSYS) { - err = fuse_fs_mknod(f->fs, path, mode, rdev); - if (!err) - err = lookup_path(f, parent, name, path, &e, - NULL); - } - fuse_finish_interrupt(f, req, &d); - free_path(f, parent, path); - } - reply_entry(req, &e, err); + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = get_path_name(f, parent, name, &path); + if (!err) { + struct fuse_intr_data d; + + fuse_prepare_interrupt(f, req, &d); + err = -ENOSYS; + if (S_ISREG(mode)) { + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = O_CREAT | O_EXCL | O_WRONLY; + err = fuse_fs_create(f->fs, path, mode, &fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, + &fi); + fuse_fs_release(f->fs, &fi); + } + } + if (err == -ENOSYS) { + err = fuse_fs_mknod(f->fs, path, mode, rdev); + if (!err) + err = lookup_path(f, parent, name, path, &e, + NULL); + } + fuse_finish_interrupt(f, req, &d); + free_path(f, parent, path); + } + reply_entry(req, &e, err); } static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; - err = get_path_name(f, parent, name, &path); - if (!err) { - struct fuse_intr_data d; + err = get_path_name(f, parent, name, &path); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_mkdir(f->fs, path, mode); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free_path(f, parent, path); - } - reply_entry(req, &e, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_mkdir(f->fs, path, mode); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free_path(f, parent, path); + } + reply_entry(req, &e, err); } static @@ -2961,45 +3032,45 @@ fuse_lib_unlink(fuse_req_t req, static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { - struct fuse *f = req_fuse_prepare(req); - struct node *wnode; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct node *wnode; + char *path; + int err; - err = get_path_wrlock(f, parent, name, &path, &wnode); - if (!err) { - struct fuse_intr_data d; + err = get_path_wrlock(f, parent, name, &path, &wnode); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_rmdir(f->fs, path); - fuse_finish_interrupt(f, req, &d); - if (!err) - remove_node(f, parent, name); - free_path_wrlock(f, parent, wnode, path); - } - reply_err(req, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_rmdir(f->fs, path); + fuse_finish_interrupt(f, req, &d); + if (!err) + remove_node(f, parent, name); + free_path_wrlock(f, parent, wnode, path); + } + reply_err(req, err); } static void fuse_lib_symlink(fuse_req_t req, const char *linkname, fuse_ino_t parent, const char *name) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; - err = get_path_name(f, parent, name, &path); - if (!err) { - struct fuse_intr_data d; + err = get_path_name(f, parent, name, &path); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_symlink(f->fs, linkname, path); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free_path(f, parent, path); - } - reply_entry(req, &e, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_symlink(f->fs, linkname, path); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free_path(f, parent, path); + } + reply_entry(req, &e, err); } static @@ -3049,52 +3120,52 @@ fuse_lib_rename(fuse_req_t req, static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *oldpath; - char *newpath; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *oldpath; + char *newpath; + int err; - err = get_path2(f, ino, NULL, newparent, newname, - &oldpath, &newpath, NULL, NULL); - if (!err) { - struct fuse_intr_data d; + err = get_path2(f, ino, NULL, newparent, newname, + &oldpath, &newpath, NULL, NULL); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_link(f->fs, oldpath, newpath); - if (!err) - err = lookup_path(f, newparent, newname, newpath, - &e, NULL); - fuse_finish_interrupt(f, req, &d); - free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath); - } - reply_entry(req, &e, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_link(f->fs, oldpath, newpath); + if (!err) + err = lookup_path(f, newparent, newname, newpath, + &e, NULL); + fuse_finish_interrupt(f, req, &d); + free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath); + } + reply_entry(req, &e, err); } static void fuse_do_release(struct fuse *f, fuse_ino_t ino, struct fuse_file_info *fi) { - struct node *node; - uint64_t fh; - int was_hidden; + struct node *node; + uint64_t fh; + int was_hidden; - fh = 0; - fuse_fs_release(f->fs, fi); + fh = 0; + fuse_fs_release(f->fs, fi); - pthread_mutex_lock(&f->lock); - node = get_node(f, ino); - assert(node->open_count > 0); - node->open_count--; - was_hidden = 0; - if (node->is_hidden && (node->open_count == 0)) { - was_hidden = 1; - node->is_hidden = 0; - fh = node->hidden_fh; - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + assert(node->open_count > 0); + node->open_count--; + was_hidden = 0; + if (node->is_hidden && (node->open_count == 0)) { + was_hidden = 1; + node->is_hidden = 0; + fh = node->hidden_fh; + } + pthread_mutex_unlock(&f->lock); - if(was_hidden) - fuse_fs_free_hide(f->fs,fh); + if(was_hidden) + fuse_fs_free_hide(f->fs,fh); } static @@ -3158,8 +3229,8 @@ fuse_lib_create(fuse_req_t req, static double diff_timespec(const struct timespec *t1, const struct timespec *t2) { - return (t1->tv_sec - t2->tv_sec) + - ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; + return (t1->tv_sec - t2->tv_sec) + + ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; } static @@ -3243,113 +3314,113 @@ fuse_lib_open(fuse_req_t req, static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_bufvec *buf = NULL; - int res; - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + struct fuse_bufvec *buf = NULL; + int res; + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_read_buf(f->fs, &buf, size, off, fi); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_read_buf(f->fs, &buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); - if (res == 0) - fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE); - else - reply_err(req, res); + if (res == 0) + fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE); + else + reply_err(req, res); - fuse_free_buf(buf); + fuse_free_buf(buf); } static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - int res; - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + int res; + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_write_buf(f->fs, buf, off, fi); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, NULL); + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_write_buf(f->fs, buf, off, fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, NULL); - if (res >= 0) - fuse_reply_write(req, res); - else - reply_err(req, res); + if (res >= 0) + fuse_reply_write(req, res); + else + reply_err(req, res); } static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - int err; - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + int err; + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsync(f->fs, datasync, fi); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsync(f->fs, datasync, fi); + fuse_finish_interrupt(f, req, &d); - reply_err(req, err); + reply_err(req, err); } static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, struct fuse_file_info *fi) { - struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; - memset(fi, 0, sizeof(struct fuse_file_info)); - fi->fh = dh->fh; - return dh; + struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; + memset(fi, 0, sizeof(struct fuse_file_info)); + fi->fh = dh->fh; + return dh; } static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *llfi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_dh *dh; - struct fuse_file_info fi; - char *path; - int err; - - dh = (struct fuse_dh *) calloc(1,sizeof(struct fuse_dh)); - if (dh == NULL) { - reply_err(req, -ENOMEM); - return; - } - - fuse_dirents_init(&dh->d); - fuse_mutex_init(&dh->lock); - - llfi->fh = (uintptr_t) dh; - - memset(&fi, 0, sizeof(fi)); - fi.flags = llfi->flags; - - err = get_path(f, ino, &path); - if (!err) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_opendir(f->fs, path, &fi); - fuse_finish_interrupt(f, req, &d); - dh->fh = fi.fh; - llfi->keep_cache = fi.keep_cache; - llfi->cache_readdir = fi.cache_readdir; - } - - if (!err) { - if (fuse_reply_open(req, llfi) == -ENOENT) { - /* The opendir syscall was interrupted, so it - must be cancelled */ - fuse_fs_releasedir(f->fs, &fi); - pthread_mutex_destroy(&dh->lock); - free(dh); - } - } else { - reply_err(req, err); - pthread_mutex_destroy(&dh->lock); - free(dh); - } - free_path(f, ino, path); + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_dh *dh; + struct fuse_file_info fi; + char *path; + int err; + + dh = (struct fuse_dh *) calloc(1,sizeof(struct fuse_dh)); + if (dh == NULL) { + reply_err(req, -ENOMEM); + return; + } + + fuse_dirents_init(&dh->d); + fuse_mutex_init(&dh->lock); + + llfi->fh = (uintptr_t) dh; + + memset(&fi, 0, sizeof(fi)); + fi.flags = llfi->flags; + + err = get_path(f, ino, &path); + if (!err) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_opendir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + dh->fh = fi.fh; + llfi->keep_cache = fi.keep_cache; + llfi->cache_readdir = fi.cache_readdir; + } + + if (!err) { + if (fuse_reply_open(req, llfi) == -ENOENT) { + /* The opendir syscall was interrupted, so it + must be cancelled */ + fuse_fs_releasedir(f->fs, &fi); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + } else { + reply_err(req, err); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + free_path(f, ino, path); } static @@ -3517,166 +3588,166 @@ fuse_lib_releasedir(fuse_req_t req_, static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *llfi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_file_info fi; - int err; - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + int err; + struct fuse_intr_data d; - get_dirhandle(llfi, &fi); + get_dirhandle(llfi, &fi); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsyncdir(f->fs, datasync, &fi); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsyncdir(f->fs, datasync, &fi); + fuse_finish_interrupt(f, req, &d); - reply_err(req, err); + reply_err(req, err); } static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - struct statvfs buf; - char *path = NULL; - int err = 0; + struct fuse *f = req_fuse_prepare(req); + struct statvfs buf; + char *path = NULL; + int err = 0; - memset(&buf, 0, sizeof(buf)); - if (ino) - err = get_path(f, ino, &path); + memset(&buf, 0, sizeof(buf)); + if (ino) + err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_statfs(f->fs, path ? path : "/", &buf); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_statfs(f->fs, path ? path : "/", &buf); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } - if (!err) - fuse_reply_statfs(req, &buf); - else - reply_err(req, err); + if (!err) + fuse_reply_statfs(req, &buf); + else + reply_err(req, err); } static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, const char *name, char *value, size_t size) { - int err; - char *path; + int err; + char *path; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_getxattr(f->fs, path, name, value, size); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - return err; + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getxattr(f->fs, path, name, value, size); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + return err; } static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { - struct fuse *f = req_fuse_prepare(req); - int res; - - if (size) { - char *value = (char *) malloc(size); - if (value == NULL) { - reply_err(req, -ENOMEM); - return; - } - res = common_getxattr(f, req, ino, name, value, size); - if (res > 0) - fuse_reply_buf(req, value, res); - else - reply_err(req, res); - free(value); - } else { - res = common_getxattr(f, req, ino, name, NULL, 0); - if (res >= 0) - fuse_reply_xattr(req, res); - else - reply_err(req, res); - } + struct fuse *f = req_fuse_prepare(req); + int res; + + if (size) { + char *value = (char *) malloc(size); + if (value == NULL) { + reply_err(req, -ENOMEM); + return; + } + res = common_getxattr(f, req, ino, name, value, size); + if (res > 0) + fuse_reply_buf(req, value, res); + else + reply_err(req, res); + free(value); + } else { + res = common_getxattr(f, req, ino, name, NULL, 0); + if (res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } } static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, char *list, size_t size) { - char *path; - int err; + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_listxattr(f->fs, path, list, size); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - return err; + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_listxattr(f->fs, path, list, size); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + return err; } static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { - struct fuse *f = req_fuse_prepare(req); - int res; - - if (size) { - char *list = (char *) malloc(size); - if (list == NULL) { - reply_err(req, -ENOMEM); - return; - } - res = common_listxattr(f, req, ino, list, size); - if (res > 0) - fuse_reply_buf(req, list, res); - else - reply_err(req, res); - free(list); - } else { - res = common_listxattr(f, req, ino, NULL, 0); - if (res >= 0) - fuse_reply_xattr(req, res); - else - reply_err(req, res); - } + struct fuse *f = req_fuse_prepare(req); + int res; + + if (size) { + char *list = (char *) malloc(size); + if (list == NULL) { + reply_err(req, -ENOMEM); + return; + } + res = common_listxattr(f, req, ino, list, size); + if (res > 0) + fuse_reply_buf(req, list, res); + else + reply_err(req, res); + free(list); + } else { + res = common_listxattr(f, req, ino, NULL, 0); + if (res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } } static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_removexattr(f->fs, path, name); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_removexattr(f->fs, path, name); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static @@ -3717,278 +3788,278 @@ fuse_lib_copy_file_range(fuse_req_t req_, static struct lock *locks_conflict(struct node *node, const struct lock *lock) { - struct lock *l; + struct lock *l; - for (l = node->locks; l; l = l->next) - if (l->owner != lock->owner && - lock->start <= l->end && l->start <= lock->end && - (l->type == F_WRLCK || lock->type == F_WRLCK)) - break; + for (l = node->locks; l; l = l->next) + if (l->owner != lock->owner && + lock->start <= l->end && l->start <= lock->end && + (l->type == F_WRLCK || lock->type == F_WRLCK)) + break; - return l; + return l; } static void delete_lock(struct lock **lockp) { - struct lock *l = *lockp; - *lockp = l->next; - free(l); + struct lock *l = *lockp; + *lockp = l->next; + free(l); } static void insert_lock(struct lock **pos, struct lock *lock) { - lock->next = *pos; - *pos = lock; + lock->next = *pos; + *pos = lock; } static int locks_insert(struct node *node, struct lock *lock) { - struct lock **lp; - struct lock *newl1 = NULL; - struct lock *newl2 = NULL; - - if (lock->type != F_UNLCK || lock->start != 0 || - lock->end != OFFSET_MAX) { - newl1 = malloc(sizeof(struct lock)); - newl2 = malloc(sizeof(struct lock)); - - if (!newl1 || !newl2) { - free(newl1); - free(newl2); - return -ENOLCK; - } - } - - for (lp = &node->locks; *lp;) { - struct lock *l = *lp; - if (l->owner != lock->owner) - goto skip; - - if (lock->type == l->type) { - if (l->end < lock->start - 1) - goto skip; - if (lock->end < l->start - 1) - break; - if (l->start <= lock->start && lock->end <= l->end) - goto out; - if (l->start < lock->start) - lock->start = l->start; - if (lock->end < l->end) - lock->end = l->end; - goto delete; - } else { - if (l->end < lock->start) - goto skip; - if (lock->end < l->start) - break; - if (lock->start <= l->start && l->end <= lock->end) - goto delete; - if (l->end <= lock->end) { - l->end = lock->start - 1; - goto skip; - } - if (lock->start <= l->start) { - l->start = lock->end + 1; - break; - } - *newl2 = *l; - newl2->start = lock->end + 1; - l->end = lock->start - 1; - insert_lock(&l->next, newl2); - newl2 = NULL; - } - skip: - lp = &l->next; - continue; - - delete: - delete_lock(lp); - } - if (lock->type != F_UNLCK) { - *newl1 = *lock; - insert_lock(lp, newl1); - newl1 = NULL; - } -out: - free(newl1); - free(newl2); - return 0; + struct lock **lp; + struct lock *newl1 = NULL; + struct lock *newl2 = NULL; + + if (lock->type != F_UNLCK || lock->start != 0 || + lock->end != OFFSET_MAX) { + newl1 = malloc(sizeof(struct lock)); + newl2 = malloc(sizeof(struct lock)); + + if (!newl1 || !newl2) { + free(newl1); + free(newl2); + return -ENOLCK; + } + } + + for (lp = &node->locks; *lp;) { + struct lock *l = *lp; + if (l->owner != lock->owner) + goto skip; + + if (lock->type == l->type) { + if (l->end < lock->start - 1) + goto skip; + if (lock->end < l->start - 1) + break; + if (l->start <= lock->start && lock->end <= l->end) + goto out; + if (l->start < lock->start) + lock->start = l->start; + if (lock->end < l->end) + lock->end = l->end; + goto delete; + } else { + if (l->end < lock->start) + goto skip; + if (lock->end < l->start) + break; + if (lock->start <= l->start && l->end <= lock->end) + goto delete; + if (l->end <= lock->end) { + l->end = lock->start - 1; + goto skip; + } + if (lock->start <= l->start) { + l->start = lock->end + 1; + break; + } + *newl2 = *l; + newl2->start = lock->end + 1; + l->end = lock->start - 1; + insert_lock(&l->next, newl2); + newl2 = NULL; + } + skip: + lp = &l->next; + continue; + + delete: + delete_lock(lp); + } + if (lock->type != F_UNLCK) { + *newl1 = *lock; + insert_lock(lp, newl1); + newl1 = NULL; + } + out: + free(newl1); + free(newl2); + return 0; } static void flock_to_lock(struct flock *flock, struct lock *lock) { - memset(lock, 0, sizeof(struct lock)); - lock->type = flock->l_type; - lock->start = flock->l_start; - lock->end = - flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; - lock->pid = flock->l_pid; + memset(lock, 0, sizeof(struct lock)); + lock->type = flock->l_type; + lock->start = flock->l_start; + lock->end = + flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; + lock->pid = flock->l_pid; } static void lock_to_flock(struct lock *lock, struct flock *flock) { - flock->l_type = lock->type; - flock->l_start = lock->start; - flock->l_len = - (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; - flock->l_pid = lock->pid; + flock->l_type = lock->type; + flock->l_start = lock->start; + flock->l_len = + (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; + flock->l_pid = lock->pid; } static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct fuse_intr_data d; - struct flock lock; - struct lock l; - int err; - int errlock; - - fuse_prepare_interrupt(f, req, &d); - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - err = fuse_fs_flush(f->fs, fi); - errlock = fuse_fs_lock(f->fs, fi, F_SETLK, &lock); - fuse_finish_interrupt(f, req, &d); - - if (errlock != -ENOSYS) { - flock_to_lock(&lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - locks_insert(get_node(f, ino), &l); - pthread_mutex_unlock(&f->lock); - - /* if op.lock() is defined FLUSH is needed regardless - of op.flush() */ - if (err == -ENOSYS) - err = 0; - } - return err; + struct fuse_intr_data d; + struct flock lock; + struct lock l; + int err; + int errlock; + + fuse_prepare_interrupt(f, req, &d); + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + err = fuse_fs_flush(f->fs, fi); + errlock = fuse_fs_lock(f->fs, fi, F_SETLK, &lock); + fuse_finish_interrupt(f, req, &d); + + if (errlock != -ENOSYS) { + flock_to_lock(&lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + + /* if op.lock() is defined FLUSH is needed regardless + of op.flush() */ + if (err == -ENOSYS) + err = 0; + } + return err; } static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - int err = 0; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + int err = 0; - if (fi->flush) { - err = fuse_flush_common(f, req, ino, fi); - if (err == -ENOSYS) - err = 0; - } + if (fi->flush) { + err = fuse_flush_common(f, req, ino, fi); + if (err == -ENOSYS) + err = 0; + } - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, ino, fi); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, fi); + fuse_finish_interrupt(f, req, &d); - reply_err(req, err); + reply_err(req, err); } static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - int err; + struct fuse *f = req_fuse_prepare(req); + int err; - err = fuse_flush_common(f, req, ino, fi); + err = fuse_flush_common(f, req, ino, fi); - reply_err(req, err); + reply_err(req, err); } static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int cmd) { - struct fuse *f = req_fuse_prepare(req); - int err; - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + int err; + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_lock(f->fs, fi, cmd, lock); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_lock(f->fs, fi, cmd, lock); + fuse_finish_interrupt(f, req, &d); - return err; + return err; } static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock) { - int err; - struct lock l; - struct lock *conflict; - struct fuse *f = req_fuse(req); - - flock_to_lock(lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - conflict = locks_conflict(get_node(f, ino), &l); - if (conflict) - lock_to_flock(conflict, lock); - pthread_mutex_unlock(&f->lock); - if (!conflict) - err = fuse_lock_common(req, ino, fi, lock, F_GETLK); - else - err = 0; - - if (!err) - fuse_reply_lock(req, lock); - else - reply_err(req, err); + int err; + struct lock l; + struct lock *conflict; + struct fuse *f = req_fuse(req); + + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + conflict = locks_conflict(get_node(f, ino), &l); + if (conflict) + lock_to_flock(conflict, lock); + pthread_mutex_unlock(&f->lock); + if (!conflict) + err = fuse_lock_common(req, ino, fi, lock, F_GETLK); + else + err = 0; + + if (!err) + fuse_reply_lock(req, lock); + else + reply_err(req, err); } static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep) { - int err = fuse_lock_common(req, ino, fi, lock, - sleep ? F_SETLKW : F_SETLK); - if (!err) { - struct fuse *f = req_fuse(req); - struct lock l; - flock_to_lock(lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - locks_insert(get_node(f, ino), &l); - pthread_mutex_unlock(&f->lock); - } - reply_err(req, err); + int err = fuse_lock_common(req, ino, fi, lock, + sleep ? F_SETLKW : F_SETLK); + if (!err) { + struct fuse *f = req_fuse(req); + struct lock l; + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + } + reply_err(req, err); } static void fuse_lib_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op) { - struct fuse *f = req_fuse_prepare(req); - int err; - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + int err; + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_flock(f->fs, fi, op); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_flock(f->fs, fi, op); + fuse_finish_interrupt(f, req, &d); - reply_err(req, err); + reply_err(req, err); } static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_bmap(f->fs, path, blocksize, &idx); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - if (!err) - fuse_reply_bmap(req, idx); - else - reply_err(req, err); + err = get_path(f, ino, &path); + if (!err) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_bmap(f->fs, path, blocksize, &idx); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + if (!err) + fuse_reply_bmap(req, idx); + else + reply_err(req, err); } static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned long cmd, void *arg, @@ -3996,329 +4067,329 @@ static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned long cmd, vo const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz_) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_file_info fi; - char *out_buf = NULL; - int err; - uint32_t out_bufsz = out_bufsz_; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_file_info fi; + char *out_buf = NULL; + int err; + uint32_t out_bufsz = out_bufsz_; - err = -EPERM; - if (flags & FUSE_IOCTL_UNRESTRICTED) - goto err; + err = -EPERM; + if (flags & FUSE_IOCTL_UNRESTRICTED) + goto err; - if (flags & FUSE_IOCTL_DIR) - get_dirhandle(llfi, &fi); - else - fi = *llfi; + if (flags & FUSE_IOCTL_DIR) + get_dirhandle(llfi, &fi); + else + fi = *llfi; - if (out_bufsz) { - err = -ENOMEM; - out_buf = malloc(out_bufsz); - if (!out_buf) - goto err; - } + if (out_bufsz) { + err = -ENOMEM; + out_buf = malloc(out_bufsz); + if (!out_buf) + goto err; + } - assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz); - if (out_buf) - memcpy(out_buf, in_buf, in_bufsz); + assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz); + if (out_buf) + memcpy(out_buf, in_buf, in_bufsz); - fuse_prepare_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_ioctl(f->fs, cmd, arg, &fi, flags, - out_buf ?: (void *)in_buf, &out_bufsz); + err = fuse_fs_ioctl(f->fs, cmd, arg, &fi, flags, + out_buf ?: (void *)in_buf, &out_bufsz); - fuse_finish_interrupt(f, req, &d); + fuse_finish_interrupt(f, req, &d); - fuse_reply_ioctl(req, err, out_buf, out_bufsz); - goto out; -err: - reply_err(req, err); -out: - free(out_buf); + fuse_reply_ioctl(req, err, out_buf, out_bufsz); + goto out; + err: + reply_err(req, err); + out: + free(out_buf); } static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - int err; - unsigned revents = 0; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + int err; + unsigned revents = 0; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_poll(f->fs, fi, ph, &revents); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_poll(f->fs, fi, ph, &revents); + fuse_finish_interrupt(f, req, &d); - if (!err) - fuse_reply_poll(req, revents); - else - reply_err(req, err); + if (!err) + fuse_reply_poll(req, revents); + else + reply_err(req, err); } static void fuse_lib_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, - off_t offset, off_t length, struct fuse_file_info *fi) + off_t offset, off_t length, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + int err; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fallocate(f->fs, mode, offset, length, fi); - fuse_finish_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fallocate(f->fs, mode, offset, length, fi); + fuse_finish_interrupt(f, req, &d); - reply_err(req, err); + reply_err(req, err); } static int clean_delay(struct fuse *f) { - /* - * This is calculating the delay between clean runs. To - * reduce the number of cleans we are doing them 10 times - * within the remember window. - */ - int min_sleep = 60; - int max_sleep = 3600; - int sleep_time = f->conf.remember / 10; + /* + * This is calculating the delay between clean runs. To + * reduce the number of cleans we are doing them 10 times + * within the remember window. + */ + int min_sleep = 60; + int max_sleep = 3600; + int sleep_time = f->conf.remember / 10; - if (sleep_time > max_sleep) - return max_sleep; - if (sleep_time < min_sleep) - return min_sleep; - return sleep_time; + if (sleep_time > max_sleep) + return max_sleep; + if (sleep_time < min_sleep) + return min_sleep; + return sleep_time; } int fuse_clean_cache(struct fuse *f) { - struct node_lru *lnode; - struct list_head *curr, *next; - struct node *node; - struct timespec now; + struct node_lru *lnode; + struct list_head *curr, *next; + struct node *node; + struct timespec now; - pthread_mutex_lock(&f->lock); + pthread_mutex_lock(&f->lock); - curr_time(&now); + curr_time(&now); - for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) { - double age; + for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) { + double age; - next = curr->next; - lnode = list_entry(curr, struct node_lru, lru); - node = &lnode->node; + next = curr->next; + lnode = list_entry(curr, struct node_lru, lru); + node = &lnode->node; - age = diff_timespec(&now, &lnode->forget_time); - if (age <= f->conf.remember) - break; + age = diff_timespec(&now, &lnode->forget_time); + if (age <= f->conf.remember) + break; - assert(node->nlookup == 1); + assert(node->nlookup == 1); - /* Don't forget active directories */ - if (node->refctr > 1) - continue; + /* Don't forget active directories */ + if (node->refctr > 1) + continue; - node->nlookup = 0; - unhash_name(f, node); - unref_node(f, node); - } - pthread_mutex_unlock(&f->lock); + node->nlookup = 0; + unhash_name(f, node); + unref_node(f, node); + } + pthread_mutex_unlock(&f->lock); - return clean_delay(f); + return clean_delay(f); } static struct fuse_lowlevel_ops fuse_path_ops = { - .init = fuse_lib_init, - .destroy = fuse_lib_destroy, - .lookup = fuse_lib_lookup, - .forget = fuse_lib_forget, - .forget_multi = fuse_lib_forget_multi, - .getattr = fuse_lib_getattr, - .setattr = fuse_lib_setattr, - .access = fuse_lib_access, - .readlink = fuse_lib_readlink, - .mknod = fuse_lib_mknod, - .mkdir = fuse_lib_mkdir, - .unlink = fuse_lib_unlink, - .rmdir = fuse_lib_rmdir, - .symlink = fuse_lib_symlink, - .rename = fuse_lib_rename, - .link = fuse_lib_link, - .create = fuse_lib_create, - .open = fuse_lib_open, - .read = fuse_lib_read, - .write_buf = fuse_lib_write_buf, - .flush = fuse_lib_flush, - .release = fuse_lib_release, - .fsync = fuse_lib_fsync, - .opendir = fuse_lib_opendir, - .readdir = fuse_lib_readdir, - .readdir_plus = fuse_lib_readdir_plus, - .releasedir = fuse_lib_releasedir, - .fsyncdir = fuse_lib_fsyncdir, - .statfs = fuse_lib_statfs, - .setxattr = fuse_lib_setxattr, - .getxattr = fuse_lib_getxattr, - .listxattr = fuse_lib_listxattr, - .removexattr = fuse_lib_removexattr, - .getlk = fuse_lib_getlk, - .setlk = fuse_lib_setlk, - .flock = fuse_lib_flock, - .bmap = fuse_lib_bmap, - .ioctl = fuse_lib_ioctl, - .poll = fuse_lib_poll, - .fallocate = fuse_lib_fallocate, - .copy_file_range = fuse_lib_copy_file_range, + .init = fuse_lib_init, + .destroy = fuse_lib_destroy, + .lookup = fuse_lib_lookup, + .forget = fuse_lib_forget, + .forget_multi = fuse_lib_forget_multi, + .getattr = fuse_lib_getattr, + .setattr = fuse_lib_setattr, + .access = fuse_lib_access, + .readlink = fuse_lib_readlink, + .mknod = fuse_lib_mknod, + .mkdir = fuse_lib_mkdir, + .unlink = fuse_lib_unlink, + .rmdir = fuse_lib_rmdir, + .symlink = fuse_lib_symlink, + .rename = fuse_lib_rename, + .link = fuse_lib_link, + .create = fuse_lib_create, + .open = fuse_lib_open, + .read = fuse_lib_read, + .write_buf = fuse_lib_write_buf, + .flush = fuse_lib_flush, + .release = fuse_lib_release, + .fsync = fuse_lib_fsync, + .opendir = fuse_lib_opendir, + .readdir = fuse_lib_readdir, + .readdir_plus = fuse_lib_readdir_plus, + .releasedir = fuse_lib_releasedir, + .fsyncdir = fuse_lib_fsyncdir, + .statfs = fuse_lib_statfs, + .setxattr = fuse_lib_setxattr, + .getxattr = fuse_lib_getxattr, + .listxattr = fuse_lib_listxattr, + .removexattr = fuse_lib_removexattr, + .getlk = fuse_lib_getlk, + .setlk = fuse_lib_setlk, + .flock = fuse_lib_flock, + .bmap = fuse_lib_bmap, + .ioctl = fuse_lib_ioctl, + .poll = fuse_lib_poll, + .fallocate = fuse_lib_fallocate, + .copy_file_range = fuse_lib_copy_file_range, }; int fuse_notify_poll(struct fuse_pollhandle *ph) { - return fuse_lowlevel_notify_poll(ph); + return fuse_lowlevel_notify_poll(ph); } static void free_cmd(struct fuse_cmd *cmd) { - free(cmd->buf); - free(cmd); + free(cmd->buf); + free(cmd); } void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) { - fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch); - free_cmd(cmd); + fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch); + free_cmd(cmd); } int fuse_exited(struct fuse *f) { - return fuse_session_exited(f->se); + return fuse_session_exited(f->se); } struct fuse_session *fuse_get_session(struct fuse *f) { - return f->se; + return f->se; } static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize) { - struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd)); - if (cmd == NULL) { - fprintf(stderr, "fuse: failed to allocate cmd\n"); - return NULL; - } - cmd->buf = (char *) malloc(bufsize); - if (cmd->buf == NULL) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(cmd); - return NULL; - } - return cmd; + struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd)); + if (cmd == NULL) { + fprintf(stderr, "fuse: failed to allocate cmd\n"); + return NULL; + } + cmd->buf = (char *) malloc(bufsize); + if (cmd->buf == NULL) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + free(cmd); + return NULL; + } + return cmd; } struct fuse_cmd *fuse_read_cmd(struct fuse *f) { - struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize); - if (cmd != NULL) { - int res = fuse_chan_recv(&ch, cmd->buf, bufsize); - if (res <= 0) { - free_cmd(cmd); - if (res < 0 && res != -EINTR && res != -EAGAIN) - fuse_exit(f); - return NULL; - } - cmd->buflen = res; - cmd->ch = ch; - } - return cmd; + struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize); + if (cmd != NULL) { + int res = fuse_chan_recv(&ch, cmd->buf, bufsize); + if (res <= 0) { + free_cmd(cmd); + if (res < 0 && res != -EINTR && res != -EAGAIN) + fuse_exit(f); + return NULL; + } + cmd->buflen = res; + cmd->ch = ch; + } + return cmd; } static int fuse_session_loop_remember(struct fuse *f) { - struct fuse_session *se = f->se; - int res = 0; - struct timespec now; - time_t next_clean; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char *) malloc(bufsize); - struct pollfd fds = { - .fd = fuse_chan_fd(ch), - .events = POLLIN - }; - - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } - - curr_time(&now); - next_clean = now.tv_sec; - while (!fuse_session_exited(se)) { - struct fuse_chan *tmpch = ch; - struct fuse_buf fbuf = { - .mem = buf, - .size = bufsize, - }; - unsigned timeout; - - curr_time(&now); - if (now.tv_sec < next_clean) - timeout = next_clean - now.tv_sec; - else - timeout = 0; - - res = poll(&fds, 1, timeout * 1000); - if (res == -1) { - if (errno == -EINTR) - continue; - else - break; - } else if (res > 0) { - res = fuse_session_receive_buf(se, &fbuf, &tmpch); - - if (res == -EINTR) - continue; - if (res <= 0) - break; - - fuse_session_process_buf(se, &fbuf, tmpch); - } else { - timeout = fuse_clean_cache(f); - curr_time(&now); - next_clean = now.tv_sec + timeout; - } - } - - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; + struct fuse_session *se = f->se; + int res = 0; + struct timespec now; + time_t next_clean; + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + char *buf = (char *) malloc(bufsize); + struct pollfd fds = { + .fd = fuse_chan_fd(ch), + .events = POLLIN + }; + + if (!buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + return -1; + } + + curr_time(&now); + next_clean = now.tv_sec; + while (!fuse_session_exited(se)) { + struct fuse_chan *tmpch = ch; + struct fuse_buf fbuf = { + .mem = buf, + .size = bufsize, + }; + unsigned timeout; + + curr_time(&now); + if (now.tv_sec < next_clean) + timeout = next_clean - now.tv_sec; + else + timeout = 0; + + res = poll(&fds, 1, timeout * 1000); + if (res == -1) { + if (errno == -EINTR) + continue; + else + break; + } else if (res > 0) { + res = fuse_session_receive_buf(se, &fbuf, &tmpch); + + if (res == -EINTR) + continue; + if (res <= 0) + break; + + fuse_session_process_buf(se, &fbuf, tmpch); + } else { + timeout = fuse_clean_cache(f); + curr_time(&now); + next_clean = now.tv_sec + timeout; + } + } + + free(buf); + fuse_session_reset(se); + return res < 0 ? -1 : 0; } int fuse_loop(struct fuse *f) { - if (!f) - return -1; + if (!f) + return -1; - if (lru_enabled(f)) - return fuse_session_loop_remember(f); + if (lru_enabled(f)) + return fuse_session_loop_remember(f); - return fuse_session_loop(f->se); + return fuse_session_loop(f->se); } int fuse_invalidate(struct fuse *f, const char *path) { - (void) f; - (void) path; - return -EINVAL; + (void) f; + (void) path; + return -EINVAL; } void fuse_exit(struct fuse *f) { - fuse_session_exit(f->se); + fuse_session_exit(f->se); } struct fuse_context *fuse_get_context(void) { - return &fuse_get_context_internal()->ctx; + return &fuse_get_context_internal()->ctx; } /* @@ -4329,354 +4400,354 @@ struct fuse_context *fuse_get_context(void) struct fuse_context *fuse_get_context_compat22(void); struct fuse_context *fuse_get_context_compat22(void) { - return &fuse_get_context_internal()->ctx; + return &fuse_get_context_internal()->ctx; } FUSE_SYMVER(".symver fuse_get_context_compat22,fuse_get_context@FUSE_2.2"); int fuse_getgroups(int size, gid_t list[]) { - fuse_req_t req = fuse_get_context_internal()->req; - return fuse_req_getgroups(req, size, list); + fuse_req_t req = fuse_get_context_internal()->req; + return fuse_req_getgroups(req, size, list); } int fuse_interrupted(void) { - return fuse_req_interrupted(fuse_get_context_internal()->req); + return fuse_req_interrupted(fuse_get_context_internal()->req); } void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) { - (void) func; - /* no-op */ + (void) func; + /* no-op */ } enum { - KEY_HELP, + KEY_HELP, }; #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } static const struct fuse_opt fuse_lib_opts[] = { - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_LIB_OPT("debug", debug, 1), - FUSE_LIB_OPT("-d", debug, 1), - FUSE_LIB_OPT("umask=", set_mode, 1), - FUSE_LIB_OPT("umask=%o", umask, 0), - FUSE_LIB_OPT("uid=", set_uid, 1), - FUSE_LIB_OPT("uid=%d", uid, 0), - FUSE_LIB_OPT("gid=", set_gid, 1), - FUSE_LIB_OPT("gid=%d", gid, 0), - FUSE_LIB_OPT("noforget", remember, -1), - FUSE_LIB_OPT("remember=%u", remember, 0), - FUSE_LIB_OPT("intr", intr, 1), - FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), - FUSE_LIB_OPT("threads=%d", threads, 0), - FUSE_LIB_OPT("use_ino", use_ino, 1), - FUSE_OPT_END + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_LIB_OPT("debug", debug, 1), + FUSE_LIB_OPT("-d", debug, 1), + FUSE_LIB_OPT("umask=", set_mode, 1), + FUSE_LIB_OPT("umask=%o", umask, 0), + FUSE_LIB_OPT("uid=", set_uid, 1), + FUSE_LIB_OPT("uid=%d", uid, 0), + FUSE_LIB_OPT("gid=", set_gid, 1), + FUSE_LIB_OPT("gid=%d", gid, 0), + FUSE_LIB_OPT("noforget", remember, -1), + FUSE_LIB_OPT("remember=%u", remember, 0), + FUSE_LIB_OPT("intr", intr, 1), + FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), + FUSE_LIB_OPT("threads=%d", threads, 0), + FUSE_LIB_OPT("use_ino", use_ino, 1), + FUSE_OPT_END }; static void fuse_lib_help(void) { - fprintf(stderr, -" -o umask=M set file permissions (octal)\n" -" -o uid=N set file owner\n" -" -o gid=N set file group\n" -" -o noforget never forget cached inodes\n" -" -o remember=T remember cached inodes for T seconds (0s)\n" -" -o intr allow requests to be interrupted\n" -" -o intr_signal=NUM signal to send on interrupt (%i)\n" -" -o threads=NUM number of worker threads. 0 = autodetect.\n" -" Negative values autodetect then divide by\n" -" absolute value. default = 0\n" -"\n", FUSE_DEFAULT_INTR_SIGNAL); + fprintf(stderr, + " -o umask=M set file permissions (octal)\n" + " -o uid=N set file owner\n" + " -o gid=N set file group\n" + " -o noforget never forget cached inodes\n" + " -o remember=T remember cached inodes for T seconds (0s)\n" + " -o intr allow requests to be interrupted\n" + " -o intr_signal=NUM signal to send on interrupt (%i)\n" + " -o threads=NUM number of worker threads. 0 = autodetect.\n" + " Negative values autodetect then divide by\n" + " absolute value. default = 0\n" + "\n", FUSE_DEFAULT_INTR_SIGNAL); } static int fuse_lib_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - (void) arg; (void) outargs; + (void) arg; (void) outargs; - if (key == KEY_HELP) { - struct fuse_config *conf = (struct fuse_config *) data; - fuse_lib_help(); - conf->help = 1; - } + if (key == KEY_HELP) { + struct fuse_config *conf = (struct fuse_config *) data; + fuse_lib_help(); + conf->help = 1; + } - return 1; + return 1; } int fuse_is_lib_option(const char *opt) { - return fuse_lowlevel_is_lib_option(opt) || - fuse_opt_match(fuse_lib_opts, opt); + return fuse_lowlevel_is_lib_option(opt) || + fuse_opt_match(fuse_lib_opts, opt); } static int fuse_init_intr_signal(int signum, int *installed) { - struct sigaction old_sa; + struct sigaction old_sa; - if (sigaction(signum, NULL, &old_sa) == -1) { - perror("fuse: cannot get old signal handler"); - return -1; - } + if (sigaction(signum, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } - if (old_sa.sa_handler == SIG_DFL) { - struct sigaction sa; + if (old_sa.sa_handler == SIG_DFL) { + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = fuse_intr_sighandler; - sigemptyset(&sa.sa_mask); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = fuse_intr_sighandler; + sigemptyset(&sa.sa_mask); - if (sigaction(signum, &sa, NULL) == -1) { - perror("fuse: cannot set interrupt signal handler"); - return -1; - } - *installed = 1; - } - return 0; + if (sigaction(signum, &sa, NULL) == -1) { + perror("fuse: cannot set interrupt signal handler"); + return -1; + } + *installed = 1; + } + return 0; } static void fuse_restore_intr_signal(int signum) { - struct sigaction sa; + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = SIG_DFL; - sigaction(signum, &sa, NULL); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); } struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *user_data) { - struct fuse_fs *fs; + struct fuse_fs *fs; - if (sizeof(struct fuse_operations) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); - op_size = sizeof(struct fuse_operations); - } + if (sizeof(struct fuse_operations) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); + op_size = sizeof(struct fuse_operations); + } - fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); - if (!fs) { - fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); - return NULL; - } + fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); + if (!fs) { + fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); + return NULL; + } - fs->user_data = user_data; - if (op) - memcpy(&fs->op, op, op_size); - return fs; + fs->user_data = user_data; + if (op) + memcpy(&fs->op, op, op_size); + return fs; } static int node_table_init(struct node_table *t) { - t->size = NODE_TABLE_MIN_SIZE; - t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size); - if (t->array == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - t->use = 0; - t->split = 0; + t->size = NODE_TABLE_MIN_SIZE; + t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size); + if (t->array == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + t->use = 0; + t->split = 0; - return 0; + return 0; } static void *fuse_prune_nodes(void *fuse) { - struct fuse *f = fuse; - int sleep_time; + struct fuse *f = fuse; + int sleep_time; - while(1) { - sleep_time = fuse_clean_cache(f); - sleep(sleep_time); - } - return NULL; + while(1) { + sleep_time = fuse_clean_cache(f); + sleep(sleep_time); + } + return NULL; } int fuse_start_cleanup_thread(struct fuse *f) { - if (lru_enabled(f)) - return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f); + if (lru_enabled(f)) + return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f); - return 0; + return 0; } void fuse_stop_cleanup_thread(struct fuse *f) { - if (lru_enabled(f)) { - pthread_mutex_lock(&f->lock); - pthread_cancel(f->prune_thread); - pthread_mutex_unlock(&f->lock); - pthread_join(f->prune_thread, NULL); - } + if (lru_enabled(f)) { + pthread_mutex_lock(&f->lock); + pthread_cancel(f->prune_thread); + pthread_mutex_unlock(&f->lock); + pthread_join(f->prune_thread, NULL); + } } struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data, int compat) { - struct fuse *f; - struct node *root; - struct fuse_fs *fs; - struct fuse_lowlevel_ops llop = fuse_path_ops; - - if (fuse_create_context_key() == -1) - goto out; - - f = (struct fuse *) calloc(1, sizeof(struct fuse)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out_delete_context_key; - } - - fs = fuse_fs_new(op, op_size, user_data); - if (!fs) - goto out_free; - - fs->compat = compat; - f->fs = fs; - - /* Oh f**k, this is ugly! */ - if (!fs->op.lock) { - llop.getlk = NULL; - llop.setlk = NULL; - } - - f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; - - f->pagesize = getpagesize(); - init_list_head(&f->partial_slabs); - init_list_head(&f->full_slabs); - init_list_head(&f->lru_table); - - if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, - fuse_lib_opt_proc) == -1) - goto out_free_fs; - - if (compat && compat <= 25) { - if (fuse_sync_compat_args(args) == -1) - goto out_free_fs; - } - - f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); - if (f->se == NULL) { - goto out_free_fs; - } - - fuse_session_add_chan(f->se, ch); - - /* Trace topmost layer by default */ - srand(time(NULL)); - f->fs->debug = f->conf.debug; - f->ctr = 0; - f->generation = rand64(); - if (node_table_init(&f->name_table) == -1) - goto out_free_session; - - if (node_table_init(&f->id_table) == -1) - goto out_free_name_table; - - fuse_mutex_init(&f->lock); - - root = alloc_node(f); - if (root == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_id_table; - } - if (lru_enabled(f)) { - struct node_lru *lnode = node_lru(root); - init_list_head(&lnode->lru); - } - - strcpy(root->inline_name, "/"); - root->name = root->inline_name; - - if (f->conf.intr && - fuse_init_intr_signal(f->conf.intr_signal, - &f->intr_installed) == -1) - goto out_free_root; - - root->parent = NULL; - root->nodeid = FUSE_ROOT_ID; - inc_nlookup(root); - hash_id(f, root); - - return f; - -out_free_root: - free(root); -out_free_id_table: - free(f->id_table.array); -out_free_name_table: - free(f->name_table.array); -out_free_session: - fuse_session_destroy(f->se); -out_free_fs: - /* Horrible compatibility hack to stop the destructor from being - called on the filesystem without init being called first */ - fs->op.destroy = NULL; - fuse_fs_destroy(f->fs); -out_free: - free(f); -out_delete_context_key: - fuse_delete_context_key(); -out: - return NULL; + struct fuse *f; + struct node *root; + struct fuse_fs *fs; + struct fuse_lowlevel_ops llop = fuse_path_ops; + + if (fuse_create_context_key() == -1) + goto out; + + f = (struct fuse *) calloc(1, sizeof(struct fuse)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out_delete_context_key; + } + + fs = fuse_fs_new(op, op_size, user_data); + if (!fs) + goto out_free; + + fs->compat = compat; + f->fs = fs; + + /* Oh f**k, this is ugly! */ + if (!fs->op.lock) { + llop.getlk = NULL; + llop.setlk = NULL; + } + + f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; + + f->pagesize = getpagesize(); + init_list_head(&f->partial_slabs); + init_list_head(&f->full_slabs); + init_list_head(&f->lru_table); + + if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, + fuse_lib_opt_proc) == -1) + goto out_free_fs; + + if (compat && compat <= 25) { + if (fuse_sync_compat_args(args) == -1) + goto out_free_fs; + } + + f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); + if (f->se == NULL) { + goto out_free_fs; + } + + fuse_session_add_chan(f->se, ch); + + /* Trace topmost layer by default */ + srand(time(NULL)); + f->fs->debug = f->conf.debug; + f->ctr = 0; + f->generation = rand64(); + if (node_table_init(&f->name_table) == -1) + goto out_free_session; + + if (node_table_init(&f->id_table) == -1) + goto out_free_name_table; + + fuse_mutex_init(&f->lock); + + root = alloc_node(f); + if (root == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_id_table; + } + if (lru_enabled(f)) { + struct node_lru *lnode = node_lru(root); + init_list_head(&lnode->lru); + } + + strcpy(root->inline_name, "/"); + root->name = root->inline_name; + + if (f->conf.intr && + fuse_init_intr_signal(f->conf.intr_signal, + &f->intr_installed) == -1) + goto out_free_root; + + root->parent = NULL; + root->nodeid = FUSE_ROOT_ID; + inc_nlookup(root); + hash_id(f, root); + + return f; + + out_free_root: + free(root); + out_free_id_table: + free(f->id_table.array); + out_free_name_table: + free(f->name_table.array); + out_free_session: + fuse_session_destroy(f->se); + out_free_fs: + /* Horrible compatibility hack to stop the destructor from being + called on the filesystem without init being called first */ + fs->op.destroy = NULL; + fuse_fs_destroy(f->fs); + out_free: + free(f); + out_delete_context_key: + fuse_delete_context_key(); + out: + return NULL; } struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data) { - return fuse_new_common(ch, args, op, op_size, user_data, 0); + return fuse_new_common(ch, args, op, op_size, user_data, 0); } void fuse_destroy(struct fuse *f) { - size_t i; + size_t i; - if (f->conf.intr && f->intr_installed) - fuse_restore_intr_signal(f->conf.intr_signal); + if (f->conf.intr && f->intr_installed) + fuse_restore_intr_signal(f->conf.intr_signal); - if (f->fs) { - struct fuse_context_i *c = fuse_get_context_internal(); + if (f->fs) { + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; - for (i = 0; i < f->id_table.size; i++) { - struct node *node; - - for (node = f->id_table.array[i]; node != NULL; node = node->id_next) - { - if (node->is_hidden) - fuse_fs_free_hide(f->fs,node->hidden_fh); - } - } - } - for (i = 0; i < f->id_table.size; i++) { - struct node *node; - struct node *next; + for (i = 0; i < f->id_table.size; i++) { + struct node *node; - for (node = f->id_table.array[i]; node != NULL; node = next) { - next = node->id_next; - free_node(f, node); - f->id_table.use--; - } - } - assert(list_empty(&f->partial_slabs)); - assert(list_empty(&f->full_slabs)); + for (node = f->id_table.array[i]; node != NULL; node = node->id_next) + { + if (node->is_hidden) + fuse_fs_free_hide(f->fs,node->hidden_fh); + } + } + } + for (i = 0; i < f->id_table.size; i++) { + struct node *node; + struct node *next; + + for (node = f->id_table.array[i]; node != NULL; node = next) { + next = node->id_next; + free_node(f, node); + f->id_table.use--; + } + } + assert(list_empty(&f->partial_slabs)); + assert(list_empty(&f->full_slabs)); - free(f->id_table.array); - free(f->name_table.array); - pthread_mutex_destroy(&f->lock); - fuse_session_destroy(f->se); - free(f); - fuse_delete_context_key(); + free(f->id_table.array); + free(f->name_table.array); + pthread_mutex_destroy(&f->lock); + fuse_session_destroy(f->se); + free(f); + fuse_delete_context_key(); } static @@ -4685,13 +4756,13 @@ fuse_new_common_compat25(int fd, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, int compat) { - struct fuse *f = NULL; - struct fuse_chan *ch = fuse_kern_chan_new(fd); + struct fuse *f = NULL; + struct fuse_chan *ch = fuse_kern_chan_new(fd); - if (ch) - f = fuse_new_common(ch, args, op, op_size, NULL, compat); + if (ch) + f = fuse_new_common(ch, args, op, op_size, NULL, compat); - return f; + return f; } #if !defined(__FreeBSD__) && !defined(__NetBSD__) @@ -4700,49 +4771,49 @@ static struct fuse *fuse_new_common_compat(int fd, const char *opts, const struct fuse_operations *op, size_t op_size, int compat) { - struct fuse *f; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - - if (fuse_opt_add_arg(&args, "") == -1) - return NULL; - if (opts && - (fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } + struct fuse *f; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + + if (fuse_opt_add_arg(&args, "") == -1) + return NULL; + if (opts && + (fuse_opt_add_arg(&args, "-o") == -1 || + fuse_opt_add_arg(&args, opts) == -1)) { + fuse_opt_free_args(&args); + return NULL; + } - f = fuse_new_common_compat25(fd, &args, op, op_size, compat); - fuse_opt_free_args(&args); + f = fuse_new_common_compat25(fd, &args, op, op_size, compat); + fuse_opt_free_args(&args); - return f; + return f; } struct fuse *fuse_new_compat22(int fd, const char *opts, const struct fuse_operations_compat22 *op, size_t op_size) { - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - op_size, 22); + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + op_size, 22); } struct fuse *fuse_new_compat2(int fd, const char *opts, const struct fuse_operations_compat2 *op) { - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), - 21); + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), + 21); } struct fuse *fuse_new_compat1(int fd, int flags, const struct fuse_operations_compat1 *op) { - const char *opts = NULL; - if (flags & FUSE_DEBUG_COMPAT1) - opts = "debug"; - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), - 11); + const char *opts = NULL; + if (flags & FUSE_DEBUG_COMPAT1) + opts = "debug"; + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat1), + 11); } FUSE_SYMVER(".symver fuse_exited,__fuse_exited@"); @@ -4758,8 +4829,8 @@ struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, const struct fuse_operations_compat25 *op, size_t op_size) { - return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op, - op_size, 25); + return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op, + op_size, 25); } FUSE_SYMVER(".symver fuse_new_compat25,fuse_new@FUSE_2.5"); diff --git a/libfuse/lib/fuse_i.h b/libfuse/lib/fuse_i.h index fa371560..766acc7a 100644 --- a/libfuse/lib/fuse_i.h +++ b/libfuse/lib/fuse_i.h @@ -12,85 +12,89 @@ struct fuse_chan; struct fuse_ll; -struct fuse_session { - struct fuse_session_ops op; +struct fuse_session +{ + struct fuse_session_ops op; - int (*receive_buf)(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp); + int (*receive_buf)(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan **chp); - void (*process_buf)(void *data, const struct fuse_buf *buf, - struct fuse_chan *ch); + void (*process_buf)(void *data, const struct fuse_buf *buf, + struct fuse_chan *ch); - void *data; + void *data; - volatile int exited; + volatile int exited; - struct fuse_chan *ch; + struct fuse_chan *ch; }; -struct fuse_req { - struct fuse_ll *f; - 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_req +{ + struct fuse_ll *f; + 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; +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; }; -struct fuse_ll { - int debug; - int allow_root; - int atomic_o_trunc; - int no_remote_posix_lock; - int no_remote_flock; - int big_writes; - int splice_write; - int splice_move; - int splice_read; - int no_splice_write; - int no_splice_move; - int no_splice_read; - 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; - pthread_key_t pipe_key; - int broken_splice_nonblock; - uint64_t notify_ctr; - struct fuse_notify_req notify_list; +struct fuse_ll +{ + int debug; + int allow_root; + int no_remote_posix_lock; + int no_remote_flock; + int big_writes; + int splice_write; + int splice_move; + int splice_read; + int no_splice_write; + int no_splice_move; + int no_splice_read; + 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; + pthread_key_t pipe_key; + int broken_splice_nonblock; + uint64_t notify_ctr; + struct fuse_notify_req notify_list; }; -struct fuse_cmd { - char *buf; - size_t buflen; - struct fuse_chan *ch; +struct fuse_cmd +{ + char *buf; + size_t buflen; + struct fuse_chan *ch; }; struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, @@ -102,8 +106,8 @@ int fuse_sync_compat_args(struct fuse_args *args); struct fuse_chan *fuse_kern_chan_new(int fd); struct fuse_session *fuse_lowlevel_new_common(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); void fuse_kern_unmount_compat22(const char *mountpoint); int fuse_chan_clearfd(struct fuse_chan *ch); diff --git a/libfuse/lib/fuse_kern_chan.c b/libfuse/lib/fuse_kern_chan.c index e8448a5f..8bfe8ac2 100644 --- a/libfuse/lib/fuse_kern_chan.c +++ b/libfuse/lib/fuse_kern_chan.c @@ -18,69 +18,69 @@ static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf, size_t size) { - struct fuse_chan *ch = *chp; - int err; - ssize_t res; - struct fuse_session *se = fuse_chan_session(ch); - assert(se != NULL); - -restart: - res = read(fuse_chan_fd(ch), buf, size); - err = errno; - - if (fuse_session_exited(se)) - return 0; - if (res == -1) { - /* ENOENT means the operation was interrupted, it's safe - to restart */ - if (err == ENOENT) - goto restart; - - if (err == ENODEV) { - fuse_session_exit(se); - return 0; - } - /* Errors occurring during normal operation: EINTR (read - interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem - umounted) */ - if (err != EINTR && err != EAGAIN) - perror("fuse: reading device"); - return -err; - } - if ((size_t) res < sizeof(struct fuse_in_header)) { - fprintf(stderr, "short read on fuse device\n"); - return -EIO; - } - return res; + struct fuse_chan *ch = *chp; + int err; + ssize_t res; + struct fuse_session *se = fuse_chan_session(ch); + assert(se != NULL); + + restart: + res = read(fuse_chan_fd(ch), buf, size); + err = errno; + + if (fuse_session_exited(se)) + return 0; + if (res == -1) { + /* ENOENT means the operation was interrupted, it's safe + to restart */ + if (err == ENOENT) + goto restart; + + if (err == ENODEV) { + fuse_session_exit(se); + return 0; + } + /* Errors occurring during normal operation: EINTR (read + interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem + umounted) */ + if (err != EINTR && err != EAGAIN) + perror("fuse: reading device"); + return -err; + } + if ((size_t) res < sizeof(struct fuse_in_header)) { + fprintf(stderr, "short read on fuse device\n"); + return -EIO; + } + return res; } static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) { - if (iov) { - ssize_t res = writev(fuse_chan_fd(ch), iov, count); - int err = errno; - - if (res == -1) { - struct fuse_session *se = fuse_chan_session(ch); - - assert(se != NULL); - - /* ENOENT means the operation was interrupted */ - if (!fuse_session_exited(se) && err != ENOENT) - perror("fuse: writing device"); - return -err; - } - } - return 0; + if (iov) { + ssize_t res = writev(fuse_chan_fd(ch), iov, count); + int err = errno; + + if (res == -1) { + struct fuse_session *se = fuse_chan_session(ch); + + assert(se != NULL); + + /* ENOENT means the operation was interrupted */ + if (!fuse_session_exited(se) && err != ENOENT) + perror("fuse: writing device"); + return -err; + } + } + return 0; } static void fuse_kern_chan_destroy(struct fuse_chan *ch) { - int fd = fuse_chan_fd(ch); + int fd = fuse_chan_fd(ch); - if (fd != -1) - close(fd); + if (fd != -1) + close(fd); } struct fuse_chan * diff --git a/libfuse/lib/fuse_loop.c b/libfuse/lib/fuse_loop.c index 277080ef..e180577b 100644 --- a/libfuse/lib/fuse_loop.c +++ b/libfuse/lib/fuse_loop.c @@ -14,33 +14,33 @@ int fuse_session_loop(struct fuse_session *se) { - int res = 0; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char*)calloc(bufsize,1); - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } - - while (!fuse_session_exited(se)) { - struct fuse_chan *tmpch = ch; - struct fuse_buf fbuf = { - .mem = buf, - .size = bufsize, - }; - - res = fuse_session_receive_buf(se, &fbuf, &tmpch); - - if (res == -EINTR) - continue; - if (res <= 0) - break; - - fuse_session_process_buf(se, &fbuf, tmpch); - } - - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; + int res = 0; + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + char *buf = (char*)calloc(bufsize,1); + if (!buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + return -1; + } + + while (!fuse_session_exited(se)) { + struct fuse_chan *tmpch = ch; + struct fuse_buf fbuf = { + .mem = buf, + .size = bufsize, + }; + + res = fuse_session_receive_buf(se, &fbuf, &tmpch); + + if (res == -EINTR) + continue; + if (res <= 0) + break; + + fuse_session_process_buf(se, &fbuf, tmpch); + } + + free(buf); + fuse_session_reset(se); + return res < 0 ? -1 : 0; } diff --git a/libfuse/lib/fuse_loop_mt.c b/libfuse/lib/fuse_loop_mt.c index 6b1ed003..d9b76565 100644 --- a/libfuse/lib/fuse_loop_mt.c +++ b/libfuse/lib/fuse_loop_mt.c @@ -25,147 +25,147 @@ #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" struct fuse_worker { - struct fuse_worker *prev; - struct fuse_worker *next; - pthread_t thread_id; - size_t bufsize; - char *buf; - struct fuse_mt *mt; + struct fuse_worker *prev; + struct fuse_worker *next; + pthread_t thread_id; + size_t bufsize; + char *buf; + struct fuse_mt *mt; }; struct fuse_mt { - struct fuse_session *se; - struct fuse_chan *prevch; - struct fuse_worker main; - sem_t finish; - int exit; - int error; + struct fuse_session *se; + struct fuse_chan *prevch; + struct fuse_worker main; + sem_t finish; + int exit; + int error; }; static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next) { - struct fuse_worker *prev = next->prev; - w->next = next; - w->prev = prev; - prev->next = w; - next->prev = w; + struct fuse_worker *prev = next->prev; + w->next = next; + w->prev = prev; + prev->next = w; + next->prev = w; } static void list_del_worker(struct fuse_worker *w) { - struct fuse_worker *prev = w->prev; - struct fuse_worker *next = w->next; - prev->next = next; - next->prev = prev; + struct fuse_worker *prev = w->prev; + struct fuse_worker *next = w->next; + prev->next = next; + next->prev = prev; } static int fuse_loop_start_thread(struct fuse_mt *mt); static void *fuse_do_work(void *data) { - struct fuse_worker *w = (struct fuse_worker *) data; - struct fuse_mt *mt = w->mt; - - while (!fuse_session_exited(mt->se)) { - struct fuse_chan *ch = mt->prevch; - struct fuse_buf fbuf = { - .mem = w->buf, - .size = w->bufsize, - }; - int res; - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - res = fuse_session_receive_buf(mt->se, &fbuf, &ch); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - if (res == -EINTR) - continue; - if (res <= 0) { - if (res < 0) { - fuse_session_exit(mt->se); - mt->error = -1; - } - break; - } - - if (mt->exit) - return NULL; - - fuse_session_process_buf(mt->se, &fbuf, ch); - } - - sem_post(&mt->finish); - - return NULL; + struct fuse_worker *w = (struct fuse_worker *) data; + struct fuse_mt *mt = w->mt; + + while (!fuse_session_exited(mt->se)) { + struct fuse_chan *ch = mt->prevch; + struct fuse_buf fbuf = { + .mem = w->buf, + .size = w->bufsize, + }; + int res; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + res = fuse_session_receive_buf(mt->se, &fbuf, &ch); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (res == -EINTR) + continue; + if (res <= 0) { + if (res < 0) { + fuse_session_exit(mt->se); + mt->error = -1; + } + break; + } + + if (mt->exit) + return NULL; + + fuse_session_process_buf(mt->se, &fbuf, ch); + } + + sem_post(&mt->finish); + + return NULL; } int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) { - sigset_t oldset; - sigset_t newset; - int res; - pthread_attr_t attr; - char *stack_size; - - /* Override default stack size */ - pthread_attr_init(&attr); - stack_size = getenv(ENVNAME_THREAD_STACK); - if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size))) - fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size); - - /* Disallow signal reception in worker threads */ - sigemptyset(&newset); - sigaddset(&newset, SIGTERM); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - res = pthread_create(thread_id, &attr, func, arg); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - pthread_attr_destroy(&attr); - if (res != 0) { - fprintf(stderr, "fuse: error creating thread: %s\n", - strerror(res)); - return -1; - } - - return 0; + sigset_t oldset; + sigset_t newset; + int res; + pthread_attr_t attr; + char *stack_size; + + /* Override default stack size */ + pthread_attr_init(&attr); + stack_size = getenv(ENVNAME_THREAD_STACK); + if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size))) + fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size); + + /* Disallow signal reception in worker threads */ + sigemptyset(&newset); + sigaddset(&newset, SIGTERM); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGHUP); + sigaddset(&newset, SIGQUIT); + pthread_sigmask(SIG_BLOCK, &newset, &oldset); + res = pthread_create(thread_id, &attr, func, arg); + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + pthread_attr_destroy(&attr); + if (res != 0) { + fprintf(stderr, "fuse: error creating thread: %s\n", + strerror(res)); + return -1; + } + + return 0; } static int fuse_loop_start_thread(struct fuse_mt *mt) { - int res; - struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); - if (!w) { - fprintf(stderr, "fuse: failed to allocate worker structure\n"); - return -1; - } - memset(w, 0, sizeof(struct fuse_worker)); - w->bufsize = fuse_chan_bufsize(mt->prevch); - w->buf = calloc(w->bufsize,1); - w->mt = mt; - if (!w->buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(w); - return -1; - } - - res = fuse_start_thread(&w->thread_id, fuse_do_work, w); - if (res == -1) { - free(w->buf); - free(w); - return -1; - } - list_add_worker(w, &mt->main); - - return 0; + int res; + struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); + if (!w) { + fprintf(stderr, "fuse: failed to allocate worker structure\n"); + return -1; + } + memset(w, 0, sizeof(struct fuse_worker)); + w->bufsize = fuse_chan_bufsize(mt->prevch); + w->buf = calloc(w->bufsize,1); + w->mt = mt; + if (!w->buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + free(w); + return -1; + } + + res = fuse_start_thread(&w->thread_id, fuse_do_work, w); + if (res == -1) { + free(w->buf); + free(w); + return -1; + } + list_add_worker(w, &mt->main); + + return 0; } static void fuse_join_worker(struct fuse_worker *w) { - pthread_join(w->thread_id, NULL); - list_del_worker(w); - free(w->buf); - free(w); + pthread_join(w->thread_id, NULL); + list_del_worker(w); + free(w->buf); + free(w); } static int number_of_threads(void) @@ -180,46 +180,46 @@ static int number_of_threads(void) int fuse_session_loop_mt(struct fuse_session *se, const int _threads) { - int i; - int err; - int threads; - struct fuse_mt mt; - struct fuse_worker *w; - - memset(&mt, 0, sizeof(struct fuse_mt)); - mt.se = se; - mt.prevch = fuse_session_next_chan(se, NULL); - mt.error = 0; - mt.main.thread_id = pthread_self(); - mt.main.prev = mt.main.next = &mt.main; - sem_init(&mt.finish, 0, 0); - - threads = ((_threads > 0) ? _threads : number_of_threads()); - if(_threads < 0) - threads /= -_threads; - if(threads == 0) - threads = 1; - - err = 0; - for(i = 0; (i < threads) && !err; i++) - err = fuse_loop_start_thread(&mt); - - if (!err) { - /* sem_wait() is interruptible */ - while (!fuse_session_exited(se)) - sem_wait(&mt.finish); - - for (w = mt.main.next; w != &mt.main; w = w->next) - pthread_cancel(w->thread_id); - mt.exit = 1; - - while (mt.main.next != &mt.main) - fuse_join_worker(mt.main.next); - - err = mt.error; - } - - sem_destroy(&mt.finish); - fuse_session_reset(se); - return err; + int i; + int err; + int threads; + struct fuse_mt mt; + struct fuse_worker *w; + + memset(&mt, 0, sizeof(struct fuse_mt)); + mt.se = se; + mt.prevch = fuse_session_next_chan(se, NULL); + mt.error = 0; + mt.main.thread_id = pthread_self(); + mt.main.prev = mt.main.next = &mt.main; + sem_init(&mt.finish, 0, 0); + + threads = ((_threads > 0) ? _threads : number_of_threads()); + if(_threads < 0) + threads /= -_threads; + if(threads == 0) + threads = 1; + + err = 0; + for(i = 0; (i < threads) && !err; i++) + err = fuse_loop_start_thread(&mt); + + if (!err) { + /* sem_wait() is interruptible */ + while (!fuse_session_exited(se)) + sem_wait(&mt.finish); + + for (w = mt.main.next; w != &mt.main; w = w->next) + pthread_cancel(w->thread_id); + mt.exit = 1; + + while (mt.main.next != &mt.main) + fuse_join_worker(mt.main.next); + + err = mt.error; + } + + sem_destroy(&mt.finish); + fuse_session_reset(se); + return err; } diff --git a/libfuse/lib/fuse_lowlevel.c b/libfuse/lib/fuse_lowlevel.c index d3345e02..bcea660f 100644 --- a/libfuse/lib/fuse_lowlevel.c +++ b/libfuse/lib/fuse_lowlevel.c @@ -37,21 +37,21 @@ #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_chan *ch; - struct fuse_ll *f; + uint64_t kh; + struct fuse_chan *ch; + struct fuse_ll *f; }; static size_t pagesize; static __attribute__((constructor)) void fuse_ll_init_pagesize(void) { - pagesize = getpagesize(); + pagesize = getpagesize(); } static @@ -95,214 +95,214 @@ convert_attr(const struct fuse_setattr_in *attr_, 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_ll *f = req->f; + int ctr; + struct fuse_ll *f = req->f; - pthread_mutex_lock(&f->lock); - req->u.ni.func = NULL; - req->u.ni.data = NULL; - list_del_req(req); - ctr = --req->ctr; - pthread_mutex_unlock(&f->lock); - if (!ctr) - destroy_req(req); + pthread_mutex_lock(&f->lock); + req->u.ni.func = NULL; + req->u.ni.data = NULL; + list_del_req(req); + ctr = --req->ctr; + pthread_mutex_unlock(&f->lock); + if (!ctr) + destroy_req(req); } static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) { - struct fuse_req *req; + struct fuse_req *req; - req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); - if (req == NULL) { - fprintf(stderr, "fuse: failed to allocate request\n"); - } else { - req->f = f; - 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) { + fprintf(stderr, "fuse: failed to allocate request\n"); + } else { + req->f = f; + req->ctr = 1; + list_init_req(req); + fuse_mutex_init(&req->lock); + } - return req; + return req; } static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch, struct iovec *iov, int count) { - struct fuse_out_header *out = iov[0].iov_base; - - out->len = iov_length(iov, count); - if (f->debug) { - if (out->unique == 0) { - fprintf(stderr, "NOTIFY: code=%d length=%u\n", - out->error, out->len); - } else if (out->error) { - fprintf(stderr, - " unique: %llu, error: %i (%s), outsize: %i\n", - (unsigned long long) out->unique, out->error, - strerror(-out->error), out->len); - } else { - fprintf(stderr, - " unique: %llu, success, outsize: %i\n", - (unsigned long long) out->unique, out->len); - } - } + struct fuse_out_header *out = iov[0].iov_base; + + out->len = iov_length(iov, count); + if (f->debug) { + if (out->unique == 0) { + fprintf(stderr, "NOTIFY: code=%d length=%u\n", + out->error, out->len); + } else if (out->error) { + fprintf(stderr, + " unique: %llu, error: %i (%s), outsize: %i\n", + (unsigned long long) out->unique, out->error, + strerror(-out->error), out->len); + } else { + fprintf(stderr, + " unique: %llu, success, outsize: %i\n", + (unsigned long long) out->unique, out->len); + } + } - return fuse_chan_send(ch, iov, count); + return fuse_chan_send(ch, iov, count); } int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count) { - struct fuse_out_header out; + struct fuse_out_header out; - if (error <= -1000 || error > 0) { - fprintf(stderr, "fuse: bad error value: %i\n", error); - error = -ERANGE; - } + if (error <= -1000 || error > 0) { + fprintf(stderr, "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->f, req->ch, iov, count); + return fuse_send_msg(req->f, req->ch, iov, count); } static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, 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) { - 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; } size_t fuse_dirent_size(size_t namelen) { - return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); + return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); } char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, off_t off) { - unsigned namelen = strlen(name); - unsigned entlen = FUSE_NAME_OFFSET + namelen; - unsigned entsize = fuse_dirent_size(namelen); - unsigned padlen = entsize - entlen; - struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + unsigned namelen = strlen(name); + unsigned entlen = FUSE_NAME_OFFSET + namelen; + unsigned entsize = fuse_dirent_size(namelen); + unsigned padlen = entsize - entlen; + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; - dirent->ino = stbuf->st_ino; - dirent->off = off; - dirent->namelen = namelen; - dirent->type = (stbuf->st_mode & 0170000) >> 12; - strncpy(dirent->name, name, namelen); - if (padlen) - memset(buf + entlen, 0, padlen); + dirent->ino = stbuf->st_ino; + dirent->off = off; + dirent->namelen = namelen; + dirent->type = (stbuf->st_mode & 0170000) >> 12; + strncpy(dirent->name, name, namelen); + if (padlen) + memset(buf + entlen, 0, padlen); - return buf + entsize; + return buf + entsize; } size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off) { - size_t entsize; + size_t entsize; - (void) req; - entsize = fuse_dirent_size(strlen(name)); - if (entsize <= bufsize && buf) - fuse_add_dirent(buf, name, stbuf, off); - return entsize; + (void) req; + entsize = fuse_dirent_size(strlen(name)); + if (entsize <= bufsize && buf) + fuse_add_dirent(buf, name, stbuf, off); + return entsize; } static void convert_statfs(const struct statvfs *stbuf, 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 @@ -314,9 +314,9 @@ fuse_reply_err(fuse_req_t req_, void fuse_reply_none(fuse_req_t req) { - if (req->ch) - fuse_chan_send(req->ch, NULL, 0); - fuse_free_req(req); + if (req->ch) + fuse_chan_send(req->ch, NULL, 0); + fuse_free_req(req); } static @@ -336,47 +336,47 @@ fill_entry(struct fuse_entry_out *arg, 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->nonseekable) - arg->open_flags |= FOPEN_NONSEEKABLE; - if (f->cache_readdir) - arg->open_flags |= FOPEN_CACHE_DIR; + 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->nonseekable) + arg->open_flags |= FOPEN_NONSEEKABLE; + if (f->cache_readdir) + arg->open_flags |= FOPEN_CACHE_DIR; } int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) { - struct fuse_entry_out arg; - size_t size = req->f->conn.proto_minor < 9 ? - FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg); + struct fuse_entry_out arg; + size_t size = req->f->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->f->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->f->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) { - char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)]; - size_t entrysize = req->f->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->f->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 @@ -398,31 +398,31 @@ fuse_reply_attr(fuse_req_t req, 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_ll *f, struct fuse_chan *ch, @@ -430,620 +430,620 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch, struct fuse_bufvec *buf, size_t len) { - struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); - void *mbuf; - int res; + struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); + void *mbuf; + int res; - /* 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(f, 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(f, ch, iov, iov_count); + } - res = posix_memalign(&mbuf, pagesize, len); - if (res != 0) - return res; + res = posix_memalign(&mbuf, pagesize, len); + if (res != 0) + return res; - mem_buf.buf[0].mem = mbuf; - res = fuse_buf_copy(&mem_buf, buf, 0); - if (res < 0) { - free(mbuf); - return -res; - } - len = res; + mem_buf.buf[0].mem = mbuf; + res = fuse_buf_copy(&mem_buf, buf, 0); + if (res < 0) { + free(mbuf); + return -res; + } + len = res; - iov[iov_count].iov_base = mbuf; - iov[iov_count].iov_len = len; - iov_count++; - res = fuse_send_msg(f, ch, iov, iov_count); - free(mbuf); + iov[iov_count].iov_base = mbuf; + iov[iov_count].iov_len = len; + iov_count++; + res = fuse_send_msg(f, ch, iov, iov_count); + free(mbuf); - return res; + return res; } struct fuse_ll_pipe { - size_t size; - int can_grow; - int pipe[2]; + size_t size; + int can_grow; + int pipe[2]; }; static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp) { - close(llp->pipe[0]); - close(llp->pipe[1]); - free(llp); + close(llp->pipe[0]); + close(llp->pipe[1]); + free(llp); } #ifdef HAVE_SPLICE static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_ll *f) { - struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); - if (llp == NULL) { - int res; + struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); + if (llp == NULL) { + int res; - llp = malloc(sizeof(struct fuse_ll_pipe)); - if (llp == NULL) - return NULL; + llp = malloc(sizeof(struct fuse_ll_pipe)); + if (llp == NULL) + return NULL; - res = pipe(llp->pipe); - if (res == -1) { - free(llp); - return NULL; - } + res = pipe(llp->pipe); + if (res == -1) { + free(llp); + return NULL; + } - if (fcntl(llp->pipe[0], F_SETFL, O_NONBLOCK) == -1 || - fcntl(llp->pipe[1], F_SETFL, O_NONBLOCK) == -1) { - close(llp->pipe[0]); - close(llp->pipe[1]); - free(llp); - return NULL; - } + if (fcntl(llp->pipe[0], F_SETFL, O_NONBLOCK) == -1 || + fcntl(llp->pipe[1], F_SETFL, O_NONBLOCK) == -1) { + close(llp->pipe[0]); + close(llp->pipe[1]); + free(llp); + return NULL; + } - /* - *the default size is 16 pages on linux - */ - llp->size = pagesize * 16; - llp->can_grow = 1; + /* + *the default size is 16 pages on linux + */ + llp->size = pagesize * 16; + llp->can_grow = 1; - pthread_setspecific(f->pipe_key, llp); - } + pthread_setspecific(f->pipe_key, llp); + } - return llp; + return llp; } #endif static void fuse_ll_clear_pipe(struct fuse_ll *f) { - struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); - if (llp) { - pthread_setspecific(f->pipe_key, NULL); - fuse_ll_pipe_free(llp); - } + struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); + if (llp) { + pthread_setspecific(f->pipe_key, NULL); + fuse_ll_pipe_free(llp); + } } #if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE) static int read_back(int fd, char *buf, size_t len) { - int res; + int res; - res = read(fd, buf, len); - if (res == -1) { - fprintf(stderr, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno)); - return -EIO; - } - if (res != len) { - fprintf(stderr, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len); - return -EIO; - } - return 0; + res = read(fd, buf, len); + if (res == -1) { + fprintf(stderr, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno)); + return -EIO; + } + if (res != len) { + fprintf(stderr, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len); + return -EIO; + } + return 0; } static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, - struct iovec *iov, int iov_count, - struct fuse_bufvec *buf, unsigned int flags) -{ - int res; - size_t len = fuse_buf_size(buf); - struct fuse_out_header *out = iov[0].iov_base; - struct fuse_ll_pipe *llp; - int splice_flags; - size_t pipesize; - size_t total_fd_size; - size_t idx; - size_t headerlen; - struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len); - - if (f->broken_splice_nonblock) - goto fallback; - - if (flags & FUSE_BUF_NO_SPLICE) - goto fallback; - - total_fd_size = 0; - for (idx = buf->idx; idx < buf->count; idx++) { - if (buf->buf[idx].flags & FUSE_BUF_IS_FD) { - total_fd_size = buf->buf[idx].size; - if (idx == buf->idx) - total_fd_size -= buf->off; - } - } - if (total_fd_size < 2 * pagesize) - goto fallback; - - if (f->conn.proto_minor < 14 || - !(f->conn.want & FUSE_CAP_SPLICE_WRITE)) - goto fallback; - - llp = fuse_ll_get_pipe(f); - if (llp == NULL) - goto fallback; - - - headerlen = iov_length(iov, iov_count); - - out->len = headerlen + len; - - /* - * Heuristic for the required pipe size, does not work if the - * source contains less than page size fragments - */ - pipesize = pagesize * (iov_count + buf->count + 1) + out->len; - - if (llp->size < pipesize) { - if (llp->can_grow) { - res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize); - if (res == -1) { - llp->can_grow = 0; - goto fallback; - } - llp->size = res; - } - if (llp->size < pipesize) - goto fallback; - } - - - res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK); - if (res == -1) - goto fallback; - - if (res != headerlen) { - res = -EIO; - fprintf(stderr, "fuse: short vmsplice to pipe: %u/%zu\n", res, - headerlen); - goto clear_pipe; - } - - pipe_buf.buf[0].flags = FUSE_BUF_IS_FD; - pipe_buf.buf[0].fd = llp->pipe[1]; - - res = fuse_buf_copy(&pipe_buf, buf, - FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK); - if (res < 0) { - if (res == -EAGAIN || res == -EINVAL) { - /* - * Should only get EAGAIN on kernels with - * broken SPLICE_F_NONBLOCK support (<= - * 2.6.35) where this error or a short read is - * returned even if the pipe itself is not - * full - * - * EINVAL might mean that splice can't handle - * this combination of input and output. - */ - if (res == -EAGAIN) - f->broken_splice_nonblock = 1; - - pthread_setspecific(f->pipe_key, NULL); - fuse_ll_pipe_free(llp); - goto fallback; - } - res = -res; - goto clear_pipe; - } - - if (res != 0 && res < len) { - struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); - void *mbuf; - size_t now_len = res; - /* - * For regular files a short count is either - * 1) due to EOF, or - * 2) because of broken SPLICE_F_NONBLOCK (see above) - * - * For other inputs it's possible that we overflowed - * the pipe because of small buffer fragments. - */ - - res = posix_memalign(&mbuf, pagesize, len); - if (res != 0) - goto clear_pipe; - - mem_buf.buf[0].mem = mbuf; - mem_buf.off = now_len; - res = fuse_buf_copy(&mem_buf, buf, 0); - if (res > 0) { - char *tmpbuf; - size_t extra_len = res; - /* - * Trickiest case: got more data. Need to get - * back the data from the pipe and then fall - * back to regular write. - */ - tmpbuf = malloc(headerlen); - if (tmpbuf == NULL) { - free(mbuf); - res = ENOMEM; - goto clear_pipe; - } - res = read_back(llp->pipe[0], tmpbuf, headerlen); - free(tmpbuf); - if (res != 0) { - free(mbuf); - goto clear_pipe; - } - res = read_back(llp->pipe[0], mbuf, now_len); - if (res != 0) { - free(mbuf); - goto clear_pipe; - } - len = now_len + extra_len; - iov[iov_count].iov_base = mbuf; - iov[iov_count].iov_len = len; - iov_count++; - res = fuse_send_msg(f, ch, iov, iov_count); - free(mbuf); - return res; - } - free(mbuf); - res = now_len; - } - len = res; - out->len = headerlen + len; - - if (f->debug) { - fprintf(stderr, - " unique: %llu, success, outsize: %i (splice)\n", - (unsigned long long) out->unique, out->len); - } - - splice_flags = 0; - if ((flags & FUSE_BUF_SPLICE_MOVE) && - (f->conn.want & FUSE_CAP_SPLICE_MOVE)) - splice_flags |= SPLICE_F_MOVE; - - res = splice(llp->pipe[0], NULL, - fuse_chan_fd(ch), NULL, out->len, splice_flags); - if (res == -1) { - res = -errno; - perror("fuse: splice from pipe"); - goto clear_pipe; - } - if (res != out->len) { - res = -EIO; - fprintf(stderr, "fuse: short splice from pipe: %u/%u\n", - res, out->len); - goto clear_pipe; - } - return 0; - -clear_pipe: - fuse_ll_clear_pipe(f); - return res; - -fallback: - return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); + struct iovec *iov, int iov_count, + struct fuse_bufvec *buf, unsigned int flags) +{ + int res; + size_t len = fuse_buf_size(buf); + struct fuse_out_header *out = iov[0].iov_base; + struct fuse_ll_pipe *llp; + int splice_flags; + size_t pipesize; + size_t total_fd_size; + size_t idx; + size_t headerlen; + struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len); + + if (f->broken_splice_nonblock) + goto fallback; + + if (flags & FUSE_BUF_NO_SPLICE) + goto fallback; + + total_fd_size = 0; + for (idx = buf->idx; idx < buf->count; idx++) { + if (buf->buf[idx].flags & FUSE_BUF_IS_FD) { + total_fd_size = buf->buf[idx].size; + if (idx == buf->idx) + total_fd_size -= buf->off; + } + } + if (total_fd_size < 2 * pagesize) + goto fallback; + + if (f->conn.proto_minor < 14 || + !(f->conn.want & FUSE_CAP_SPLICE_WRITE)) + goto fallback; + + llp = fuse_ll_get_pipe(f); + if (llp == NULL) + goto fallback; + + + headerlen = iov_length(iov, iov_count); + + out->len = headerlen + len; + + /* + * Heuristic for the required pipe size, does not work if the + * source contains less than page size fragments + */ + pipesize = pagesize * (iov_count + buf->count + 1) + out->len; + + if (llp->size < pipesize) { + if (llp->can_grow) { + res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize); + if (res == -1) { + llp->can_grow = 0; + goto fallback; + } + llp->size = res; + } + if (llp->size < pipesize) + goto fallback; + } + + + res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK); + if (res == -1) + goto fallback; + + if (res != headerlen) { + res = -EIO; + fprintf(stderr, "fuse: short vmsplice to pipe: %u/%zu\n", res, + headerlen); + goto clear_pipe; + } + + pipe_buf.buf[0].flags = FUSE_BUF_IS_FD; + pipe_buf.buf[0].fd = llp->pipe[1]; + + res = fuse_buf_copy(&pipe_buf, buf, + FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK); + if (res < 0) { + if (res == -EAGAIN || res == -EINVAL) { + /* + * Should only get EAGAIN on kernels with + * broken SPLICE_F_NONBLOCK support (<= + * 2.6.35) where this error or a short read is + * returned even if the pipe itself is not + * full + * + * EINVAL might mean that splice can't handle + * this combination of input and output. + */ + if (res == -EAGAIN) + f->broken_splice_nonblock = 1; + + pthread_setspecific(f->pipe_key, NULL); + fuse_ll_pipe_free(llp); + goto fallback; + } + res = -res; + goto clear_pipe; + } + + if (res != 0 && res < len) { + struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); + void *mbuf; + size_t now_len = res; + /* + * For regular files a short count is either + * 1) due to EOF, or + * 2) because of broken SPLICE_F_NONBLOCK (see above) + * + * For other inputs it's possible that we overflowed + * the pipe because of small buffer fragments. + */ + + res = posix_memalign(&mbuf, pagesize, len); + if (res != 0) + goto clear_pipe; + + mem_buf.buf[0].mem = mbuf; + mem_buf.off = now_len; + res = fuse_buf_copy(&mem_buf, buf, 0); + if (res > 0) { + char *tmpbuf; + size_t extra_len = res; + /* + * Trickiest case: got more data. Need to get + * back the data from the pipe and then fall + * back to regular write. + */ + tmpbuf = malloc(headerlen); + if (tmpbuf == NULL) { + free(mbuf); + res = ENOMEM; + goto clear_pipe; + } + res = read_back(llp->pipe[0], tmpbuf, headerlen); + free(tmpbuf); + if (res != 0) { + free(mbuf); + goto clear_pipe; + } + res = read_back(llp->pipe[0], mbuf, now_len); + if (res != 0) { + free(mbuf); + goto clear_pipe; + } + len = now_len + extra_len; + iov[iov_count].iov_base = mbuf; + iov[iov_count].iov_len = len; + iov_count++; + res = fuse_send_msg(f, ch, iov, iov_count); + free(mbuf); + return res; + } + free(mbuf); + res = now_len; + } + len = res; + out->len = headerlen + len; + + if (f->debug) { + fprintf(stderr, + " unique: %llu, success, outsize: %i (splice)\n", + (unsigned long long) out->unique, out->len); + } + + splice_flags = 0; + if ((flags & FUSE_BUF_SPLICE_MOVE) && + (f->conn.want & FUSE_CAP_SPLICE_MOVE)) + splice_flags |= SPLICE_F_MOVE; + + res = splice(llp->pipe[0], NULL, + fuse_chan_fd(ch), NULL, out->len, splice_flags); + if (res == -1) { + res = -errno; + perror("fuse: splice from pipe"); + goto clear_pipe; + } + if (res != out->len) { + res = -EIO; + fprintf(stderr, "fuse: short splice from pipe: %u/%u\n", + res, out->len); + goto clear_pipe; + } + return 0; + + clear_pipe: + fuse_ll_clear_pipe(f); + return res; + + fallback: + return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); } #else static int fuse_send_data_iov(struct fuse_ll *f, 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(f, ch, iov, iov_count, buf, len); + return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); } #endif int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, 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->f, 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->f, 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->f->conn.proto_minor < 4 ? - FUSE_COMPAT_STATFS_SIZE : sizeof(arg); + struct fuse_statfs_out arg; + size_t size = req->f->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; + struct fuse_ioctl_iovec *fiov; + size_t i; - fiov = malloc(sizeof(fiov[0]) * count); - if (!fiov) - return NULL; + 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; - } + for (i = 0; i < count; i++) { + fiov[i].base = (uintptr_t) iov[i].iov_base; + fiov[i].len = iov[i].iov_len; + } - return fiov; + 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->f->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); - - return res; - -enomem: - res = fuse_reply_err(req, ENOMEM); - goto out; + 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->f->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); + + return res; + + enomem: + res = fuse_reply_err(req, ENOMEM); + goto out; } int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size) { - int count; - struct iovec iov[3]; - struct fuse_ioctl_out arg; + int count; + struct iovec iov[3]; + struct fuse_ioctl_out arg; - arg.result = result; - arg.flags = 0; - arg.in_iovs = 0; - arg.out_iovs = 0; + arg.result = result; + arg.flags = 0; + arg.in_iovs = 0; + arg.out_iovs = 0; - count = 1; - iov[count].iov_base = &arg; - iov[count].iov_len = sizeof(arg); - count++; + count = 1; + 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) { - 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)); } 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->f->op.lookup) - req->f->op.lookup(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.lookup) + req->f->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->f->op.forget) - req->f->op.forget(req, nodeid, arg->nlookup); - else - fuse_reply_none(req); + if (req->f->op.forget) + req->f->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) { - 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->f->op.forget_multi) { - req->f->op.forget_multi(req, arg->count, - (struct fuse_forget_data *) param); - } else if (req->f->op.forget) { - for (i = 0; i < arg->count; i++) { - struct fuse_forget_one *forget = ¶m[i]; - struct fuse_req *dummy_req; + if (req->f->op.forget_multi) { + req->f->op.forget_multi(req, arg->count, + (struct fuse_forget_data *) param); + } else if (req->f->op.forget) { + for (i = 0; i < arg->count; i++) { + struct fuse_forget_one *forget = ¶m[i]; + struct fuse_req *dummy_req; - dummy_req = fuse_ll_alloc_req(req->f); - if (dummy_req == NULL) - break; + dummy_req = fuse_ll_alloc_req(req->f); + 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->f->op.forget(dummy_req, forget->nodeid, - forget->nlookup); - } - fuse_reply_none(req); - } else { - fuse_reply_none(req); - } + req->f->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->f->conn.proto_minor >= 9) { - struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg; + if (req->f->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->f->op.getattr) - req->f->op.getattr(req, nodeid, fip); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.getattr) + req->f->op.getattr(req, nodeid, fip); + else + fuse_reply_err(req, ENOSYS); } static @@ -1090,308 +1090,308 @@ do_setattr(fuse_req_t req_, 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->f->op.access) - req->f->op.access(req, nodeid, arg->mask); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.access) + req->f->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->f->op.readlink) - req->f->op.readlink(req, nodeid); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.readlink) + req->f->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->f->conn.proto_minor >= 12) - req->ctx.umask = arg->umask; - else - name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE; + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else + name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE; - if (req->f->op.mknod) - req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.mknod) + req->f->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->f->conn.proto_minor >= 12) - req->ctx.umask = arg->umask; + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; - if (req->f->op.mkdir) - req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.mkdir) + req->f->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->f->op.unlink) - req->f->op.unlink(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.unlink) + req->f->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->f->op.rmdir) - req->f->op.rmdir(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.rmdir) + req->f->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->f->op.symlink) - req->f->op.symlink(req, linkname, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.symlink) + req->f->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->f->op.rename) - req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.rename) + req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); + 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->f->op.link) - req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.link) + req->f->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->f->op.create) { - struct fuse_file_info fi; - char *name = PARAM(arg); + if (req->f->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->f->conn.proto_minor >= 12) - req->ctx.umask = arg->umask; - else - name = (char *) inarg + sizeof(struct fuse_open_in); + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else + name = (char *) inarg + sizeof(struct fuse_open_in); - req->f->op.create(req, nodeid, name, arg->mode, &fi); - } else - fuse_reply_err(req, ENOSYS); + req->f->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->f->op.open) - req->f->op.open(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if (req->f->op.open) + req->f->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->f->op.read) { - struct fuse_file_info fi; + if (req->f->op.read) { + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - if (req->f->conn.proto_minor >= 9) { - fi.lock_owner = arg->lock_owner; - fi.flags = arg->flags; - } - req->f->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->f->conn.proto_minor >= 9) { + fi.lock_owner = arg->lock_owner; + fi.flags = arg->flags; + } + req->f->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; - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.writepage = arg->write_flags & 1; - - if (req->f->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->f->op.write) - req->f->op.write(req, nodeid, param, arg->size, - arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + 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 & 1; + + if (req->f->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->f->op.write) + req->f->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_ll *f = req->f; - 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 & 1; - - if (req->f->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) { - fprintf(stderr, "fuse: do_write_buf: buffer size too small\n"); - fuse_reply_err(req, EIO); - goto out; - } - bufv.buf[0].size = arg->size; - - req->f->op.write_buf(req, nodeid, &bufv, arg->offset, &fi); - -out: - /* Need to reset the pipe if ->write_buf() didn't consume all data */ - if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) - fuse_ll_clear_pipe(f); + struct fuse_ll *f = req->f; + 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 & 1; + + if (req->f->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) { + fprintf(stderr, "fuse: do_write_buf: buffer size too small\n"); + fuse_reply_err(req, EIO); + goto out; + } + bufv.buf[0].size = arg->size; + + req->f->op.write_buf(req, nodeid, &bufv, arg->offset, &fi); + + out: + /* Need to reset the pipe if ->write_buf() didn't consume all data */ + if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) + fuse_ll_clear_pipe(f); } 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->f->conn.proto_minor >= 7) - fi.lock_owner = arg->lock_owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.flush = 1; + if (req->f->conn.proto_minor >= 7) + fi.lock_owner = arg->lock_owner; - if (req->f->op.flush) - req->f->op.flush(req, nodeid, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.flush) + req->f->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; - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - if (req->f->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->f->op.release) - req->f->op.release(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + 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->f->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->f->op.release) + req->f->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; + struct fuse_fsync_in *arg = (struct fuse_fsync_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->f->op.fsync) - req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.fsync) + req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &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->f->op.opendir) - req->f->op.opendir(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if (req->f->op.opendir) + req->f->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->f->op.readdir) - req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.readdir) + req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } static @@ -1414,594 +1414,594 @@ do_readdir_plus(fuse_req_t req_, 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->f->op.releasedir) - req->f->op.releasedir(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + if (req->f->op.releasedir) + req->f->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; + struct fuse_fsync_in *arg = (struct fuse_fsync_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->f->op.fsyncdir) - req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.fsyncdir) + req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &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->f->op.statfs) - req->f->op.statfs(req, nodeid); - else { - struct statvfs buf = { - .f_namemax = 255, - .f_bsize = 512, - }; - fuse_reply_statfs(req, &buf); - } + if (req->f->op.statfs) + req->f->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->f->op.setxattr) - req->f->op.setxattr(req, nodeid, name, value, arg->size, - arg->flags); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.setxattr) + req->f->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->f->op.getxattr) - req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.getxattr) + req->f->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->f->op.listxattr) - req->f->op.listxattr(req, nodeid, arg->size); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.listxattr) + req->f->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->f->op.removexattr) - req->f->op.removexattr(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.removexattr) + req->f->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) { - 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->f->op.getlk) - req->f->op.getlk(req, nodeid, &fi, &flock); - else - fuse_reply_err(req, ENOSYS); + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.getlk) + req->f->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->f->op.flock) - req->f->op.flock(req, nodeid, &fi, op); - else - fuse_reply_err(req, ENOSYS); - } else { - convert_fuse_file_lock(&arg->lk, &flock); - if (req->f->op.setlk) - req->f->op.setlk(req, nodeid, &fi, &flock, sleep); - else - fuse_reply_err(req, ENOSYS); - } + 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->f->op.flock) + req->f->op.flock(req, nodeid, &fi, op); + else + fuse_reply_err(req, ENOSYS); + } else { + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.setlk) + req->f->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_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->list.next; curr != &f->list; curr = curr->next) { - if (curr->unique == req->u.i.unique) { - fuse_interrupt_func_t func; - void *data; - - curr->ctr++; - pthread_mutex_unlock(&f->lock); - - /* Ugh, ugly locking */ - pthread_mutex_lock(&curr->lock); - pthread_mutex_lock(&f->lock); - curr->interrupted = 1; - func = curr->u.ni.func; - data = curr->u.ni.data; - pthread_mutex_unlock(&f->lock); - if (func) - func(curr, data); - pthread_mutex_unlock(&curr->lock); - - pthread_mutex_lock(&f->lock); - curr->ctr--; - if (!curr->ctr) - destroy_req(curr); - - return 1; - } - } - for (curr = f->interrupts.next; curr != &f->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->u.i.unique) - return 1; - } - return 0; + struct fuse_req *curr; + + for (curr = f->list.next; curr != &f->list; curr = curr->next) { + if (curr->unique == req->u.i.unique) { + fuse_interrupt_func_t func; + void *data; + + curr->ctr++; + pthread_mutex_unlock(&f->lock); + + /* Ugh, ugly locking */ + pthread_mutex_lock(&curr->lock); + pthread_mutex_lock(&f->lock); + curr->interrupted = 1; + func = curr->u.ni.func; + data = curr->u.ni.data; + pthread_mutex_unlock(&f->lock); + if (func) + func(curr, data); + pthread_mutex_unlock(&curr->lock); + + pthread_mutex_lock(&f->lock); + curr->ctr--; + if (!curr->ctr) + destroy_req(curr); + + return 1; + } + } + for (curr = f->interrupts.next; curr != &f->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_ll *f = req->f; + struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; + struct fuse_ll *f = req->f; - (void) nodeid; - if (f->debug) - fprintf(stderr, "INTERRUPT: %llu\n", - (unsigned long long) arg->unique); + (void) nodeid; + if (f->debug) + fprintf(stderr, "INTERRUPT: %llu\n", + (unsigned long long) arg->unique); - req->u.i.unique = arg->unique; + req->u.i.unique = arg->unique; - pthread_mutex_lock(&f->lock); - if (find_interrupted(f, req)) - destroy_req(req); - else - list_add_req(req, &f->interrupts); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + if (find_interrupted(f, req)) + destroy_req(req); + else + list_add_req(req, &f->interrupts); + pthread_mutex_unlock(&f->lock); } static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->interrupts.next; curr != &f->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->unique) { - req->interrupted = 1; - list_del_req(curr); - free(curr); - return NULL; - } - } - curr = f->interrupts.next; - if (curr != &f->interrupts) { - list_del_req(curr); - list_init_req(curr); - return curr; - } else - return NULL; + struct fuse_req *curr; + + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if (curr->u.i.unique == req->unique) { + req->interrupted = 1; + list_del_req(curr); + free(curr); + return NULL; + } + } + curr = f->interrupts.next; + if (curr != &f->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->f->op.bmap) - req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.bmap) + req->f->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; - - if (flags & FUSE_IOCTL_DIR && - !(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) { - fuse_reply_err(req, ENOTTY); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 && - !(flags & FUSE_IOCTL_32BIT)) { - req->ioctl_64bit = 1; - } - - if (req->f->op.ioctl) - req->f->op.ioctl(req, nodeid, (unsigned long)arg->cmd, - (void *)(uintptr_t)arg->arg, &fi, flags, - in_buf, arg->in_size, arg->out_size); - else - fuse_reply_err(req, ENOSYS); + 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->f->conn.want & FUSE_CAP_IOCTL_DIR)) { + fuse_reply_err(req, ENOTTY); + return; + } + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + + if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 && + !(flags & FUSE_IOCTL_32BIT)) { + req->ioctl_64bit = 1; + } + + if (req->f->op.ioctl) + req->f->op.ioctl(req, nodeid, (unsigned long)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; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; - if (req->f->op.poll) { - struct fuse_pollhandle *ph = NULL; + if (req->f->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->ch = req->ch; - ph->f = req->f; - } + 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->ch = req->ch; + ph->f = req->f; + } - req->f->op.poll(req, nodeid, &fi, ph); - } else { - fuse_reply_err(req, ENOSYS); - } + req->f->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->f->op.fallocate) - req->f->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.fallocate) + req->f->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &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_ll *f = req->f; - size_t bufsize = fuse_chan_bufsize(req->ch); - - (void) nodeid; - if (f->debug) { - fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); - if (arg->major == 7 && arg->minor >= 6) { - fprintf(stderr, "flags=0x%08x\n", arg->flags); - fprintf(stderr, "max_readahead=0x%08x\n", - arg->max_readahead); - } - } - f->conn.proto_major = arg->major; - f->conn.proto_minor = arg->minor; - f->conn.capable = 0; - f->conn.want = 0; - - memset(&outarg, 0, sizeof(outarg)); - - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - outarg.max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ; - - if (arg->major < 7) { - fprintf(stderr, "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 < f->conn.max_readahead) - f->conn.max_readahead = arg->max_readahead; - if (arg->flags & FUSE_ASYNC_READ) - f->conn.capable |= FUSE_CAP_ASYNC_READ; - if (arg->flags & FUSE_POSIX_LOCKS) - f->conn.capable |= FUSE_CAP_POSIX_LOCKS; - if (arg->flags & FUSE_ATOMIC_O_TRUNC) - f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC; - if (arg->flags & FUSE_EXPORT_SUPPORT) - f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT; - if (arg->flags & FUSE_BIG_WRITES) - f->conn.capable |= FUSE_CAP_BIG_WRITES; - if (arg->flags & FUSE_DONT_MASK) - f->conn.capable |= FUSE_CAP_DONT_MASK; - if (arg->flags & FUSE_FLOCK_LOCKS) - f->conn.capable |= FUSE_CAP_FLOCK_LOCKS; - if (arg->flags & FUSE_POSIX_ACL) - f->conn.capable |= FUSE_CAP_POSIX_ACL; - if (arg->flags & FUSE_CACHE_SYMLINKS) - f->conn.capable |= FUSE_CAP_CACHE_SYMLINKS; - if (arg->flags & FUSE_ASYNC_DIO) - f->conn.capable |= FUSE_CAP_ASYNC_DIO; - if (arg->flags & FUSE_PARALLEL_DIROPS) - f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; - if (arg->flags & FUSE_MAX_PAGES) - f->conn.capable |= FUSE_CAP_MAX_PAGES; - if (arg->flags & FUSE_WRITEBACK_CACHE) - f->conn.capable |= FUSE_CAP_WRITEBACK_CACHE; - if (arg->flags & FUSE_DO_READDIRPLUS) - f->conn.capable |= FUSE_CAP_READDIR_PLUS; - if (arg->flags & FUSE_READDIRPLUS_AUTO) - f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO; - } else { - f->conn.want &= ~FUSE_CAP_ASYNC_READ; - f->conn.max_readahead = 0; - } - - if (req->f->conn.proto_minor >= 14) { + struct fuse_init_in *arg = (struct fuse_init_in *) inarg; + struct fuse_init_out outarg; + struct fuse_ll *f = req->f; + size_t bufsize = fuse_chan_bufsize(req->ch); + + (void) nodeid; + if (f->debug) { + fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); + if (arg->major == 7 && arg->minor >= 6) { + fprintf(stderr, "flags=0x%08x\n", arg->flags); + fprintf(stderr, "max_readahead=0x%08x\n", + arg->max_readahead); + } + } + f->conn.proto_major = arg->major; + f->conn.proto_minor = arg->minor; + f->conn.capable = 0; + f->conn.want = 0; + + memset(&outarg, 0, sizeof(outarg)); + + outarg.major = FUSE_KERNEL_VERSION; + outarg.minor = FUSE_KERNEL_MINOR_VERSION; + outarg.max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ; + + if (arg->major < 7) { + fprintf(stderr, "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 < f->conn.max_readahead) + f->conn.max_readahead = arg->max_readahead; + if (arg->flags & FUSE_ASYNC_READ) + f->conn.capable |= FUSE_CAP_ASYNC_READ; + if (arg->flags & FUSE_POSIX_LOCKS) + f->conn.capable |= FUSE_CAP_POSIX_LOCKS; + if (arg->flags & FUSE_ATOMIC_O_TRUNC) + f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC; + if (arg->flags & FUSE_EXPORT_SUPPORT) + f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT; + if (arg->flags & FUSE_BIG_WRITES) + f->conn.capable |= FUSE_CAP_BIG_WRITES; + if (arg->flags & FUSE_DONT_MASK) + f->conn.capable |= FUSE_CAP_DONT_MASK; + if (arg->flags & FUSE_FLOCK_LOCKS) + f->conn.capable |= FUSE_CAP_FLOCK_LOCKS; + if (arg->flags & FUSE_POSIX_ACL) + f->conn.capable |= FUSE_CAP_POSIX_ACL; + if (arg->flags & FUSE_CACHE_SYMLINKS) + f->conn.capable |= FUSE_CAP_CACHE_SYMLINKS; + if (arg->flags & FUSE_ASYNC_DIO) + f->conn.capable |= FUSE_CAP_ASYNC_DIO; + if (arg->flags & FUSE_PARALLEL_DIROPS) + f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; + if (arg->flags & FUSE_MAX_PAGES) + f->conn.capable |= FUSE_CAP_MAX_PAGES; + if (arg->flags & FUSE_WRITEBACK_CACHE) + f->conn.capable |= FUSE_CAP_WRITEBACK_CACHE; + if (arg->flags & FUSE_DO_READDIRPLUS) + f->conn.capable |= FUSE_CAP_READDIR_PLUS; + if (arg->flags & FUSE_READDIRPLUS_AUTO) + f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO; + } else { + f->conn.want &= ~FUSE_CAP_ASYNC_READ; + f->conn.max_readahead = 0; + } + + if (req->f->conn.proto_minor >= 14) { #ifdef HAVE_SPLICE #ifdef HAVE_VMSPLICE - f->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; - if (f->splice_write) - f->conn.want |= FUSE_CAP_SPLICE_WRITE; - if (f->splice_move) - f->conn.want |= FUSE_CAP_SPLICE_MOVE; + f->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; + if (f->splice_write) + f->conn.want |= FUSE_CAP_SPLICE_WRITE; + if (f->splice_move) + f->conn.want |= FUSE_CAP_SPLICE_MOVE; #endif - f->conn.capable |= FUSE_CAP_SPLICE_READ; - if (f->splice_read) - f->conn.want |= FUSE_CAP_SPLICE_READ; + f->conn.capable |= FUSE_CAP_SPLICE_READ; + if (f->splice_read) + f->conn.want |= FUSE_CAP_SPLICE_READ; #endif - } - if (req->f->conn.proto_minor >= 18) - f->conn.capable |= FUSE_CAP_IOCTL_DIR; - - if (f->op.getlk && f->op.setlk && !f->no_remote_posix_lock) - f->conn.want |= FUSE_CAP_POSIX_LOCKS; - if (f->op.flock && !f->no_remote_flock) - f->conn.want |= FUSE_CAP_FLOCK_LOCKS; - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - - bufsize -= 4096; - if (bufsize < f->conn.max_write) - f->conn.max_write = bufsize; - - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata, &f->conn); - - if (f->no_splice_read) - f->conn.want &= ~FUSE_CAP_SPLICE_READ; - if (f->no_splice_write) - f->conn.want &= ~FUSE_CAP_SPLICE_WRITE; - if (f->no_splice_move) - f->conn.want &= ~FUSE_CAP_SPLICE_MOVE; - - if ((arg->flags & FUSE_MAX_PAGES) && (f->conn.want & FUSE_CAP_MAX_PAGES)) - { - outarg.flags |= FUSE_MAX_PAGES; - outarg.max_pages = f->conn.max_pages; - } - - if (f->conn.want & FUSE_CAP_ASYNC_READ) - outarg.flags |= FUSE_ASYNC_READ; - if (f->conn.want & FUSE_CAP_POSIX_LOCKS) - outarg.flags |= FUSE_POSIX_LOCKS; - if (f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) - outarg.flags |= FUSE_ATOMIC_O_TRUNC; - if (f->conn.want & FUSE_CAP_EXPORT_SUPPORT) - outarg.flags |= FUSE_EXPORT_SUPPORT; - if (f->conn.want & FUSE_CAP_BIG_WRITES) - outarg.flags |= FUSE_BIG_WRITES; - if (f->conn.want & FUSE_CAP_DONT_MASK) - outarg.flags |= FUSE_DONT_MASK; - if (f->conn.want & FUSE_CAP_FLOCK_LOCKS) - outarg.flags |= FUSE_FLOCK_LOCKS; - if (f->conn.want & FUSE_CAP_POSIX_ACL) - outarg.flags |= FUSE_POSIX_ACL; - if (f->conn.want & FUSE_CAP_CACHE_SYMLINKS) - outarg.flags |= FUSE_CACHE_SYMLINKS; - if (f->conn.want & FUSE_CAP_ASYNC_DIO) - outarg.flags |= FUSE_ASYNC_DIO; - if (f->conn.want & FUSE_CAP_PARALLEL_DIROPS) - outarg.flags |= FUSE_PARALLEL_DIROPS; - if (f->conn.want & FUSE_CAP_WRITEBACK_CACHE) - outarg.flags |= FUSE_WRITEBACK_CACHE; - if (f->conn.want & FUSE_CAP_READDIR_PLUS) - outarg.flags |= FUSE_DO_READDIRPLUS; - if (f->conn.want & FUSE_CAP_READDIR_PLUS_AUTO) - outarg.flags |= FUSE_READDIRPLUS_AUTO; - - outarg.max_readahead = f->conn.max_readahead; - outarg.max_write = f->conn.max_write; - if (f->conn.proto_minor >= 13) { - if (f->conn.max_background >= (1 << 16)) - f->conn.max_background = (1 << 16) - 1; - if (f->conn.congestion_threshold > f->conn.max_background) - f->conn.congestion_threshold = f->conn.max_background; - if (!f->conn.congestion_threshold) { - f->conn.congestion_threshold = - f->conn.max_background * 3 / 4; - } - - outarg.max_background = f->conn.max_background; - outarg.congestion_threshold = f->conn.congestion_threshold; - } - - if (f->debug) { - fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); - fprintf(stderr, " flags=0x%08x\n", outarg.flags); - fprintf(stderr, " max_readahead=0x%08x\n", - outarg.max_readahead); - fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); - fprintf(stderr, " max_background=%i\n", - outarg.max_background); - fprintf(stderr, " congestion_threshold=%i\n", - outarg.congestion_threshold); - fprintf(stderr, " max_pages=%d\n",outarg.max_pages); - } - - size_t outargsize; - if(arg->minor < 5) - outargsize = FUSE_COMPAT_INIT_OUT_SIZE; - else if(arg->minor < 23) - outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE; - else - outargsize = sizeof(outarg); - - send_reply_ok(req, &outarg, outargsize); + } + if (req->f->conn.proto_minor >= 18) + f->conn.capable |= FUSE_CAP_IOCTL_DIR; + + if (f->op.getlk && f->op.setlk && !f->no_remote_posix_lock) + f->conn.want |= FUSE_CAP_POSIX_LOCKS; + if (f->op.flock && !f->no_remote_flock) + f->conn.want |= FUSE_CAP_FLOCK_LOCKS; + + if (bufsize < FUSE_MIN_READ_BUFFER) { + fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", + bufsize); + bufsize = FUSE_MIN_READ_BUFFER; + } + + bufsize -= 4096; + if (bufsize < f->conn.max_write) + f->conn.max_write = bufsize; + + f->got_init = 1; + if (f->op.init) + f->op.init(f->userdata, &f->conn); + + if (f->no_splice_read) + f->conn.want &= ~FUSE_CAP_SPLICE_READ; + if (f->no_splice_write) + f->conn.want &= ~FUSE_CAP_SPLICE_WRITE; + if (f->no_splice_move) + f->conn.want &= ~FUSE_CAP_SPLICE_MOVE; + + if ((arg->flags & FUSE_MAX_PAGES) && (f->conn.want & FUSE_CAP_MAX_PAGES)) + { + outarg.flags |= FUSE_MAX_PAGES; + outarg.max_pages = f->conn.max_pages; + } + + if (f->conn.want & FUSE_CAP_ASYNC_READ) + outarg.flags |= FUSE_ASYNC_READ; + if (f->conn.want & FUSE_CAP_POSIX_LOCKS) + outarg.flags |= FUSE_POSIX_LOCKS; + if (f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) + outarg.flags |= FUSE_ATOMIC_O_TRUNC; + if (f->conn.want & FUSE_CAP_EXPORT_SUPPORT) + outarg.flags |= FUSE_EXPORT_SUPPORT; + if (f->conn.want & FUSE_CAP_BIG_WRITES) + outarg.flags |= FUSE_BIG_WRITES; + if (f->conn.want & FUSE_CAP_DONT_MASK) + outarg.flags |= FUSE_DONT_MASK; + if (f->conn.want & FUSE_CAP_FLOCK_LOCKS) + outarg.flags |= FUSE_FLOCK_LOCKS; + if (f->conn.want & FUSE_CAP_POSIX_ACL) + outarg.flags |= FUSE_POSIX_ACL; + if (f->conn.want & FUSE_CAP_CACHE_SYMLINKS) + outarg.flags |= FUSE_CACHE_SYMLINKS; + if (f->conn.want & FUSE_CAP_ASYNC_DIO) + outarg.flags |= FUSE_ASYNC_DIO; + if (f->conn.want & FUSE_CAP_PARALLEL_DIROPS) + outarg.flags |= FUSE_PARALLEL_DIROPS; + if (f->conn.want & FUSE_CAP_WRITEBACK_CACHE) + outarg.flags |= FUSE_WRITEBACK_CACHE; + if (f->conn.want & FUSE_CAP_READDIR_PLUS) + outarg.flags |= FUSE_DO_READDIRPLUS; + if (f->conn.want & FUSE_CAP_READDIR_PLUS_AUTO) + outarg.flags |= FUSE_READDIRPLUS_AUTO; + + outarg.max_readahead = f->conn.max_readahead; + outarg.max_write = f->conn.max_write; + if (f->conn.proto_minor >= 13) { + if (f->conn.max_background >= (1 << 16)) + f->conn.max_background = (1 << 16) - 1; + if (f->conn.congestion_threshold > f->conn.max_background) + f->conn.congestion_threshold = f->conn.max_background; + if (!f->conn.congestion_threshold) { + f->conn.congestion_threshold = + f->conn.max_background * 3 / 4; + } + + outarg.max_background = f->conn.max_background; + outarg.congestion_threshold = f->conn.congestion_threshold; + } + + if (f->debug) { + fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); + fprintf(stderr, " flags=0x%08x\n", outarg.flags); + fprintf(stderr, " max_readahead=0x%08x\n", + outarg.max_readahead); + fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); + fprintf(stderr, " max_background=%i\n", + outarg.max_background); + fprintf(stderr, " congestion_threshold=%i\n", + outarg.congestion_threshold); + fprintf(stderr, " max_pages=%d\n",outarg.max_pages); + } + + size_t outargsize; + if(arg->minor < 5) + outargsize = FUSE_COMPAT_INIT_OUT_SIZE; + else if(arg->minor < 23) + outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE; + else + outargsize = sizeof(outarg); + + send_reply_ok(req, &outarg, outargsize); } static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_ll *f = req->f; + struct fuse_ll *f = req->f; - (void) nodeid; - (void) inarg; + (void) nodeid; + (void) inarg; - f->got_destroy = 1; - if (f->op.destroy) - f->op.destroy(f->userdata); + f->got_destroy = 1; + if (f->op.destroy) + f->op.destroy(f->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 *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) { - struct fuse_ll *f = req->f; - struct fuse_notify_req *nreq; - struct fuse_notify_req *head; + struct fuse_ll *f = req->f; + struct fuse_notify_req *nreq; + struct fuse_notify_req *head; - pthread_mutex_lock(&f->lock); - head = &f->notify_list; - for (nreq = head->next; nreq != head; nreq = nreq->next) { - if (nreq->unique == req->unique) { - list_del_nreq(nreq); - break; - } - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + head = &f->notify_list; + for (nreq = head->next; nreq != head; nreq = nreq->next) { + if (nreq->unique == req->unique) { + list_del_nreq(nreq); + break; + } + } + pthread_mutex_unlock(&f->lock); - if (nreq != head) - nreq->reply(nreq, req, nodeid, inarg, buf); + if (nreq != head) + nreq->reply(nreq, req, nodeid, inarg, buf); } static @@ -2035,161 +2035,161 @@ do_copy_file_range(fuse_req_t req_, static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch, int notify_code, struct iovec *iov, int count) { - struct fuse_out_header out; + struct fuse_out_header out; - if (!f->got_init) - return -ENOTCONN; + if (!f->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(f, ch, iov, count); + return fuse_send_msg(f, ch, 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->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2); - } else { - return 0; - } + return send_notify_iov(ph->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2); + } else { + return 0; + } } int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, off_t off, off_t len) { - struct fuse_notify_inval_inode_out outarg; - struct fuse_ll *f; - struct iovec iov[2]; + struct fuse_notify_inval_inode_out outarg; + struct fuse_ll *f; + struct iovec iov[2]; - if (!ch) - return -EINVAL; + if (!ch) + return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; + f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + if (!f) + return -ENODEV; - 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(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2); + return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2); } int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, const char *name, size_t namelen) { - struct fuse_notify_inval_entry_out outarg; - struct fuse_ll *f; - struct iovec iov[3]; + struct fuse_notify_inval_entry_out outarg; + struct fuse_ll *f; + struct iovec iov[3]; - if (!ch) - return -EINVAL; + if (!ch) + return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; + f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + if (!f) + return -ENODEV; - 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(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); + return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); } int fuse_lowlevel_notify_delete(struct fuse_chan *ch, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen) { - struct fuse_notify_delete_out outarg; - struct fuse_ll *f; - struct iovec iov[3]; + struct fuse_notify_delete_out outarg; + struct fuse_ll *f; + struct iovec iov[3]; - if (!ch) - return -EINVAL; + if (!ch) + return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; + f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + if (!f) + return -ENODEV; - if (f->conn.proto_minor < 18) - return -ENOSYS; + if (f->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(f, ch, FUSE_NOTIFY_DELETE, iov, 3); + return send_notify_iov(f, ch, FUSE_NOTIFY_DELETE, iov, 3); } int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, 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 fuse_ll *f; - 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 fuse_ll *f; + struct iovec iov[3]; + size_t size = fuse_buf_size(bufv); + int res; - if (!ch) - return -EINVAL; + if (!ch) + return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; + f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + if (!f) + return -ENODEV; - if (f->conn.proto_minor < 15) - return -ENOSYS; + if (f->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(f, ch, iov, 2, bufv, flags); - if (res > 0) - res = -res; + res = fuse_send_data_iov(f, ch, 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, @@ -2197,97 +2197,97 @@ static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, const void *inarg, const struct fuse_buf *ibuf) { - struct fuse_ll *f = req->f; - 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) { - fprintf(stderr, "fuse: retrieve reply: buffer size too small\n"); - fuse_reply_none(req); - goto out; - } - bufv.buf[0].size = arg->size; - - if (req->f->op.retrieve_reply) { - req->f->op.retrieve_reply(req, rreq->cookie, ino, - arg->offset, &bufv); - } else { - fuse_reply_none(req); - } -out: - free(rreq); - if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) - fuse_ll_clear_pipe(f); + struct fuse_ll *f = req->f; + 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) { + fprintf(stderr, "fuse: retrieve reply: buffer size too small\n"); + fuse_reply_none(req); + goto out; + } + bufv.buf[0].size = arg->size; + + if (req->f->op.retrieve_reply) { + req->f->op.retrieve_reply(req, rreq->cookie, ino, + arg->offset, &bufv); + } else { + fuse_reply_none(req); + } + out: + free(rreq); + if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) + fuse_ll_clear_pipe(f); } int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, size_t size, off_t offset, void *cookie) { - struct fuse_notify_retrieve_out outarg; - struct fuse_ll *f; - struct iovec iov[2]; - struct fuse_retrieve_req *rreq; - int err; + struct fuse_notify_retrieve_out outarg; + struct fuse_ll *f; + struct iovec iov[2]; + struct fuse_retrieve_req *rreq; + int err; - if (!ch) - return -EINVAL; + if (!ch) + return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; + f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + if (!f) + return -ENODEV; - if (f->conn.proto_minor < 15) - return -ENOSYS; + if (f->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(&f->lock); - rreq->cookie = cookie; - rreq->nreq.unique = f->notify_ctr++; - rreq->nreq.reply = fuse_ll_retrieve_reply; - list_add_nreq(&rreq->nreq, &f->notify_list); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + rreq->cookie = cookie; + rreq->nreq.unique = f->notify_ctr++; + rreq->nreq.reply = fuse_ll_retrieve_reply; + list_add_nreq(&rreq->nreq, &f->notify_list); + pthread_mutex_unlock(&f->lock); - outarg.notify_unique = rreq->nreq.unique; - outarg.nodeid = ino; - outarg.offset = offset; - outarg.size = size; + outarg.notify_unique = rreq->nreq.unique; + outarg.nodeid = ino; + outarg.offset = offset; + outarg.size = size; - 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(f, ch, FUSE_NOTIFY_RETRIEVE, iov, 2); - if (err) { - pthread_mutex_lock(&f->lock); - list_del_nreq(&rreq->nreq); - pthread_mutex_unlock(&f->lock); - free(rreq); - } + err = send_notify_iov(f, ch, FUSE_NOTIFY_RETRIEVE, iov, 2); + if (err) { + pthread_mutex_lock(&f->lock); + list_del_nreq(&rreq->nreq); + pthread_mutex_unlock(&f->lock); + free(rreq); + } - return err; + return err; } void *fuse_req_userdata(fuse_req_t req) { - return req->f->userdata; + return req->f->userdata; } const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) { - return &req->ctx; + return &req->ctx; } /* @@ -2298,7 +2298,7 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req); const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req) { - return fuse_req_ctx(req); + return fuse_req_ctx(req); } #ifndef __NetBSD__ FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4"); @@ -2308,30 +2308,30 @@ FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4"); void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data) { - pthread_mutex_lock(&req->lock); - pthread_mutex_lock(&req->f->lock); - req->u.ni.func = func; - req->u.ni.data = data; - pthread_mutex_unlock(&req->f->lock); - if (req->interrupted && func) - func(req, data); - pthread_mutex_unlock(&req->lock); + pthread_mutex_lock(&req->lock); + pthread_mutex_lock(&req->f->lock); + req->u.ni.func = func; + req->u.ni.data = data; + pthread_mutex_unlock(&req->f->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->f->lock); - interrupted = req->interrupted; - pthread_mutex_unlock(&req->f->lock); + pthread_mutex_lock(&req->f->lock); + interrupted = req->interrupted; + pthread_mutex_unlock(&req->f->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" }, @@ -2384,396 +2384,396 @@ static struct { 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; } static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, struct fuse_bufvec *src) { - int res = fuse_buf_copy(dst, src, 0); - if (res < 0) { - fprintf(stderr, "fuse: copy from pipe: %s\n", strerror(-res)); - return res; - } - if (res < fuse_buf_size(dst)) { - fprintf(stderr, "fuse: copy from pipe: short read\n"); - return -1; - } - return 0; + int res = fuse_buf_copy(dst, src, 0); + if (res < 0) { + fprintf(stderr, "fuse: copy from pipe: %s\n", strerror(-res)); + return res; + } + if (res < fuse_buf_size(dst)) { + fprintf(stderr, "fuse: copy from pipe: short read\n"); + return -1; + } + return 0; } static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, struct fuse_chan *ch) { - struct fuse_ll *f = (struct fuse_ll *) data; - const size_t write_header_size = sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in); - struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 }; - struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size); - struct fuse_in_header *in; - const void *inarg; - struct fuse_req *req; - void *mbuf = NULL; - int err; - int res; - - if (buf->flags & FUSE_BUF_IS_FD) { - if (buf->size < tmpbuf.buf[0].size) - tmpbuf.buf[0].size = buf->size; - - mbuf = malloc(tmpbuf.buf[0].size); - if (mbuf == NULL) { - fprintf(stderr, "fuse: failed to allocate header\n"); - goto clear_pipe; - } - tmpbuf.buf[0].mem = mbuf; - - res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); - if (res < 0) - goto clear_pipe; - - in = mbuf; - } else { - in = buf->mem; - } - - if (f->debug) { - fprintf(stderr, - "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu, pid: %u\n", - (unsigned long long) in->unique, - opname((enum fuse_opcode) in->opcode), in->opcode, - (unsigned long) in->nodeid, buf->size, in->pid); - } - - req = fuse_ll_alloc_req(f); - 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(f, ch, &iov, 1); - goto clear_pipe; - } - - 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 (!f->got_init) { - enum fuse_opcode expected; - - expected = f->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; - if (f->allow_root && - in->uid != f->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_READDIRPLUS && - in->opcode != FUSE_FSYNCDIR && - in->opcode != FUSE_RELEASEDIR && - in->opcode != FUSE_NOTIFY_REPLY) - 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(&f->lock); - intr = check_interrupt(f, req); - list_add_req(req, &f->list); - pthread_mutex_unlock(&f->lock); - if (intr) - fuse_reply_err(intr, EAGAIN); - } - - if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size && - (in->opcode != FUSE_WRITE || !f->op.write_buf) && - in->opcode != FUSE_NOTIFY_REPLY) { - void *newmbuf; - - err = ENOMEM; - newmbuf = realloc(mbuf, buf->size); - if (newmbuf == NULL) - goto reply_err; - mbuf = newmbuf; - - tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size); - tmpbuf.buf[0].mem = mbuf + write_header_size; - - res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); - err = -res; - if (res < 0) - goto reply_err; - - in = mbuf; - } - - inarg = (void *) &in[1]; - if (in->opcode == FUSE_WRITE && f->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); - -out_free: - free(mbuf); - return; - -reply_err: - fuse_reply_err(req, err); -clear_pipe: - if (buf->flags & FUSE_BUF_IS_FD) - fuse_ll_clear_pipe(f); - goto out_free; + struct fuse_ll *f = (struct fuse_ll *) data; + const size_t write_header_size = sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in); + struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 }; + struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size); + struct fuse_in_header *in; + const void *inarg; + struct fuse_req *req; + void *mbuf = NULL; + int err; + int res; + + if (buf->flags & FUSE_BUF_IS_FD) { + if (buf->size < tmpbuf.buf[0].size) + tmpbuf.buf[0].size = buf->size; + + mbuf = malloc(tmpbuf.buf[0].size); + if (mbuf == NULL) { + fprintf(stderr, "fuse: failed to allocate header\n"); + goto clear_pipe; + } + tmpbuf.buf[0].mem = mbuf; + + res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); + if (res < 0) + goto clear_pipe; + + in = mbuf; + } else { + in = buf->mem; + } + + if (f->debug) { + fprintf(stderr, + "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu, pid: %u\n", + (unsigned long long) in->unique, + opname((enum fuse_opcode) in->opcode), in->opcode, + (unsigned long) in->nodeid, buf->size, in->pid); + } + + req = fuse_ll_alloc_req(f); + 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(f, ch, &iov, 1); + goto clear_pipe; + } + + 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 (!f->got_init) { + enum fuse_opcode expected; + + expected = f->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; + if (f->allow_root && + in->uid != f->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_READDIRPLUS && + in->opcode != FUSE_FSYNCDIR && + in->opcode != FUSE_RELEASEDIR && + in->opcode != FUSE_NOTIFY_REPLY) + 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(&f->lock); + intr = check_interrupt(f, req); + list_add_req(req, &f->list); + pthread_mutex_unlock(&f->lock); + if (intr) + fuse_reply_err(intr, EAGAIN); + } + + if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size && + (in->opcode != FUSE_WRITE || !f->op.write_buf) && + in->opcode != FUSE_NOTIFY_REPLY) { + void *newmbuf; + + err = ENOMEM; + newmbuf = realloc(mbuf, buf->size); + if (newmbuf == NULL) + goto reply_err; + mbuf = newmbuf; + + tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size); + tmpbuf.buf[0].mem = mbuf + write_header_size; + + res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); + err = -res; + if (res < 0) + goto reply_err; + + in = mbuf; + } + + inarg = (void *) &in[1]; + if (in->opcode == FUSE_WRITE && f->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); + + out_free: + free(mbuf); + return; + + reply_err: + fuse_reply_err(req, err); + clear_pipe: + if (buf->flags & FUSE_BUF_IS_FD) + fuse_ll_clear_pipe(f); + goto out_free; } static void fuse_ll_process(void *data, const char *buf, size_t len, struct fuse_chan *ch) { - struct fuse_buf fbuf = { - .mem = (void *) buf, - .size = len, - }; + struct fuse_buf fbuf = { + .mem = (void *) buf, + .size = len, + }; - fuse_ll_process_buf(data, &fbuf, ch); + fuse_ll_process_buf(data, &fbuf, ch); } enum { - KEY_HELP, - KEY_VERSION, + KEY_HELP, + KEY_VERSION, }; static const struct fuse_opt fuse_ll_opts[] = { - { "debug", offsetof(struct fuse_ll, debug), 1 }, - { "-d", offsetof(struct fuse_ll, debug), 1 }, - { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, - { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, - { "max_background=%u", offsetof(struct fuse_ll, conn.max_background), 0 }, - { "congestion_threshold=%u", - offsetof(struct fuse_ll, conn.congestion_threshold), 0 }, - { "no_remote_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, - { "no_remote_lock", offsetof(struct fuse_ll, no_remote_flock), 1}, - { "no_remote_flock", offsetof(struct fuse_ll, no_remote_flock), 1}, - { "no_remote_posix_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, - { "splice_write", offsetof(struct fuse_ll, splice_write), 1}, - { "no_splice_write", offsetof(struct fuse_ll, no_splice_write), 1}, - { "splice_move", offsetof(struct fuse_ll, splice_move), 1}, - { "no_splice_move", offsetof(struct fuse_ll, no_splice_move), 1}, - { "splice_read", offsetof(struct fuse_ll, splice_read), 1}, - { "no_splice_read", offsetof(struct fuse_ll, no_splice_read), 1}, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END + { "debug", offsetof(struct fuse_ll, debug), 1 }, + { "-d", offsetof(struct fuse_ll, debug), 1 }, + { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, + { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, + { "max_background=%u", offsetof(struct fuse_ll, conn.max_background), 0 }, + { "congestion_threshold=%u", + offsetof(struct fuse_ll, conn.congestion_threshold), 0 }, + { "no_remote_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, + { "no_remote_lock", offsetof(struct fuse_ll, no_remote_flock), 1}, + { "no_remote_flock", offsetof(struct fuse_ll, no_remote_flock), 1}, + { "no_remote_posix_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, + { "splice_write", offsetof(struct fuse_ll, splice_write), 1}, + { "no_splice_write", offsetof(struct fuse_ll, no_splice_write), 1}, + { "splice_move", offsetof(struct fuse_ll, splice_move), 1}, + { "no_splice_move", offsetof(struct fuse_ll, no_splice_move), 1}, + { "splice_read", offsetof(struct fuse_ll, splice_read), 1}, + { "no_splice_read", offsetof(struct fuse_ll, no_splice_read), 1}, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END }; static void fuse_ll_version(void) { - fprintf(stderr, "using FUSE kernel interface version %i.%i\n", - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); + fprintf(stderr, "using FUSE kernel interface version %i.%i\n", + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } static void fuse_ll_help(void) { - fprintf(stderr, -" -o max_readahead=N set maximum readahead\n" -" -o max_background=N set number of maximum background requests\n" -" -o congestion_threshold=N set kernel's congestion threshold\n" -" -o no_remote_lock disable remote file locking\n" -" -o no_remote_flock disable remote file locking (BSD)\n" -" -o no_remote_posix_lock disable remove file locking (POSIX)\n" -" -o [no_]splice_write use splice to write to the fuse device\n" -" -o [no_]splice_move move data while splicing to the fuse device\n" -" -o [no_]splice_read use splice to read from the fuse device\n" -); + fprintf(stderr, + " -o max_readahead=N set maximum readahead\n" + " -o max_background=N set number of maximum background requests\n" + " -o congestion_threshold=N set kernel's congestion threshold\n" + " -o no_remote_lock disable remote file locking\n" + " -o no_remote_flock disable remote file locking (BSD)\n" + " -o no_remote_posix_lock disable remove file locking (POSIX)\n" + " -o [no_]splice_write use splice to write to the fuse device\n" + " -o [no_]splice_move move data while splicing to the fuse device\n" + " -o [no_]splice_read use splice to read from the fuse device\n" + ); } static int fuse_ll_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - (void) data; (void) outargs; + (void) data; (void) outargs; - switch (key) { - case KEY_HELP: - fuse_ll_help(); - break; + switch (key) { + case KEY_HELP: + fuse_ll_help(); + break; - case KEY_VERSION: - fuse_ll_version(); - break; + case KEY_VERSION: + fuse_ll_version(); + break; - default: - fprintf(stderr, "fuse: unknown option `%s'\n", arg); - } + default: + fprintf(stderr, "fuse: unknown option `%s'\n", arg); + } - return -1; + return -1; } int fuse_lowlevel_is_lib_option(const char *opt) { - return fuse_opt_match(fuse_ll_opts, opt); + return fuse_opt_match(fuse_ll_opts, opt); } static void fuse_ll_destroy(void *data) { - struct fuse_ll *f = (struct fuse_ll *) data; - struct fuse_ll_pipe *llp; + struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_ll_pipe *llp; - if (f->got_init && !f->got_destroy) { - if (f->op.destroy) - f->op.destroy(f->userdata); - } - llp = pthread_getspecific(f->pipe_key); - if (llp != NULL) - fuse_ll_pipe_free(llp); - pthread_key_delete(f->pipe_key); - pthread_mutex_destroy(&f->lock); - free(f->cuse_data); - free(f); + if (f->got_init && !f->got_destroy) { + if (f->op.destroy) + f->op.destroy(f->userdata); + } + llp = pthread_getspecific(f->pipe_key); + if (llp != NULL) + fuse_ll_pipe_free(llp); + pthread_key_delete(f->pipe_key); + pthread_mutex_destroy(&f->lock); + free(f->cuse_data); + free(f); } static void fuse_ll_pipe_destructor(void *data) { - struct fuse_ll_pipe *llp = data; - fuse_ll_pipe_free(llp); + struct fuse_ll_pipe *llp = data; + fuse_ll_pipe_free(llp); } #ifdef HAVE_SPLICE static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan **chp) { - struct fuse_chan *ch = *chp; - struct fuse_ll *f = fuse_session_data(se); - size_t bufsize = buf->size; - struct fuse_ll_pipe *llp; - struct fuse_buf tmpbuf; - int err; - int res; - - if (f->conn.proto_minor < 14 || !(f->conn.want & FUSE_CAP_SPLICE_READ)) - goto fallback; - - llp = fuse_ll_get_pipe(f); - if (llp == NULL) - goto fallback; - - if (llp->size < bufsize) { - if (llp->can_grow) { - res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize); - if (res == -1) { - llp->can_grow = 0; - goto fallback; - } - llp->size = res; - } - if (llp->size < bufsize) - goto fallback; - } - - res = splice(fuse_chan_fd(ch), NULL, llp->pipe[1], NULL, bufsize, 0); - err = errno; - - if (fuse_session_exited(se)) - return 0; - - if (res == -1) { - if (err == ENODEV) { - fuse_session_exit(se); - return 0; - } - if (err != EINTR && err != EAGAIN) - perror("fuse: splice from device"); - return -err; - } - - if (res < sizeof(struct fuse_in_header)) { - fprintf(stderr, "short splice from fuse device\n"); - return -EIO; - } - - tmpbuf = (struct fuse_buf) { - .size = res, - .flags = FUSE_BUF_IS_FD, - .fd = llp->pipe[0], - }; - - /* - * Don't bother with zero copy for small requests. - * fuse_loop_mt() needs to check for FORGET so this more than - * just an optimization. - */ - if (res < sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in) + pagesize) { - struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 }; - struct fuse_bufvec dst = { .buf[0] = *buf, .count = 1 }; - - res = fuse_buf_copy(&dst, &src, 0); - if (res < 0) { - fprintf(stderr, "fuse: copy from pipe: %s\n", - strerror(-res)); - fuse_ll_clear_pipe(f); - return res; - } - if (res < tmpbuf.size) { - fprintf(stderr, "fuse: copy from pipe: short read\n"); - fuse_ll_clear_pipe(f); - return -EIO; - } - buf->size = tmpbuf.size; - return buf->size; - } - - *buf = tmpbuf; - - return res; - -fallback: - res = fuse_chan_recv(chp, buf->mem, bufsize); - if (res <= 0) - return res; - - buf->size = res; - - return res; + struct fuse_chan *ch = *chp; + struct fuse_ll *f = fuse_session_data(se); + size_t bufsize = buf->size; + struct fuse_ll_pipe *llp; + struct fuse_buf tmpbuf; + int err; + int res; + + if (f->conn.proto_minor < 14 || !(f->conn.want & FUSE_CAP_SPLICE_READ)) + goto fallback; + + llp = fuse_ll_get_pipe(f); + if (llp == NULL) + goto fallback; + + if (llp->size < bufsize) { + if (llp->can_grow) { + res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize); + if (res == -1) { + llp->can_grow = 0; + goto fallback; + } + llp->size = res; + } + if (llp->size < bufsize) + goto fallback; + } + + res = splice(fuse_chan_fd(ch), NULL, llp->pipe[1], NULL, bufsize, 0); + err = errno; + + if (fuse_session_exited(se)) + return 0; + + if (res == -1) { + if (err == ENODEV) { + fuse_session_exit(se); + return 0; + } + if (err != EINTR && err != EAGAIN) + perror("fuse: splice from device"); + return -err; + } + + if (res < sizeof(struct fuse_in_header)) { + fprintf(stderr, "short splice from fuse device\n"); + return -EIO; + } + + tmpbuf = (struct fuse_buf) { + .size = res, + .flags = FUSE_BUF_IS_FD, + .fd = llp->pipe[0], + }; + + /* + * Don't bother with zero copy for small requests. + * fuse_loop_mt() needs to check for FORGET so this more than + * just an optimization. + */ + if (res < sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in) + pagesize) { + struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 }; + struct fuse_bufvec dst = { .buf[0] = *buf, .count = 1 }; + + res = fuse_buf_copy(&dst, &src, 0); + if (res < 0) { + fprintf(stderr, "fuse: copy from pipe: %s\n", + strerror(-res)); + fuse_ll_clear_pipe(f); + return res; + } + if (res < tmpbuf.size) { + fprintf(stderr, "fuse: copy from pipe: short read\n"); + fuse_ll_clear_pipe(f); + return -EIO; + } + buf->size = tmpbuf.size; + return buf->size; + } + + *buf = tmpbuf; + + return res; + + fallback: + res = fuse_chan_recv(chp, buf->mem, bufsize); + if (res <= 0) + return res; + + buf->size = res; + + return res; } #else static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan **chp) { - (void) se; + (void) se; - int res = fuse_chan_recv(chp, buf->mem, buf->size); - if (res <= 0) - return res; + int res = fuse_chan_recv(chp, buf->mem, buf->size); + if (res <= 0) + return res; - buf->size = res; + buf->size = res; - return res; + return res; } #endif @@ -2787,66 +2787,66 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata) { - int err; - struct fuse_ll *f; - struct fuse_session *se; - struct fuse_session_ops sop = { - .process = fuse_ll_process, - .destroy = fuse_ll_destroy, - }; - - if (sizeof(struct fuse_lowlevel_ops) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); - op_size = sizeof(struct fuse_lowlevel_ops); - } - - f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out; - } - - f->conn.max_write = UINT_MAX; - f->conn.max_readahead = UINT_MAX; - list_init_req(&f->list); - list_init_req(&f->interrupts); - list_init_nreq(&f->notify_list); - f->notify_ctr = 1; - fuse_mutex_init(&f->lock); - - err = pthread_key_create(&f->pipe_key, fuse_ll_pipe_destructor); - if (err) { - fprintf(stderr, "fuse: failed to create thread specific key: %s\n", - strerror(err)); - goto out_free; - } - - if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) - goto out_key_destroy; - - if (f->debug) - fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); - - memcpy(&f->op, op, op_size); - f->owner = getuid(); - f->userdata = userdata; - - se = fuse_session_new(&sop, f); - if (!se) - goto out_key_destroy; - - se->receive_buf = fuse_ll_receive_buf; - se->process_buf = fuse_ll_process_buf; - - return se; - -out_key_destroy: - pthread_key_delete(f->pipe_key); -out_free: - pthread_mutex_destroy(&f->lock); - free(f); -out: - return NULL; + int err; + struct fuse_ll *f; + struct fuse_session *se; + struct fuse_session_ops sop = { + .process = fuse_ll_process, + .destroy = fuse_ll_destroy, + }; + + if (sizeof(struct fuse_lowlevel_ops) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); + op_size = sizeof(struct fuse_lowlevel_ops); + } + + f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out; + } + + f->conn.max_write = UINT_MAX; + f->conn.max_readahead = UINT_MAX; + list_init_req(&f->list); + list_init_req(&f->interrupts); + list_init_nreq(&f->notify_list); + f->notify_ctr = 1; + fuse_mutex_init(&f->lock); + + err = pthread_key_create(&f->pipe_key, fuse_ll_pipe_destructor); + if (err) { + fprintf(stderr, "fuse: failed to create thread specific key: %s\n", + strerror(err)); + goto out_free; + } + + if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) + goto out_key_destroy; + + if (f->debug) + fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); + + memcpy(&f->op, op, op_size); + f->owner = getuid(); + f->userdata = userdata; + + se = fuse_session_new(&sop, f); + if (!se) + goto out_key_destroy; + + se->receive_buf = fuse_ll_receive_buf; + se->process_buf = fuse_ll_process_buf; + + return se; + + out_key_destroy: + pthread_key_delete(f->pipe_key); + out_free: + pthread_mutex_destroy(&f->lock); + free(f); + out: + return NULL; } @@ -2854,67 +2854,67 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata) { - return fuse_lowlevel_new_common(args, op, op_size, userdata); + return fuse_lowlevel_new_common(args, op, op_size, userdata); } #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; - - 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 == -1) { - ret = -EIO; - goto out_free; - } - - if (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; + 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); + + 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 == -1) { + ret = -EIO; + goto out_free; + } + + if (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; } #else /* linux */ /* @@ -2922,7 +2922,7 @@ out_free: */ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) { - return -ENOSYS; + return -ENOSYS; } #endif @@ -2931,97 +2931,97 @@ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) static void fill_open_compat(struct fuse_open_out *arg, const struct fuse_file_info_compat *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; + arg->fh = f->fh; + if (f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if (f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; } static void convert_statfs_compat(const struct statfs *compatbuf, struct statvfs *buf) { - buf->f_bsize = compatbuf->f_bsize; - buf->f_blocks = compatbuf->f_blocks; - buf->f_bfree = compatbuf->f_bfree; - buf->f_bavail = compatbuf->f_bavail; - buf->f_files = compatbuf->f_files; - buf->f_ffree = compatbuf->f_ffree; - buf->f_namemax = compatbuf->f_namelen; + buf->f_bsize = compatbuf->f_bsize; + buf->f_blocks = compatbuf->f_blocks; + buf->f_bfree = compatbuf->f_bfree; + buf->f_bavail = compatbuf->f_bavail; + buf->f_files = compatbuf->f_files; + buf->f_ffree = compatbuf->f_ffree; + buf->f_namemax = compatbuf->f_namelen; } int fuse_reply_open_compat(fuse_req_t req, const struct fuse_file_info_compat *f) { - struct fuse_open_out arg; + struct fuse_open_out arg; - memset(&arg, 0, sizeof(arg)); - fill_open_compat(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_open_compat(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf) { - struct statvfs newbuf; + struct statvfs newbuf; - memset(&newbuf, 0, sizeof(newbuf)); - convert_statfs_compat(stbuf, &newbuf); + memset(&newbuf, 0, sizeof(newbuf)); + convert_statfs_compat(stbuf, &newbuf); - return fuse_reply_statfs(req, &newbuf); + return fuse_reply_statfs(req, &newbuf); } struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat *op, + size_t op_size, void *userdata) { - struct fuse_session *se; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + struct fuse_session *se; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (opts && - (fuse_opt_add_arg(&args, "") == -1 || - fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, - op_size, userdata); - fuse_opt_free_args(&args); + if (opts && + (fuse_opt_add_arg(&args, "") == -1 || + fuse_opt_add_arg(&args, "-o") == -1 || + fuse_opt_add_arg(&args, opts) == -1)) { + fuse_opt_free_args(&args); + return NULL; + } + se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, + op_size, userdata); + fuse_opt_free_args(&args); - return se; + return se; } struct fuse_ll_compat_conf { - unsigned max_read; - int set_max_read; + unsigned max_read; + int set_max_read; }; static const struct fuse_opt fuse_ll_opts_compat[] = { - { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, - { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END + { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, + { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END }; int fuse_sync_compat_args(struct fuse_args *args) { - struct fuse_ll_compat_conf conf; + struct fuse_ll_compat_conf conf; - memset(&conf, 0, sizeof(conf)); - if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) - return -1; + memset(&conf, 0, sizeof(conf)); + if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) + return -1; - if (fuse_opt_insert_arg(args, 1, "-osync_read")) - return -1; + if (fuse_opt_insert_arg(args, 1, "-osync_read")) + return -1; - if (conf.set_max_read) { - char tmpbuf[64]; + if (conf.set_max_read) { + char tmpbuf[64]; - sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); - if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) - return -1; - } - return 0; + sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); + if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) + return -1; + } + return 0; } FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4"); @@ -3032,22 +3032,22 @@ FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4"); int fuse_sync_compat_args(struct fuse_args *args) { - (void) args; - return 0; + (void) args; + return 0; } #endif /* __FreeBSD__ || __NetBSD__ */ struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata) { - if (fuse_sync_compat_args(args) == -1) - return NULL; + if (fuse_sync_compat_args(args) == -1) + return NULL; - return fuse_lowlevel_new_common(args, - (const struct fuse_lowlevel_ops *) op, - op_size, userdata); + return fuse_lowlevel_new_common(args, + (const struct fuse_lowlevel_ops *) op, + op_size, userdata); } FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5"); diff --git a/libfuse/lib/fuse_misc.h b/libfuse/lib/fuse_misc.h index 5fa14675..434e40da 100644 --- a/libfuse/lib/fuse_misc.h +++ b/libfuse/lib/fuse_misc.h @@ -11,8 +11,8 @@ /* Versioned symbols cannot be used in some cases because it - - confuse the dynamic linker in uClibc - - not supported on MacOSX (in MachO binary format) + - 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) @@ -26,11 +26,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/libfuse/lib/fuse_mt.c b/libfuse/lib/fuse_mt.c index 6cc30344..b720f0fe 100644 --- a/libfuse/lib/fuse_mt.c +++ b/libfuse/lib/fuse_mt.c @@ -16,109 +16,110 @@ #include #include -struct procdata { - struct fuse *f; - struct fuse_chan *prevch; - struct fuse_session *prevse; - fuse_processor_t proc; - void *data; +struct procdata +{ + struct fuse *f; + struct fuse_chan *prevch; + struct fuse_session *prevse; + fuse_processor_t proc; + void *data; }; static void mt_session_proc(void *data, const char *buf, size_t len, struct fuse_chan *ch) { - struct procdata *pd = (struct procdata *) data; - struct fuse_cmd *cmd = *(struct fuse_cmd **) buf; + struct procdata *pd = (struct procdata *) data; + struct fuse_cmd *cmd = *(struct fuse_cmd **) buf; - (void) len; - (void) ch; - pd->proc(pd->f, cmd, pd->data); + (void) len; + (void) ch; + pd->proc(pd->f, cmd, pd->data); } static void mt_session_exit(void *data, int val) { - struct procdata *pd = (struct procdata *) data; - if (val) - fuse_session_exit(pd->prevse); - else - fuse_session_reset(pd->prevse); + struct procdata *pd = (struct procdata *) data; + if (val) + fuse_session_exit(pd->prevse); + else + fuse_session_reset(pd->prevse); } static int mt_session_exited(void *data) { - struct procdata *pd = (struct procdata *) data; - return fuse_session_exited(pd->prevse); + struct procdata *pd = (struct procdata *) data; + return fuse_session_exited(pd->prevse); } static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size) { - struct fuse_cmd *cmd; - struct procdata *pd = (struct procdata *) fuse_chan_data(*chp); + struct fuse_cmd *cmd; + struct procdata *pd = (struct procdata *) fuse_chan_data(*chp); - assert(size >= sizeof(cmd)); + assert(size >= sizeof(cmd)); - cmd = fuse_read_cmd(pd->f); - if (cmd == NULL) - return 0; + cmd = fuse_read_cmd(pd->f); + if (cmd == NULL) + return 0; - *(struct fuse_cmd **) buf = cmd; + *(struct fuse_cmd **) buf = cmd; - return sizeof(cmd); + return sizeof(cmd); } int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data) { - int res; - struct procdata pd; - struct fuse_session *prevse = fuse_get_session(f); - struct fuse_session *se; - struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL); - struct fuse_chan *ch; - struct fuse_session_ops sop = { - .exit = mt_session_exit, - .exited = mt_session_exited, - .process = mt_session_proc, - }; - struct fuse_chan_ops cop = { - .receive = mt_chan_receive, - }; - - pd.f = f; - pd.prevch = prevch; - pd.prevse = prevse; - pd.proc = proc; - pd.data = data; - - se = fuse_session_new(&sop, &pd); - if (se == NULL) - return -1; - - ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), - sizeof(struct fuse_cmd *), &pd); - if (ch == NULL) { - fuse_session_destroy(se); - return -1; - } - fuse_session_add_chan(se, ch); - res = fuse_session_loop_mt(se, - fuse_config_num_threads(f)); - fuse_session_destroy(se); - return res; + int res; + struct procdata pd; + struct fuse_session *prevse = fuse_get_session(f); + struct fuse_session *se; + struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL); + struct fuse_chan *ch; + struct fuse_session_ops sop = { + .exit = mt_session_exit, + .exited = mt_session_exited, + .process = mt_session_proc, + }; + struct fuse_chan_ops cop = { + .receive = mt_chan_receive, + }; + + pd.f = f; + pd.prevch = prevch; + pd.prevse = prevse; + pd.proc = proc; + pd.data = data; + + se = fuse_session_new(&sop, &pd); + if (se == NULL) + return -1; + + ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), + sizeof(struct fuse_cmd *), &pd); + if (ch == NULL) { + fuse_session_destroy(se); + return -1; + } + fuse_session_add_chan(se, ch); + res = fuse_session_loop_mt(se, + fuse_config_num_threads(f)); + fuse_session_destroy(se); + return res; } int fuse_loop_mt(struct fuse *f) { - if (f == NULL) - return -1; + if (f == NULL) + return -1; - int res = fuse_start_cleanup_thread(f); - if (res) - return -1; + int res = fuse_start_cleanup_thread(f); + if (res) + return -1; - res = fuse_session_loop_mt(fuse_get_session(f), - fuse_config_num_threads(f)); - fuse_stop_cleanup_thread(f); - return res; + res = fuse_session_loop_mt(fuse_get_session(f), + fuse_config_num_threads(f)); + fuse_stop_cleanup_thread(f); + return res; } FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@"); diff --git a/libfuse/lib/fuse_opt.c b/libfuse/lib/fuse_opt.c index a2118ced..5605f4b7 100644 --- a/libfuse/lib/fuse_opt.c +++ b/libfuse/lib/fuse_opt.c @@ -14,412 +14,417 @@ #include #include -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; +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 fuse_opt_free_args(struct fuse_args *args) +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) +static +int +alloc_failed(void) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; } -int fuse_opt_add_arg(struct fuse_args *args, const char *arg) +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) { - 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); } int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg); int fuse_opt_insert_arg_compat(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) { - fprintf(stderr, "fuse: missing argument after `%s'\n", opt); - return -1; - } - ctx->argctr++; - return 0; + if (ctx->argctr + 1 >= ctx->argc) { + fprintf(stderr, "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) { - 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) { - 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) { - assert(format[0] == '%'); - if (format[1] == 's') { - char *copy = strdup(param); - if (!copy) - return alloc_failed(); - - *(char **) var = copy; - } else { - if (sscanf(param, format, var) != 1) { - fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); - return -1; - } - } - return 0; + assert(format[0] == '%'); + if (format[1] == 's') { + char *copy = strdup(param); + if (!copy) + return alloc_failed(); + + *(char **) var = copy; + } else { + if (sscanf(param, format, var) != 1) { + fprintf(stderr, "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) { - if (opt->offset == -1U) { - if (call_proc(ctx, arg, opt->value, iso) == -1) - return -1; - } else { - void *var = 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 = 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) { - int res; - char *newarg; - char *param; + int res; + char *newarg; + char *param; - if (next_arg(ctx, arg) == -1) - return -1; + if (next_arg(ctx, arg) == -1) + return -1; - param = ctx->argv[ctx->argctr]; - newarg = malloc(sep + strlen(param) + 1); - if (!newarg) - return alloc_failed(); + 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); + memcpy(newarg, arg, sep); + strcpy(newarg + sep, param); + res = process_opt(ctx, opt, sep, newarg, iso); + free(newarg); - return res; + 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) { - fprintf(stderr, "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) { + fprintf(stderr, "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) { - 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; } /* This symbol version was mistakenly added to the version script */ diff --git a/libfuse/lib/fuse_session.c b/libfuse/lib/fuse_session.c index 6e110683..5773ec72 100644 --- a/libfuse/lib/fuse_session.c +++ b/libfuse/lib/fuse_session.c @@ -17,222 +17,218 @@ #include #include -struct fuse_chan { - struct fuse_chan_ops op; - - struct fuse_session *se; - - int fd; - - size_t bufsize; - - void *data; - - int compat; +struct fuse_chan +{ + struct fuse_chan_ops op; + struct fuse_session *se; + int fd; + size_t bufsize; + void *data; + int compat; }; struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) { - struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); - if (se == NULL) { - fprintf(stderr, "fuse: failed to allocate session\n"); - return NULL; - } + struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); + if (se == NULL) { + fprintf(stderr, "fuse: failed to allocate session\n"); + return NULL; + } - memset(se, 0, sizeof(*se)); - se->op = *op; - se->data = data; + memset(se, 0, sizeof(*se)); + se->op = *op; + se->data = data; - return se; + return se; } void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) { - assert(se->ch == NULL); - assert(ch->se == NULL); - se->ch = ch; - ch->se = se; + assert(se->ch == NULL); + assert(ch->se == NULL); + se->ch = ch; + ch->se = se; } void fuse_session_remove_chan(struct fuse_chan *ch) { - struct fuse_session *se = ch->se; - if (se) { - assert(se->ch == ch); - se->ch = NULL; - ch->se = NULL; - } + struct fuse_session *se = ch->se; + if (se) { + assert(se->ch == ch); + se->ch = NULL; + ch->se = NULL; + } } struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, struct fuse_chan *ch) { - assert(ch == NULL || ch == se->ch); - if (ch == NULL) - return se->ch; - else - return NULL; + assert(ch == NULL || ch == se->ch); + if (ch == NULL) + return se->ch; + else + return NULL; } void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, struct fuse_chan *ch) { - se->op.process(se->data, buf, len, ch); + se->op.process(se->data, buf, len, ch); } void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf, struct fuse_chan *ch) { - if (se->process_buf) { - se->process_buf(se->data, buf, ch); - } else { - assert(!(buf->flags & FUSE_BUF_IS_FD)); - fuse_session_process(se->data, buf->mem, buf->size, ch); - } + if (se->process_buf) { + se->process_buf(se->data, buf, ch); + } else { + assert(!(buf->flags & FUSE_BUF_IS_FD)); + fuse_session_process(se->data, buf->mem, buf->size, ch); + } } int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan **chp) { - int res; + int res; - if (se->receive_buf) { - res = se->receive_buf(se, buf, chp); - } else { - res = fuse_chan_recv(chp, buf->mem, buf->size); - if (res > 0) - buf->size = res; - } + if (se->receive_buf) { + res = se->receive_buf(se, buf, chp); + } else { + res = fuse_chan_recv(chp, buf->mem, buf->size); + if (res > 0) + buf->size = res; + } - return res; + return res; } void fuse_session_destroy(struct fuse_session *se) { - if (se->op.destroy) - se->op.destroy(se->data); - if (se->ch != NULL) - fuse_chan_destroy(se->ch); - free(se); + if (se->op.destroy) + se->op.destroy(se->data); + if (se->ch != NULL) + fuse_chan_destroy(se->ch); + free(se); } void fuse_session_exit(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 1); - se->exited = 1; + if (se->op.exit) + se->op.exit(se->data, 1); + se->exited = 1; } void fuse_session_reset(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 0); - se->exited = 0; + if (se->op.exit) + se->op.exit(se->data, 0); + se->exited = 0; } int fuse_session_exited(struct fuse_session *se) { - if (se->op.exited) - return se->op.exited(se->data); - else - return se->exited; + if (se->op.exited) + return se->op.exited(se->data); + else + return se->exited; } void *fuse_session_data(struct fuse_session *se) { - return se->data; + return se->data; } static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, size_t bufsize, void *data, int compat) { - struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); - if (ch == NULL) { - fprintf(stderr, "fuse: failed to allocate channel\n"); - return NULL; - } + struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); + if (ch == NULL) { + fprintf(stderr, "fuse: failed to allocate channel\n"); + return NULL; + } - memset(ch, 0, sizeof(*ch)); - ch->op = *op; - ch->fd = fd; - ch->bufsize = bufsize; - ch->data = data; - ch->compat = compat; + memset(ch, 0, sizeof(*ch)); + ch->op = *op; + ch->fd = fd; + ch->bufsize = bufsize; + ch->data = data; + ch->compat = compat; - return ch; + return ch; } struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, size_t bufsize, void *data) { - return fuse_chan_new_common(op, fd, bufsize, data, 0); + return fuse_chan_new_common(op, fd, bufsize, data, 0); } struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, int fd, size_t bufsize, void *data) { - return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize, - data, 24); + return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize, + data, 24); } int fuse_chan_fd(struct fuse_chan *ch) { - return ch->fd; + return ch->fd; } int fuse_chan_clearfd(struct fuse_chan *ch) { - int fd = ch->fd; - ch->fd = -1; - return fd; + int fd = ch->fd; + ch->fd = -1; + return fd; } size_t fuse_chan_bufsize(struct fuse_chan *ch) { - return ch->bufsize; + return ch->bufsize; } void *fuse_chan_data(struct fuse_chan *ch) { - return ch->data; + return ch->data; } struct fuse_session *fuse_chan_session(struct fuse_chan *ch) { - return ch->se; + return ch->se; } int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size) { - struct fuse_chan *ch = *chp; - if (ch->compat) - return ((struct fuse_chan_ops_compat24 *) &ch->op) - ->receive(ch, buf, size); - else - return ch->op.receive(chp, buf, size); + struct fuse_chan *ch = *chp; + if (ch->compat) + return ((struct fuse_chan_ops_compat24 *) &ch->op) + ->receive(ch, buf, size); + else + return ch->op.receive(chp, buf, size); } int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size) { - int res; + int res; - res = fuse_chan_recv(&ch, buf, size); - return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0; + res = fuse_chan_recv(&ch, buf, size); + return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0; } int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) { - return ch->op.send(ch, iov, count); + return ch->op.send(ch, iov, count); } void fuse_chan_destroy(struct fuse_chan *ch) { - fuse_session_remove_chan(ch); - if (ch->op.destroy) - ch->op.destroy(ch); - free(ch); + fuse_session_remove_chan(ch); + if (ch->op.destroy) + ch->op.destroy(ch); + free(ch); } #ifndef __FreeBSD__ diff --git a/libfuse/lib/fuse_signals.c b/libfuse/lib/fuse_signals.c index 353cb24b..ad550d8f 100644 --- a/libfuse/lib/fuse_signals.c +++ b/libfuse/lib/fuse_signals.c @@ -16,57 +16,56 @@ static struct fuse_session *fuse_instance; static void exit_handler(int sig) { - (void) sig; - if (fuse_instance) - fuse_session_exit(fuse_instance); + (void) sig; + if (fuse_instance) + fuse_session_exit(fuse_instance); } 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 (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, SIG_IGN, 0) == -1) - return -1; + 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, SIG_IGN, 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) - fprintf(stderr, - "fuse: fuse_remove_signal_handlers: unknown session\n"); - else - fuse_instance = NULL; + if (fuse_instance != se) + fprintf(stderr, + "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, SIG_IGN, 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, SIG_IGN, 1); } - diff --git a/libfuse/lib/helper.c b/libfuse/lib/helper.c index 75bb291b..95b6d18b 100644 --- a/libfuse/lib/helper.c +++ b/libfuse/lib/helper.c @@ -23,9 +23,9 @@ #include enum { - KEY_HELP, - KEY_HELP_NOHEADER, - KEY_VERSION, + KEY_HELP, + KEY_HELP_NOHEADER, + KEY_VERSION, }; struct helper_opts @@ -42,109 +42,109 @@ static const struct fuse_opt fuse_helper_opts[] = { - FUSE_HELPER_OPT("-d", foreground), - FUSE_HELPER_OPT("debug", foreground), - FUSE_HELPER_OPT("-f", foreground), - FUSE_HELPER_OPT("-s", singlethread), - FUSE_HELPER_OPT("fsname=", nodefault_subtype), - FUSE_HELPER_OPT("subtype=", nodefault_subtype), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END -}; + FUSE_HELPER_OPT("-d", foreground), + FUSE_HELPER_OPT("debug", foreground), + FUSE_HELPER_OPT("-f", foreground), + FUSE_HELPER_OPT("-s", singlethread), + FUSE_HELPER_OPT("fsname=", nodefault_subtype), + FUSE_HELPER_OPT("subtype=", nodefault_subtype), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END + }; static void usage(const char *progname) { - fprintf(stderr, - "usage: %s mountpoint [options]\n\n", progname); - fprintf(stderr, - "general options:\n" - " -o opt,[opt...] mount options\n" - " -h --help print help\n" - " -V --version print version\n" - "\n"); + fprintf(stderr, + "usage: %s mountpoint [options]\n\n", progname); + fprintf(stderr, + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + " -V --version print version\n" + "\n"); } static void helper_help(void) { - fprintf(stderr, - "FUSE options:\n" - " -d -o debug enable debug output (implies -f)\n" - " -f foreground operation\n" - " -s disable multi-threaded operation\n" - "\n" - ); + fprintf(stderr, + "FUSE options:\n" + " -d -o debug enable debug output (implies -f)\n" + " -f foreground operation\n" + " -s disable multi-threaded operation\n" + "\n" + ); } static void helper_version(void) { - fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); + fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); } static int fuse_helper_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - struct helper_opts *hopts = data; - - switch (key) { - case KEY_HELP: - usage(outargs->argv[0]); - /* fall through */ - - case KEY_HELP_NOHEADER: - helper_help(); - return fuse_opt_add_arg(outargs, "-h"); - - case KEY_VERSION: - helper_version(); - return 1; - - case FUSE_OPT_KEY_NONOPT: - if (!hopts->mountpoint) { - char mountpoint[PATH_MAX]; - if (realpath(arg, mountpoint) == NULL) { - fprintf(stderr, - "fuse: bad mount point `%s': %s\n", - arg, strerror(errno)); - return -1; - } - return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); - } else { - fprintf(stderr, "fuse: invalid argument `%s'\n", arg); - return -1; - } - - default: - return 1; - } + struct helper_opts *hopts = data; + + switch (key) { + case KEY_HELP: + usage(outargs->argv[0]); + /* fall through */ + + case KEY_HELP_NOHEADER: + helper_help(); + return fuse_opt_add_arg(outargs, "-h"); + + case KEY_VERSION: + helper_version(); + return 1; + + case FUSE_OPT_KEY_NONOPT: + if (!hopts->mountpoint) { + char mountpoint[PATH_MAX]; + if (realpath(arg, mountpoint) == NULL) { + fprintf(stderr, + "fuse: bad mount point `%s': %s\n", + arg, strerror(errno)); + return -1; + } + return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); + } else { + fprintf(stderr, "fuse: invalid argument `%s'\n", arg); + return -1; + } + + default: + return 1; + } } static int add_default_subtype(const char *progname, struct fuse_args *args) { - int res; - char *subtype_opt; - const char *basename = strrchr(progname, '/'); - if (basename == NULL) - basename = progname; - else if (basename[1] != '\0') - basename++; - - subtype_opt = (char *) malloc(strlen(basename) + 64); - if (subtype_opt == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - sprintf(subtype_opt, "-osubtype=%s", basename); - res = fuse_opt_add_arg(args, subtype_opt); - free(subtype_opt); - return res; + int res; + char *subtype_opt; + const char *basename = strrchr(progname, '/'); + if (basename == NULL) + basename = progname; + else if (basename[1] != '\0') + basename++; + + subtype_opt = (char *) malloc(strlen(basename) + 64); + if (subtype_opt == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + sprintf(subtype_opt, "-osubtype=%s", basename); + res = fuse_opt_add_arg(args, subtype_opt); + free(subtype_opt); + return res; } int @@ -191,54 +191,54 @@ fuse_parse_cmdline(struct fuse_args *args_, 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: - 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 initializatation */ - completed = 1; - write(waiter[1], &completed, sizeof(completed)); - close(waiter[0]); - close(waiter[1]); - } - 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: + 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 initializatation */ + completed = 1; + write(waiter[1], &completed, sizeof(completed)); + close(waiter[0]); + close(waiter[1]); + } + return 0; } static @@ -280,17 +280,17 @@ fuse_mount(const char *mountpoint_, static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) { - if (mountpoint) { - int fd = ch ? fuse_chan_clearfd(ch) : -1; - fuse_kern_unmount(mountpoint, fd); - if (ch) - fuse_chan_destroy(ch); - } + if (mountpoint) { + int fd = ch ? fuse_chan_clearfd(ch) : -1; + fuse_kern_unmount(mountpoint, fd); + if (ch) + fuse_chan_destroy(ch); + } } void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) { - fuse_unmount_common(mountpoint, ch); + fuse_unmount_common(mountpoint, ch); } struct fuse *fuse_setup_common(int argc, char *argv[], @@ -302,115 +302,115 @@ struct fuse *fuse_setup_common(int argc, char *argv[], void *user_data, int compat) { - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; - struct fuse *fuse; - int foreground; - int res; - - res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); - if (res == -1) - return NULL; - - ch = fuse_mount_common(*mountpoint, &args); - if (!ch) { - fuse_opt_free_args(&args); - goto err_free; - } - - fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); - fuse_opt_free_args(&args); - if (fuse == NULL) - goto err_unmount; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_unmount; - - res = fuse_set_signal_handlers(fuse_get_session(fuse)); - if (res == -1) - goto err_unmount; - - if (fd) - *fd = fuse_chan_fd(ch); - - return fuse; - -err_unmount: - fuse_unmount_common(*mountpoint, ch); - if (fuse) - fuse_destroy(fuse); -err_free: - free(*mountpoint); - return NULL; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse_chan *ch; + struct fuse *fuse; + int foreground; + int res; + + res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); + if (res == -1) + return NULL; + + ch = fuse_mount_common(*mountpoint, &args); + if (!ch) { + fuse_opt_free_args(&args); + goto err_free; + } + + fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); + fuse_opt_free_args(&args); + if (fuse == NULL) + goto err_unmount; + + res = fuse_daemonize(foreground); + if (res == -1) + goto err_unmount; + + res = fuse_set_signal_handlers(fuse_get_session(fuse)); + if (res == -1) + goto err_unmount; + + if (fd) + *fd = fuse_chan_fd(ch); + + return fuse; + + err_unmount: + fuse_unmount_common(*mountpoint, ch); + if (fuse) + fuse_destroy(fuse); + err_free: + free(*mountpoint); + return NULL; } struct fuse *fuse_setup(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, char **mountpoint, int *multithreaded, void *user_data) { - return fuse_setup_common(argc, argv, op, op_size, mountpoint, - multithreaded, NULL, user_data, 0); + return fuse_setup_common(argc, argv, op, op_size, mountpoint, + multithreaded, NULL, user_data, 0); } static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) { - struct fuse_session *se = fuse_get_session(fuse); - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - fuse_remove_signal_handlers(se); - fuse_unmount_common(mountpoint, ch); - fuse_destroy(fuse); - free(mountpoint); + struct fuse_session *se = fuse_get_session(fuse); + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + fuse_remove_signal_handlers(se); + fuse_unmount_common(mountpoint, ch); + fuse_destroy(fuse); + free(mountpoint); } void fuse_teardown(struct fuse *fuse, char *mountpoint) { - fuse_teardown_common(fuse, mountpoint); + fuse_teardown_common(fuse, mountpoint); } static int fuse_main_common(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data, int compat) { - struct fuse *fuse; - char *mountpoint; - int multithreaded; - int res; - - fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, - &multithreaded, NULL, user_data, compat); - if (fuse == NULL) - return 1; - - if (multithreaded) - res = fuse_loop_mt(fuse); - else - res = fuse_loop(fuse); - - fuse_teardown_common(fuse, mountpoint); - if (res == -1) - return 1; - - return 0; + struct fuse *fuse; + char *mountpoint; + int multithreaded; + int res; + + fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, + &multithreaded, NULL, user_data, compat); + if (fuse == NULL) + return 1; + + if (multithreaded) + res = fuse_loop_mt(fuse); + else + res = fuse_loop(fuse); + + fuse_teardown_common(fuse, mountpoint); + if (res == -1) + return 1; + + return 0; } int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data) { - return fuse_main_common(argc, argv, op, op_size, user_data, 0); + return fuse_main_common(argc, argv, op, op_size, user_data, 0); } #undef fuse_main int fuse_main(void); int fuse_main(void) { - fprintf(stderr, "fuse_main(): This function does not exist\n"); - return -1; + fprintf(stderr, "fuse_main(): This function does not exist\n"); + return -1; } int fuse_version(void) { - return FUSE_VERSION; + return FUSE_VERSION; } #include "fuse_compat.h" @@ -422,9 +422,9 @@ struct fuse *fuse_setup_compat22(int argc, char *argv[], size_t op_size, char **mountpoint, int *multithreaded, int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, - 22); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + op_size, mountpoint, multithreaded, fd, NULL, + 22); } struct fuse *fuse_setup_compat2(int argc, char *argv[], @@ -432,39 +432,39 @@ struct fuse *fuse_setup_compat2(int argc, char *argv[], char **mountpoint, int *multithreaded, int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), - mountpoint, multithreaded, fd, NULL, 21); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), + mountpoint, multithreaded, fd, NULL, 21); } int fuse_main_real_compat22(int argc, char *argv[], const struct fuse_operations_compat22 *op, size_t op_size) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - op_size, NULL, 22); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + op_size, NULL, 22); } void fuse_main_compat1(int argc, char *argv[], const struct fuse_operations_compat1 *op) { - fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), NULL, 11); + fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat1), NULL, 11); } int fuse_main_compat2(int argc, char *argv[], const struct fuse_operations_compat2 *op) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), NULL, - 21); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), NULL, + 21); } int fuse_mount_compat1(const char *mountpoint, const char *args[]) { - /* just ignore mount args for now */ - (void) args; - return fuse_mount_compat22(mountpoint, NULL); + /* just ignore mount args for now */ + (void) args; + return fuse_mount_compat22(mountpoint, NULL); } FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@"); @@ -481,28 +481,28 @@ struct fuse *fuse_setup_compat25(int argc, char *argv[], size_t op_size, char **mountpoint, int *multithreaded, int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, - 25); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + op_size, mountpoint, multithreaded, fd, NULL, + 25); } int fuse_main_real_compat25(int argc, char *argv[], const struct fuse_operations_compat25 *op, size_t op_size) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - op_size, NULL, 25); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + op_size, NULL, 25); } void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint) { - (void) fd; - fuse_teardown_common(fuse, mountpoint); + (void) fd; + fuse_teardown_common(fuse, mountpoint); } int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args) { - return fuse_kern_mount(mountpoint, args); + return fuse_kern_mount(mountpoint, args); } FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5"); diff --git a/libfuse/lib/mount_bsd.c b/libfuse/lib/mount_bsd.c index 3aec3e3e..23747bc4 100644 --- a/libfuse/lib/mount_bsd.c +++ b/libfuse/lib/mount_bsd.c @@ -28,364 +28,364 @@ #define FUSE_DEV_TRUNK "/dev/fuse" enum { - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, - KEY_KERN + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, + KEY_KERN }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + char *kernel_opts; }; #define FUSE_DUAL_OPT_KEY(templ, key) \ - FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key) + FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key) static const struct fuse_opt fuse_mount_opts[] = { - { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, - { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - /* standard FreeBSD mount options */ - FUSE_DUAL_OPT_KEY("dev", KEY_KERN), - FUSE_DUAL_OPT_KEY("async", KEY_KERN), - FUSE_DUAL_OPT_KEY("atime", KEY_KERN), - FUSE_DUAL_OPT_KEY("dev", KEY_KERN), - FUSE_DUAL_OPT_KEY("exec", KEY_KERN), - FUSE_DUAL_OPT_KEY("suid", KEY_KERN), - FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN), - FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN), - FUSE_DUAL_OPT_KEY("sync", KEY_KERN), - FUSE_DUAL_OPT_KEY("union", KEY_KERN), - FUSE_DUAL_OPT_KEY("userquota", KEY_KERN), - FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN), - FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN), - FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN), - FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN), - FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN), - FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN), - FUSE_DUAL_OPT_KEY("acls", KEY_KERN), - FUSE_DUAL_OPT_KEY("force", KEY_KERN), - FUSE_DUAL_OPT_KEY("update", KEY_KERN), - FUSE_DUAL_OPT_KEY("ro", KEY_KERN), - FUSE_DUAL_OPT_KEY("rw", KEY_KERN), - FUSE_DUAL_OPT_KEY("auto", KEY_KERN), - /* options supported under both Linux and FBSD */ - FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN), - FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN), - FUSE_OPT_KEY("max_read=", KEY_KERN), - FUSE_OPT_KEY("subtype=", KEY_KERN), - /* FBSD FUSE specific mount options */ - FUSE_DUAL_OPT_KEY("private", KEY_KERN), - FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN), - FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN), - FUSE_OPT_KEY("nosync_unmount", KEY_KERN), - /* stock FBSD mountopt parsing routine lets anything be negated... */ - /* - * Linux specific mount options, but let just the mount util - * handle them - */ - FUSE_OPT_KEY("fsname=", KEY_KERN), - FUSE_OPT_KEY("nonempty", KEY_KERN), - FUSE_OPT_KEY("large_read", KEY_KERN), - FUSE_OPT_END + { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, + { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + /* standard FreeBSD mount options */ + FUSE_DUAL_OPT_KEY("dev", KEY_KERN), + FUSE_DUAL_OPT_KEY("async", KEY_KERN), + FUSE_DUAL_OPT_KEY("atime", KEY_KERN), + FUSE_DUAL_OPT_KEY("dev", KEY_KERN), + FUSE_DUAL_OPT_KEY("exec", KEY_KERN), + FUSE_DUAL_OPT_KEY("suid", KEY_KERN), + FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN), + FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN), + FUSE_DUAL_OPT_KEY("sync", KEY_KERN), + FUSE_DUAL_OPT_KEY("union", KEY_KERN), + FUSE_DUAL_OPT_KEY("userquota", KEY_KERN), + FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN), + FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN), + FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN), + FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN), + FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN), + FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN), + FUSE_DUAL_OPT_KEY("acls", KEY_KERN), + FUSE_DUAL_OPT_KEY("force", KEY_KERN), + FUSE_DUAL_OPT_KEY("update", KEY_KERN), + FUSE_DUAL_OPT_KEY("ro", KEY_KERN), + FUSE_DUAL_OPT_KEY("rw", KEY_KERN), + FUSE_DUAL_OPT_KEY("auto", KEY_KERN), + /* options supported under both Linux and FBSD */ + FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN), + FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN), + FUSE_OPT_KEY("max_read=", KEY_KERN), + FUSE_OPT_KEY("subtype=", KEY_KERN), + /* FBSD FUSE specific mount options */ + FUSE_DUAL_OPT_KEY("private", KEY_KERN), + FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN), + FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN), + FUSE_OPT_KEY("nosync_unmount", KEY_KERN), + /* stock FBSD mountopt parsing routine lets anything be negated... */ + /* + * Linux specific mount options, but let just the mount util + * handle them + */ + FUSE_OPT_KEY("fsname=", KEY_KERN), + FUSE_OPT_KEY("nonempty", KEY_KERN), + FUSE_OPT_KEY("large_read", KEY_KERN), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, - " -o allow_root allow access to root\n" - ); - system(FUSERMOUNT_PROG " --help"); - fputc('\n', stderr); + fprintf(stderr, + " -o allow_root allow access to root\n" + ); + system(FUSERMOUNT_PROG " --help"); + fputc('\n', stderr); } static void mount_version(void) { - system(FUSERMOUNT_PROG " --version"); + system(FUSERMOUNT_PROG " --version"); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - - case KEY_KERN: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + + case KEY_KERN: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } void fuse_unmount_compat22(const char *mountpoint) { - char dev[128]; - char *ssc, *umount_cmd; - FILE *sf; - int rv; - char seekscript[] = - /* error message is annoying in help output */ - "exec 2>/dev/null; " - "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " - "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " - " { if ($3 == %d) print $10; }' | " - "/usr/bin/sort | " - "/usr/bin/uniq | " - "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; - - (void) mountpoint; - - /* - * If we don't know the fd, we have to resort to the scripted - * solution -- iterating over the fd-s is unpractical, as we - * don't know how many of open files we have. (This could be - * looked up in procfs -- however, that's optional on FBSD; or - * read out from the kmem -- however, that's bound to - * privileges (in fact, that's what happens when we call the - * setgid kmem fstat(1) utility). - */ - if (asprintf(&ssc, seekscript, getpid()) == -1) - return; - - errno = 0; - sf = popen(ssc, "r"); - free(ssc); - if (! sf) - return; - - fgets(dev, sizeof(dev), sf); - rv = pclose(sf); - if (rv) - return; - - if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1) - return; - system(umount_cmd); - free(umount_cmd); + char dev[128]; + char *ssc, *umount_cmd; + FILE *sf; + int rv; + char seekscript[] = + /* error message is annoying in help output */ + "exec 2>/dev/null; " + "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " + "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " + " { if ($3 == %d) print $10; }' | " + "/usr/bin/sort | " + "/usr/bin/uniq | " + "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; + + (void) mountpoint; + + /* + * If we don't know the fd, we have to resort to the scripted + * solution -- iterating over the fd-s is unpractical, as we + * don't know how many of open files we have. (This could be + * looked up in procfs -- however, that's optional on FBSD; or + * read out from the kmem -- however, that's bound to + * privileges (in fact, that's what happens when we call the + * setgid kmem fstat(1) utility). + */ + if (asprintf(&ssc, seekscript, getpid()) == -1) + return; + + errno = 0; + sf = popen(ssc, "r"); + free(ssc); + if (! sf) + return; + + fgets(dev, sizeof(dev), sf); + rv = pclose(sf); + if (rv) + return; + + if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1) + return; + system(umount_cmd); + free(umount_cmd); } static void do_unmount(char *dev, int fd) { - char device_path[SPECNAMELEN + 12]; - const char *argv[4]; - const char umount_cmd[] = "/sbin/umount"; - pid_t pid; + char device_path[SPECNAMELEN + 12]; + const char *argv[4]; + const char umount_cmd[] = "/sbin/umount"; + pid_t pid; - snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev); + snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev); - argv[0] = umount_cmd; - argv[1] = "-f"; - argv[2] = device_path; - argv[3] = NULL; + argv[0] = umount_cmd; + argv[1] = "-f"; + argv[2] = device_path; + argv[3] = NULL; - pid = fork(); + pid = fork(); - if (pid == -1) - return; + if (pid == -1) + return; - if (pid == 0) { - close(fd); - execvp(umount_cmd, (char **)argv); - exit(1); - } + if (pid == 0) { + close(fd); + execvp(umount_cmd, (char **)argv); + exit(1); + } - waitpid(pid, NULL, 0); + waitpid(pid, NULL, 0); } void fuse_kern_unmount(const char *mountpoint, int fd) { - char *ep, dev[128]; - struct stat sbuf; + char *ep, dev[128]; + struct stat sbuf; - (void)mountpoint; + (void)mountpoint; - if (fstat(fd, &sbuf) == -1) - goto out; + if (fstat(fd, &sbuf) == -1) + goto out; - devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); + devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); - if (strncmp(dev, "fuse", 4)) - goto out; + if (strncmp(dev, "fuse", 4)) + goto out; - strtol(dev + 4, &ep, 10); - if (*ep != '\0') - goto out; + strtol(dev + 4, &ep, 10); + if (*ep != '\0') + goto out; - do_unmount(dev, fd); + do_unmount(dev, fd); -out: - close(fd); + out: + close(fd); } /* Check if kernel is doing init in background */ static int init_backgrounded(void) { - unsigned ibg, len; + unsigned ibg, len; - len = sizeof(ibg); + len = sizeof(ibg); - if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) - return 0; + if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) + return 0; - return ibg; + return ibg; } static int fuse_mount_core(const char *mountpoint, const char *opts) { - const char *mountprog = FUSERMOUNT_PROG; - int fd; - char *fdnam, *dev; - pid_t pid, cpid; - int status; - - fdnam = getenv("FUSE_DEV_FD"); - - if (fdnam) { - char *ep; - - fd = strtol(fdnam, &ep, 10); - - if (*ep != '\0') { - fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); - return -1; - } - - if (fd < 0) - return -1; - - goto mount; - } - - dev = getenv("FUSE_DEV_NAME"); - - if (! dev) - dev = (char *)FUSE_DEV_TRUNK; - - if ((fd = open(dev, O_RDWR)) < 0) { - perror("fuse: failed to open fuse device"); - return -1; - } - -mount: - if (getenv("FUSE_NO_MOUNT") || ! mountpoint) - goto out; - - pid = fork(); - cpid = pid; - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - return -1; - } - - if (pid == 0) { - if (! init_backgrounded()) { - /* - * If init is not backgrounded, we have to - * call the mount util backgrounded, to avoid - * deadlock. - */ - - pid = fork(); - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - exit(1); - } - } - - if (pid == 0) { - const char *argv[32]; - int a = 0; - - if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) { - perror("fuse: failed to assemble mount arguments"); - exit(1); - } - - argv[a++] = mountprog; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = fdnam; - argv[a++] = mountpoint; - argv[a++] = NULL; - execvp(mountprog, (char **) argv); - perror("fuse: failed to exec mount program"); - exit(1); - } - - exit(0); - } - - if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) { - perror("fuse: failed to mount file system"); - close(fd); - return -1; - } - -out: - return fd; + const char *mountprog = FUSERMOUNT_PROG; + int fd; + char *fdnam, *dev; + pid_t pid, cpid; + int status; + + fdnam = getenv("FUSE_DEV_FD"); + + if (fdnam) { + char *ep; + + fd = strtol(fdnam, &ep, 10); + + if (*ep != '\0') { + fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); + return -1; + } + + if (fd < 0) + return -1; + + goto mount; + } + + dev = getenv("FUSE_DEV_NAME"); + + if (! dev) + dev = (char *)FUSE_DEV_TRUNK; + + if ((fd = open(dev, O_RDWR)) < 0) { + perror("fuse: failed to open fuse device"); + return -1; + } + + mount: + if (getenv("FUSE_NO_MOUNT") || ! mountpoint) + goto out; + + pid = fork(); + cpid = pid; + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + return -1; + } + + if (pid == 0) { + if (! init_backgrounded()) { + /* + * If init is not backgrounded, we have to + * call the mount util backgrounded, to avoid + * deadlock. + */ + + pid = fork(); + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + exit(1); + } + } + + if (pid == 0) { + const char *argv[32]; + int a = 0; + + if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) { + perror("fuse: failed to assemble mount arguments"); + exit(1); + } + + argv[a++] = mountprog; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = fdnam; + argv[a++] = mountpoint; + argv[a++] = NULL; + execvp(mountprog, (char **) argv); + perror("fuse: failed to exec mount program"); + exit(1); + } + + exit(0); + } + + if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) { + perror("fuse: failed to mount file system"); + close(fd); + return -1; + } + + out: + return fd; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - - memset(&mo, 0, sizeof(mo)); - /* mount util should not try to spawn the daemon */ - setenv("MOUNT_FUSEFS_SAFE", "1", 1); - /* to notify the mount util it's called from lib */ - setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - if (mo.ishelp) - return 0; - - res = fuse_mount_core(mountpoint, mo.kernel_opts); -out: - free(mo.kernel_opts); - return res; + struct mount_opts mo; + int res = -1; + + memset(&mo, 0, sizeof(mo)); + /* mount util should not try to spawn the daemon */ + setenv("MOUNT_FUSEFS_SAFE", "1", 1); + /* to notify the mount util it's called from lib */ + setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + if (mo.ishelp) + return 0; + + res = fuse_mount_core(mountpoint, mo.kernel_opts); + out: + free(mo.kernel_opts); + return res; } FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2"); diff --git a/libfuse/lib/mount_generic.c b/libfuse/lib/mount_generic.c index 4a3f1bd5..1c4f5c63 100644 --- a/libfuse/lib/mount_generic.c +++ b/libfuse/lib/mount_generic.c @@ -51,200 +51,200 @@ #endif enum { - KEY_KERN_FLAG, - KEY_KERN_OPT, - KEY_FUSERMOUNT_OPT, - KEY_SUBTYPE_OPT, - KEY_MTAB_OPT, - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, + KEY_KERN_FLAG, + KEY_KERN_OPT, + KEY_FUSERMOUNT_OPT, + KEY_SUBTYPE_OPT, + KEY_MTAB_OPT, + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - int flags; - int nonempty; - int auto_unmount; - int blkdev; - char *fsname; - char *subtype; - char *subtype_opt; - char *mtab_opts; - char *fusermount_opts; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + int flags; + int nonempty; + int auto_unmount; + int blkdev; + char *fsname; + char *subtype; + char *subtype_opt; + char *mtab_opts; + char *fusermount_opts; + char *kernel_opts; }; #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } static const struct fuse_opt fuse_mount_opts[] = { - FUSE_MOUNT_OPT("allow_other", allow_other), - FUSE_MOUNT_OPT("allow_root", allow_root), - FUSE_MOUNT_OPT("nonempty", nonempty), - FUSE_MOUNT_OPT("blkdev", blkdev), - FUSE_MOUNT_OPT("auto_unmount", auto_unmount), - FUSE_MOUNT_OPT("fsname=%s", fsname), - FUSE_MOUNT_OPT("subtype=%s", subtype), - FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), - FUSE_OPT_KEY("large_read", KEY_KERN_OPT), - FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), - FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), - FUSE_OPT_KEY("context=", KEY_KERN_OPT), - FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT), - FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT), - FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("user=", KEY_MTAB_OPT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("ro", KEY_KERN_FLAG), - FUSE_OPT_KEY("rw", KEY_KERN_FLAG), - FUSE_OPT_KEY("suid", KEY_KERN_FLAG), - FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), - FUSE_OPT_KEY("dev", KEY_KERN_FLAG), - FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), - FUSE_OPT_KEY("exec", KEY_KERN_FLAG), - FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), - FUSE_OPT_KEY("async", KEY_KERN_FLAG), - FUSE_OPT_KEY("sync", KEY_KERN_FLAG), - FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), - FUSE_OPT_KEY("atime", KEY_KERN_FLAG), - FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END + FUSE_MOUNT_OPT("allow_other", allow_other), + FUSE_MOUNT_OPT("allow_root", allow_root), + FUSE_MOUNT_OPT("nonempty", nonempty), + FUSE_MOUNT_OPT("blkdev", blkdev), + FUSE_MOUNT_OPT("auto_unmount", auto_unmount), + FUSE_MOUNT_OPT("fsname=%s", fsname), + FUSE_MOUNT_OPT("subtype=%s", subtype), + FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), + FUSE_OPT_KEY("large_read", KEY_KERN_OPT), + FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), + FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), + FUSE_OPT_KEY("context=", KEY_KERN_OPT), + FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT), + FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT), + FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("user=", KEY_MTAB_OPT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("ro", KEY_KERN_FLAG), + FUSE_OPT_KEY("rw", KEY_KERN_FLAG), + FUSE_OPT_KEY("suid", KEY_KERN_FLAG), + FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), + FUSE_OPT_KEY("dev", KEY_KERN_FLAG), + FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), + FUSE_OPT_KEY("exec", KEY_KERN_FLAG), + FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), + FUSE_OPT_KEY("async", KEY_KERN_FLAG), + FUSE_OPT_KEY("sync", KEY_KERN_FLAG), + FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), + FUSE_OPT_KEY("atime", KEY_KERN_FLAG), + FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, -" -o allow_other allow access to other users\n" -" -o allow_root allow access to root\n" -" -o auto_unmount auto unmount on process termination\n" -" -o nonempty allow mounts over non-empty file/dir\n" -" -o default_permissions enable permission checking by kernel\n" -" -o fsname=NAME set filesystem name\n" -" -o subtype=NAME set filesystem type\n" -" -o large_read issue large read requests (2.4 only)\n" -" -o max_read=N set maximum size of read requests\n" -"\n"); + fprintf(stderr, + " -o allow_other allow access to other users\n" + " -o allow_root allow access to root\n" + " -o auto_unmount auto unmount on process termination\n" + " -o nonempty allow mounts over non-empty file/dir\n" + " -o default_permissions enable permission checking by kernel\n" + " -o fsname=NAME set filesystem name\n" + " -o subtype=NAME set filesystem type\n" + " -o large_read issue large read requests (2.4 only)\n" + " -o max_read=N set maximum size of read requests\n" + "\n"); } static void exec_fusermount(const char *argv[]) { - execv(FUSERMOUNT_DIR "/mergerfs-" FUSERMOUNT_PROG, (char **) argv); - execvp("mergerfs-" FUSERMOUNT_PROG, (char **) argv); - execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); - execvp(FUSERMOUNT_PROG, (char **) argv); + execv(FUSERMOUNT_DIR "/mergerfs-" FUSERMOUNT_PROG, (char **) argv); + execvp("mergerfs-" FUSERMOUNT_PROG, (char **) argv); + execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); + execvp(FUSERMOUNT_PROG, (char **) argv); } static void mount_version(void) { - int pid = fork(); - if (!pid) { - const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; - exec_fusermount(argv); - _exit(1); - } else if (pid != -1) - waitpid(pid, NULL, 0); + int pid = fork(); + if (!pid) { + const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; + exec_fusermount(argv); + _exit(1); + } else if (pid != -1) + waitpid(pid, NULL, 0); } struct mount_flags { - const char *opt; - unsigned long flag; - int on; + const char *opt; + unsigned long flag; + int on; }; static const struct mount_flags mount_flags[] = { - {"rw", MS_RDONLY, 0}, - {"ro", MS_RDONLY, 1}, - {"suid", MS_NOSUID, 0}, - {"nosuid", MS_NOSUID, 1}, - {"dev", MS_NODEV, 0}, - {"nodev", MS_NODEV, 1}, - {"exec", MS_NOEXEC, 0}, - {"noexec", MS_NOEXEC, 1}, - {"async", MS_SYNCHRONOUS, 0}, - {"sync", MS_SYNCHRONOUS, 1}, - {"atime", MS_NOATIME, 0}, - {"noatime", MS_NOATIME, 1}, + {"rw", MS_RDONLY, 0}, + {"ro", MS_RDONLY, 1}, + {"suid", MS_NOSUID, 0}, + {"nosuid", MS_NOSUID, 1}, + {"dev", MS_NODEV, 0}, + {"nodev", MS_NODEV, 1}, + {"exec", MS_NOEXEC, 0}, + {"noexec", MS_NOEXEC, 1}, + {"async", MS_SYNCHRONOUS, 0}, + {"sync", MS_SYNCHRONOUS, 1}, + {"atime", MS_NOATIME, 0}, + {"noatime", MS_NOATIME, 1}, #ifndef __NetBSD__ - {"dirsync", MS_DIRSYNC, 1}, + {"dirsync", MS_DIRSYNC, 1}, #endif - {NULL, 0, 0} + {NULL, 0, 0} }; static void set_mount_flag(const char *s, int *flags) { - int i; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - const char *opt = mount_flags[i].opt; - if (strcmp(opt, s) == 0) { - if (mount_flags[i].on) - *flags |= mount_flags[i].flag; - else - *flags &= ~mount_flags[i].flag; - return; - } - } - fprintf(stderr, "fuse: internal error, can't find mount flag\n"); - abort(); + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strcmp(opt, s) == 0) { + if (mount_flags[i].on) + *flags |= mount_flags[i].flag; + else + *flags &= ~mount_flags[i].flag; + return; + } + } + fprintf(stderr, "fuse: internal error, can't find mount flag\n"); + abort(); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - case KEY_KERN_FLAG: - set_mount_flag(arg, &mo->flags); - return 0; - - case KEY_KERN_OPT: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_FUSERMOUNT_OPT: - return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg); - - case KEY_SUBTYPE_OPT: - return fuse_opt_add_opt(&mo->subtype_opt, arg); - - case KEY_MTAB_OPT: - return fuse_opt_add_opt(&mo->mtab_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + case KEY_KERN_FLAG: + set_mount_flag(arg, &mo->flags); + return 0; + + case KEY_KERN_OPT: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_FUSERMOUNT_OPT: + return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg); + + case KEY_SUBTYPE_OPT: + return fuse_opt_add_opt(&mo->subtype_opt, arg); + + case KEY_MTAB_OPT: + return fuse_opt_add_opt(&mo->mtab_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } /* return value: @@ -253,393 +253,393 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key, */ static int receive_fd(int fd) { - struct msghdr msg; - struct iovec iov; - char buf[1]; - int rv; - size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; - struct cmsghdr *cmsg; - - iov.iov_base = buf; - iov.iov_len = 1; - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - /* old BSD implementations should use msg_accrights instead of - * msg_control; the interface is different. */ - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof(ccmsg); - - while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); - if (rv == -1) { - perror("recvmsg"); - return -1; - } - if(!rv) { - /* EOF */ - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg->cmsg_type != SCM_RIGHTS) { - fprintf(stderr, "got control message of unknown type %d\n", - cmsg->cmsg_type); - return -1; - } - return *(int*)CMSG_DATA(cmsg); + struct msghdr msg; + struct iovec iov; + char buf[1]; + int rv; + size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; + struct cmsghdr *cmsg; + + iov.iov_base = buf; + iov.iov_len = 1; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + /* old BSD implementations should use msg_accrights instead of + * msg_control; the interface is different. */ + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof(ccmsg); + + while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); + if (rv == -1) { + perror("recvmsg"); + return -1; + } + if(!rv) { + /* EOF */ + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg->cmsg_type != SCM_RIGHTS) { + fprintf(stderr, "got control message of unknown type %d\n", + cmsg->cmsg_type); + return -1; + } + return *(int*)CMSG_DATA(cmsg); } void fuse_kern_unmount(const char *mountpoint, int fd) { - int res; - int pid; + int res; + int pid; - if (!mountpoint) - return; + if (!mountpoint) + return; - if (fd != -1) { - struct pollfd pfd; + if (fd != -1) { + struct pollfd pfd; - pfd.fd = fd; - pfd.events = 0; - res = poll(&pfd, 1, 0); + pfd.fd = fd; + pfd.events = 0; + res = poll(&pfd, 1, 0); - /* Need to close file descriptor, otherwise synchronous umount - would recurse into filesystem, and deadlock. + /* Need to close file descriptor, otherwise synchronous umount + would recurse into filesystem, and deadlock. - Caller expects fuse_kern_unmount to close the fd, so close it - anyway. */ - close(fd); + Caller expects fuse_kern_unmount to close the fd, so close it + anyway. */ + close(fd); - /* If file poll returns POLLERR on the device file descriptor, - then the filesystem is already unmounted */ - if (res == 1 && (pfd.revents & POLLERR)) - return; - } + /* If file poll returns POLLERR on the device file descriptor, + then the filesystem is already unmounted */ + if (res == 1 && (pfd.revents & POLLERR)) + return; + } - if (geteuid() == 0) { - fuse_mnt_umount("fuse", mountpoint, mountpoint, 1); - return; - } + if (geteuid() == 0) { + fuse_mnt_umount("fuse", mountpoint, mountpoint, 1); + return; + } - res = umount2(mountpoint, 2); - if (res == 0) - return; + res = umount2(mountpoint, 2); + if (res == 0) + return; - pid = fork(); - if(pid == -1) - return; + pid = fork(); + if(pid == -1) + return; - if(pid == 0) { - const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", - "--", mountpoint, NULL }; + if(pid == 0) { + const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", + "--", mountpoint, NULL }; - exec_fusermount(argv); - _exit(1); - } - waitpid(pid, NULL, 0); + exec_fusermount(argv); + _exit(1); + } + waitpid(pid, NULL, 0); } void fuse_unmount_compat22(const char *mountpoint) { - fuse_kern_unmount(mountpoint, -1); + fuse_kern_unmount(mountpoint, -1); } static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo, - const char *opts, int quiet) + const char *opts, int quiet) { - int fds[2], pid; - int res; - int rv; - - if (!mountpoint) { - fprintf(stderr, "fuse: missing mountpoint parameter\n"); - return -1; - } - - res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) { - perror("fuse: socketpair() failed"); - return -1; - } - - pid = fork(); - if(pid == -1) { - perror("fuse: fork() failed"); - close(fds[0]); - close(fds[1]); - return -1; - } - - if(pid == 0) { - char env[10]; - const char *argv[32]; - int a = 0; - - if (quiet) { - int fd = open("/dev/null", O_RDONLY); - if (fd != -1) { - dup2(fd, 1); - dup2(fd, 2); - } - } - - argv[a++] = FUSERMOUNT_PROG; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = "--"; - argv[a++] = mountpoint; - argv[a++] = NULL; - - close(fds[1]); - fcntl(fds[0], F_SETFD, 0); - snprintf(env, sizeof(env), "%i", fds[0]); - setenv(FUSE_COMMFD_ENV, env, 1); - exec_fusermount(argv); - perror("fuse: failed to exec fusermount"); - _exit(1); - } - - close(fds[0]); - rv = receive_fd(fds[1]); - - if (!mo->auto_unmount) { - /* with auto_unmount option fusermount will not exit until - this socket is closed */ - close(fds[1]); - waitpid(pid, NULL, 0); /* bury zombie */ - } - - return rv; + int fds[2], pid; + int res; + int rv; + + if (!mountpoint) { + fprintf(stderr, "fuse: missing mountpoint parameter\n"); + return -1; + } + + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if(res == -1) { + perror("fuse: socketpair() failed"); + return -1; + } + + pid = fork(); + if(pid == -1) { + perror("fuse: fork() failed"); + close(fds[0]); + close(fds[1]); + return -1; + } + + if(pid == 0) { + char env[10]; + const char *argv[32]; + int a = 0; + + if (quiet) { + int fd = open("/dev/null", O_RDONLY); + if (fd != -1) { + dup2(fd, 1); + dup2(fd, 2); + } + } + + argv[a++] = FUSERMOUNT_PROG; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = "--"; + argv[a++] = mountpoint; + argv[a++] = NULL; + + close(fds[1]); + fcntl(fds[0], F_SETFD, 0); + snprintf(env, sizeof(env), "%i", fds[0]); + setenv(FUSE_COMMFD_ENV, env, 1); + exec_fusermount(argv); + perror("fuse: failed to exec fusermount"); + _exit(1); + } + + close(fds[0]); + rv = receive_fd(fds[1]); + + if (!mo->auto_unmount) { + /* with auto_unmount option fusermount will not exit until + this socket is closed */ + close(fds[1]); + waitpid(pid, NULL, 0); /* bury zombie */ + } + + return rv; } int fuse_mount_compat22(const char *mountpoint, const char *opts) { - struct mount_opts mo; - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; + struct mount_opts mo; + memset(&mo, 0, sizeof(mo)); + mo.flags = MS_NOSUID | MS_NODEV; - return fuse_mount_fusermount(mountpoint, &mo, opts, 0); + return fuse_mount_fusermount(mountpoint, &mo, opts, 0); } static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, const char *mnt_opts) { - char tmp[128]; - const char *devname = "/dev/fuse"; - char *source = NULL; - char *type = NULL; - struct stat stbuf; - int fd; - int res; - - if (!mnt) { - fprintf(stderr, "fuse: missing mountpoint parameter\n"); - return -1; - } - - res = stat(mnt, &stbuf); - if (res == -1) { - fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", - mnt, strerror(errno)); - return -1; - } - - if (!mo->nonempty) { - res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, - stbuf.st_size); - if (res == -1) - return -1; - } - - if (mo->auto_unmount) { - /* Tell the caller to fallback to fusermount because - auto-unmount does not work otherwise. */ - return -2; - } - - fd = open(devname, O_RDWR); - if (fd == -1) { - if (errno == ENODEV || errno == ENOENT) - fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n"); - else - fprintf(stderr, "fuse: failed to open %s: %s\n", - devname, strerror(errno)); - return -1; - } - - snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u", - fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); - - res = fuse_opt_add_opt(&mo->kernel_opts, tmp); - if (res == -1) - goto out_close; - - source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + - (mo->subtype ? strlen(mo->subtype) : 0) + - strlen(devname) + 32); - - type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); - if (!type || !source) { - fprintf(stderr, "fuse: failed to allocate memory\n"); - goto out_close; - } - - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->subtype) { - strcat(type, "."); - strcat(type, mo->subtype); - } - strcpy(source, - mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); - - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - if (res == -1 && errno == ENODEV && mo->subtype) { - /* Probably missing subtype support */ - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->fsname) { - if (!mo->blkdev) - sprintf(source, "%s#%s", mo->subtype, - mo->fsname); - } else { - strcpy(source, type); - } - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - } - if (res == -1) { - /* - * Maybe kernel doesn't support unprivileged mounts, in this - * case try falling back to fusermount - */ - if (errno == EPERM) { - res = -2; - } else { - int errno_save = errno; - if (mo->blkdev && errno == ENODEV && - !fuse_mnt_check_fuseblk()) - fprintf(stderr, - "fuse: 'fuseblk' support missing\n"); - else - fprintf(stderr, "fuse: mount failed: %s\n", - strerror(errno_save)); - } - - goto out_close; - } + char tmp[128]; + const char *devname = "/dev/fuse"; + char *source = NULL; + char *type = NULL; + struct stat stbuf; + int fd; + int res; + + if (!mnt) { + fprintf(stderr, "fuse: missing mountpoint parameter\n"); + return -1; + } + + res = stat(mnt, &stbuf); + if (res == -1) { + fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", + mnt, strerror(errno)); + return -1; + } + + if (!mo->nonempty) { + res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, + stbuf.st_size); + if (res == -1) + return -1; + } + + if (mo->auto_unmount) { + /* Tell the caller to fallback to fusermount because + auto-unmount does not work otherwise. */ + return -2; + } + + fd = open(devname, O_RDWR); + if (fd == -1) { + if (errno == ENODEV || errno == ENOENT) + fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n"); + else + fprintf(stderr, "fuse: failed to open %s: %s\n", + devname, strerror(errno)); + return -1; + } + + snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u", + fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); + + res = fuse_opt_add_opt(&mo->kernel_opts, tmp); + if (res == -1) + goto out_close; + + source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + + (mo->subtype ? strlen(mo->subtype) : 0) + + strlen(devname) + 32); + + type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); + if (!type || !source) { + fprintf(stderr, "fuse: failed to allocate memory\n"); + goto out_close; + } + + strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); + if (mo->subtype) { + strcat(type, "."); + strcat(type, mo->subtype); + } + strcpy(source, + mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); + + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + if (res == -1 && errno == ENODEV && mo->subtype) { + /* Probably missing subtype support */ + strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); + if (mo->fsname) { + if (!mo->blkdev) + sprintf(source, "%s#%s", mo->subtype, + mo->fsname); + } else { + strcpy(source, type); + } + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + } + if (res == -1) { + /* + * Maybe kernel doesn't support unprivileged mounts, in this + * case try falling back to fusermount + */ + if (errno == EPERM) { + res = -2; + } else { + int errno_save = errno; + if (mo->blkdev && errno == ENODEV && + !fuse_mnt_check_fuseblk()) + fprintf(stderr, + "fuse: 'fuseblk' support missing\n"); + else + fprintf(stderr, "fuse: mount failed: %s\n", + strerror(errno_save)); + } + + goto out_close; + } #ifndef __NetBSD__ #ifndef IGNORE_MTAB - if (geteuid() == 0) { - char *newmnt = fuse_mnt_resolve_path("fuse", mnt); - res = -1; - if (!newmnt) - goto out_umount; - - res = fuse_mnt_add_mount("fuse", source, newmnt, type, - mnt_opts); - free(newmnt); - if (res == -1) - goto out_umount; - } + if (geteuid() == 0) { + char *newmnt = fuse_mnt_resolve_path("fuse", mnt); + res = -1; + if (!newmnt) + goto out_umount; + + res = fuse_mnt_add_mount("fuse", source, newmnt, type, + mnt_opts); + free(newmnt); + if (res == -1) + goto out_umount; + } #endif /* IGNORE_MTAB */ #endif /* __NetBSD__ */ - free(type); - free(source); - - return fd; - -out_umount: - umount2(mnt, 2); /* lazy umount */ -out_close: - free(type); - free(source); - close(fd); - return res; + free(type); + free(source); + + return fd; + + out_umount: + umount2(mnt, 2); /* lazy umount */ + out_close: + free(type); + free(source); + close(fd); + return res; } static int get_mnt_flag_opts(char **mnt_optsp, int flags) { - int i; + int i; - if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) - return -1; + if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) + return -1; - for (i = 0; mount_flags[i].opt != NULL; i++) { - if (mount_flags[i].on && (flags & mount_flags[i].flag) && - fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) - return -1; - } - return 0; + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) + return -1; + } + return 0; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - char *mnt_opts = NULL; - - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - res = 0; - if (mo.ishelp) - goto out; - - res = -1; - if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) - goto out; - if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) - goto out; - if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) - goto out; - - res = fuse_mount_sys(mountpoint, &mo, mnt_opts); - if (res == -2) { - if (mo.fusermount_opts && - fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) - goto out; - - if (mo.subtype) { - char *tmp_opts = NULL; - - res = -1; - if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || - fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { - free(tmp_opts); - goto out; - } - - res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1); - free(tmp_opts); - if (res == -1) - res = fuse_mount_fusermount(mountpoint, &mo, - mnt_opts, 0); - } else { - res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0); - } - } -out: - free(mnt_opts); - free(mo.fsname); - free(mo.subtype); - free(mo.fusermount_opts); - free(mo.subtype_opt); - free(mo.kernel_opts); - free(mo.mtab_opts); - return res; + struct mount_opts mo; + int res = -1; + char *mnt_opts = NULL; + + memset(&mo, 0, sizeof(mo)); + mo.flags = MS_NOSUID | MS_NODEV; + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + res = 0; + if (mo.ishelp) + goto out; + + res = -1; + if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) + goto out; + if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) + goto out; + if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) + goto out; + + res = fuse_mount_sys(mountpoint, &mo, mnt_opts); + if (res == -2) { + if (mo.fusermount_opts && + fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) + goto out; + + if (mo.subtype) { + char *tmp_opts = NULL; + + res = -1; + if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || + fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { + free(tmp_opts); + goto out; + } + + res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1); + free(tmp_opts); + if (res == -1) + res = fuse_mount_fusermount(mountpoint, &mo, + mnt_opts, 0); + } else { + res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0); + } + } + out: + free(mnt_opts); + free(mo.fsname); + free(mo.subtype); + free(mo.fusermount_opts); + free(mo.subtype_opt); + free(mo.kernel_opts); + free(mo.mtab_opts); + return res; } FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2"); diff --git a/libfuse/lib/mount_util.c b/libfuse/lib/mount_util.c index defb92f6..b9eefca8 100644 --- a/libfuse/lib/mount_util.c +++ b/libfuse/lib/mount_util.c @@ -31,333 +31,333 @@ #else static int mtab_needs_update(const char *mnt) { - int res; - struct stat stbuf; - - /* If mtab is within new mount, don't touch it */ - if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && - _PATH_MOUNTED[strlen(mnt)] == '/') - return 0; - - /* - * Skip mtab update if /etc/mtab: - * - * - doesn't exist, - * - is a symlink, - * - is on a read-only filesystem. - */ - res = lstat(_PATH_MOUNTED, &stbuf); - if (res == -1) { - if (errno == ENOENT) - return 0; - } else { - uid_t ruid; - int err; - - if (S_ISLNK(stbuf.st_mode)) - return 0; - - ruid = getuid(); - if (ruid != 0) - setreuid(0, -1); - - res = access(_PATH_MOUNTED, W_OK); - err = (res == -1) ? errno : 0; - if (ruid != 0) - setreuid(ruid, -1); - - if (err == EROFS) - return 0; - } - - return 1; + int res; + struct stat stbuf; + + /* If mtab is within new mount, don't touch it */ + if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && + _PATH_MOUNTED[strlen(mnt)] == '/') + return 0; + + /* + * Skip mtab update if /etc/mtab: + * + * - doesn't exist, + * - is a symlink, + * - is on a read-only filesystem. + */ + res = lstat(_PATH_MOUNTED, &stbuf); + if (res == -1) { + if (errno == ENOENT) + return 0; + } else { + uid_t ruid; + int err; + + if (S_ISLNK(stbuf.st_mode)) + return 0; + + ruid = getuid(); + if (ruid != 0) + setreuid(0, -1); + + res = access(_PATH_MOUNTED, W_OK); + err = (res == -1) ? errno : 0; + if (ruid != 0) + setreuid(ruid, -1); + + if (err == EROFS) + return 0; + } + + return 1; } #endif /* __NetBSD__ */ static int add_mount(const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts) + const char *mnt, const char *type, const char *opts) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", - "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); - fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) - res = -1; + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", + "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); + fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) + res = -1; out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); + sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + return res; } int fuse_mnt_add_mount(const char *progname, const char *fsname, const char *mnt, const char *type, const char *opts) { - if (!mtab_needs_update(mnt)) - return 0; + if (!mtab_needs_update(mnt)) + return 0; - return add_mount(progname, fsname, mnt, type, opts); + return add_mount(progname, fsname, mnt, type, opts); } static int exec_umount(const char *progname, const char *rel_mnt, int lazy) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - if (lazy) { - execle("/bin/umount", "/bin/umount", "-i", rel_mnt, - "-l", NULL, &env); - } else { - execle("/bin/umount", "/bin/umount", "-i", rel_mnt, - NULL, &env); - } - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) { - res = -1; - } + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + if (lazy) { + execle("/bin/umount", "/bin/umount", "-i", rel_mnt, + "-l", NULL, &env); + } else { + execle("/bin/umount", "/bin/umount", "-i", rel_mnt, + NULL, &env); + } + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) { + res = -1; + } out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return res; } int fuse_mnt_umount(const char *progname, const char *abs_mnt, const char *rel_mnt, int lazy) { - int res; + int res; - if (!mtab_needs_update(abs_mnt)) { - res = umount2(rel_mnt, lazy ? 2 : 0); - if (res == -1) - fprintf(stderr, "%s: failed to unmount %s: %s\n", - progname, abs_mnt, strerror(errno)); - return res; - } + if (!mtab_needs_update(abs_mnt)) { + res = umount2(rel_mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, abs_mnt, strerror(errno)); + return res; + } - return exec_umount(progname, rel_mnt, lazy); + return exec_umount(progname, rel_mnt, lazy); } static int remove_mount(const char *progname, const char *mnt) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", - "--fake", mnt, NULL, &env); - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) - res = -1; + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", + "--fake", mnt, NULL, &env); + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) + res = -1; out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return res; } int fuse_mnt_remove_mount(const char *progname, const char *mnt) { - if (!mtab_needs_update(mnt)) - return 0; + if (!mtab_needs_update(mnt)) + return 0; - return remove_mount(progname, mnt); + return remove_mount(progname, mnt); } char *fuse_mnt_resolve_path(const char *progname, const char *orig) { - char buf[PATH_MAX]; - char *copy; - char *dst; - char *end; - char *lastcomp; - const char *toresolv; - - if (!orig[0]) { - fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, - orig); - return NULL; - } - - copy = strdup(orig); - if (copy == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return NULL; - } - - toresolv = copy; - lastcomp = NULL; - for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); - if (end[0] != '/') { - char *tmp; - end[1] = '\0'; - tmp = strrchr(copy, '/'); - if (tmp == NULL) { - lastcomp = copy; - toresolv = "."; - } else { - lastcomp = tmp + 1; - if (tmp == copy) - toresolv = "/"; - } - if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { - lastcomp = NULL; - toresolv = copy; - } - else if (tmp) - tmp[0] = '\0'; - } - if (realpath(toresolv, buf) == NULL) { - fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, - strerror(errno)); - free(copy); - return NULL; - } - if (lastcomp == NULL) - dst = strdup(buf); - else { - dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); - if (dst) { - unsigned buflen = strlen(buf); - if (buflen && buf[buflen-1] == '/') - sprintf(dst, "%s%s", buf, lastcomp); - else - sprintf(dst, "%s/%s", buf, lastcomp); - } - } - free(copy); - if (dst == NULL) - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return dst; + char buf[PATH_MAX]; + char *copy; + char *dst; + char *end; + char *lastcomp; + const char *toresolv; + + if (!orig[0]) { + fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, + orig); + return NULL; + } + + copy = strdup(orig); + if (copy == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return NULL; + } + + toresolv = copy; + lastcomp = NULL; + for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); + if (end[0] != '/') { + char *tmp; + end[1] = '\0'; + tmp = strrchr(copy, '/'); + if (tmp == NULL) { + lastcomp = copy; + toresolv = "."; + } else { + lastcomp = tmp + 1; + if (tmp == copy) + toresolv = "/"; + } + if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { + lastcomp = NULL; + toresolv = copy; + } + else if (tmp) + tmp[0] = '\0'; + } + if (realpath(toresolv, buf) == NULL) { + fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, + strerror(errno)); + free(copy); + return NULL; + } + if (lastcomp == NULL) + dst = strdup(buf); + else { + dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); + if (dst) { + unsigned buflen = strlen(buf); + if (buflen && buf[buflen-1] == '/') + sprintf(dst, "%s%s", buf, lastcomp); + else + sprintf(dst, "%s/%s", buf, lastcomp); + } + } + free(copy); + if (dst == NULL) + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return dst; } int fuse_mnt_check_empty(const char *progname, const char *mnt, mode_t rootmode, off_t rootsize) { - int isempty = 1; - - if (S_ISDIR(rootmode)) { - struct dirent *ent; - DIR *dp = opendir(mnt); - if (dp == NULL) { - fprintf(stderr, - "%s: failed to open mountpoint for reading: %s\n", - progname, strerror(errno)); - return -1; - } - while ((ent = readdir(dp)) != NULL) { - if (strcmp(ent->d_name, ".") != 0 && - strcmp(ent->d_name, "..") != 0) { - isempty = 0; - break; - } - } - closedir(dp); - } else if (rootsize) - isempty = 0; - - if (!isempty) { - fprintf(stderr, "%s: mountpoint is not empty\n", progname); - fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); - return -1; - } - return 0; + int isempty = 1; + + if (S_ISDIR(rootmode)) { + struct dirent *ent; + DIR *dp = opendir(mnt); + if (dp == NULL) { + fprintf(stderr, + "%s: failed to open mountpoint for reading: %s\n", + progname, strerror(errno)); + return -1; + } + while ((ent = readdir(dp)) != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) { + isempty = 0; + break; + } + } + closedir(dp); + } else if (rootsize) + isempty = 0; + + if (!isempty) { + fprintf(stderr, "%s: mountpoint is not empty\n", progname); + fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); + return -1; + } + return 0; } int fuse_mnt_check_fuseblk(void) { - char buf[256]; - FILE *f = fopen("/proc/filesystems", "r"); - if (!f) - return 1; - - while (fgets(buf, sizeof(buf), f)) - if (strstr(buf, "fuseblk\n")) { - fclose(f); - return 1; - } - - fclose(f); - return 0; + char buf[256]; + FILE *f = fopen("/proc/filesystems", "r"); + if (!f) + return 1; + + while (fgets(buf, sizeof(buf), f)) + if (strstr(buf, "fuseblk\n")) { + fclose(f); + return 1; + } + + fclose(f); + return 0; } diff --git a/libfuse/lib/ulockmgr.c b/libfuse/lib/ulockmgr.c index b875c507..718d37c6 100644 --- a/libfuse/lib/ulockmgr.c +++ b/libfuse/lib/ulockmgr.c @@ -22,28 +22,28 @@ #include struct message { - unsigned intr : 1; - unsigned nofd : 1; - pthread_t thr; - int cmd; - int fd; - struct flock lock; - int error; + unsigned intr : 1; + unsigned nofd : 1; + pthread_t thr; + int cmd; + int fd; + struct flock lock; + int error; }; struct fd_store { - struct fd_store *next; - int fd; - int inuse; + struct fd_store *next; + int fd; + int inuse; }; struct owner { - struct owner *next; - struct owner *prev; - struct fd_store *fds; - void *id; - size_t id_len; - int cfd; + struct owner *next; + struct owner *prev; + struct fd_store *fds; + void *id; + size_t id_len; + int cfd; }; static pthread_mutex_t ulockmgr_lock; @@ -54,19 +54,19 @@ static struct owner owner_list = { .next = &owner_list, .prev = &owner_list }; static void list_del_owner(struct owner *owner) { - struct owner *prev = owner->prev; - struct owner *next = owner->next; - prev->next = next; - next->prev = prev; + struct owner *prev = owner->prev; + struct owner *next = owner->next; + prev->next = next; + next->prev = prev; } static void list_add_owner(struct owner *owner, struct owner *next) { - struct owner *prev = next->prev; - owner->next = next; - owner->prev = prev; - prev->next = owner; - next->prev = owner; + struct owner *prev = next->prev; + owner->next = next; + owner->prev = prev; + prev->next = owner; + next->prev = owner; } /* @@ -77,368 +77,368 @@ static void list_add_owner(struct owner *owner, struct owner *next) */ static int do_recv(int sock, void *buf, size_t len, int flags) { - int res = recv(sock, buf, len, flags); - if (res == 0) - res = recv(sock, buf, len, flags); + int res = recv(sock, buf, len, flags); + if (res == 0) + res = recv(sock, buf, len, flags); - return res; + return res; } static int ulockmgr_send_message(int sock, void *buf, size_t buflen, int *fdp, int numfds) { - struct msghdr msg; - struct cmsghdr *p_cmsg; - struct iovec vec; - size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; - int res; - - assert(numfds <= MAX_SEND_FDS); - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - p_cmsg = CMSG_FIRSTHDR(&msg); - p_cmsg->cmsg_level = SOL_SOCKET; - p_cmsg->cmsg_type = SCM_RIGHTS; - p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); - memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); - msg.msg_controllen = p_cmsg->cmsg_len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - vec.iov_base = buf; - vec.iov_len = buflen; - res = sendmsg(sock, &msg, MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: sendmsg"); - return -1; - } - if ((size_t) res != buflen) { - fprintf(stderr, "libulockmgr: sendmsg short\n"); - return -1; - } - return 0; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; + int res; + + assert(numfds <= MAX_SEND_FDS); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + p_cmsg = CMSG_FIRSTHDR(&msg); + p_cmsg->cmsg_level = SOL_SOCKET; + p_cmsg->cmsg_type = SCM_RIGHTS; + p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); + memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); + msg.msg_controllen = p_cmsg->cmsg_len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + vec.iov_base = buf; + vec.iov_len = buflen; + res = sendmsg(sock, &msg, MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: sendmsg"); + return -1; + } + if ((size_t) res != buflen) { + fprintf(stderr, "libulockmgr: sendmsg short\n"); + return -1; + } + return 0; } static int ulockmgr_start_daemon(void) { - int sv[2]; - int res; - char tmp[64]; - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - return -1; - } - snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); - res = system(tmp); - close(sv[0]); - if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { - close(sv[1]); - return -1; - } - ulockmgr_cfd = sv[1]; - return 0; + int sv[2]; + int res; + char tmp[64]; + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + return -1; + } + snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); + res = system(tmp); + close(sv[0]); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { + close(sv[1]); + return -1; + } + ulockmgr_cfd = sv[1]; + return 0; } static struct owner *ulockmgr_new_owner(const void *id, size_t id_len) { - int sv[2]; - int res; - char c = 'm'; - struct owner *o; - - if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) - return NULL; - - o = calloc(1, sizeof(struct owner) + id_len); - if (!o) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return NULL; - } - o->id = o + 1; - o->id_len = id_len; - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - goto out_free; - } - res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); - close(sv[0]); - if (res == -1) { - close(ulockmgr_cfd); - ulockmgr_cfd = -1; - goto out_close; - } - - o->cfd = sv[1]; - memcpy(o->id, id, id_len); - list_add_owner(o, &owner_list); - - return o; - -out_close: - close(sv[1]); -out_free: - free(o); - return NULL; + int sv[2]; + int res; + char c = 'm'; + struct owner *o; + + if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) + return NULL; + + o = calloc(1, sizeof(struct owner) + id_len); + if (!o) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return NULL; + } + o->id = o + 1; + o->id_len = id_len; + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + goto out_free; + } + res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); + close(sv[0]); + if (res == -1) { + close(ulockmgr_cfd); + ulockmgr_cfd = -1; + goto out_close; + } + + o->cfd = sv[1]; + memcpy(o->id, id, id_len); + list_add_owner(o, &owner_list); + + return o; + + out_close: + close(sv[1]); + out_free: + free(o); + return NULL; } static int ulockmgr_send_request(struct message *msg, const void *id, size_t id_len) { - int sv[2]; - int cfd; - struct owner *o; - struct fd_store *f = NULL; - struct fd_store *newf = NULL; - struct fd_store **fp; - int fd = msg->fd; - int cmd = msg->cmd; - int res; - int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && - msg->lock.l_start == 0 && msg->lock.l_len == 0); - - for (o = owner_list.next; o != &owner_list; o = o->next) - if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) - break; - - if (o == &owner_list) - o = NULL; - - if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) - o = ulockmgr_new_owner(id, id_len); - - if (!o) { - if (cmd == F_GETLK) { - res = fcntl(msg->fd, F_GETLK, &msg->lock); - return (res == -1) ? -errno : 0; - } else if (msg->lock.l_type == F_UNLCK) - return 0; - else - return -ENOLCK; - } - - if (unlockall) - msg->nofd = 1; - else { - for (fp = &o->fds; *fp; fp = &(*fp)->next) { - f = *fp; - if (f->fd == fd) { - msg->nofd = 1; - break; - } - } - } - - if (!msg->nofd) { - newf = f = calloc(1, sizeof(struct fd_store)); - if (!f) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return -ENOLCK; - } - } - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - free(newf); - return -ENOLCK; - } - - cfd = sv[1]; - sv[1] = msg->fd; - res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, - msg->nofd ? 1 : 2); - close(sv[0]); - if (res == -1) { - free(newf); - close(cfd); - return -EIO; - } - - if (newf) { - newf->fd = msg->fd; - newf->next = o->fds; - o->fds = newf; - } - if (f) - f->inuse++; - - res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); - if (res == -1) { - perror("libulockmgr: recv"); - msg->error = EIO; - } else if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - } else if (cmd == F_SETLKW && msg->error == EAGAIN) { - pthread_mutex_unlock(&ulockmgr_lock); - while (1) { - sigset_t old; - sigset_t unblock; - int errno_save; - - sigemptyset(&unblock); - sigaddset(&unblock, SIGUSR1); - pthread_sigmask(SIG_UNBLOCK, &unblock, &old); - res = do_recv(cfd, msg, sizeof(struct message), - MSG_WAITALL); - errno_save = errno; - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (res == sizeof(struct message)) - break; - else if (res >= 0) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - break; - } else if (errno_save != EINTR) { - errno = errno_save; - perror("libulockmgr: recv"); - msg->error = EIO; - break; - } - msg->intr = 1; - res = send(o->cfd, msg, sizeof(struct message), - MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: send"); - msg->error = EIO; - break; - } - if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: send short\n"); - msg->error = EIO; - break; - } - } - pthread_mutex_lock(&ulockmgr_lock); - - } - if (f) - f->inuse--; - close(cfd); - if (unlockall) { - for (fp = &o->fds; *fp;) { - f = *fp; - if (f->fd == fd && !f->inuse) { - *fp = f->next; - free(f); - } else - fp = &f->next; - } - if (!o->fds) { - list_del_owner(o); - close(o->cfd); - free(o); - } - /* Force OK on unlock-all, since it _will_ succeed once the - owner is deleted */ - msg->error = 0; - } - - return -msg->error; + int sv[2]; + int cfd; + struct owner *o; + struct fd_store *f = NULL; + struct fd_store *newf = NULL; + struct fd_store **fp; + int fd = msg->fd; + int cmd = msg->cmd; + int res; + int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && + msg->lock.l_start == 0 && msg->lock.l_len == 0); + + for (o = owner_list.next; o != &owner_list; o = o->next) + if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) + break; + + if (o == &owner_list) + o = NULL; + + if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) + o = ulockmgr_new_owner(id, id_len); + + if (!o) { + if (cmd == F_GETLK) { + res = fcntl(msg->fd, F_GETLK, &msg->lock); + return (res == -1) ? -errno : 0; + } else if (msg->lock.l_type == F_UNLCK) + return 0; + else + return -ENOLCK; + } + + if (unlockall) + msg->nofd = 1; + else { + for (fp = &o->fds; *fp; fp = &(*fp)->next) { + f = *fp; + if (f->fd == fd) { + msg->nofd = 1; + break; + } + } + } + + if (!msg->nofd) { + newf = f = calloc(1, sizeof(struct fd_store)); + if (!f) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return -ENOLCK; + } + } + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + free(newf); + return -ENOLCK; + } + + cfd = sv[1]; + sv[1] = msg->fd; + res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, + msg->nofd ? 1 : 2); + close(sv[0]); + if (res == -1) { + free(newf); + close(cfd); + return -EIO; + } + + if (newf) { + newf->fd = msg->fd; + newf->next = o->fds; + o->fds = newf; + } + if (f) + f->inuse++; + + res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); + if (res == -1) { + perror("libulockmgr: recv"); + msg->error = EIO; + } else if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + } else if (cmd == F_SETLKW && msg->error == EAGAIN) { + pthread_mutex_unlock(&ulockmgr_lock); + while (1) { + sigset_t old; + sigset_t unblock; + int errno_save; + + sigemptyset(&unblock); + sigaddset(&unblock, SIGUSR1); + pthread_sigmask(SIG_UNBLOCK, &unblock, &old); + res = do_recv(cfd, msg, sizeof(struct message), + MSG_WAITALL); + errno_save = errno; + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (res == sizeof(struct message)) + break; + else if (res >= 0) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + break; + } else if (errno_save != EINTR) { + errno = errno_save; + perror("libulockmgr: recv"); + msg->error = EIO; + break; + } + msg->intr = 1; + res = send(o->cfd, msg, sizeof(struct message), + MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: send"); + msg->error = EIO; + break; + } + if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: send short\n"); + msg->error = EIO; + break; + } + } + pthread_mutex_lock(&ulockmgr_lock); + + } + if (f) + f->inuse--; + close(cfd); + if (unlockall) { + for (fp = &o->fds; *fp;) { + f = *fp; + if (f->fd == fd && !f->inuse) { + *fp = f->next; + free(f); + } else + fp = &f->next; + } + if (!o->fds) { + list_del_owner(o); + close(o->cfd); + free(o); + } + /* Force OK on unlock-all, since it _will_ succeed once the + owner is deleted */ + msg->error = 0; + } + + return -msg->error; } #ifdef DEBUG static uint32_t owner_hash(const unsigned char *id, size_t id_len) { - uint32_t h = 0; - size_t i; - for (i = 0; i < id_len; i++) - h = ((h << 8) | (h >> 24)) ^ id[i]; + uint32_t h = 0; + size_t i; + for (i = 0; i < id_len; i++) + h = ((h << 8) | (h >> 24)) ^ id[i]; - return h; + return h; } #endif static int ulockmgr_canonicalize(int fd, struct flock *lock) { - off_t offset; - if (lock->l_whence == SEEK_CUR) { - offset = lseek(fd, 0, SEEK_CUR); - if (offset == (off_t) -1) - return -errno; - } else if (lock->l_whence == SEEK_END) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) - return -errno; - - offset = stbuf.st_size; - } else - offset = 0; - - lock->l_whence = SEEK_SET; - lock->l_start += offset; - - if (lock->l_start < 0) - return -EINVAL; - - if (lock->l_len < 0) { - lock->l_start += lock->l_len; - if (lock->l_start < 0) - return -EINVAL; - lock->l_len = -lock->l_len; - } - if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) - return -EINVAL; - - return 0; + off_t offset; + if (lock->l_whence == SEEK_CUR) { + offset = lseek(fd, 0, SEEK_CUR); + if (offset == (off_t) -1) + return -errno; + } else if (lock->l_whence == SEEK_END) { + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) + return -errno; + + offset = stbuf.st_size; + } else + offset = 0; + + lock->l_whence = SEEK_SET; + lock->l_start += offset; + + if (lock->l_start < 0) + return -EINVAL; + + if (lock->l_len < 0) { + lock->l_start += lock->l_len; + if (lock->l_start < 0) + return -EINVAL; + lock->l_len = -lock->l_len; + } + if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) + return -EINVAL; + + return 0; } int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, size_t owner_len) { - int err; - struct message msg; - sigset_t old; - sigset_t block; + int err; + struct message msg; + sigset_t old; + sigset_t block; - if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) - return -EINVAL; + if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) + return -EINVAL; - if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK && - lock->l_type != F_UNLCK) - return -EINVAL; + if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK && + lock->l_type != F_UNLCK) + return -EINVAL; - if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && - lock->l_whence != SEEK_END) - return -EINVAL; + if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && + lock->l_whence != SEEK_END) + return -EINVAL; #ifdef DEBUG - fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", - cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, - owner_hash(owner, owner_len)); + fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", + cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, + owner_hash(owner, owner_len)); #endif - /* Unlock should never block anyway */ - if (cmd == F_SETLKW && lock->l_type == F_UNLCK) - cmd = F_SETLK; - - memset(&msg, 0, sizeof(struct message)); - msg.cmd = cmd; - msg.fd = fd; - msg.lock = *lock; - err = ulockmgr_canonicalize(fd, &msg.lock); - if (err) - return err; - - sigemptyset(&block); - sigaddset(&block, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &block, &old); - pthread_mutex_lock(&ulockmgr_lock); - err = ulockmgr_send_request(&msg, owner, owner_len); - pthread_mutex_unlock(&ulockmgr_lock); - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (!err && cmd == F_GETLK) { - if (msg.lock.l_type == F_UNLCK) - lock->l_type = F_UNLCK; - else - *lock = msg.lock; - } - - return err; + /* Unlock should never block anyway */ + if (cmd == F_SETLKW && lock->l_type == F_UNLCK) + cmd = F_SETLK; + + memset(&msg, 0, sizeof(struct message)); + msg.cmd = cmd; + msg.fd = fd; + msg.lock = *lock; + err = ulockmgr_canonicalize(fd, &msg.lock); + if (err) + return err; + + sigemptyset(&block); + sigaddset(&block, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &block, &old); + pthread_mutex_lock(&ulockmgr_lock); + err = ulockmgr_send_request(&msg, owner, owner_len); + pthread_mutex_unlock(&ulockmgr_lock); + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (!err && cmd == F_GETLK) { + if (msg.lock.l_type == F_UNLCK) + lock->l_type = F_UNLCK; + else + *lock = msg.lock; + } + + return err; } From 5f12fb6a5fe976b9bdaafd3d7a1fc45e616a4f2d Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sat, 1 Aug 2020 18:04:13 -0400 Subject: [PATCH 2/6] libfuse cleanup: remove unnecessary files --- libfuse/fuse.pc.in | 11 - libfuse/lib/Makefile.am | 42 ---- libfuse/lib/fuse_versionscript | 207 --------------- libfuse/lib/ulockmgr.c | 444 --------------------------------- libfuse/util/Makefile.am | 58 ----- libfuse/util/init_script | 89 ------- libfuse/util/udev.rules | 1 - libfuse/util/ulockmgr_server.c | 425 ------------------------------- 8 files changed, 1277 deletions(-) delete mode 100644 libfuse/fuse.pc.in delete mode 100644 libfuse/lib/Makefile.am delete mode 100644 libfuse/lib/fuse_versionscript delete mode 100644 libfuse/lib/ulockmgr.c delete mode 100644 libfuse/util/Makefile.am delete mode 100755 libfuse/util/init_script delete mode 100644 libfuse/util/udev.rules delete mode 100644 libfuse/util/ulockmgr_server.c diff --git a/libfuse/fuse.pc.in b/libfuse/fuse.pc.in deleted file mode 100644 index 8fdb8415..00000000 --- a/libfuse/fuse.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: fuse -Description: Filesystem in Userspace -Version: @VERSION@ -Libs: -L${libdir} -lfuse -pthread -Libs.private: @libfuse_libs@ -Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64 diff --git a/libfuse/lib/Makefile.am b/libfuse/lib/Makefile.am deleted file mode 100644 index 7c8104a7..00000000 --- a/libfuse/lib/Makefile.am +++ /dev/null @@ -1,42 +0,0 @@ -## Process this file with automake to produce Makefile.in - -AUTOMAKE_OPTIONS = subdir-objects -AM_CPPFLAGS = -I$(top_srcdir)/include -DFUSERMOUNT_DIR=\"$(bindir)\" \ - -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=26 - -lib_LTLIBRARIES = libfuse.la libulockmgr.la - -if BSD -mount_source = mount_bsd.c -else -mount_source = mount.c mount_util.c mount_util.h -endif - -libfuse_la_SOURCES = \ - fuse.c \ - fuse_i.h \ - fuse_kern_chan.c \ - fuse_loop.c \ - fuse_loop_mt.c \ - fuse_lowlevel.c \ - fuse_misc.h \ - fuse_mt.c \ - fuse_opt.c \ - fuse_session.c \ - fuse_signals.c \ - buffer.c \ - cuse_lowlevel.c \ - helper.c \ - $(mount_source) - -libfuse_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 2:9:7 \ - -Wl,--version-script,$(srcdir)/fuse_versionscript - -if NETBSD -libfuse_la_LIBADD = -lperfuse -lpuffs -endif - -libulockmgr_la_SOURCES = ulockmgr.c -libulockmgr_la_LDFLAGS = -pthread -version-number 1:0:1 - -EXTRA_DIST = fuse_versionscript diff --git a/libfuse/lib/fuse_versionscript b/libfuse/lib/fuse_versionscript deleted file mode 100644 index 8d91887d..00000000 --- a/libfuse/lib/fuse_versionscript +++ /dev/null @@ -1,207 +0,0 @@ -FUSE_2.2 { - global: - fuse_destroy; - fuse_exit; - fuse_exited; - fuse_invalidate; - fuse_is_lib_option; - fuse_loop; - fuse_loop_mt; - fuse_loop_mt_proc; - fuse_main; - fuse_main_compat1; - fuse_main_compat2; - fuse_mount_compat1; - fuse_new_compat1; - fuse_new_compat2; - fuse_process_cmd; - fuse_read_cmd; - fuse_set_getcontext_func; - fuse_setup_compat2; -}; - -FUSE_2.4 { - global: - fuse_add_dirent; - fuse_chan_bufsize; - fuse_chan_data; - fuse_chan_destroy; - fuse_chan_fd; - fuse_chan_receive; - fuse_chan_send; - fuse_chan_session; - fuse_dirent_size; - fuse_kern_chan_new; - fuse_lowlevel_is_lib_option; - fuse_reply_attr; - fuse_reply_buf; - fuse_reply_entry; - fuse_reply_err; - fuse_reply_none; - fuse_reply_readlink; - fuse_reply_write; - fuse_reply_xattr; - fuse_req_userdata; - fuse_session_add_chan; - fuse_session_destroy; - fuse_session_exit; - fuse_session_exited; - fuse_session_loop; - fuse_session_loop_mt; - fuse_session_new; - fuse_session_next_chan; - fuse_session_process; - fuse_session_reset; -} FUSE_2.2; - -FUSE_2.5 { - global: - fuse_lowlevel_new_compat; - fuse_main_real_compat22; - fuse_mount_compat22; - fuse_new_compat22; - fuse_opt_parse; - fuse_opt_add_opt; - fuse_opt_add_arg; - fuse_opt_free_args; - fuse_opt_match; - fuse_parse_cmdline; - fuse_remove_signal_handlers; - fuse_reply_create; - fuse_reply_open; - fuse_reply_open_compat; - fuse_reply_statfs; - fuse_reply_statfs_compat; - fuse_setup_compat22; - fuse_set_signal_handlers; -} FUSE_2.4; - -FUSE_2.6 { - global: - fuse_add_direntry; - fuse_chan_new; - fuse_chan_new_compat24; - fuse_chan_recv; - fuse_daemonize; - fuse_get_session; - fuse_interrupted; - fuse_lowlevel_new; - fuse_lowlevel_new_compat25; - fuse_main_real; - fuse_main_real_compat25; - fuse_mount; - fuse_mount_compat25; - fuse_new; - fuse_new_compat25; - fuse_opt_insert_arg; - fuse_reply_lock; - fuse_req_interrupt_func; - fuse_req_interrupted; - fuse_session_remove_chan; - fuse_setup; - fuse_setup_compat25; - fuse_teardown; - fuse_teardown_compat22; - fuse_unmount; - fuse_unmount_compat22; -} FUSE_2.5; - -FUSE_2.7 { - global: - fuse_fs_access; - fuse_fs_bmap; - fuse_fs_chmod; - fuse_fs_chown; - fuse_fs_create; - fuse_fs_destroy; - fuse_fs_fgetattr; - fuse_fs_flush; - fuse_fs_fsync; - fuse_fs_fsyncdir; - fuse_fs_ftruncate; - fuse_fs_getattr; - fuse_fs_getxattr; - fuse_fs_init; - fuse_fs_link; - fuse_fs_listxattr; - fuse_fs_lock; - fuse_fs_mkdir; - fuse_fs_mknod; - fuse_fs_new; - fuse_fs_open; - fuse_fs_opendir; - fuse_fs_read; - fuse_fs_readdir; - fuse_fs_readlink; - fuse_fs_release; - fuse_fs_releasedir; - fuse_fs_removexattr; - fuse_fs_rename; - fuse_fs_rmdir; - fuse_fs_setxattr; - fuse_fs_statfs; - fuse_fs_symlink; - fuse_fs_truncate; - fuse_fs_unlink; - fuse_fs_utimens; - fuse_fs_write; - fuse_register_module; - fuse_reply_iov; - fuse_version; -} FUSE_2.6; - -FUSE_2.7.5 { - global: - fuse_reply_bmap; -} FUSE_2.7; - -FUSE_2.8 { - global: - cuse_lowlevel_new; - cuse_lowlevel_main; - cuse_lowlevel_setup; - cuse_lowlevel_teardown; - fuse_fs_ioctl; - fuse_fs_poll; - fuse_get_context; - fuse_getgroups; - fuse_lowlevel_notify_inval_entry; - fuse_lowlevel_notify_inval_inode; - fuse_lowlevel_notify_poll; - fuse_notify_poll; - fuse_opt_add_opt_escaped; - fuse_pollhandle_destroy; - fuse_reply_ioctl; - fuse_reply_ioctl_iov; - fuse_reply_ioctl_retry; - fuse_reply_poll; - fuse_req_ctx; - fuse_req_getgroups; - fuse_session_data; -} FUSE_2.7.5; - -FUSE_2.9 { - global: - fuse_buf_copy; - fuse_buf_size; - fuse_fs_read_buf; - fuse_fs_write_buf; - fuse_lowlevel_notify_retrieve; - fuse_lowlevel_notify_store; - fuse_reply_data; - fuse_session_process_buf; - fuse_session_receive_buf; - fuse_start_cleanup_thread; - fuse_stop_cleanup_thread; - fuse_clean_cache; - fuse_lowlevel_notify_delete; - fuse_fs_flock; -} FUSE_2.8; - -FUSE_2.9.1 { - global: - fuse_fs_fallocate; - - local: - *; -} FUSE_2.9; diff --git a/libfuse/lib/ulockmgr.c b/libfuse/lib/ulockmgr.c deleted file mode 100644 index 718d37c6..00000000 --- a/libfuse/lib/ulockmgr.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - libulockmgr: Userspace Lock Manager Library - Copyright (C) 2006 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB -*/ - -/* #define DEBUG 1 */ - -#include "ulockmgr.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct message { - unsigned intr : 1; - unsigned nofd : 1; - pthread_t thr; - int cmd; - int fd; - struct flock lock; - int error; -}; - -struct fd_store { - struct fd_store *next; - int fd; - int inuse; -}; - -struct owner { - struct owner *next; - struct owner *prev; - struct fd_store *fds; - void *id; - size_t id_len; - int cfd; -}; - -static pthread_mutex_t ulockmgr_lock; -static int ulockmgr_cfd = -1; -static struct owner owner_list = { .next = &owner_list, .prev = &owner_list }; - -#define MAX_SEND_FDS 2 - -static void list_del_owner(struct owner *owner) -{ - struct owner *prev = owner->prev; - struct owner *next = owner->next; - prev->next = next; - next->prev = prev; -} - -static void list_add_owner(struct owner *owner, struct owner *next) -{ - struct owner *prev = next->prev; - owner->next = next; - owner->prev = prev; - prev->next = owner; - next->prev = owner; -} - -/* - * There's a bug in the linux kernel (< 2.6.22) recv() implementation - * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return - * zero, even if data was available. Retrying the recv will return - * the data in this case. - */ -static int do_recv(int sock, void *buf, size_t len, int flags) -{ - int res = recv(sock, buf, len, flags); - if (res == 0) - res = recv(sock, buf, len, flags); - - return res; -} - -static int ulockmgr_send_message(int sock, void *buf, size_t buflen, - int *fdp, int numfds) -{ - struct msghdr msg; - struct cmsghdr *p_cmsg; - struct iovec vec; - size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; - int res; - - assert(numfds <= MAX_SEND_FDS); - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - p_cmsg = CMSG_FIRSTHDR(&msg); - p_cmsg->cmsg_level = SOL_SOCKET; - p_cmsg->cmsg_type = SCM_RIGHTS; - p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); - memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); - msg.msg_controllen = p_cmsg->cmsg_len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - vec.iov_base = buf; - vec.iov_len = buflen; - res = sendmsg(sock, &msg, MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: sendmsg"); - return -1; - } - if ((size_t) res != buflen) { - fprintf(stderr, "libulockmgr: sendmsg short\n"); - return -1; - } - return 0; -} - -static int ulockmgr_start_daemon(void) -{ - int sv[2]; - int res; - char tmp[64]; - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - return -1; - } - snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); - res = system(tmp); - close(sv[0]); - if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { - close(sv[1]); - return -1; - } - ulockmgr_cfd = sv[1]; - return 0; -} - -static struct owner *ulockmgr_new_owner(const void *id, size_t id_len) -{ - int sv[2]; - int res; - char c = 'm'; - struct owner *o; - - if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) - return NULL; - - o = calloc(1, sizeof(struct owner) + id_len); - if (!o) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return NULL; - } - o->id = o + 1; - o->id_len = id_len; - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - goto out_free; - } - res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); - close(sv[0]); - if (res == -1) { - close(ulockmgr_cfd); - ulockmgr_cfd = -1; - goto out_close; - } - - o->cfd = sv[1]; - memcpy(o->id, id, id_len); - list_add_owner(o, &owner_list); - - return o; - - out_close: - close(sv[1]); - out_free: - free(o); - return NULL; -} - -static int ulockmgr_send_request(struct message *msg, const void *id, - size_t id_len) -{ - int sv[2]; - int cfd; - struct owner *o; - struct fd_store *f = NULL; - struct fd_store *newf = NULL; - struct fd_store **fp; - int fd = msg->fd; - int cmd = msg->cmd; - int res; - int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && - msg->lock.l_start == 0 && msg->lock.l_len == 0); - - for (o = owner_list.next; o != &owner_list; o = o->next) - if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) - break; - - if (o == &owner_list) - o = NULL; - - if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) - o = ulockmgr_new_owner(id, id_len); - - if (!o) { - if (cmd == F_GETLK) { - res = fcntl(msg->fd, F_GETLK, &msg->lock); - return (res == -1) ? -errno : 0; - } else if (msg->lock.l_type == F_UNLCK) - return 0; - else - return -ENOLCK; - } - - if (unlockall) - msg->nofd = 1; - else { - for (fp = &o->fds; *fp; fp = &(*fp)->next) { - f = *fp; - if (f->fd == fd) { - msg->nofd = 1; - break; - } - } - } - - if (!msg->nofd) { - newf = f = calloc(1, sizeof(struct fd_store)); - if (!f) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return -ENOLCK; - } - } - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - free(newf); - return -ENOLCK; - } - - cfd = sv[1]; - sv[1] = msg->fd; - res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, - msg->nofd ? 1 : 2); - close(sv[0]); - if (res == -1) { - free(newf); - close(cfd); - return -EIO; - } - - if (newf) { - newf->fd = msg->fd; - newf->next = o->fds; - o->fds = newf; - } - if (f) - f->inuse++; - - res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); - if (res == -1) { - perror("libulockmgr: recv"); - msg->error = EIO; - } else if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - } else if (cmd == F_SETLKW && msg->error == EAGAIN) { - pthread_mutex_unlock(&ulockmgr_lock); - while (1) { - sigset_t old; - sigset_t unblock; - int errno_save; - - sigemptyset(&unblock); - sigaddset(&unblock, SIGUSR1); - pthread_sigmask(SIG_UNBLOCK, &unblock, &old); - res = do_recv(cfd, msg, sizeof(struct message), - MSG_WAITALL); - errno_save = errno; - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (res == sizeof(struct message)) - break; - else if (res >= 0) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - break; - } else if (errno_save != EINTR) { - errno = errno_save; - perror("libulockmgr: recv"); - msg->error = EIO; - break; - } - msg->intr = 1; - res = send(o->cfd, msg, sizeof(struct message), - MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: send"); - msg->error = EIO; - break; - } - if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: send short\n"); - msg->error = EIO; - break; - } - } - pthread_mutex_lock(&ulockmgr_lock); - - } - if (f) - f->inuse--; - close(cfd); - if (unlockall) { - for (fp = &o->fds; *fp;) { - f = *fp; - if (f->fd == fd && !f->inuse) { - *fp = f->next; - free(f); - } else - fp = &f->next; - } - if (!o->fds) { - list_del_owner(o); - close(o->cfd); - free(o); - } - /* Force OK on unlock-all, since it _will_ succeed once the - owner is deleted */ - msg->error = 0; - } - - return -msg->error; -} - -#ifdef DEBUG -static uint32_t owner_hash(const unsigned char *id, size_t id_len) -{ - uint32_t h = 0; - size_t i; - for (i = 0; i < id_len; i++) - h = ((h << 8) | (h >> 24)) ^ id[i]; - - return h; -} -#endif - -static int ulockmgr_canonicalize(int fd, struct flock *lock) -{ - off_t offset; - if (lock->l_whence == SEEK_CUR) { - offset = lseek(fd, 0, SEEK_CUR); - if (offset == (off_t) -1) - return -errno; - } else if (lock->l_whence == SEEK_END) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) - return -errno; - - offset = stbuf.st_size; - } else - offset = 0; - - lock->l_whence = SEEK_SET; - lock->l_start += offset; - - if (lock->l_start < 0) - return -EINVAL; - - if (lock->l_len < 0) { - lock->l_start += lock->l_len; - if (lock->l_start < 0) - return -EINVAL; - lock->l_len = -lock->l_len; - } - if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) - return -EINVAL; - - return 0; -} - -int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, - size_t owner_len) -{ - int err; - struct message msg; - sigset_t old; - sigset_t block; - - if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) - return -EINVAL; - - if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK && - lock->l_type != F_UNLCK) - return -EINVAL; - - if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && - lock->l_whence != SEEK_END) - return -EINVAL; - -#ifdef DEBUG - fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", - cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, - owner_hash(owner, owner_len)); -#endif - - /* Unlock should never block anyway */ - if (cmd == F_SETLKW && lock->l_type == F_UNLCK) - cmd = F_SETLK; - - memset(&msg, 0, sizeof(struct message)); - msg.cmd = cmd; - msg.fd = fd; - msg.lock = *lock; - err = ulockmgr_canonicalize(fd, &msg.lock); - if (err) - return err; - - sigemptyset(&block); - sigaddset(&block, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &block, &old); - pthread_mutex_lock(&ulockmgr_lock); - err = ulockmgr_send_request(&msg, owner, owner_len); - pthread_mutex_unlock(&ulockmgr_lock); - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (!err && cmd == F_GETLK) { - if (msg.lock.l_type == F_UNLCK) - lock->l_type = F_UNLCK; - else - *lock = msg.lock; - } - - return err; -} diff --git a/libfuse/util/Makefile.am b/libfuse/util/Makefile.am deleted file mode 100644 index 059d5fc2..00000000 --- a/libfuse/util/Makefile.am +++ /dev/null @@ -1,58 +0,0 @@ -## Process this file with automake to produce Makefile.in - -AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -bin_PROGRAMS = fusermount ulockmgr_server -noinst_PROGRAMS = mount.fuse - -# we re-use mount_util.c from the library, but do want to keep ourself -# as stand-alone as possible. in order to make an out-of-source build -# possible, we "generate" the file from its original location by -# copying it over. -fusermount_SOURCES = fusermount.c mount_util.c -fusermount_CPPFLAGS = -I$(top_srcdir)/lib -BUILT_SOURCES = mount_util.c -mount_util.c: $(top_srcdir)/lib/mount_util.c - @cp $(top_srcdir)/lib/mount_util.c . - -mount_fuse_SOURCES = mount.fuse.c - -ulockmgr_server_SOURCES = ulockmgr_server.c -ulockmgr_server_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_REENTRANT -ulockmgr_server_LDFLAGS = -pthread - -install-exec-hook: - -chmod u+s $(DESTDIR)$(bindir)/fusermount - @if test ! -e $(DESTDIR)/dev/fuse; then \ - $(MKDIR_P) $(DESTDIR)/dev; \ - echo "mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true"; \ - mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true; \ - fi - -EXTRA_DIST = udev.rules init_script - -MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@ -UDEV_RULES_PATH = @UDEV_RULES_PATH@ -INIT_D_PATH = @INIT_D_PATH@ - -install-exec-local: - $(MKDIR_P) $(DESTDIR)$(MOUNT_FUSE_PATH) - $(INSTALL_PROGRAM) $(builddir)/mount.fuse $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse - $(MKDIR_P) $(DESTDIR)$(INIT_D_PATH) - $(INSTALL_SCRIPT) $(srcdir)/init_script $(DESTDIR)$(INIT_D_PATH)/fuse - @if test -x /usr/sbin/update-rc.d; then \ - echo "/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true"; \ - /usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true; \ - fi - -install-data-local: - $(MKDIR_P) $(DESTDIR)$(UDEV_RULES_PATH) - $(INSTALL_DATA) $(srcdir)/udev.rules $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules - -uninstall-local: - rm -f $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse - rm -f $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules - rm -f $(DESTDIR)$(INIT_D_PATH)/fuse - @if test -x /usr/sbin/update-rc.d; then \ - echo "/usr/sbin/update-rc.d fuse remove || true"; \ - /usr/sbin/update-rc.d fuse remove || true; \ - fi diff --git a/libfuse/util/init_script b/libfuse/util/init_script deleted file mode 100755 index 331b33ad..00000000 --- a/libfuse/util/init_script +++ /dev/null @@ -1,89 +0,0 @@ -#! /bin/sh -### BEGIN INIT INFO -# Provides: fuse -# Required-Start: -# Should-Start: udev -# Required-Stop: -# Default-Start: S -# Default-Stop: -# Short-Description: Start and stop fuse. -# Description: Load the fuse module and mount the fuse control -# filesystem. -### END INIT INFO - -set -e - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -MOUNTPOINT=/sys/fs/fuse/connections - -# Gracefully exit if the package has been removed. -which fusermount &>/dev/null || exit 5 - -case "$1" in - start|restart|force-reload) - if ! grep -qw fuse /proc/filesystems; then - echo -n "Loading fuse module" - if ! modprobe fuse >/dev/null 2>&1; then - echo " failed!" - exit 1 - else - echo "." - fi - else - echo "Fuse filesystem already available." - fi - if grep -qw fusectl /proc/filesystems && \ - ! grep -qw $MOUNTPOINT /proc/mounts; then - echo -n "Mounting fuse control filesystem" - if ! mount -t fusectl fusectl $MOUNTPOINT >/dev/null 2>&1; then - echo " failed!" - exit 1 - else - echo "." - fi - else - echo "Fuse control filesystem already available." - fi - ;; - stop) - if ! grep -qw fuse /proc/filesystems; then - echo "Fuse filesystem not loaded." - exit 7 - fi - if grep -qw $MOUNTPOINT /proc/mounts; then - echo -n "Unmounting fuse control filesystem" - if ! umount $MOUNTPOINT >/dev/null 2>&1; then - echo " failed!" - else - echo "." - fi - else - echo "Fuse control filesystem not mounted." - fi - if grep -qw "^fuse" /proc/modules; then - echo -n "Unloading fuse module" - if ! rmmod fuse >/dev/null 2>&1; then - echo " failed!" - else - echo "." - fi - else - echo "Fuse module not loaded." - fi - ;; - status) - echo -n "Checking fuse filesystem" - if ! grep -qw fuse /proc/filesystems; then - echo " not available." - exit 3 - else - echo " ok." - fi - ;; - *) - echo "Usage: $0 {start|stop|restart|force-reload|status}" - exit 1 - ;; -esac - -exit 0 diff --git a/libfuse/util/udev.rules b/libfuse/util/udev.rules deleted file mode 100644 index 95851114..00000000 --- a/libfuse/util/udev.rules +++ /dev/null @@ -1 +0,0 @@ -KERNEL=="fuse", MODE="0666" diff --git a/libfuse/util/ulockmgr_server.c b/libfuse/util/ulockmgr_server.c deleted file mode 100644 index 273c7d92..00000000 --- a/libfuse/util/ulockmgr_server.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - ulockmgr_server: Userspace Lock Manager Server - Copyright (C) 2006 Miklos Szeredi - - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. -*/ - -/* #define DEBUG 1 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct message { - unsigned intr : 1; - unsigned nofd : 1; - pthread_t thr; - int cmd; - int fd; - struct flock lock; - int error; -}; - -struct fd_store { - struct fd_store *next; - int fd; - int origfd; - int inuse; -}; - -struct owner { - struct fd_store *fds; - pthread_mutex_t lock; -}; - -struct req_data { - struct owner *o; - int cfd; - struct fd_store *f; - struct message msg; -}; - -#define MAX_SEND_FDS 2 - -static int receive_message(int sock, void *buf, size_t buflen, int *fdp, - int *numfds) -{ - struct msghdr msg; - struct iovec iov; - size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; - struct cmsghdr *cmsg; - int res; - int i; - - assert(*numfds <= MAX_SEND_FDS); - iov.iov_base = buf; - iov.iov_len = buflen; - - memset(&msg, 0, sizeof(msg)); - memset(ccmsg, -1, sizeof(ccmsg)); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof(ccmsg); - - res = recvmsg(sock, &msg, MSG_WAITALL); - if (!res) { - /* retry on zero return, see do_recv() in ulockmgr.c */ - res = recvmsg(sock, &msg, MSG_WAITALL); - if (!res) - return 0; - } - if (res == -1) { - perror("ulockmgr_server: recvmsg"); - return -1; - } - if ((size_t) res != buflen) { - fprintf(stderr, "ulockmgr_server: short message received\n"); - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg) { - if (cmsg->cmsg_type != SCM_RIGHTS) { - fprintf(stderr, - "ulockmgr_server: unknown control message %d\n", - cmsg->cmsg_type); - return -1; - } - memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); - if (msg.msg_flags & MSG_CTRUNC) { - fprintf(stderr, - "ulockmgr_server: control message truncated\n"); - for (i = 0; i < *numfds; i++) - close(fdp[i]); - *numfds = 0; - } - } else { - if (msg.msg_flags & MSG_CTRUNC) { - fprintf(stderr, - "ulockmgr_server: control message truncated(*)\n"); - - /* There's a bug in the Linux kernel, that if - not all file descriptors were allocated, - then the cmsg header is not filled in */ - cmsg = (struct cmsghdr *) ccmsg; - memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); - for (i = 0; i < *numfds; i++) - close(fdp[i]); - } - *numfds = 0; - } - return res; -} - -static int closefrom(int minfd) -{ - DIR *dir = opendir("/proc/self/fd"); - if (dir) { - int dfd = dirfd(dir); - struct dirent *ent; - while ((ent = readdir(dir))) { - char *end; - int fd = strtol(ent->d_name, &end, 10); - if (ent->d_name[0] && !end[0] && fd >= minfd && - fd != dfd) - close(fd); - } - closedir(dir); - } - return 0; -} - -static void send_reply(int cfd, struct message *msg) -{ - int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL); - if (res == -1) - perror("ulockmgr_server: sending reply"); -#ifdef DEBUG - fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error); -#endif -} - -static void *process_request(void *d_) -{ - struct req_data *d = d_; - int res; - - assert(d->msg.cmd == F_SETLKW); - res = fcntl(d->f->fd, F_SETLK, &d->msg.lock); - if (res == -1 && errno == EAGAIN) { - d->msg.error = EAGAIN; - d->msg.thr = pthread_self(); - send_reply(d->cfd, &d->msg); - res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock); - } - d->msg.error = (res == -1) ? errno : 0; - pthread_mutex_lock(&d->o->lock); - d->f->inuse--; - pthread_mutex_unlock(&d->o->lock); - send_reply(d->cfd, &d->msg); - close(d->cfd); - free(d); - - return NULL; -} - -static void process_message(struct owner *o, struct message *msg, int cfd, - int fd) -{ - struct fd_store *f = NULL; - struct fd_store *newf = NULL; - struct fd_store **fp; - struct req_data *d; - pthread_t tid; - int res; - -#ifdef DEBUG - fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n", - msg->cmd, msg->lock.l_type, msg->lock.l_whence, - msg->lock.l_start, msg->lock.l_len); -#endif - - if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK && - msg->lock.l_start == 0 && msg->lock.l_len == 0) { - for (fp = &o->fds; *fp;) { - f = *fp; - if (f->origfd == msg->fd && !f->inuse) { - close(f->fd); - *fp = f->next; - free(f); - } else - fp = &f->next; - } - if (!msg->nofd) - close(fd); - - msg->error = 0; - send_reply(cfd, msg); - close(cfd); - return; - } - - if (msg->nofd) { - for (fp = &o->fds; *fp; fp = &(*fp)->next) { - f = *fp; - if (f->origfd == msg->fd) - break; - } - if (!*fp) { - fprintf(stderr, "ulockmgr_server: fd %i not found\n", - msg->fd); - msg->error = EIO; - send_reply(cfd, msg); - close(cfd); - return; - } - } else { - newf = f = malloc(sizeof(struct fd_store)); - if (!f) { - msg->error = ENOLCK; - send_reply(cfd, msg); - close(cfd); - return; - } - - f->fd = fd; - f->origfd = msg->fd; - f->inuse = 0; - } - - if (msg->cmd == F_GETLK || msg->cmd == F_SETLK || - msg->lock.l_type == F_UNLCK) { - res = fcntl(f->fd, msg->cmd, &msg->lock); - msg->error = (res == -1) ? errno : 0; - send_reply(cfd, msg); - close(cfd); - if (newf) { - newf->next = o->fds; - o->fds = newf; - } - return; - } - - d = malloc(sizeof(struct req_data)); - if (!d) { - msg->error = ENOLCK; - send_reply(cfd, msg); - close(cfd); - free(newf); - return; - } - - f->inuse++; - d->o = o; - d->cfd = cfd; - d->f = f; - d->msg = *msg; - res = pthread_create(&tid, NULL, process_request, d); - if (res) { - msg->error = ENOLCK; - send_reply(cfd, msg); - close(cfd); - free(d); - f->inuse--; - free(newf); - return; - } - - if (newf) { - newf->next = o->fds; - o->fds = newf; - } - pthread_detach(tid); -} - -static void sigusr1_handler(int sig) -{ - (void) sig; - /* Nothing to do */ -} - -static void process_owner(int cfd) -{ - struct owner o; - struct sigaction sa; - - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = sigusr1_handler; - sigemptyset(&sa.sa_mask); - - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - perror("ulockmgr_server: cannot set sigusr1 signal handler"); - exit(1); - } - - memset(&o, 0, sizeof(struct owner)); - pthread_mutex_init(&o.lock, NULL); - while (1) { - struct message msg; - int rfds[2]; - int res; - int numfds = 2; - - res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds); - if (!res) - break; - if (res == -1) - exit(1); - - if (msg.intr) { - if (numfds != 0) - fprintf(stderr, - "ulockmgr_server: too many fds for intr\n"); - pthread_kill(msg.thr, SIGUSR1); - } else { - if (numfds != 2) - continue; - - pthread_mutex_lock(&o.lock); - process_message(&o, &msg, rfds[0], rfds[1]); - pthread_mutex_unlock(&o.lock); - } - } - if (o.fds) - fprintf(stderr, - "ulockmgr_server: open file descriptors on exit\n"); -} - -int main(int argc, char *argv[]) -{ - int nullfd; - char *end; - int cfd; - sigset_t empty; - - if (argc != 2 || !argv[1][0]) - goto out_inval; - - cfd = strtol(argv[1], &end, 10); - if (*end) - goto out_inval; - - /* demonize current process */ - switch(fork()) { - case -1: - perror("ulockmgr_server: fork"); - exit(1); - case 0: - break; - default: - _exit(0); - } - - if (setsid() == -1) { - perror("ulockmgr_server: setsid"); - exit(1); - } - - (void) chdir("/"); - - sigemptyset(&empty); - sigprocmask(SIG_SETMASK, &empty, NULL); - - if (dup2(cfd, 4) == -1) { - perror("ulockmgr_server: dup2"); - exit(1); - } - cfd = 4; - nullfd = open("/dev/null", O_RDWR); - if (nullfd >= 0) { - dup2(nullfd, 0); - dup2(nullfd, 1); - } - close(3); - closefrom(5); - while (1) { - char c; - int sock; - int pid; - int numfds = 1; - int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds); - if (!res) - break; - if (res == -1) - exit(1); - assert(numfds == 1); - - pid = fork(); - if (pid == -1) { - perror("ulockmgr_server: fork"); - close(sock); - continue; - } - if (pid == 0) { - close(cfd); - pid = fork(); - if (pid == -1) { - perror("ulockmgr_server: fork"); - _exit(1); - } - if (pid == 0) - process_owner(sock); - _exit(0); - } - waitpid(pid, NULL, 0); - close(sock); - } - return 0; - -out_inval: - fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]); - return 1; -} From 3bfdd78434d9b2eaa55cc77f49ffe5aa43498da3 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sat, 1 Aug 2020 18:51:23 -0400 Subject: [PATCH 3/6] libfuse cleanup: remove cuse --- libfuse/Makefile | 1 - libfuse/include/Makefile.am | 17 -- libfuse/include/cuse_lowlevel.h | 87 -------- libfuse/lib/cuse_lowlevel.c | 371 -------------------------------- libfuse/lib/fuse_i.h | 3 - libfuse/lib/fuse_lowlevel.c | 85 +------- 6 files changed, 8 insertions(+), 556 deletions(-) delete mode 100644 libfuse/include/Makefile.am delete mode 100644 libfuse/include/cuse_lowlevel.h delete mode 100644 libfuse/lib/cuse_lowlevel.c diff --git a/libfuse/Makefile b/libfuse/Makefile index e3001aa3..7fec8a9b 100644 --- a/libfuse/Makefile +++ b/libfuse/Makefile @@ -31,7 +31,6 @@ INSTALLMAN1DIR = $(DESTDIR)$(MAN1DIR) SRC = \ lib/buffer.c \ - lib/cuse_lowlevel.c \ lib/fuse_dirents.c \ lib/fuse.c \ lib/fuse_kern_chan.c \ diff --git a/libfuse/include/Makefile.am b/libfuse/include/Makefile.am deleted file mode 100644 index 663e164c..00000000 --- a/libfuse/include/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -## Process this file with automake to produce Makefile.in - -fuseincludedir=$(includedir)/fuse - -fuseinclude_HEADERS = \ - fuse.h \ - fuse_compat.h \ - fuse_common.h \ - fuse_common_compat.h \ - fuse_lowlevel.h \ - fuse_lowlevel_compat.h \ - fuse_opt.h \ - cuse_lowlevel.h - -include_HEADERS = old/fuse.h ulockmgr.h - -noinst_HEADERS = fuse_kernel.h diff --git a/libfuse/include/cuse_lowlevel.h b/libfuse/include/cuse_lowlevel.h deleted file mode 100644 index e80a9c3d..00000000 --- a/libfuse/include/cuse_lowlevel.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - CUSE: Character device in Userspace - Copyright (C) 2008-2009 SUSE Linux Products GmbH - Copyright (C) 2008-2009 Tejun Heo - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. - - Read example/cusexmp.c for usages. -*/ - -#ifndef _CUSE_LOWLEVEL_H_ -#define _CUSE_LOWLEVEL_H_ - -#ifndef FUSE_USE_VERSION -#define FUSE_USE_VERSION 29 -#endif - -#include "fuse_lowlevel.h" - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */ - - struct fuse_session; - - struct cuse_info { - unsigned dev_major; - unsigned dev_minor; - unsigned dev_info_argc; - const char **dev_info_argv; - unsigned flags; - }; - - /* - * Most ops behave almost identically to the matching fuse_lowlevel - * ops except that they don't take @ino. - * - * init_done : called after initialization is complete - * read/write : always direct IO, simultaneous operations allowed - * ioctl : might be in unrestricted mode depending on ci->flags - */ - struct cuse_lowlevel_ops { - void (*init) (void *userdata, struct fuse_conn_info *conn); - void (*init_done) (void *userdata); - void (*destroy) (void *userdata); - void (*open) (fuse_req_t req, struct fuse_file_info *fi); - void (*read) (fuse_req_t req, size_t size, off_t off, - struct fuse_file_info *fi); - void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off, - struct fuse_file_info *fi); - void (*flush) (fuse_req_t req, struct fuse_file_info *fi); - void (*release) (fuse_req_t req, struct fuse_file_info *fi); - void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi); - void (*ioctl) (fuse_req_t req, int cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz); - void (*poll) (fuse_req_t req, struct fuse_file_info *fi, - struct fuse_pollhandle *ph); - }; - - struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - void *userdata); - - struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - int *multithreaded, void *userdata); - - void cuse_lowlevel_teardown(struct fuse_session *se); - - int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, void *userdata); - -#ifdef __cplusplus -} -#endif - -#endif /* _CUSE_LOWLEVEL_H_ */ diff --git a/libfuse/lib/cuse_lowlevel.c b/libfuse/lib/cuse_lowlevel.c deleted file mode 100644 index d42badbd..00000000 --- a/libfuse/lib/cuse_lowlevel.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - CUSE: Character device in Userspace - Copyright (C) 2008 SUSE Linux Products GmbH - Copyright (C) 2008 Tejun Heo - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -#include "cuse_lowlevel.h" -#include "fuse_kernel.h" -#include "fuse_i.h" -#include "fuse_opt.h" -#include "fuse_misc.h" - -#include -#include -#include -#include -#include -#include - -struct cuse_data { - struct cuse_lowlevel_ops clop; - unsigned max_read; - unsigned dev_major; - unsigned dev_minor; - unsigned flags; - unsigned dev_info_len; - char dev_info[]; -}; - -static struct cuse_lowlevel_ops *req_clop(fuse_req_t req) -{ - return &req->f->cuse_data->clop; -} - -static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->open(req, fi); -} - -static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->read(req, size, off, fi); -} - -static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->write(req, buf, size, off, fi); -} - -static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->flush(req, fi); -} - -static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->release(req, fi); -} - -static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->fsync(req, datasync, fi); -} - -static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz) -{ - (void)ino; - req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz, - out_bufsz); -} - -static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, struct fuse_pollhandle *ph) -{ - (void)ino; - req_clop(req)->poll(req, fi, ph); -} - -static size_t cuse_pack_info(int argc, const char **argv, char *buf) -{ - size_t size = 0; - int i; - - for (i = 0; i < argc; i++) { - size_t len; - - len = strlen(argv[i]) + 1; - size += len; - if (buf) { - memcpy(buf, argv[i], len); - buf += len; - } - } - - return size; -} - -static struct cuse_data *cuse_prep_data(const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop) -{ - struct cuse_data *cd; - size_t dev_info_len; - - dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, - NULL); - - if (dev_info_len > CUSE_INIT_INFO_MAX) { - fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n", - dev_info_len, CUSE_INIT_INFO_MAX); - return NULL; - } - - cd = calloc(1, sizeof(*cd) + dev_info_len); - if (!cd) { - fprintf(stderr, "cuse: failed to allocate cuse_data\n"); - return NULL; - } - - memcpy(&cd->clop, clop, sizeof(cd->clop)); - cd->max_read = 131072; - cd->dev_major = ci->dev_major; - cd->dev_minor = ci->dev_minor; - cd->dev_info_len = dev_info_len; - cd->flags = ci->flags; - cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info); - - return cd; -} - -struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - void *userdata) -{ - struct fuse_lowlevel_ops lop; - struct cuse_data *cd; - struct fuse_session *se; - struct fuse_ll *ll; - - cd = cuse_prep_data(ci, clop); - if (!cd) - return NULL; - - memset(&lop, 0, sizeof(lop)); - lop.init = clop->init; - lop.destroy = clop->destroy; - lop.open = clop->open ? cuse_fll_open : NULL; - lop.read = clop->read ? cuse_fll_read : NULL; - lop.write = clop->write ? cuse_fll_write : NULL; - lop.flush = clop->flush ? cuse_fll_flush : NULL; - lop.release = clop->release ? cuse_fll_release : NULL; - lop.fsync = clop->fsync ? cuse_fll_fsync : NULL; - lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL; - lop.poll = clop->poll ? cuse_fll_poll : NULL; - - se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata); - if (!se) { - free(cd); - return NULL; - } - ll = se->data; - ll->cuse_data = cd; - - return se; -} - -static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg, - char *dev_info, unsigned dev_info_len) -{ - struct iovec iov[3]; - - iov[1].iov_base = arg; - iov[1].iov_len = sizeof(struct cuse_init_out); - iov[2].iov_base = dev_info; - iov[2].iov_len = dev_info_len; - - return fuse_send_reply_iov_nofree(req, 0, iov, 3); -} - -void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) -{ - struct fuse_init_in *arg = (struct fuse_init_in *) inarg; - struct cuse_init_out outarg; - struct fuse_ll *f = req->f; - struct cuse_data *cd = f->cuse_data; - size_t bufsize = fuse_chan_bufsize(req->ch); - struct cuse_lowlevel_ops *clop = req_clop(req); - - (void) nodeid; - if (f->debug) { - fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor); - fprintf(stderr, "flags=0x%08x\n", arg->flags); - } - f->conn.proto_major = arg->major; - f->conn.proto_minor = arg->minor; - f->conn.capable = 0; - f->conn.want = 0; - - if (arg->major < 7) { - fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); - return; - } - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fprintf(stderr, "cuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - - bufsize -= 4096; - if (bufsize < f->conn.max_write) - f->conn.max_write = bufsize; - - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata, &f->conn); - - memset(&outarg, 0, sizeof(outarg)); - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - outarg.flags = cd->flags; - outarg.max_read = cd->max_read; - outarg.max_write = f->conn.max_write; - outarg.dev_major = cd->dev_major; - outarg.dev_minor = cd->dev_minor; - - if (f->debug) { - fprintf(stderr, " CUSE_INIT: %u.%u\n", - outarg.major, outarg.minor); - fprintf(stderr, " flags=0x%08x\n", outarg.flags); - fprintf(stderr, " max_read=0x%08x\n", outarg.max_read); - fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); - fprintf(stderr, " dev_major=%u\n", outarg.dev_major); - fprintf(stderr, " dev_minor=%u\n", outarg.dev_minor); - fprintf(stderr, " dev_info: %.*s\n", cd->dev_info_len, - cd->dev_info); - } - - cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len); - - if (clop->init_done) - clop->init_done(f->userdata); - - fuse_free_req(req); -} - -struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - int *multithreaded, void *userdata) -{ - const char *devname = "/dev/cuse"; - static const struct fuse_opt kill_subtype_opts[] = { - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_END - }; - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_session *se; - struct fuse_chan *ch; - int fd; - int foreground; - int res; - - res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground); - if (res == -1) - goto err_args; - - res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL); - if (res == -1) - goto err_args; - - /* - * 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); - - se = cuse_lowlevel_new(&args, ci, clop, userdata); - fuse_opt_free_args(&args); - if (se == NULL) - goto err_args; - - fd = open(devname, O_RDWR); - if (fd == -1) { - if (errno == ENODEV || errno == ENOENT) - fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n"); - else - fprintf(stderr, "cuse: failed to open %s: %s\n", - devname, strerror(errno)); - goto err_se; - } - - ch = fuse_kern_chan_new(fd); - if (!ch) { - close(fd); - goto err_se; - } - - fuse_session_add_chan(se, ch); - - res = fuse_set_signal_handlers(se); - if (res == -1) - goto err_se; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_sig; - - return se; - - err_sig: - fuse_remove_signal_handlers(se); - err_se: - fuse_session_destroy(se); - err_args: - fuse_opt_free_args(&args); - return NULL; -} - -void cuse_lowlevel_teardown(struct fuse_session *se) -{ - fuse_remove_signal_handlers(se); - fuse_session_destroy(se); -} - -int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, void *userdata) -{ - struct fuse_session *se; - int multithreaded; - int res; - - se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded, - userdata); - if (se == NULL) - return 1; - - if (multithreaded) - res = fuse_session_loop_mt(se, 0); - else - res = fuse_session_loop(se); - - cuse_lowlevel_teardown(se); - if (res == -1) - return 1; - - return 0; -} diff --git a/libfuse/lib/fuse_i.h b/libfuse/lib/fuse_i.h index 766acc7a..4eb3bfaa 100644 --- a/libfuse/lib/fuse_i.h +++ b/libfuse/lib/fuse_i.h @@ -76,7 +76,6 @@ struct fuse_ll int no_splice_read; struct fuse_lowlevel_ops op; int got_init; - struct cuse_data *cuse_data; void *userdata; uid_t owner; struct fuse_conn_info conn; @@ -129,6 +128,4 @@ struct fuse *fuse_setup_common(int argc, char *argv[], void *user_data, int compat); -void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg); - int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg); diff --git a/libfuse/lib/fuse_lowlevel.c b/libfuse/lib/fuse_lowlevel.c index bcea660f..22f96b22 100644 --- a/libfuse/lib/fuse_lowlevel.c +++ b/libfuse/lib/fuse_lowlevel.c @@ -2377,7 +2377,6 @@ static struct { [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" }, - [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) @@ -2470,13 +2469,15 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, req->ch = ch; err = EIO; - if (!f->got_init) { - enum fuse_opcode expected; + if(!f->got_init) + { + enum fuse_opcode expected; - expected = f->cuse_data ? CUSE_INIT : FUSE_INIT; - if (in->opcode != expected) - goto reply_err; - } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) + expected = FUSE_INIT; + if (in->opcode != expected) + goto reply_err; + } + else if(in->opcode == FUSE_INIT) goto reply_err; err = EACCES; @@ -2653,7 +2654,6 @@ static void fuse_ll_destroy(void *data) fuse_ll_pipe_free(llp); pthread_key_delete(f->pipe_key); pthread_mutex_destroy(&f->lock); - free(f->cuse_data); free(f); } @@ -2857,75 +2857,6 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, return fuse_lowlevel_new_common(args, op, op_size, userdata); } -#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; - - 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 == -1) { - ret = -EIO; - goto out_free; - } - - if (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; -} -#else /* linux */ -/* - * This is currently not implemented on other than Linux... - */ -int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) -{ - return -ENOSYS; -} -#endif - #if !defined(__FreeBSD__) && !defined(__NetBSD__) static void fill_open_compat(struct fuse_open_out *arg, From 3c761b708b2b314376c7e812201cdfcc243e7c59 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sat, 1 Aug 2020 22:44:00 -0400 Subject: [PATCH 4/6] libfuse cleanup: remove libfuse API compatibility --- libfuse/include/fuse.h | 47 ----- libfuse/include/fuse_common.h | 34 ---- libfuse/include/fuse_common_compat.h | 27 --- libfuse/include/fuse_compat.h | 197 -------------------- libfuse/include/fuse_lowlevel.h | 22 --- libfuse/include/fuse_lowlevel_compat.h | 157 ---------------- libfuse/include/old/fuse.h | 9 - libfuse/lib/fuse.c | 246 +------------------------ libfuse/lib/fuse_i.h | 8 +- libfuse/lib/fuse_lowlevel.c | 152 +-------------- libfuse/lib/fuse_opt.c | 10 - libfuse/lib/fuse_session.c | 27 +-- libfuse/lib/helper.c | 113 +----------- libfuse/lib/mount_bsd.c | 49 ----- libfuse/lib/mount_generic.c | 18 -- 15 files changed, 24 insertions(+), 1092 deletions(-) delete mode 100644 libfuse/include/fuse_common_compat.h delete mode 100644 libfuse/include/fuse_compat.h delete mode 100644 libfuse/include/fuse_lowlevel_compat.h delete mode 100644 libfuse/include/old/fuse.h diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index 9d5f0f43..8e2c9474 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -929,53 +929,6 @@ extern "C" { /** Get session from fuse object */ struct fuse_session *fuse_get_session(struct fuse *f); - /* ----------------------------------------------------------- * - * Compatibility stuff * - * ----------------------------------------------------------- */ - -#if FUSE_USE_VERSION < 26 -# include "fuse_compat.h" -# undef fuse_main -# if FUSE_USE_VERSION == 25 -# define fuse_main(argc, argv, op) \ - fuse_main_real_compat25(argc, argv, op, sizeof(*(op))) -# define fuse_new fuse_new_compat25 -# define fuse_setup fuse_setup_compat25 -# define fuse_teardown fuse_teardown_compat22 -# define fuse_operations fuse_operations_compat25 -# elif FUSE_USE_VERSION == 22 -# define fuse_main(argc, argv, op) \ - fuse_main_real_compat22(argc, argv, op, sizeof(*(op))) -# define fuse_new fuse_new_compat22 -# define fuse_setup fuse_setup_compat22 -# define fuse_teardown fuse_teardown_compat22 -# define fuse_operations fuse_operations_compat22 -# define fuse_file_info fuse_file_info_compat -# elif FUSE_USE_VERSION == 24 -# error Compatibility with high-level API version 24 not supported -# else -# define fuse_dirfil_t fuse_dirfil_t_compat -# define __fuse_read_cmd fuse_read_cmd -# define __fuse_process_cmd fuse_process_cmd -# define __fuse_loop_mt fuse_loop_mt_proc -# if FUSE_USE_VERSION == 21 -# define fuse_operations fuse_operations_compat2 -# define fuse_main fuse_main_compat2 -# define fuse_new fuse_new_compat2 -# define __fuse_setup fuse_setup_compat2 -# define __fuse_teardown fuse_teardown_compat22 -# define __fuse_exited fuse_exited -# define __fuse_set_getcontext_func fuse_set_getcontext_func -# else -# define fuse_statfs fuse_statfs_compat1 -# define fuse_operations fuse_operations_compat1 -# define fuse_main fuse_main_compat1 -# define fuse_new fuse_new_compat1 -# define FUSE_DEBUG FUSE_DEBUG_COMPAT1 -# endif -# endif -#endif - #ifdef __cplusplus } #endif diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index 79feb44e..c7d47ea8 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -479,40 +479,6 @@ extern "C" { */ void fuse_remove_signal_handlers(struct fuse_session *se); - /* ----------------------------------------------------------- * - * Compatibility stuff * - * ----------------------------------------------------------- */ - -#if FUSE_USE_VERSION < 26 -# ifdef __FreeBSD__ -# if FUSE_USE_VERSION < 25 -# error On FreeBSD API version 25 or greater must be used -# endif -# endif -# include "fuse_common_compat.h" -# undef FUSE_MINOR_VERSION -# undef fuse_main -# define fuse_unmount fuse_unmount_compat22 -# if FUSE_USE_VERSION == 25 -# define FUSE_MINOR_VERSION 5 -# define fuse_mount fuse_mount_compat25 -# elif FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22 -# define FUSE_MINOR_VERSION 4 -# define fuse_mount fuse_mount_compat22 -# elif FUSE_USE_VERSION == 21 -# define FUSE_MINOR_VERSION 1 -# define fuse_mount fuse_mount_compat22 -# elif FUSE_USE_VERSION == 11 -# warning Compatibility with API version 11 is deprecated -# undef FUSE_MAJOR_VERSION -# define FUSE_MAJOR_VERSION 1 -# define FUSE_MINOR_VERSION 1 -# define fuse_mount fuse_mount_compat1 -# else -# error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported -# endif -#endif - #ifdef __cplusplus } #endif diff --git a/libfuse/include/fuse_common_compat.h b/libfuse/include/fuse_common_compat.h deleted file mode 100644 index dea34468..00000000 --- a/libfuse/include/fuse_common_compat.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -/* these definitions provide source compatibility to prior versions. - Do not include this file directly! */ - -struct fuse_file_info_compat -{ - int flags; - unsigned long fh; - int writepage; - unsigned int direct_io : 1; - unsigned int keep_cache : 1; -}; - -int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args); - -int fuse_mount_compat22(const char *mountpoint, const char *opts); - -int fuse_mount_compat1(const char *mountpoint, const char *args[]); - -void fuse_unmount_compat22(const char *mountpoint); diff --git a/libfuse/include/fuse_compat.h b/libfuse/include/fuse_compat.h deleted file mode 100644 index a2147a62..00000000 --- a/libfuse/include/fuse_compat.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -/* these definitions provide source compatibility to prior versions. - Do not include this file directly! */ - -struct fuse_operations_compat25 -{ - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info *); - int (*read) (const char *, char *, size_t, off_t, - struct fuse_file_info *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info *); - int (*statfs) (const char *, struct statvfs *); - int (*flush) (const char *, struct fuse_file_info *); - int (*release) (const char *, struct fuse_file_info *); - int (*fsync) (const char *, int, struct fuse_file_info *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info *); - int (*readdir) (const char *, void *, off_t, - struct fuse_file_info *); - int (*releasedir) (const char *, struct fuse_file_info *); - int (*fsyncdir) (const char *, int, struct fuse_file_info *); - void *(*init) (void); - void (*destroy) (void *); - int (*access) (const char *, int); - int (*create) (const char *, mode_t, struct fuse_file_info *); - int (*ftruncate) (const char *, off_t, struct fuse_file_info *); - int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); -}; - -struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, - const struct fuse_operations_compat25 *op, - size_t op_size); - -int fuse_main_real_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size); - -struct fuse *fuse_setup_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd); - -void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint); - -#if !defined(__FreeBSD__) && !defined(__NetBSD__) -#include - -struct fuse_operations_compat22 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info_compat *); - int (*read) (const char *, char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *, struct fuse_file_info_compat *); - int (*release) (const char *, struct fuse_file_info_compat *); - int (*fsync) (const char *, int, struct fuse_file_info_compat *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info_compat *); - int (*readdir) (const char *, void *, off_t, - struct fuse_file_info_compat *); - int (*releasedir) (const char *, struct fuse_file_info_compat *); - int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *); - void *(*init) (void); - void (*destroy) (void *); -}; - -struct fuse *fuse_new_compat22(int fd, const char *opts, - const struct fuse_operations_compat22 *op, - size_t op_size); - -struct fuse *fuse_setup_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd); - -int fuse_main_real_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size); - -struct fuse_operations_compat2 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); - int (*setxattr) (const char *, const char *, const char *, - size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); -}; - -int fuse_main_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op); - -struct fuse *fuse_new_compat2(int fd, const char *opts, - const struct fuse_operations_compat2 *op); - -struct fuse *fuse_setup_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op, - char **mountpoint, int *multithreaded, int *fd); - -struct fuse_statfs_compat1 { - long block_size; - long blocks; - long blocks_free; - long files; - long files_free; - long namelen; -}; - -struct fuse_operations_compat1 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (struct fuse_statfs_compat1 *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); -}; - -#define FUSE_DEBUG_COMPAT1 (1 << 1) - -struct fuse *fuse_new_compat1(int fd, int flags, - const struct fuse_operations_compat1 *op); - -void fuse_main_compat1(int argc, char *argv[], - const struct fuse_operations_compat1 *op); - -#endif /* __FreeBSD__ || __NetBSD__ */ diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index 8054b149..d3e43e64 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -1834,28 +1834,6 @@ extern "C" { */ void fuse_chan_destroy(struct fuse_chan *ch); - /* ----------------------------------------------------------- * - * Compatibility stuff * - * ----------------------------------------------------------- */ - -#if FUSE_USE_VERSION < 26 -# include "fuse_lowlevel_compat.h" -# define fuse_chan_ops fuse_chan_ops_compat24 -# define fuse_chan_new fuse_chan_new_compat24 -# if FUSE_USE_VERSION == 25 -# define fuse_lowlevel_ops fuse_lowlevel_ops_compat25 -# define fuse_lowlevel_new fuse_lowlevel_new_compat25 -# elif FUSE_USE_VERSION == 24 -# define fuse_lowlevel_ops fuse_lowlevel_ops_compat -# define fuse_lowlevel_new fuse_lowlevel_new_compat -# define fuse_file_info fuse_file_info_compat -# define fuse_reply_statfs fuse_reply_statfs_compat -# define fuse_reply_open fuse_reply_open_compat -# else -# error Compatibility with low-level API version < 24 not supported -# endif -#endif - #ifdef __cplusplus } #endif diff --git a/libfuse/include/fuse_lowlevel_compat.h b/libfuse/include/fuse_lowlevel_compat.h deleted file mode 100644 index 5c4649d7..00000000 --- a/libfuse/include/fuse_lowlevel_compat.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -/* these definitions provide source compatibility to prior versions. - Do not include this file directly! */ - -struct fuse_lowlevel_ops_compat25 -{ - void (*init) (void *userdata); - void (*destroy) (void *userdata); - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); - void (*getattr) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info *fi); - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - void (*open) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi); - void (*flush) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*release) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - void (*opendir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - void (*statfs) (fuse_req_t req); - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi); -}; - -struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata); - -size_t fuse_dirent_size(size_t namelen); - -char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, - off_t off); - -#if !defined(__FreeBSD__) && !defined(__NetBSD__) - -#include - -struct fuse_lowlevel_ops_compat -{ - void (*init) (void *userdata); - void (*destroy) (void *userdata); - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); - void (*getattr) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info_compat *fi); - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - void (*open) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info_compat *fi); - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info_compat *fi); - void (*flush) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*release) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info_compat *fi); - void (*opendir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info_compat *fi); - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info_compat *fi); - void (*statfs) (fuse_req_t req); - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info_compat *fi); -}; - -int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf); - -int fuse_reply_open_compat(fuse_req_t req, - const struct fuse_file_info_compat *fi); - -struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata); - -#endif /* __FreeBSD__ || __NetBSD__ */ - -struct fuse_chan_ops_compat24 { - int (*receive)(struct fuse_chan *ch, char *buf, size_t size); - int (*send)(struct fuse_chan *ch, const struct iovec iov[], - size_t count); - void (*destroy)(struct fuse_chan *ch); -}; - -struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, - int fd, size_t bufsize, void *data); - -int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size); -struct fuse_chan *fuse_kern_chan_new(int fd); diff --git a/libfuse/include/old/fuse.h b/libfuse/include/old/fuse.h deleted file mode 100644 index 3db0945a..00000000 --- a/libfuse/include/old/fuse.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - This header is for compatibility with older software using FUSE. - - Please use 'pkg-config --cflags fuse' to set include path. The - correct usage is still '#include ', not '#include - '. -*/ - -#include "fuse/fuse.h" diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index 93d6c278..fd7bdd0d 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -15,8 +15,6 @@ #include "fuse_lowlevel.h" #include "fuse_opt.h" #include "fuse_misc.h" -#include "fuse_common_compat.h" -#include "fuse_compat.h" #include "fuse_kernel.h" #include "fuse_dirents.h" @@ -75,7 +73,6 @@ struct fuse_fs { struct fuse_operations op; void *user_data; - int compat; int debug; }; @@ -1424,128 +1421,6 @@ static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, fuse_do_prepare_interrupt(req, d); } -#if !defined(__FreeBSD__) && !defined(__NetBSD__) - -static int fuse_compat_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) -{ - int err; - if (!fs->compat || fs->compat >= 25) - err = fs->op.open(path, fi); - else if (fs->compat == 22) { - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op)->open(path,&tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - } else - err = ((struct fuse_operations_compat2 *) &fs->op) - ->open(path, fi->flags); - return err; -} - -static int fuse_compat_release(struct fuse_fs *fs, - struct fuse_file_info *fi) -{ - if (!fs->compat || fs->compat >= 22) - return fs->op.release(fi); - else - return ((struct fuse_operations_compat2 *) &fs->op) - ->release(NULL, fi->flags); -} - -static int fuse_compat_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) -{ - if (!fs->compat || fs->compat >= 25) - return fs->op.opendir(path, fi); - else { - int err; - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op) - ->opendir(path, &tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - return err; - } -} - -static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf, - struct statvfs *stbuf) -{ - stbuf->f_bsize = compatbuf->block_size; - stbuf->f_blocks = compatbuf->blocks; - stbuf->f_bfree = compatbuf->blocks_free; - stbuf->f_bavail = compatbuf->blocks_free; - stbuf->f_files = compatbuf->files; - stbuf->f_ffree = compatbuf->files_free; - stbuf->f_namemax = compatbuf->namelen; -} - -static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf) -{ - stbuf->f_bsize = oldbuf->f_bsize; - stbuf->f_blocks = oldbuf->f_blocks; - stbuf->f_bfree = oldbuf->f_bfree; - stbuf->f_bavail = oldbuf->f_bavail; - stbuf->f_files = oldbuf->f_files; - stbuf->f_ffree = oldbuf->f_ffree; - stbuf->f_namemax = oldbuf->f_namelen; -} - -static int fuse_compat_statfs(struct fuse_fs *fs, const char *path, - struct statvfs *buf) -{ - int err; - - if (!fs->compat || fs->compat >= 25) { - err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf); - } else if (fs->compat > 11) { - struct statfs oldbuf; - err = ((struct fuse_operations_compat22 *) &fs->op) - ->statfs("/", &oldbuf); - if (!err) - convert_statfs_old(&oldbuf, buf); - } else { - struct fuse_statfs_compat1 compatbuf; - memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); - err = ((struct fuse_operations_compat1 *) &fs->op) - ->statfs(&compatbuf); - if (!err) - convert_statfs_compat(&compatbuf, buf); - } - return err; -} - -#else /* __FreeBSD__ || __NetBSD__ */ - -static inline int fuse_compat_open(struct fuse_fs *fs, char *path, - struct fuse_file_info *fi) -{ - return fs->op.open(path, fi); -} - -static inline int fuse_compat_release(struct fuse_fs *fs, - struct fuse_file_info *fi) -{ - return fs->op.release(fi); -} - -static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) -{ - return fs->op.opendir(path, fi); -} - -static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path, - struct statvfs *buf) -{ - return fs->op.statfs(fs->compat == 25 ? "/" : path, buf); -} - -#endif /* __FreeBSD__ || __NetBSD__ */ - int fuse_fs_getattr(struct fuse_fs *fs, const char *path, @@ -1679,7 +1554,7 @@ int fuse_fs_release(struct fuse_fs *fs, fi->flush ? "+flush" : "", (unsigned long long) fi->fh, fi->flags); - return fuse_compat_release(fs, fi); + return fs->op.release(fi); } else { return 0; } @@ -1696,7 +1571,7 @@ int fuse_fs_opendir(struct fuse_fs *fs, const char *path, fprintf(stderr, "opendir flags: 0x%x %s\n", fi->flags, path); - err = fuse_compat_opendir(fs, path, fi); + err = fs->op.opendir(path,fi); if (fs->debug && !err) fprintf(stderr, " opendir[%lli] flags: 0x%x %s\n", @@ -1719,7 +1594,7 @@ int fuse_fs_open(struct fuse_fs *fs, const char *path, fprintf(stderr, "open flags: 0x%x %s\n", fi->flags, path); - err = fuse_compat_open(fs, path, fi); + err = fs->op.open(path,fi); if (fs->debug && !err) fprintf(stderr, " open[%lli] flags: 0x%x %s\n", @@ -1941,7 +1816,7 @@ int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) if (fs->debug) fprintf(stderr, "statfs %s\n", path); - return fuse_compat_statfs(fs, path, buf); + return fs->op.statfs(path,buf); } else { buf->f_namemax = 255; buf->f_bsize = 512; @@ -4392,24 +4267,6 @@ struct fuse_context *fuse_get_context(void) return &fuse_get_context_internal()->ctx; } -/* - * The size of fuse_context got extended, so need to be careful about - * incompatibility (i.e. a new binary cannot work with an old - * library). - */ -struct fuse_context *fuse_get_context_compat22(void); -struct fuse_context *fuse_get_context_compat22(void) -{ - return &fuse_get_context_internal()->ctx; -} -FUSE_SYMVER(".symver fuse_get_context_compat22,fuse_get_context@FUSE_2.2"); - -int fuse_getgroups(int size, gid_t list[]) -{ - fuse_req_t req = fuse_get_context_internal()->req; - return fuse_req_getgroups(req, size, list); -} - int fuse_interrupted(void) { return fuse_req_interrupted(fuse_get_context_internal()->req); @@ -4588,7 +4445,7 @@ void fuse_stop_cleanup_thread(struct fuse *f) struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *op, - size_t op_size, void *user_data, int compat) + size_t op_size, void *user_data) { struct fuse *f; struct node *root; @@ -4608,7 +4465,6 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, if (!fs) goto out_free; - fs->compat = compat; f->fs = fs; /* Oh f**k, this is ugly! */ @@ -4628,11 +4484,6 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, fuse_lib_opt_proc) == -1) goto out_free_fs; - if (compat && compat <= 25) { - if (fuse_sync_compat_args(args) == -1) - goto out_free_fs; - } - f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); if (f->se == NULL) { goto out_free_fs; @@ -4703,7 +4554,7 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data) { - return fuse_new_common(ch, args, op, op_size, user_data, 0); + return fuse_new_common(ch, args, op, op_size, user_data); } void fuse_destroy(struct fuse *f) @@ -4750,91 +4601,6 @@ void fuse_destroy(struct fuse *f) fuse_delete_context_key(); } -static -struct fuse * -fuse_new_common_compat25(int fd, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, int compat) -{ - struct fuse *f = NULL; - struct fuse_chan *ch = fuse_kern_chan_new(fd); - - if (ch) - f = fuse_new_common(ch, args, op, op_size, NULL, compat); - - return f; -} - -#if !defined(__FreeBSD__) && !defined(__NetBSD__) - -static struct fuse *fuse_new_common_compat(int fd, const char *opts, - const struct fuse_operations *op, - size_t op_size, int compat) -{ - struct fuse *f; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - - if (fuse_opt_add_arg(&args, "") == -1) - return NULL; - if (opts && - (fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - - f = fuse_new_common_compat25(fd, &args, op, op_size, compat); - fuse_opt_free_args(&args); - - return f; -} - -struct fuse *fuse_new_compat22(int fd, const char *opts, - const struct fuse_operations_compat22 *op, - size_t op_size) -{ - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - op_size, 22); -} - -struct fuse *fuse_new_compat2(int fd, const char *opts, - const struct fuse_operations_compat2 *op) -{ - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), - 21); -} - -struct fuse *fuse_new_compat1(int fd, int flags, - const struct fuse_operations_compat1 *op) -{ - const char *opts = NULL; - if (flags & FUSE_DEBUG_COMPAT1) - opts = "debug"; - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), - 11); -} - -FUSE_SYMVER(".symver fuse_exited,__fuse_exited@"); -FUSE_SYMVER(".symver fuse_process_cmd,__fuse_process_cmd@"); -FUSE_SYMVER(".symver fuse_read_cmd,__fuse_read_cmd@"); -FUSE_SYMVER(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@"); -FUSE_SYMVER(".symver fuse_new_compat2,fuse_new@"); -FUSE_SYMVER(".symver fuse_new_compat22,fuse_new@FUSE_2.2"); - -#endif /* __FreeBSD__ || __NetBSD__ */ - -struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, - const struct fuse_operations_compat25 *op, - size_t op_size) -{ - return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op, - op_size, 25); -} - -FUSE_SYMVER(".symver fuse_new_compat25,fuse_new@FUSE_2.5"); - int fuse_config_num_threads(const struct fuse *fuse_) { diff --git a/libfuse/lib/fuse_i.h b/libfuse/lib/fuse_i.h index 4eb3bfaa..80b5a683 100644 --- a/libfuse/lib/fuse_i.h +++ b/libfuse/lib/fuse_i.h @@ -98,9 +98,7 @@ struct fuse_cmd struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *op, - size_t op_size, void *user_data, int compat); - -int fuse_sync_compat_args(struct fuse_args *args); + size_t op_size, void *user_data); struct fuse_chan *fuse_kern_chan_new(int fd); @@ -108,7 +106,6 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); -void fuse_kern_unmount_compat22(const char *mountpoint); int fuse_chan_clearfd(struct fuse_chan *ch); void fuse_kern_unmount(const char *mountpoint, int fd); @@ -125,7 +122,6 @@ struct fuse *fuse_setup_common(int argc, char *argv[], char **mountpoint, int *multithreaded, int *fd, - void *user_data, - int compat); + void *user_data); int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg); diff --git a/libfuse/lib/fuse_lowlevel.c b/libfuse/lib/fuse_lowlevel.c index 22f96b22..8a922477 100644 --- a/libfuse/lib/fuse_lowlevel.c +++ b/libfuse/lib/fuse_lowlevel.c @@ -13,8 +13,6 @@ #include "fuse_kernel.h" #include "fuse_opt.h" #include "fuse_misc.h" -#include "fuse_common_compat.h" -#include "fuse_lowlevel_compat.h" #include #include @@ -2290,21 +2288,6 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) return &req->ctx; } -/* - * The size of fuse_ctx got extended, so need to be careful about - * incompatibility (i.e. a new binary cannot work with an old - * library). - */ -const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req); -const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req) -{ - return fuse_req_ctx(req); -} -#ifndef __NetBSD__ -FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4"); -#endif - - void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data) { @@ -2849,136 +2832,11 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, return NULL; } - -struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata) +struct fuse_session* +fuse_lowlevel_new(struct fuse_args *args, + const struct fuse_lowlevel_ops *op, + size_t op_size, + void *userdata) { return fuse_lowlevel_new_common(args, op, op_size, userdata); } - -#if !defined(__FreeBSD__) && !defined(__NetBSD__) - -static void fill_open_compat(struct fuse_open_out *arg, - const struct fuse_file_info_compat *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; -} - -static void convert_statfs_compat(const struct statfs *compatbuf, - struct statvfs *buf) -{ - buf->f_bsize = compatbuf->f_bsize; - buf->f_blocks = compatbuf->f_blocks; - buf->f_bfree = compatbuf->f_bfree; - buf->f_bavail = compatbuf->f_bavail; - buf->f_files = compatbuf->f_files; - buf->f_ffree = compatbuf->f_ffree; - buf->f_namemax = compatbuf->f_namelen; -} - -int fuse_reply_open_compat(fuse_req_t req, - const struct fuse_file_info_compat *f) -{ - struct fuse_open_out arg; - - memset(&arg, 0, sizeof(arg)); - fill_open_compat(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); -} - -int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf) -{ - struct statvfs newbuf; - - memset(&newbuf, 0, sizeof(newbuf)); - convert_statfs_compat(stbuf, &newbuf); - - return fuse_reply_statfs(req, &newbuf); -} - -struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata) -{ - struct fuse_session *se; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - - if (opts && - (fuse_opt_add_arg(&args, "") == -1 || - fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, - op_size, userdata); - fuse_opt_free_args(&args); - - return se; -} - -struct fuse_ll_compat_conf { - unsigned max_read; - int set_max_read; -}; - -static const struct fuse_opt fuse_ll_opts_compat[] = { - { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, - { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END -}; - -int fuse_sync_compat_args(struct fuse_args *args) -{ - struct fuse_ll_compat_conf conf; - - memset(&conf, 0, sizeof(conf)); - if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) - return -1; - - if (fuse_opt_insert_arg(args, 1, "-osync_read")) - return -1; - - if (conf.set_max_read) { - char tmpbuf[64]; - - sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); - if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) - return -1; - } - return 0; -} - -FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4"); -FUSE_SYMVER(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4"); -FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4"); - -#else /* __FreeBSD__ || __NetBSD__ */ - -int fuse_sync_compat_args(struct fuse_args *args) -{ - (void) args; - return 0; -} - -#endif /* __FreeBSD__ || __NetBSD__ */ - -struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata) -{ - if (fuse_sync_compat_args(args) == -1) - return NULL; - - return fuse_lowlevel_new_common(args, - (const struct fuse_lowlevel_ops *) op, - op_size, userdata); -} - -FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5"); diff --git a/libfuse/lib/fuse_opt.c b/libfuse/lib/fuse_opt.c index 5605f4b7..391a0666 100644 --- a/libfuse/lib/fuse_opt.c +++ b/libfuse/lib/fuse_opt.c @@ -97,13 +97,6 @@ int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) return fuse_opt_insert_arg_common(args, pos, arg); } -int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, - const char *arg); -int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *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) { @@ -426,6 +419,3 @@ int fuse_opt_parse(struct fuse_args *args, void *data, fuse_opt_free_args(&ctx.outargs); return res; } - -/* This symbol version was mistakenly added to the version script */ -FUSE_SYMVER(".symver fuse_opt_insert_arg_compat,fuse_opt_insert_arg@FUSE_2.5"); diff --git a/libfuse/lib/fuse_session.c b/libfuse/lib/fuse_session.c index 5773ec72..ea6eacc5 100644 --- a/libfuse/lib/fuse_session.c +++ b/libfuse/lib/fuse_session.c @@ -8,8 +8,6 @@ #include "fuse_i.h" #include "fuse_misc.h" -#include "fuse_common_compat.h" -#include "fuse_lowlevel_compat.h" #include #include @@ -24,7 +22,6 @@ struct fuse_chan int fd; size_t bufsize; void *data; - int compat; }; struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) @@ -141,8 +138,7 @@ void *fuse_session_data(struct fuse_session *se) } static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data, - int compat) + size_t bufsize, void *data) { struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); if (ch == NULL) { @@ -155,7 +151,6 @@ static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, ch->fd = fd; ch->bufsize = bufsize; ch->data = data; - ch->compat = compat; return ch; } @@ -163,14 +158,7 @@ static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, size_t bufsize, void *data) { - return fuse_chan_new_common(op, fd, bufsize, data, 0); -} - -struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, - int fd, size_t bufsize, void *data) -{ - return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize, - data, 24); + return fuse_chan_new_common(op, fd, bufsize, data); } int fuse_chan_fd(struct fuse_chan *ch) @@ -203,11 +191,8 @@ struct fuse_session *fuse_chan_session(struct fuse_chan *ch) int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size) { struct fuse_chan *ch = *chp; - if (ch->compat) - return ((struct fuse_chan_ops_compat24 *) &ch->op) - ->receive(ch, buf, size); - else - return ch->op.receive(chp, buf, size); + + return ch->op.receive(chp, buf, size); } int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size) @@ -230,7 +215,3 @@ void fuse_chan_destroy(struct fuse_chan *ch) ch->op.destroy(ch); free(ch); } - -#ifndef __FreeBSD__ -FUSE_SYMVER(".symver fuse_chan_new_compat24,fuse_chan_new@FUSE_2.4"); -#endif diff --git a/libfuse/lib/helper.c b/libfuse/lib/helper.c index 95b6d18b..c1e6d7f1 100644 --- a/libfuse/lib/helper.c +++ b/libfuse/lib/helper.c @@ -11,7 +11,6 @@ #include "fuse_misc.h" #include "fuse_opt.h" #include "fuse_lowlevel.h" -#include "fuse_common_compat.h" #include #include @@ -260,7 +259,7 @@ fuse_mount_common(const char *mountpoint_, close(fd); } while(fd >= 0 && fd <= 2); - fd = fuse_mount_compat25(mountpoint_, args_); + fd = fuse_kern_mount(mountpoint_,args_); if(fd == -1) return NULL; @@ -299,8 +298,7 @@ struct fuse *fuse_setup_common(int argc, char *argv[], char **mountpoint, int *multithreaded, int *fd, - void *user_data, - int compat) + void *user_data) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_chan *ch; @@ -318,7 +316,7 @@ struct fuse *fuse_setup_common(int argc, char *argv[], goto err_free; } - fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); + fuse = fuse_new_common(ch, &args, op, op_size, user_data); fuse_opt_free_args(&args); if (fuse == NULL) goto err_unmount; @@ -350,7 +348,7 @@ struct fuse *fuse_setup(int argc, char *argv[], char **mountpoint, int *multithreaded, void *user_data) { return fuse_setup_common(argc, argv, op, op_size, mountpoint, - multithreaded, NULL, user_data, 0); + multithreaded, NULL, user_data); } static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) @@ -370,7 +368,7 @@ void fuse_teardown(struct fuse *fuse, char *mountpoint) static int fuse_main_common(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, - void *user_data, int compat) + void *user_data) { struct fuse *fuse; char *mountpoint; @@ -378,7 +376,7 @@ static int fuse_main_common(int argc, char *argv[], int res; fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, - &multithreaded, NULL, user_data, compat); + &multithreaded, NULL, user_data); if (fuse == NULL) return 1; @@ -397,7 +395,7 @@ static int fuse_main_common(int argc, char *argv[], int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data) { - return fuse_main_common(argc, argv, op, op_size, user_data, 0); + return fuse_main_common(argc, argv, op, op_size, user_data); } #undef fuse_main @@ -412,100 +410,3 @@ int fuse_version(void) { return FUSE_VERSION; } - -#include "fuse_compat.h" - -#if !defined(__FreeBSD__) && !defined(__NetBSD__) - -struct fuse *fuse_setup_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd) -{ - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, - 22); -} - -struct fuse *fuse_setup_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op, - char **mountpoint, int *multithreaded, - int *fd) -{ - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), - mountpoint, multithreaded, fd, NULL, 21); -} - -int fuse_main_real_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size) -{ - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - op_size, NULL, 22); -} - -void fuse_main_compat1(int argc, char *argv[], - const struct fuse_operations_compat1 *op) -{ - fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), NULL, 11); -} - -int fuse_main_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op) -{ - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), NULL, - 21); -} - -int fuse_mount_compat1(const char *mountpoint, const char *args[]) -{ - /* just ignore mount args for now */ - (void) args; - return fuse_mount_compat22(mountpoint, NULL); -} - -FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@"); -FUSE_SYMVER(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2"); -FUSE_SYMVER(".symver fuse_teardown,__fuse_teardown@"); -FUSE_SYMVER(".symver fuse_main_compat2,fuse_main@"); -FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2"); - -#endif /* __FreeBSD__ || __NetBSD__ */ - - -struct fuse *fuse_setup_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd) -{ - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, - 25); -} - -int fuse_main_real_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size) -{ - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - op_size, NULL, 25); -} - -void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint) -{ - (void) fd; - fuse_teardown_common(fuse, mountpoint); -} - -int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args) -{ - return fuse_kern_mount(mountpoint, args); -} - -FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5"); -FUSE_SYMVER(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2"); -FUSE_SYMVER(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5"); -FUSE_SYMVER(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5"); diff --git a/libfuse/lib/mount_bsd.c b/libfuse/lib/mount_bsd.c index 23747bc4..82e7b6c7 100644 --- a/libfuse/lib/mount_bsd.c +++ b/libfuse/lib/mount_bsd.c @@ -145,53 +145,6 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key, return 1; } -void fuse_unmount_compat22(const char *mountpoint) -{ - char dev[128]; - char *ssc, *umount_cmd; - FILE *sf; - int rv; - char seekscript[] = - /* error message is annoying in help output */ - "exec 2>/dev/null; " - "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " - "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " - " { if ($3 == %d) print $10; }' | " - "/usr/bin/sort | " - "/usr/bin/uniq | " - "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; - - (void) mountpoint; - - /* - * If we don't know the fd, we have to resort to the scripted - * solution -- iterating over the fd-s is unpractical, as we - * don't know how many of open files we have. (This could be - * looked up in procfs -- however, that's optional on FBSD; or - * read out from the kmem -- however, that's bound to - * privileges (in fact, that's what happens when we call the - * setgid kmem fstat(1) utility). - */ - if (asprintf(&ssc, seekscript, getpid()) == -1) - return; - - errno = 0; - sf = popen(ssc, "r"); - free(ssc); - if (! sf) - return; - - fgets(dev, sizeof(dev), sf); - rv = pclose(sf); - if (rv) - return; - - if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1) - return; - system(umount_cmd); - free(umount_cmd); -} - static void do_unmount(char *dev, int fd) { char device_path[SPECNAMELEN + 12]; @@ -387,5 +340,3 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) free(mo.kernel_opts); return res; } - -FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2"); diff --git a/libfuse/lib/mount_generic.c b/libfuse/lib/mount_generic.c index 1c4f5c63..249ef74f 100644 --- a/libfuse/lib/mount_generic.c +++ b/libfuse/lib/mount_generic.c @@ -10,7 +10,6 @@ #include "fuse_i.h" #include "fuse_misc.h" #include "fuse_opt.h" -#include "fuse_common_compat.h" #include "mount_util.h" #include @@ -343,11 +342,6 @@ void fuse_kern_unmount(const char *mountpoint, int fd) waitpid(pid, NULL, 0); } -void fuse_unmount_compat22(const char *mountpoint) -{ - fuse_kern_unmount(mountpoint, -1); -} - static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo, const char *opts, int quiet) { @@ -418,15 +412,6 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo, return rv; } -int fuse_mount_compat22(const char *mountpoint, const char *opts) -{ - struct mount_opts mo; - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; - - return fuse_mount_fusermount(mountpoint, &mo, opts, 0); -} - static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, const char *mnt_opts) { @@ -641,6 +626,3 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) free(mo.mtab_opts); return res; } - -FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2"); -FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2"); From dc1b698847456174c20ffe393f9c46eab6b86be8 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sun, 2 Aug 2020 16:01:23 -0400 Subject: [PATCH 5/6] libfuse cleanup: remove single threaded --- libfuse/Makefile | 1 - libfuse/include/fuse.h | 13 +----- libfuse/include/fuse_common.h | 7 ++-- libfuse/include/fuse_lowlevel.h | 8 ---- libfuse/lib/fuse.c | 73 --------------------------------- libfuse/lib/fuse_i.h | 1 - libfuse/lib/fuse_loop.c | 46 --------------------- libfuse/lib/fuse_mt.c | 4 +- libfuse/lib/helper.c | 34 ++++++--------- 9 files changed, 17 insertions(+), 170 deletions(-) delete mode 100644 libfuse/lib/fuse_loop.c diff --git a/libfuse/Makefile b/libfuse/Makefile index 7fec8a9b..c8845fba 100644 --- a/libfuse/Makefile +++ b/libfuse/Makefile @@ -34,7 +34,6 @@ SRC = \ lib/fuse_dirents.c \ lib/fuse.c \ lib/fuse_kern_chan.c \ - lib/fuse_loop.c \ lib/fuse_loop_mt.c \ lib/fuse_lowlevel.c \ lib/fuse_mt.c \ diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index 8e2c9474..1feff3f2 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -664,17 +664,6 @@ extern "C" { */ void fuse_destroy(struct fuse *f); - /** - * FUSE event loop. - * - * Requests from the kernel are processed, and the appropriate - * operations are called. - * - * @param f the FUSE handle - * @return 0 if no error occurred, -1 otherwise - */ - int fuse_loop(struct fuse *f); - /** * Exit from event loop * @@ -903,7 +892,7 @@ extern "C" { /** This is the part of fuse_main() before the event loop */ struct fuse *fuse_setup(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, - char **mountpoint, int *multithreaded, + char **mountpoint, void *user_data); /** This is the part of fuse_main() after the event loop */ diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index c7d47ea8..0de750ef 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -235,7 +235,6 @@ extern "C" { * * '-f' foreground * '-d' '-odebug' foreground, but keep the debug option - * '-s' single threaded * '-h' '--help' help * '-ho' help without header * '-ofsname=..' file system name, if not present, then set to the program @@ -245,12 +244,12 @@ extern "C" { * * @param args argument vector * @param mountpoint the returned mountpoint, should be freed after use - * @param multithreaded set to 1 unless the '-s' option is present * @param foreground set to 1 if one of the relevant options is present * @return 0 on success, -1 on failure */ - int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground); + int fuse_parse_cmdline(struct fuse_args *args, + char **mountpoint, + int *foreground); /** * Go into the background diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index d3e43e64..ffb7e1f0 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -1698,14 +1698,6 @@ extern "C" { */ void *fuse_session_data(struct fuse_session *se); - /** - * Enter a single threaded event loop - * - * @param se the session - * @return 0 on success, -1 on error - */ - int fuse_session_loop(struct fuse_session *se); - /** * Enter a multi-threaded event loop * diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index fd7bdd0d..8a53495b 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -4177,79 +4177,6 @@ struct fuse_cmd *fuse_read_cmd(struct fuse *f) return cmd; } -static int fuse_session_loop_remember(struct fuse *f) -{ - struct fuse_session *se = f->se; - int res = 0; - struct timespec now; - time_t next_clean; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char *) malloc(bufsize); - struct pollfd fds = { - .fd = fuse_chan_fd(ch), - .events = POLLIN - }; - - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } - - curr_time(&now); - next_clean = now.tv_sec; - while (!fuse_session_exited(se)) { - struct fuse_chan *tmpch = ch; - struct fuse_buf fbuf = { - .mem = buf, - .size = bufsize, - }; - unsigned timeout; - - curr_time(&now); - if (now.tv_sec < next_clean) - timeout = next_clean - now.tv_sec; - else - timeout = 0; - - res = poll(&fds, 1, timeout * 1000); - if (res == -1) { - if (errno == -EINTR) - continue; - else - break; - } else if (res > 0) { - res = fuse_session_receive_buf(se, &fbuf, &tmpch); - - if (res == -EINTR) - continue; - if (res <= 0) - break; - - fuse_session_process_buf(se, &fbuf, tmpch); - } else { - timeout = fuse_clean_cache(f); - curr_time(&now); - next_clean = now.tv_sec + timeout; - } - } - - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; -} - -int fuse_loop(struct fuse *f) -{ - if (!f) - return -1; - - if (lru_enabled(f)) - return fuse_session_loop_remember(f); - - return fuse_session_loop(f->se); -} - int fuse_invalidate(struct fuse *f, const char *path) { (void) f; diff --git a/libfuse/lib/fuse_i.h b/libfuse/lib/fuse_i.h index 80b5a683..d951f4ad 100644 --- a/libfuse/lib/fuse_i.h +++ b/libfuse/lib/fuse_i.h @@ -120,7 +120,6 @@ struct fuse *fuse_setup_common(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, char **mountpoint, - int *multithreaded, int *fd, void *user_data); diff --git a/libfuse/lib/fuse_loop.c b/libfuse/lib/fuse_loop.c deleted file mode 100644 index e180577b..00000000 --- a/libfuse/lib/fuse_loop.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB -*/ - -#include "fuse_lowlevel.h" - -#include -#include -#include - -int fuse_session_loop(struct fuse_session *se) -{ - int res = 0; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char*)calloc(bufsize,1); - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } - - while (!fuse_session_exited(se)) { - struct fuse_chan *tmpch = ch; - struct fuse_buf fbuf = { - .mem = buf, - .size = bufsize, - }; - - res = fuse_session_receive_buf(se, &fbuf, &tmpch); - - if (res == -EINTR) - continue; - if (res <= 0) - break; - - fuse_session_process_buf(se, &fbuf, tmpch); - } - - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; -} diff --git a/libfuse/lib/fuse_mt.c b/libfuse/lib/fuse_mt.c index b720f0fe..6a2f9581 100644 --- a/libfuse/lib/fuse_mt.c +++ b/libfuse/lib/fuse_mt.c @@ -62,7 +62,7 @@ static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size) if (cmd == NULL) return 0; - *(struct fuse_cmd **) buf = cmd; + *(struct fuse_cmd **)buf = cmd; return sizeof(cmd); } @@ -121,5 +121,3 @@ int fuse_loop_mt(struct fuse *f) fuse_stop_cleanup_thread(f); return res; } - -FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@"); diff --git a/libfuse/lib/helper.c b/libfuse/lib/helper.c index c1e6d7f1..c9f0cc5f 100644 --- a/libfuse/lib/helper.c +++ b/libfuse/lib/helper.c @@ -29,7 +29,6 @@ enum { struct helper_opts { - int singlethread; int foreground; int nodefault_subtype; char *mountpoint; @@ -41,20 +40,19 @@ static const struct fuse_opt fuse_helper_opts[] = { - FUSE_HELPER_OPT("-d", foreground), + FUSE_HELPER_OPT("-d", foreground), FUSE_HELPER_OPT("debug", foreground), - FUSE_HELPER_OPT("-f", foreground), - FUSE_HELPER_OPT("-s", singlethread), + FUSE_HELPER_OPT("-f", foreground), FUSE_HELPER_OPT("fsname=", nodefault_subtype), FUSE_HELPER_OPT("subtype=", nodefault_subtype), FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), FUSE_OPT_KEY("-V", KEY_VERSION), FUSE_OPT_KEY("--version", KEY_VERSION), FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), FUSE_OPT_END }; @@ -77,7 +75,6 @@ static void helper_help(void) "FUSE options:\n" " -d -o debug enable debug output (implies -f)\n" " -f foreground operation\n" - " -s disable multi-threaded operation\n" "\n" ); } @@ -149,7 +146,6 @@ static int add_default_subtype(const char *progname, struct fuse_args *args) int fuse_parse_cmdline(struct fuse_args *args_, char **mountpoint_, - int *multithreaded_, int *foreground_) { int res; @@ -176,8 +172,6 @@ fuse_parse_cmdline(struct fuse_args *args_, else free(hopts.mountpoint); - if(multithreaded_) - *multithreaded_ = !hopts.singlethread; if(foreground_) *foreground_ = hopts.foreground; @@ -296,7 +290,6 @@ struct fuse *fuse_setup_common(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, char **mountpoint, - int *multithreaded, int *fd, void *user_data) { @@ -306,7 +299,7 @@ struct fuse *fuse_setup_common(int argc, char *argv[], int foreground; int res; - res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); + res = fuse_parse_cmdline(&args, mountpoint, &foreground); if (res == -1) return NULL; @@ -345,10 +338,10 @@ struct fuse *fuse_setup_common(int argc, char *argv[], struct fuse *fuse_setup(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, - char **mountpoint, int *multithreaded, void *user_data) + char **mountpoint, void *user_data) { return fuse_setup_common(argc, argv, op, op_size, mountpoint, - multithreaded, NULL, user_data); + NULL, user_data); } static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) @@ -372,18 +365,15 @@ static int fuse_main_common(int argc, char *argv[], { struct fuse *fuse; char *mountpoint; - int multithreaded; int res; - fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, - &multithreaded, NULL, user_data); + fuse = fuse_setup_common(argc, argv, op, op_size, + &mountpoint, + NULL, user_data); if (fuse == NULL) return 1; - if (multithreaded) - res = fuse_loop_mt(fuse); - else - res = fuse_loop(fuse); + res = fuse_loop_mt(fuse); fuse_teardown_common(fuse, mountpoint); if (res == -1) From a925fbe59c9b99ca2906c057c286fbd408cb3315 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sun, 2 Aug 2020 19:19:53 -0400 Subject: [PATCH 6/6] libfuse cleanup: extern cplusplus cleanup --- libfuse/include/extern_c.h | 9 + libfuse/include/fuse.h | 1605 ++++++++-------- libfuse/include/fuse_common.h | 718 ++++---- libfuse/include/fuse_lowlevel.h | 3023 +++++++++++++++---------------- libfuse/include/fuse_opt.h | 442 +++-- libfuse/include/ulockmgr.h | 24 - 6 files changed, 2898 insertions(+), 2923 deletions(-) create mode 100644 libfuse/include/extern_c.h delete mode 100644 libfuse/include/ulockmgr.h diff --git a/libfuse/include/extern_c.h b/libfuse/include/extern_c.h new file mode 100644 index 00000000..d838ccab --- /dev/null +++ b/libfuse/include/extern_c.h @@ -0,0 +1,9 @@ +#pragma once + +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index 1feff3f2..538216c8 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -23,6 +23,7 @@ #define FUSE_USE_VERSION 21 #endif +#include "extern_c.h" #include "fuse_common.h" #include "fuse_dirents.h" @@ -34,892 +35,888 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN - /* ----------------------------------------------------------- * - * Basic FUSE API * - * ----------------------------------------------------------- */ +/* ----------------------------------------------------------- * + * Basic FUSE API * + * ----------------------------------------------------------- */ - /** Handle for a FUSE filesystem */ - struct fuse; +/** Handle for a FUSE filesystem */ +struct fuse; - /** Structure containing a raw command */ - struct fuse_cmd; +/** Structure containing a raw command */ +struct fuse_cmd; - /** - * The file system operations: - * - * Most of these should work very similarly to the well known UNIX - * file system operations. A major exception is that instead of - * returning an error in 'errno', the operation should return the - * negated error value (-errno) directly. - * - * All methods are optional, but some are essential for a useful - * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, - * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock, - * init and destroy are special purpose methods, without which a full - * featured filesystem can still be implemented. - * - * Almost all operations take a path which can be of any length. - * - * Changed in fuse 2.8.0 (regardless of API version) - * Previously, paths were limited to a length of PATH_MAX. - * - * See http://fuse.sourceforge.net/wiki/ for more information. There - * is also a snapshot of the relevant wiki pages in the doc/ folder. - */ - 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. - */ - int (*getattr) (const char *, struct stat *, fuse_timeouts_t *); - - /** 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); - - /** Hide files unlinked / renamed over - * - * Allows storing of a file handle when a file is unlinked - * while open. Helps manage the fact the kernel usually does - * not send fh with getattr requests. - */ - int (*prepare_hide)(const char *name_, uint64_t *fh_); - int (*free_hide)(const uint64_t fh_); - - /** 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 */ - int (*rename) (const char *, const char *); - - /** Create a hard link to a file */ - int (*link) (const char *, const char *); - - /** Change the permission bits of a file */ - int (*chmod) (const char *, mode_t); - int (*fchmod)(const struct fuse_file_info *, const mode_t); - - /** Change the owner and group of a file */ - int (*chown) (const char *, uid_t, gid_t); - int (*fchown)(const struct fuse_file_info *, const uid_t, const gid_t); - - /** Change the size of a file */ - int (*truncate) (const char *, off_t); - - /** Change the access and/or modification times of a file - * - * Deprecated, use utimens() instead. - */ - int (*utime) (const char *, struct utimbuf *); - - /** File open operation - * - * No creation (O_CREAT, O_EXCL) and by default also no - * truncation (O_TRUNC) flags will be passed to open(). If an - * application specifies O_TRUNC, fuse first calls truncate() - * and then open(). Only if 'atomic_o_trunc' has been - * specified and kernel version is 2.6.24 or later, O_TRUNC is - * passed on to open. - * - * Unless the 'default_permissions' mount option is given, - * open should check if the operation is permitted for the - * given flags. Optionally open may also return an arbitrary - * filehandle in the fuse_file_info structure, which will be - * passed to all file operations. - * - * Changed in version 2.2 - */ - 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. - * - * Changed in version 2.2 - */ - int (*read) (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). - * - * Changed in version 2.2 - */ - int (*write) (const char *, size_t, off_t, - struct fuse_file_info *); - - /** Get file system statistics - * - * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored - * - * Replaced 'struct statfs' parameter with 'struct statvfs' in - * version 2.5 - */ - 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. So if a - * filesystem wants to return write errors in close() and the file - * has cached dirty data, this is a good place to write back data - * and return any errors. Since many applications ignore close() - * errors this is not always useful. - * - * NOTE: The flush() method may be called more than once for each - * open(). This happens if more than one file descriptor refers - * to an opened file 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 always be called - * after some writes, or that if will be called at all. - * - * Changed in version 2.2 - */ - int (*flush) (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 descriptor. 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. - * - * Changed in version 2.2 - */ - int (*release) (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. - * - * Changed in version 2.2 - */ - int (*fsync) (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, closedir and fsyncdir. - * - * Introduced in version 2.3 - */ - int (*opendir) (const char *, struct fuse_file_info *); - - /** Read directory - * - * This supersedes the old getdir() interface. New applications - * should use this. - * - * 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. This - * works just like the old getdir() method. - * - * 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'. - * - * Introduced in version 2.3 - */ - int (*readdir)(struct fuse_file_info *, - fuse_dirents_t *); - - int (*readdir_plus)(struct fuse_file_info *, - fuse_dirents_t *); - - - /** Release directory - * - * Introduced in version 2.3 - */ - int (*releasedir) (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 - * - * Introduced in version 2.3 - */ - int (*fsyncdir) (int, struct fuse_file_info *); - - /** - * Initialize filesystem - * - * The return value will passed in the private_data field of - * fuse_context to all file operations and as a parameter to the - * destroy() method. - * - * Introduced in version 2.3 - * Changed in version 2.6 - */ - void *(*init) (struct fuse_conn_info *conn); - - /** - * Clean up filesystem - * - * Called on filesystem exit. - * - * Introduced in version 2.3 - */ - void (*destroy) (void *); - - /** - * 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 - * - * Introduced in version 2.5 - */ - 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. - * - * Introduced in version 2.5 - */ - int (*create) (const char *, mode_t, struct fuse_file_info *); - - /** - * Change the size of an open file - * - * This method is called instead of the truncate() method if the - * truncation was invoked from an ftruncate() system call. - * - * If this method is not implemented or under Linux kernel - * versions earlier than 2.6.15, the truncate() method will be - * called instead. - * - * Introduced in version 2.5 - */ - int (*ftruncate) (off_t, struct fuse_file_info *); - - /** - * Get attributes from an open file - * - * This method is called instead of the getattr() method if the - * file information is available. - * - * Currently this is only called after the create() method if that - * is implemented (see above). Later it may be called for - * invocations of fstat() too. - * - * Introduced in version 2.5 - */ - int (*fgetattr) (struct stat *, struct fuse_file_info *, fuse_timeouts_t *); - - /** - * 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. - * - * Introduced in version 2.6 - */ - int (*lock) (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. - * - * See the utimensat(2) man page for details. - * - * Introduced in version 2.6 - */ - int (*utimens)(const char *, const struct timespec tv[2]); - int (*futimens)(const struct fuse_file_info *ffi_, const struct timespec tv_[2]); - - /** - * 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 - * - * Introduced in version 2.6 - */ - 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. - * - * Introduced in version 2.8 - */ - int (*ioctl) (unsigned long cmd, - void *arg, - struct fuse_file_info *ffi, - unsigned int flags, - void *data, - uint32_t *out_bufsz); - - /** - * 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. - * - * Introduced in version 2.8 - */ - int (*poll) (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. - * - * Introduced in version 2.9 - */ - int (*write_buf) (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. - * - * Introduced in version 2.9 - */ - int (*read_buf) (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. - * - * Introduced in version 2.9 - */ - int (*flock) (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. - * - * Introduced in version 2.9.1 - */ - int (*fallocate) (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)(struct fuse_file_info *fi_in, - off_t offset_in, - struct fuse_file_info *fi_out, - off_t offset_out, - size_t size, - int flags); - }; - - /** 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; - - /** User ID of the calling process */ - uid_t uid; - - /** Group ID of the calling process */ - gid_t gid; - - /** Thread ID of the calling process */ - pid_t pid; - - /** Private filesystem data */ - void *private_data; - - /** Umask of the calling process (introduced in version 2.8) */ - mode_t umask; - }; +/** + * The file system operations: + * + * Most of these should work very similarly to the well known UNIX + * file system operations. A major exception is that instead of + * returning an error in 'errno', the operation should return the + * negated error value (-errno) directly. + * + * All methods are optional, but some are essential for a useful + * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, + * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock, + * init and destroy are special purpose methods, without which a full + * featured filesystem can still be implemented. + * + * Almost all operations take a path which can be of any length. + * + * Changed in fuse 2.8.0 (regardless of API version) + * Previously, paths were limited to a length of PATH_MAX. + * + * See http://fuse.sourceforge.net/wiki/ for more information. There + * is also a snapshot of the relevant wiki pages in the doc/ folder. + */ +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. + */ + int (*getattr) (const char *, struct stat *, fuse_timeouts_t *); - /** - * Main function of FUSE. - * - * This is for the lazy. This is all that has to be called from the - * main() function. - * - * This function does the following: - * - parses command line options (-d -s and -h) - * - passes relevant mount options to the fuse_mount() - * - installs signal handlers for INT, HUP, TERM and PIPE - * - registers an exit handler to unmount the filesystem on program exit - * - creates a fuse handle - * - registers the operations - * - calls either the single-threaded or the multi-threaded event loop - * - * Note: this is currently implemented as a macro. - * - * @param argc the argument counter passed to the main() function - * @param argv the argument vector passed to the main() function - * @param op the file system operation - * @param user_data user data supplied in the context during the init() method - * @return 0 on success, nonzero on failure - */ - /* - int fuse_main(int argc, char *argv[], const struct fuse_operations *op, - void *user_data); - */ -#define fuse_main(argc, argv, op, user_data) \ - fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) + /** 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); - /* ----------------------------------------------------------- * - * More detailed API * - * ----------------------------------------------------------- */ + /** 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 new FUSE filesystem. + /** Create a directory * - * @param ch the communication channel - * @param args argument vector - * @param op the filesystem operations - * @param op_size the size of the fuse_operations structure - * @param user_data user data supplied in the context during the init() method - * @return the created FUSE handle + * 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); + + /** Hide files unlinked / renamed over + * + * Allows storing of a file handle when a file is unlinked + * while open. Helps manage the fact the kernel usually does + * not send fh with getattr requests. */ - struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, size_t op_size, - void *user_data); + int (*prepare_hide)(const char *name_, uint64_t *fh_); + int (*free_hide)(const uint64_t fh_); - /** - * Destroy the FUSE handle. + /** 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 */ + int (*rename) (const char *, const char *); + + /** Create a hard link to a file */ + int (*link) (const char *, const char *); + + /** Change the permission bits of a file */ + int (*chmod) (const char *, mode_t); + int (*fchmod)(const struct fuse_file_info *, const mode_t); + + /** Change the owner and group of a file */ + int (*chown) (const char *, uid_t, gid_t); + int (*fchown)(const struct fuse_file_info *, const uid_t, const gid_t); + + /** Change the size of a file */ + int (*truncate) (const char *, off_t); + + /** Change the access and/or modification times of a file * - * The communication channel attached to the handle is also destroyed. + * Deprecated, use utimens() instead. + */ + int (*utime) (const char *, struct utimbuf *); + + /** File open operation + * + * No creation (O_CREAT, O_EXCL) and by default also no + * truncation (O_TRUNC) flags will be passed to open(). If an + * application specifies O_TRUNC, fuse first calls truncate() + * and then open(). Only if 'atomic_o_trunc' has been + * specified and kernel version is 2.6.24 or later, O_TRUNC is + * passed on to open. * - * NOTE: This function does not unmount the filesystem. If this is - * needed, call fuse_unmount() before calling this function. + * Unless the 'default_permissions' mount option is given, + * open should check if the operation is permitted for the + * given flags. Optionally open may also return an arbitrary + * filehandle in the fuse_file_info structure, which will be + * passed to all file operations. * - * @param f the FUSE handle + * Changed in version 2.2 */ - void fuse_destroy(struct fuse *f); + int (*open) (const char *, struct fuse_file_info *); - /** - * Exit from event loop + /** Read data from an open file * - * @param f the FUSE handle + * 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. + * + * Changed in version 2.2 */ - void fuse_exit(struct fuse *f); + int (*read) (char *, size_t, off_t, + struct fuse_file_info *); - int fuse_config_num_threads(const struct fuse *fuse_); + /** 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). + * + * Changed in version 2.2 + */ + int (*write) (const char *, size_t, off_t, + struct fuse_file_info *); - /** - * FUSE event loop with multiple threads + /** Get file system statistics + * + * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored + * + * Replaced 'struct statfs' parameter with 'struct statvfs' in + * version 2.5 + */ + 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. So if a + * filesystem wants to return write errors in close() and the file + * has cached dirty data, this is a good place to write back data + * and return any errors. Since many applications ignore close() + * errors this is not always useful. + * + * NOTE: The flush() method may be called more than once for each + * open(). This happens if more than one file descriptor refers + * to an opened file 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 always be called + * after some writes, or that if will be called at all. + * + * Changed in version 2.2 + */ + int (*flush) (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 descriptor. 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. + * + * Changed in version 2.2 + */ + int (*release) (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. + * + * Changed in version 2.2 + */ + int (*fsync) (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, closedir and fsyncdir. + * + * Introduced in version 2.3 + */ + int (*opendir) (const char *, struct fuse_file_info *); + + /** Read directory + * + * This supersedes the old getdir() interface. New applications + * should use this. * - * Requests from the kernel are processed, and the appropriate - * operations are called. Request are processed in parallel by - * distributing them between multiple threads. + * The filesystem may choose between two modes of operation: * - * Calling this function requires the pthreads library to be linked to - * the application. + * 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. This + * works just like the old getdir() method. * - * @param f the FUSE handle - * @return 0 if no error occurred, -1 otherwise + * 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'. + * + * Introduced in version 2.3 + */ + int (*readdir)(struct fuse_file_info *, + fuse_dirents_t *); + + int (*readdir_plus)(struct fuse_file_info *, + fuse_dirents_t *); + + + /** Release directory + * + * Introduced in version 2.3 + */ + int (*releasedir) (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 + * + * Introduced in version 2.3 */ - int fuse_loop_mt(struct fuse *f); + int (*fsyncdir) (int, struct fuse_file_info *); /** - * Get the current context + * Initialize filesystem * - * The context is only valid for the duration of a filesystem - * operation, and thus must not be stored and used later. + * The return value will passed in the private_data field of + * fuse_context to all file operations and as a parameter to the + * destroy() method. * - * @return the context + * Introduced in version 2.3 + * Changed in version 2.6 */ - struct fuse_context *fuse_get_context(void); + void *(*init) (struct fuse_conn_info *conn); /** - * Check if the current request has already been interrupted + * Clean up filesystem + * + * Called on filesystem exit. * - * @return 1 if the request has been interrupted, 0 otherwise + * Introduced in version 2.3 */ - int fuse_interrupted(void); + void (*destroy) (void *); /** - * Obsolete, doesn't do anything + * Check file access permissions * - * @return -EINVAL + * 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 + * + * Introduced in version 2.5 */ - int fuse_invalidate(struct fuse *f, const char *path); + int (*access) (const char *, int); - /* Deprecated, don't use */ - int fuse_is_lib_option(const char *opt); + /** + * 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. + * + * Introduced in version 2.5 + */ + int (*create) (const char *, mode_t, struct fuse_file_info *); /** - * The real main function + * Change the size of an open file * - * Do not call this directly, use fuse_main() + * This method is called instead of the truncate() method if the + * truncation was invoked from an ftruncate() system call. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the truncate() method will be + * called instead. + * + * Introduced in version 2.5 */ - int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, - size_t op_size, void *user_data); + int (*ftruncate) (off_t, struct fuse_file_info *); /** - * Start the cleanup thread when using option "remember". + * Get attributes from an open file + * + * This method is called instead of the getattr() method if the + * file information is available. * - * This is done automatically by fuse_loop_mt() - * @param fuse struct fuse pointer for fuse instance - * @return 0 on success and -1 on error + * Currently this is only called after the create() method if that + * is implemented (see above). Later it may be called for + * invocations of fstat() too. + * + * Introduced in version 2.5 */ - int fuse_start_cleanup_thread(struct fuse *fuse); + int (*fgetattr) (struct stat *, struct fuse_file_info *, fuse_timeouts_t *); /** - * Stop the cleanup thread when using option "remember". + * 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. * - * This is done automatically by fuse_loop_mt() - * @param fuse struct fuse pointer for fuse instance + * Introduced in version 2.6 */ - void fuse_stop_cleanup_thread(struct fuse *fuse); + int (*lock) (struct fuse_file_info *, int cmd, + struct flock *); /** - * Iterate over cache removing stale entries - * use in conjunction with "-oremember" + * Change the access and modification times of a file with + * nanosecond resolution * - * NOTE: This is already done for the standard sessions + * This supersedes the old utime() interface. New applications + * should use this. * - * @param fuse struct fuse pointer for fuse instance - * @return the number of seconds until the next cleanup + * See the utimensat(2) man page for details. + * + * Introduced in version 2.6 */ - int fuse_clean_cache(struct fuse *fuse); + int (*utimens)(const char *, const struct timespec tv[2]); + int (*futimens)(const struct fuse_file_info *ffi_, const struct timespec tv_[2]); - /* - * Stacking API + /** + * 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 + * + * Introduced in version 2.6 */ + int (*bmap) (const char *, size_t blocksize, uint64_t *idx); /** - * Fuse filesystem object + * Ioctl * - * This is opaque object represents a filesystem layer + * 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. + * + * Introduced in version 2.8 */ - struct fuse_fs; + int (*ioctl) (unsigned long cmd, + void *arg, + struct fuse_file_info *ffi, + unsigned int flags, + void *data, + uint32_t *out_bufsz); - /* - * These functions call the relevant filesystem operation, and return - * the result. + /** + * Poll for IO readiness events * - * If the operation is not defined, they return -ENOSYS, with the - * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir, - * fuse_fs_releasedir and fuse_fs_statfs, which return 0. + * 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. + * + * Introduced in version 2.8 */ + int (*poll) (struct fuse_file_info *, + struct fuse_pollhandle *ph, unsigned *reventsp); - int fuse_fs_getattr(struct fuse_fs *fs, - const char *path, - struct stat *buf, - fuse_timeouts_t *timeout); + /** 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. + * + * Introduced in version 2.9 + */ + int (*write_buf) (struct fuse_bufvec *buf, off_t off, + struct fuse_file_info *); - int fuse_fs_fgetattr(struct fuse_fs *fs, - struct stat *buf, - struct fuse_file_info *fi, - fuse_timeouts_t *timeout); + /** 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. + * + * Introduced in version 2.9 + */ + int (*read_buf) (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. + * + * Introduced in version 2.9 + */ + int (*flock) (struct fuse_file_info *, int op); - int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, - const char *newpath); - 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_link(struct fuse_fs *fs, const char *oldpath, const char *newpath); - int fuse_fs_release(struct fuse_fs *fs, - struct fuse_file_info *fi); - int fuse_fs_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi); - int fuse_fs_read(struct fuse_fs *fs, char *buf, size_t size, - off_t off, struct fuse_file_info *fi); - int fuse_fs_read_buf(struct fuse_fs *fs, - 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 *buf, - size_t size, off_t off, struct fuse_file_info *fi); - int fuse_fs_write_buf(struct fuse_fs *fs, - struct fuse_bufvec *buf, off_t off, - struct fuse_file_info *fi); - int fuse_fs_fsync(struct fuse_fs *fs, int datasync, - struct fuse_file_info *fi); - int fuse_fs_flush(struct fuse_fs *fs, - 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); - int fuse_fs_readdir(struct fuse_fs *fs, - struct fuse_file_info *fi, - fuse_dirents_t *buf); - int fuse_fs_fsyncdir(struct fuse_fs *fs, int datasync, - struct fuse_file_info *fi); - int fuse_fs_releasedir(struct fuse_fs *fs, - struct fuse_file_info *fi); - int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, - struct fuse_file_info *fi); - int fuse_fs_lock(struct fuse_fs *fs, - struct fuse_file_info *fi, int cmd, struct flock *lock); - int fuse_fs_flock(struct fuse_fs *fs, - struct fuse_file_info *fi, int op); - int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode); - int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid); - int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size); - int fuse_fs_ftruncate(struct fuse_fs *fs, off_t size, - struct fuse_file_info *fi); - int fuse_fs_utimens(struct fuse_fs *fs, const char *path, - const struct timespec tv[2]); - 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); - int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, - 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); - int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, - 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); - int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, - uint64_t *idx); - int fuse_fs_ioctl(struct fuse_fs *fs, unsigned long cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - void *data, uint32_t *out_bufsz); - int fuse_fs_poll(struct fuse_fs *fs, - struct fuse_file_info *fi, struct fuse_pollhandle *ph, - unsigned *reventsp); - int fuse_fs_fallocate(struct fuse_fs *fs, int mode, - off_t offset, off_t length, struct fuse_file_info *fi); - void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn); - void fuse_fs_destroy(struct fuse_fs *fs); - - int fuse_fs_prepare_hide(struct fuse_fs *fs, const char *path, uint64_t *fh); - int fuse_fs_free_hide(struct fuse_fs *fs, uint64_t fh); - ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, - struct fuse_file_info *fi_in, off_t off_in, - struct fuse_file_info *fi_out, off_t off_out, - size_t len, int flags); - - int fuse_notify_poll(struct fuse_pollhandle *ph); + /** + * 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. + * + * Introduced in version 2.9.1 + */ + int (*fallocate) (int, off_t, off_t,struct fuse_file_info *); /** - * Create a new fuse filesystem object + * Copy a range of data from one file to another * - * This is usually called from the factory of a fuse module to create - * a new instance of a filesystem. + * 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. * - * @param op the filesystem operations - * @param op_size the size of the fuse_operations structure - * @param user_data user data supplied in the context during the init() method - * @return a new filesystem object + * 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. */ - struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, - void *user_data); + ssize_t (*copy_file_range)(struct fuse_file_info *fi_in, + off_t offset_in, + struct fuse_file_info *fi_out, + off_t offset_out, + size_t size, + int flags); +}; + +/** 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; - /* ----------------------------------------------------------- * - * Advanced API for event handling, don't worry about this... * - * ----------------------------------------------------------- */ + /** User ID of the calling process */ + uid_t uid; - /* NOTE: the following functions are deprecated, and will be removed - from the 3.0 API. Use the lowlevel session functions instead */ + /** Group ID of the calling process */ + gid_t gid; - /** Function type used to process commands */ - typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); + /** Thread ID of the calling process */ + pid_t pid; - /** This is the part of fuse_main() before the event loop */ - struct fuse *fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - char **mountpoint, - void *user_data); + /** Private filesystem data */ + void *private_data; - /** This is the part of fuse_main() after the event loop */ - void fuse_teardown(struct fuse *fuse, char *mountpoint); + /** Umask of the calling process (introduced in version 2.8) */ + mode_t umask; +}; - /** Read a single command. If none are read, return NULL */ - struct fuse_cmd *fuse_read_cmd(struct fuse *f); +/** + * Main function of FUSE. + * + * This is for the lazy. This is all that has to be called from the + * main() function. + * + * This function does the following: + * - parses command line options (-d -s and -h) + * - passes relevant mount options to the fuse_mount() + * - installs signal handlers for INT, HUP, TERM and PIPE + * - registers an exit handler to unmount the filesystem on program exit + * - creates a fuse handle + * - registers the operations + * - calls either the single-threaded or the multi-threaded event loop + * + * Note: this is currently implemented as a macro. + * + * @param argc the argument counter passed to the main() function + * @param argv the argument vector passed to the main() function + * @param op the file system operation + * @param user_data user data supplied in the context during the init() method + * @return 0 on success, nonzero on failure + */ +/* + int fuse_main(int argc, char *argv[], const struct fuse_operations *op, + void *user_data); +*/ +#define fuse_main(argc, argv, op, user_data) \ + fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) - /** Process a single command */ - void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd); +/* ----------------------------------------------------------- * + * More detailed API * + * ----------------------------------------------------------- */ - /** Multi threaded event loop, which calls the custom command - processor function */ - int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data); +/** + * Create a new FUSE filesystem. + * + * @param ch the communication channel + * @param args argument vector + * @param op the filesystem operations + * @param op_size the size of the fuse_operations structure + * @param user_data user data supplied in the context during the init() method + * @return the created FUSE handle + */ +struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, + const struct fuse_operations *op, size_t op_size, + void *user_data); - /** Return the exited flag, which indicates if fuse_exit() has been - called */ - int fuse_exited(struct fuse *f); +/** + * Destroy the FUSE handle. + * + * The communication channel attached to the handle is also destroyed. + * + * NOTE: This function does not unmount the filesystem. If this is + * needed, call fuse_unmount() before calling this function. + * + * @param f the FUSE handle + */ +void fuse_destroy(struct fuse *f); - /** This function is obsolete and implemented as a no-op */ - void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); +/** + * Exit from event loop + * + * @param f the FUSE handle + */ +void fuse_exit(struct fuse *f); - /** Get session from fuse object */ - struct fuse_session *fuse_get_session(struct fuse *f); +int fuse_config_num_threads(const struct fuse *fuse_); -#ifdef __cplusplus -} -#endif +/** + * FUSE event loop with multiple threads + * + * Requests from the kernel are processed, and the appropriate + * operations are called. Request are processed in parallel by + * distributing them between multiple threads. + * + * Calling this function requires the pthreads library to be linked to + * the application. + * + * @param f the FUSE handle + * @return 0 if no error occurred, -1 otherwise + */ +int fuse_loop_mt(struct fuse *f); + +/** + * Get the current context + * + * The context is only valid for the duration of a filesystem + * operation, and thus must not be stored and used later. + * + * @return the context + */ +struct fuse_context *fuse_get_context(void); + +/** + * Check if the current request has already been interrupted + * + * @return 1 if the request has been interrupted, 0 otherwise + */ +int fuse_interrupted(void); + +/** + * Obsolete, doesn't do anything + * + * @return -EINVAL + */ +int fuse_invalidate(struct fuse *f, const char *path); + +/* Deprecated, don't use */ +int fuse_is_lib_option(const char *opt); + +/** + * The real main function + * + * 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 *user_data); + +/** + * Start the cleanup thread when using option "remember". + * + * This is done automatically by fuse_loop_mt() + * @param fuse struct fuse pointer for fuse instance + * @return 0 on success and -1 on error + */ +int fuse_start_cleanup_thread(struct fuse *fuse); + +/** + * Stop the cleanup thread when using option "remember". + * + * This is done automatically by fuse_loop_mt() + * @param fuse struct fuse pointer for fuse instance + */ +void fuse_stop_cleanup_thread(struct fuse *fuse); + +/** + * Iterate over cache removing stale entries + * use in conjunction with "-oremember" + * + * NOTE: This is already done for the standard sessions + * + * @param fuse struct fuse pointer for fuse instance + * @return the number of seconds until the next cleanup + */ +int fuse_clean_cache(struct fuse *fuse); + +/* + * Stacking API + */ + +/** + * Fuse filesystem object + * + * This is opaque object represents a filesystem layer + */ +struct fuse_fs; + +/* + * These functions call the relevant filesystem operation, and return + * the result. + * + * If the operation is not defined, they return -ENOSYS, with the + * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir, + * fuse_fs_releasedir and fuse_fs_statfs, which return 0. + */ + +int fuse_fs_getattr(struct fuse_fs *fs, + const char *path, + struct stat *buf, + fuse_timeouts_t *timeout); + +int fuse_fs_fgetattr(struct fuse_fs *fs, + struct stat *buf, + struct fuse_file_info *fi, + fuse_timeouts_t *timeout); + +int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, + const char *newpath); +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_link(struct fuse_fs *fs, const char *oldpath, const char *newpath); +int fuse_fs_release(struct fuse_fs *fs, + struct fuse_file_info *fi); +int fuse_fs_open(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); +int fuse_fs_read(struct fuse_fs *fs, char *buf, size_t size, + off_t off, struct fuse_file_info *fi); +int fuse_fs_read_buf(struct fuse_fs *fs, + 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 *buf, + size_t size, off_t off, struct fuse_file_info *fi); +int fuse_fs_write_buf(struct fuse_fs *fs, + struct fuse_bufvec *buf, off_t off, + struct fuse_file_info *fi); +int fuse_fs_fsync(struct fuse_fs *fs, int datasync, + struct fuse_file_info *fi); +int fuse_fs_flush(struct fuse_fs *fs, + 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); +int fuse_fs_readdir(struct fuse_fs *fs, + struct fuse_file_info *fi, + fuse_dirents_t *buf); +int fuse_fs_fsyncdir(struct fuse_fs *fs, int datasync, + struct fuse_file_info *fi); +int fuse_fs_releasedir(struct fuse_fs *fs, + struct fuse_file_info *fi); +int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, + struct fuse_file_info *fi); +int fuse_fs_lock(struct fuse_fs *fs, + struct fuse_file_info *fi, int cmd, struct flock *lock); +int fuse_fs_flock(struct fuse_fs *fs, + struct fuse_file_info *fi, int op); +int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode); +int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid); +int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size); +int fuse_fs_ftruncate(struct fuse_fs *fs, off_t size, + struct fuse_file_info *fi); +int fuse_fs_utimens(struct fuse_fs *fs, const char *path, + const struct timespec tv[2]); +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); +int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, + 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); +int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, + 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); +int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, + uint64_t *idx); +int fuse_fs_ioctl(struct fuse_fs *fs, unsigned long cmd, void *arg, + struct fuse_file_info *fi, unsigned int flags, + void *data, uint32_t *out_bufsz); +int fuse_fs_poll(struct fuse_fs *fs, + struct fuse_file_info *fi, struct fuse_pollhandle *ph, + unsigned *reventsp); +int fuse_fs_fallocate(struct fuse_fs *fs, int mode, + off_t offset, off_t length, struct fuse_file_info *fi); +void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn); +void fuse_fs_destroy(struct fuse_fs *fs); + +int fuse_fs_prepare_hide(struct fuse_fs *fs, const char *path, uint64_t *fh); +int fuse_fs_free_hide(struct fuse_fs *fs, uint64_t fh); +ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, + struct fuse_file_info *fi_in, off_t off_in, + struct fuse_file_info *fi_out, off_t off_out, + size_t len, int flags); + +int fuse_notify_poll(struct fuse_pollhandle *ph); + +/** + * Create a new fuse filesystem object + * + * This is usually called from the factory of a fuse module to create + * a new instance of a filesystem. + * + * @param op the filesystem operations + * @param op_size the size of the fuse_operations structure + * @param user_data user data supplied in the context during the init() method + * @return a new filesystem object + */ +struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, + void *user_data); + +/* ----------------------------------------------------------- * + * Advanced API for event handling, don't worry about this... * + * ----------------------------------------------------------- */ + +/* NOTE: the following functions are deprecated, and will be removed + from the 3.0 API. Use the lowlevel session functions instead */ + +/** Function type used to process commands */ +typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); + +/** This is the part of fuse_main() before the event loop */ +struct fuse *fuse_setup(int argc, char *argv[], + const struct fuse_operations *op, size_t op_size, + char **mountpoint, + void *user_data); + +/** This is the part of fuse_main() after the event loop */ +void fuse_teardown(struct fuse *fuse, char *mountpoint); + +/** Read a single command. If none are read, return NULL */ +struct fuse_cmd *fuse_read_cmd(struct fuse *f); + +/** Process a single command */ +void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd); + +/** Multi threaded event loop, which calls the custom command + processor function */ +int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data); + +/** Return the exited flag, which indicates if fuse_exit() has been + called */ +int fuse_exited(struct fuse *f); + +/** This function is obsolete and implemented as a no-op */ +void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); + +/** Get session from fuse object */ +struct fuse_session *fuse_get_session(struct fuse *f); + +EXTERN_C_END #endif /* _FUSE_H_ */ diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index 0de750ef..96c317f9 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -15,8 +15,10 @@ #ifndef _FUSE_COMMON_H_ #define _FUSE_COMMON_H_ +#include "extern_c.h" #include "fuse_opt.h" #include "fuse_timeouts.h" + #include #include @@ -37,76 +39,74 @@ #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 #define FUSE_MAX_MAX_PAGES 256 -#ifdef __cplusplus -extern "C" { -#endif - - /** - * Information about open files - * - * Changed in version 2.5 - */ - 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 - writepage */ - uint32_t writepage : 1; - - /** Can be filled in by open, to use direct I/O on this file. - Introduced in version 2.4 */ - uint32_t direct_io : 1; - - /** Can be filled in by open, to indicate, that cached file data - need not be invalidated. Introduced in version 2.4 */ - uint32_t keep_cache : 1; - - /** Indicates a flush operation. Set in flush operation, also - maybe set in highlevel lock operation and lowlevel release - operation. Introduced in version 2.6 */ - uint32_t flush : 1; - - /** Can be filled in by open, to indicate that the file is not - seekable. Introduced in version 2.8 */ - uint32_t 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(). Introduced in version - 2.9 */ - uint32_t flock_release : 1; - - /* Requests the kernel to cache entries returned by readdir */ - uint32_t cache_readdir : 1; - - uint32_t auto_cache : 1; - - /** File handle. May be filled in by filesystem in open(). - Available in all other file operations */ - uint64_t fh; - - /** Lock owner id. Available in locking operations and flush */ - uint64_t lock_owner; - }; - - /** - * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' - * - * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests - * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking - * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag - * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." - * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB - * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations - * FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device - * FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice() - * FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device - * FUSE_CAP_IOCTL_DIR: ioctl support on directories - * FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses - */ +EXTERN_C_BEGIN + +/** + * Information about open files + * + * Changed in version 2.5 + */ +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 + writepage */ + uint32_t writepage : 1; + + /** Can be filled in by open, to use direct I/O on this file. + Introduced in version 2.4 */ + uint32_t direct_io : 1; + + /** Can be filled in by open, to indicate, that cached file data + need not be invalidated. Introduced in version 2.4 */ + uint32_t keep_cache : 1; + + /** Indicates a flush operation. Set in flush operation, also + maybe set in highlevel lock operation and lowlevel release + operation. Introduced in version 2.6 */ + uint32_t flush : 1; + + /** Can be filled in by open, to indicate that the file is not + seekable. Introduced in version 2.8 */ + uint32_t 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(). Introduced in version + 2.9 */ + uint32_t flock_release : 1; + + /* Requests the kernel to cache entries returned by readdir */ + uint32_t cache_readdir : 1; + + uint32_t auto_cache : 1; + + /** File handle. May be filled in by filesystem in open(). + Available in all other file operations */ + uint64_t fh; + + /** Lock owner id. Available in locking operations and flush */ + uint64_t lock_owner; +}; + +/** + * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' + * + * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests + * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking + * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag + * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." + * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB + * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations + * FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device + * FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice() + * FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device + * FUSE_CAP_IOCTL_DIR: ioctl support on directories + * FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses + */ #define FUSE_CAP_ASYNC_READ (1 << 0) #define FUSE_CAP_POSIX_LOCKS (1 << 1) #define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3) @@ -127,16 +127,16 @@ extern "C" { #define FUSE_CAP_CACHE_SYMLINKS (1 << 20) #define FUSE_CAP_MAX_PAGES (1 << 21) - /** - * Ioctl flags - * - * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine - * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed - * FUSE_IOCTL_RETRY: retry with new iovecs - * FUSE_IOCTL_DIR: is a directory - * - * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs - */ +/** + * Ioctl flags + * + * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine + * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed + * FUSE_IOCTL_RETRY: retry with new iovecs + * FUSE_IOCTL_DIR: is a directory + * + * 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) @@ -144,282 +144,282 @@ extern "C" { #define FUSE_IOCTL_MAX_IOV 256 +/** + * Connection information, passed to the ->init() method + * + * Some of the elements are read-write, these can be changed to + * indicate the value requested by the filesystem. The requested + * value must usually be smaller than the indicated value. + */ +struct fuse_conn_info { /** - * Connection information, passed to the ->init() method - * - * Some of the elements are read-write, these can be changed to - * indicate the value requested by the filesystem. The requested - * value must usually be smaller than the indicated value. + * Major version of the protocol (read-only) */ - 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 readahead - */ - unsigned max_readahead; - - /** - * Capability flags, that the kernel supports - */ - unsigned capable; - - /** - * Capability flags, that the filesystem wants to enable - */ - unsigned want; - - /** - * Maximum number of backgrounded requests - */ - unsigned max_background; - - /** - * Kernel congestion threshold parameter - */ - unsigned congestion_threshold; - - /** - * Max pages - */ - uint16_t max_pages; - - /** - * For future use. - */ - unsigned reserved[22]; - }; - - struct fuse_session; - struct fuse_chan; - struct fuse_pollhandle; + unsigned proto_major; /** - * Create a FUSE mountpoint - * - * Returns a control file descriptor suitable for passing to - * fuse_new() - * - * @param mountpoint the mount point path - * @param args argument vector - * @return the communication channel on success, NULL on failure + * Minor version of the protocol (read-only) + */ + unsigned proto_minor; + + /** + * Maximum size of the write buffer + */ + unsigned max_write; + + /** + * Maximum readahead + */ + unsigned max_readahead; + + /** + * Capability flags, that the kernel supports */ - struct fuse_chan *fuse_mount(const char *mountpoint, - struct fuse_args *args); + unsigned capable; /** - * Umount a FUSE mountpoint + * Capability flags, that the filesystem wants to enable + */ + unsigned want; + + /** + * Maximum number of backgrounded requests + */ + unsigned max_background; + + /** + * Kernel congestion threshold parameter + */ + unsigned congestion_threshold; + + /** + * Max pages + */ + uint16_t max_pages; + + /** + * For future use. + */ + unsigned reserved[22]; +}; + +struct fuse_session; +struct fuse_chan; +struct fuse_pollhandle; + +/** + * Create a FUSE mountpoint + * + * Returns a control file descriptor suitable for passing to + * fuse_new() + * + * @param mountpoint the mount point path + * @param args argument vector + * @return the communication channel on success, NULL on failure + */ +struct fuse_chan *fuse_mount(const char *mountpoint, + struct fuse_args *args); + +/** + * Umount a FUSE mountpoint + * + * @param mountpoint the mount point path + * @param ch the communication channel + */ +void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); + +/** + * Parse common options + * + * The following options are parsed: + * + * '-f' foreground + * '-d' '-odebug' foreground, but keep the debug option + * '-h' '--help' help + * '-ho' help without header + * '-ofsname=..' file system name, if not present, then set to the program + * name + * + * All parameters may be NULL + * + * @param args argument vector + * @param mountpoint the returned mountpoint, should be freed after use + * @param foreground set to 1 if one of the relevant options is present + * @return 0 on success, -1 on failure + */ +int fuse_parse_cmdline(struct fuse_args *args, + char **mountpoint, + int *foreground); + +/** + * Go into the background + * + * @param foreground if true, stay in the foreground + * @return 0 on success, -1 on failure + */ +int fuse_daemonize(int foreground); + +/** + * Get the version of the library + * + * @return the version + */ +int fuse_version(void); + +/** + * Destroy poll handle + * + * @param ph the poll handle + */ +void fuse_pollhandle_destroy(struct fuse_pollhandle *ph); + +/* ----------------------------------------------------------- * + * Data buffer * + * ----------------------------------------------------------- */ + +/** + * Buffer flags + */ +enum fuse_buf_flags { + /** + * Buffer contains a file descriptor * - * @param mountpoint the mount point path - * @param ch the communication channel + * If this flag is set, the .fd field is valid, otherwise the + * .mem fields is valid. */ - void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); + FUSE_BUF_IS_FD = (1 << 1), /** - * Parse common options + * Seek on the file descriptor * - * The following options are parsed: + * 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 * - * '-f' foreground - * '-d' '-odebug' foreground, but keep the debug option - * '-h' '--help' help - * '-ho' help without header - * '-ofsname=..' file system name, if not present, then set to the program - * name + * 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) * - * All parameters may be NULL + * Always fall back to using read and write instead of + * splice(2) to copy data from one file descriptor to another. * - * @param args argument vector - * @param mountpoint the returned mountpoint, should be freed after use - * @param foreground set to 1 if one of the relevant options is present - * @return 0 on success, -1 on failure + * If this flag is not set, then only fall back if splice is + * unavailable. */ - int fuse_parse_cmdline(struct fuse_args *args, - char **mountpoint, - int *foreground); + FUSE_BUF_NO_SPLICE = (1 << 1), /** - * Go into the background + * Force splice * - * @param foreground if true, stay in the foreground - * @return 0 on success, -1 on failure + * Always use splice(2) to copy data from one file descriptor + * to another. If splice is not available, return -EINVAL. */ - int fuse_daemonize(int foreground); + FUSE_BUF_FORCE_SPLICE = (1 << 2), /** - * Get the version of the library + * Try to move data with splice. * - * @return the version + * 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. */ - int fuse_version(void); + FUSE_BUF_SPLICE_MOVE = (1 << 3), /** - * Destroy poll handle + * Don't block on the pipe when copying data with splice * - * @param ph the poll handle + * 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. */ - void fuse_pollhandle_destroy(struct fuse_pollhandle *ph); - - /* ----------------------------------------------------------- * - * Data buffer * - * ----------------------------------------------------------- */ + FUSE_BUF_SPLICE_NONBLOCK= (1 << 4), +}; + +/** + * Single data buffer + * + * Generic data buffer for I/O, extended attributes, etc... Data may + * 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 { - /** - * 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), - }; + enum fuse_buf_flags flags; /** - * Buffer copy flags + * Memory pointer + * + * Used unless FUSE_BUF_IS_FD flag is set. */ - 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), - }; + void *mem; /** - * Single data buffer + * File descriptor * - * Generic data buffer for I/O, extended attributes, etc... Data may - * be supplied as a memory pointer or as a file descriptor + * Used if FUSE_BUF_IS_FD flag is set. */ - 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; - }; + int fd; /** - * Data buffer vector - * - * An array of data buffers, each containing a memory pointer or a - * file descriptor. + * File position * - * Allocate dynamically to add more than one buffer. + * Used if FUSE_BUF_FD_SEEK flag is set. + */ + off_t pos; +}; + +/** + * Data buffer vector + * + * An array of data buffers, each containing a memory pointer or a + * file descriptor. + * + * 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_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]; - }; - - /* Initialize bufvec with a single buffer of given size */ + struct fuse_buf buf[1]; +}; + +/* Initialize bufvec with a single buffer of given size */ #define FUSE_BUFVEC_INIT(size__) \ ((struct fuse_bufvec) { \ /* .count= */ 1, \ @@ -434,52 +434,50 @@ extern "C" { } } \ } ) - /** - * Get total size of data in a fuse buffer vector - * - * @param bufv buffer vector - * @return size of data - */ - size_t fuse_buf_size(const struct fuse_bufvec *bufv); - - /** - * Copy data from one buffer vector to another - * - * @param dst destination buffer vector - * @param src source buffer vector - * @param flags flags controlling the copy - * @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); - - /* ----------------------------------------------------------- * - * 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 - * process until fuse_remove_signal_handlers() is called. - * - * @param se the session to exit - * @return 0 on success, -1 on failure - */ - int fuse_set_signal_handlers(struct fuse_session *se); - - /** - * Restore default signal handlers - * - * Resets global session. After this fuse_set_signal_handlers() may - * be called again. - * - * @param se the same session as given in fuse_set_signal_handlers() - */ - void fuse_remove_signal_handlers(struct fuse_session *se); - -#ifdef __cplusplus -} -#endif +/** + * Get total size of data in a fuse buffer vector + * + * @param bufv buffer vector + * @return size of data + */ +size_t fuse_buf_size(const struct fuse_bufvec *bufv); + +/** + * Copy data from one buffer vector to another + * + * @param dst destination buffer vector + * @param src source buffer vector + * @param flags flags controlling the copy + * @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); + +/* ----------------------------------------------------------- * + * 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 + * process until fuse_remove_signal_handlers() is called. + * + * @param se the session to exit + * @return 0 on success, -1 on failure + */ +int fuse_set_signal_handlers(struct fuse_session *se); + +/** + * Restore default signal handlers + * + * Resets global session. After this fuse_set_signal_handlers() may + * be called again. + * + * @param se the same session as given in fuse_set_signal_handlers() + */ +void fuse_remove_signal_handlers(struct fuse_session *se); + +EXTERN_C_END #endif /* _FUSE_COMMON_H_ */ diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index ffb7e1f0..133ec1c5 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -23,6 +23,7 @@ #define FUSE_USE_VERSION 24 #endif +#include "extern_c.h" #include "fuse_common.h" #include @@ -33,1780 +34,1700 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN - /* ----------------------------------------------------------- * - * Miscellaneous definitions * - * ----------------------------------------------------------- */ +/* ----------------------------------------------------------- * + * Miscellaneous definitions * + * ----------------------------------------------------------- */ - /** The node ID of the root inode */ +/** The node ID of the root inode */ #define FUSE_ROOT_ID 1 - /** Inode number type */ - typedef uint64_t fuse_ino_t; +/** Inode number type */ +typedef uint64_t fuse_ino_t; - /** Request pointer type */ - typedef struct fuse_req *fuse_req_t; +/** Request pointer type */ +typedef struct fuse_req *fuse_req_t; - /** - * Session - * - * This provides hooks for processing requests, and exiting - */ - struct fuse_session; +/** + * Session + * + * This provides hooks for processing requests, and exiting + */ +struct fuse_session; - /** - * Channel - * - * A communication channel, providing hooks for sending and receiving - * messages - */ - struct fuse_chan; - - /** 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. - * - * The generation must be non-zero, otherwise FUSE will treat - * it as an error. - * - */ - 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; - - fuse_timeouts_t timeout; - }; - - /** Additional context associated with requests */ - struct fuse_ctx - { - /** User ID of the calling process */ - uid_t uid; - - /** Group ID of the calling process */ - gid_t gid; - - /** Thread ID of the calling process */ - pid_t pid; - - /** Umask of the calling process (introduced in version 2.8) */ - mode_t umask; - }; - - struct fuse_forget_data - { - fuse_ino_t ino; - uint64_t nlookup; - }; - - /* ----------------------------------------------------------- * - * Request methods and replies * - * ----------------------------------------------------------- */ +/** + * Channel + * + * A communication channel, providing hooks for sending and receiving + * messages + */ +struct fuse_chan; - /** - * Low level filesystem operations - * - * Most of the methods (with the exception of init and destroy) - * receive a request handle (fuse_req_t) as their first argument. - * This handle must be passed to one of the specified reply functions. - * - * This may be done inside the method invocation, or after the call - * has returned. The request handle is valid until one of the reply - * functions is called. - * - * Other pointer arguments (name, fuse_file_info, etc) are not valid - * after the call has returned, so if they are needed later, their - * contents have to be copied. - * - * The filesystem sometimes needs to handle a return value of -ENOENT - * from the reply function, which means, that the request was - * interrupted, and the reply discarded. For example if - * fuse_reply_open() return -ENOENT means, that the release method for - * this file will not be called. - */ - struct fuse_lowlevel_ops - { - /** - * Initialize filesystem - * - * Called before any other filesystem method - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_new() - */ - void (*init) (void *userdata, struct fuse_conn_info *conn); - - /** - * Clean up filesystem - * - * Called on filesystem exit - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_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, remdir 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 - * - * 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); +/** 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; - /** - * Set file attributes - * - * In the 'attr' argument only members indicated by the 'to_set' - * bitmask contain valid values. Other members contain undefined - * values. - * - * 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 - * - * Changed in version 2.5: - * file information filled in for ftruncate - */ - 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). - * - * 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); - - /** - * 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 (with the exception of O_CREAT, O_EXCL, O_NOCTTY and - * O_TRUNC) are available in fi->flags. - * - * 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 for more details. - * - * 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. - * - * 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. - * - * If the filesystem supports file locking operations (setlk, - * getlk) it should remove all locks belonging to 'fi->owner'. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*flush) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); +/** 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. + * + * The generation must be non-zero, otherwise FUSE will treat + * it as an error. + * + */ +uint64_t generation; - /** - * 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. - * - * 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. - * - * 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); +/** 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; - /** - * 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). - * - * Filesystem may also implement stateless directory I/O and not - * store anything in fi->fh, though that makes it impossible to - * implement standard conforming directory stream operations in - * case the contents of the directory can change between opendir - * and releasedir. - * - * 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); +fuse_timeouts_t timeout; +}; - /** - * 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. - * - * 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 *llffi); - - void (*readdir_plus)(fuse_req_t req, fuse_ino_t ino, - size_t size, off_t off, - struct fuse_file_info *ffi); - - /** - * Release an open directory - * - * For every opendir call there will be exactly one releasedir - * call. - * - * 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. - * - * 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); +/** Additional context associated with requests */ +struct fuse_ctx +{ +/** User ID of the calling process */ +uid_t uid; + +/** Group ID of the calling process */ +gid_t gid; + +/** Thread ID of the calling process */ +pid_t pid; + +/** Umask of the calling process (introduced in version 2.8) */ +mode_t umask; +}; + +struct fuse_forget_data +{ +fuse_ino_t ino; +uint64_t nlookup; +}; + +/* ----------------------------------------------------------- * + * Request methods and replies * + * ----------------------------------------------------------- */ + +/** + * Low level filesystem operations + * + * Most of the methods (with the exception of init and destroy) + * receive a request handle (fuse_req_t) as their first argument. + * This handle must be passed to one of the specified reply functions. + * + * This may be done inside the method invocation, or after the call + * has returned. The request handle is valid until one of the reply + * functions is called. + * + * Other pointer arguments (name, fuse_file_info, etc) are not valid + * after the call has returned, so if they are needed later, their + * contents have to be copied. + * + * The filesystem sometimes needs to handle a return value of -ENOENT + * from the reply function, which means, that the request was + * interrupted, and the reply discarded. For example if + * fuse_reply_open() return -ENOENT means, that the release method for + * this file will not be called. + */ +struct fuse_lowlevel_ops +{ +/** + * Initialize filesystem + * + * Called before any other filesystem method + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ +void (*init) (void *userdata, struct fuse_conn_info *conn); + +/** + * Clean up filesystem + * + * Called on filesystem exit + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ +void (*destroy) (void *userdata); - /** - * 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 - * - * 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. - * - * 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. - * - * 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 - * - * 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() 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 - * - * Introduced in version 2.5 - * - * 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. - * - * Open flags (with the exception of O_NOCTTY) are available in - * fi->flags. - * - * 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). - * - * 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 for more details. - * - * 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. - * - * Introduced in version 2.5 - * - * 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 - * - * Introduced in version 2.6 - * - * 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. - * - * Introduced in version 2.6 - * - * 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 - * - * Introduced in version 2.6 - * - * 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. - * - * Introduced in version 2.8 - * - * 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 - */ - void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned long cmd, void *arg, - struct fuse_file_info *fi, unsigned flags, - const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz); - - /** - * Poll for IO readiness - * - * Introduced in version 2.8 - * - * Note: If ph is non-NULL, the client should notify - * when IO readiness events occur by calling - * fuse_lowelevel_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. - * - * 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]). - * - * Introduced in version 2.9 - * - * 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 - * - * Introduced in version 2.9 - * - * 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. - * - * Introduced in version 2.9 - * - * 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. - * - * Introduced in version 2.9 - * - * 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. - * - * Introduced in version 2.9 - * - * 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); - - /** - * 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 of 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 of 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); - }; +/** + * 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, remdir 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); /** - * Reply with an error code or success + * Get file attributes * - * Possible requests: - * all except forget - * - * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, - * removexattr and setlk may send a zero code + * Valid replies: + * fuse_reply_attr + * fuse_reply_err * * @param req request handle - * @param err the positive error value, or zero for success - * @return zero for success, -errno for failure to send reply + * @param ino the inode number + * @param fi for future use, currently always NULL */ - int fuse_reply_err(fuse_req_t req, int err); + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); /** - * Don't send reply + * Set file attributes + * + * In the 'attr' argument only members indicated by the 'to_set' + * bitmask contain valid values. Other members contain undefined + * values. * - * Possible requests: - * forget + * 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 + * + * Changed in version 2.5: + * file information filled in for ftruncate */ - void fuse_reply_none(fuse_req_t req); + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); /** - * Reply with a directory entry - * - * Possible requests: - * lookup, mknod, mkdir, symlink, link + * Read symbolic link * - * Side effects: - * increments the lookup count on success + * Valid replies: + * fuse_reply_readlink + * fuse_reply_err * * @param req request handle - * @param e the entry parameters - * @return zero for success, -errno for failure to send reply + * @param ino the inode number */ - int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); + void (*readlink) (fuse_req_t req, fuse_ino_t ino); /** - * Reply with a directory entry and open parameters - * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache + * Create file node * - * Possible requests: - * create + * Create a regular file, character device, block device, fifo or + * socket node. * - * Side effects: - * increments the lookup count on success + * Valid replies: + * fuse_reply_entry + * fuse_reply_err * * @param req request handle - * @param e the entry parameters - * @param fi file information - * @return zero for success, -errno for failure to send reply + * @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) */ - int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, - const struct fuse_file_info *fi); + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); /** - * Reply with attributes + * Create a directory * - * Possible requests: - * getattr, setattr + * Valid replies: + * fuse_reply_entry + * fuse_reply_err * * @param req request handle - * @param attr the attributes - * @param attr_timeout validity timeout (in seconds) for the attributes - * @return zero for success, -errno for failure to send reply + * @param parent inode number of the parent directory + * @param name to create + * @param mode with which to create the new file */ - int fuse_reply_attr(fuse_req_t req, - const struct stat *attr, - const uint64_t timeout); + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); /** - * Reply with the contents of a symbolic link + * Remove a file * - * Possible requests: - * readlink + * 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 link symbolic link contents - * @return zero for success, -errno for failure to send reply + * @param parent inode number of the parent directory + * @param name to remove */ - int fuse_reply_readlink(fuse_req_t req, const char *link); + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); /** - * Reply with open parameters + * Remove a directory * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache + * 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). * - * Possible requests: - * open, opendir + * Valid replies: + * fuse_reply_err * * @param req request handle - * @param fi file information - * @return zero for success, -errno for failure to send reply + * @param parent inode number of the parent directory + * @param name to remove */ - int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); /** - * Reply with number of bytes written + * Create a symbolic link * - * Possible requests: - * write + * Valid replies: + * fuse_reply_entry + * fuse_reply_err * * @param req request handle - * @param count the number of bytes written - * @return zero for success, -errno for failure to send reply + * @param link the contents of the symbolic link + * @param parent inode number of the parent directory + * @param name to create */ - int fuse_reply_write(fuse_req_t req, size_t count); + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); - /** - * Reply with data + /** Rename a file * - * Possible requests: - * read, readdir, getxattr, listxattr + * 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). + * + * Valid replies: + * fuse_reply_err * * @param req request handle - * @param buf buffer containing data - * @param size the size of data in bytes - * @return zero for success, -errno for failure to send reply + * @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 */ - int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); /** - * Reply with data copied/moved from buffer(s) + * Create a hard link * - * Possible requests: - * read, readdir, getxattr, listxattr + * Valid replies: + * fuse_reply_entry + * fuse_reply_err * * @param req request handle - * @param bufv buffer vector - * @param flags flags controlling the copy - * @return zero for success, -errno for failure to send reply + * @param ino the old inode number + * @param newparent inode number of the new parent directory + * @param newname new name to create */ - int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, - enum fuse_buf_copy_flags flags); + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); /** - * Reply with data vector + * Open a file * - * Possible requests: - * read, readdir, getxattr, listxattr + * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and + * O_TRUNC) are available in fi->flags. * - * @param req request handle - * @param iov the vector containing the data - * @param count the size of vector - * @return zero for success, -errno for failure to send reply - */ - int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); - - /** - * Reply with filesystem statistics + * 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 for more details. * - * Possible requests: - * statfs + * Valid replies: + * fuse_reply_open + * fuse_reply_err * * @param req request handle - * @param stbuf filesystem statistics - * @return zero for success, -errno for failure to send reply + * @param ino the inode number + * @param fi file information */ - int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); /** - * Reply with needed buffer size + * 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. * - * Possible requests: - * getxattr, listxattr + * Valid replies: + * fuse_reply_buf + * fuse_reply_iov + * fuse_reply_data + * fuse_reply_err * * @param req request handle - * @param count the buffer size needed in bytes - * @return zero for success, -errno for failure to send reply + * @param ino the inode number + * @param size number of bytes to read + * @param off offset to read from + * @param fi file information */ - int fuse_reply_xattr(fuse_req_t req, size_t count); + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); /** - * Reply with file lock information + * 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. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. * - * Possible requests: - * getlk + * Valid replies: + * fuse_reply_write + * fuse_reply_err * * @param req request handle - * @param lock the lock information - * @return zero for success, -errno for failure to send reply + * @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 */ - int fuse_reply_lock(fuse_req_t req, const struct flock *lock); + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); /** - * Reply with block index + * 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. * - * Possible requests: - * bmap + * 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. + * + * If the filesystem supports file locking operations (setlk, + * getlk) it should remove all locks belonging to 'fi->owner'. + * + * Valid replies: + * fuse_reply_err * * @param req request handle - * @param idx block index within device - * @return zero for success, -errno for failure to send reply + * @param ino the inode number + * @param fi file information */ - int fuse_reply_bmap(fuse_req_t req, uint64_t idx); + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); /** - * Reply to ask for data fetch and output buffer preparation. ioctl - * will be retried with the specified input data fetched and output - * buffer prepared. + * 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. * - * Possible requests: - * ioctl + * 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 in_iov iovec specifying data to fetch from the caller - * @param in_count number of entries in in_iov - * @param out_iov iovec specifying addresses to write output to - * @param out_count number of entries in out_iov - * @return zero for success, -errno for failure to send reply + * @param ino the inode number + * @param fi file information */ - 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); + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); /** - * Reply to finish ioctl + * Synchronize file contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data. * - * Possible requests: - * ioctl + * Valid replies: + * fuse_reply_err * * @param req request handle - * @param result result to be passed to the caller - * @param buf buffer containing output data - * @param size length of output data + * @param ino the inode number + * @param datasync flag indicating if only data should be flushed + * @param fi file information */ - int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size); + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); /** - * Reply to finish ioctl with iov buffer + * 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). * - * Possible requests: - * ioctl + * Filesystem may also implement stateless directory I/O and not + * store anything in fi->fh, though that makes it impossible to + * implement standard conforming directory stream operations in + * case the contents of the directory can change between opendir + * and releasedir. + * + * Valid replies: + * fuse_reply_open + * fuse_reply_err * * @param req request handle - * @param result result to be passed to the caller - * @param iov the vector containing the data - * @param count the size of vector + * @param ino the inode number + * @param fi file information */ - int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, - int count); + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); /** - * Reply with poll result event mask + * 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. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_data + * fuse_reply_err * * @param req request handle - * @param revents poll result event mask + * @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 */ - int fuse_reply_poll(fuse_req_t req, unsigned revents); + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *llffi); - /* ----------------------------------------------------------- * - * Notification * - * ----------------------------------------------------------- */ + void (*readdir_plus)(fuse_req_t req, fuse_ino_t ino, + size_t size, off_t off, + struct fuse_file_info *ffi); /** - * Notify IO readiness event + * Release an open directory + * + * For every opendir call there will be exactly one releasedir + * call. * - * For more information, please read comment for poll operation. + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. * - * @param ph poll handle to notify IO readiness event for + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information */ - int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); /** - * Notify to invalidate cache for an inode + * 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. * - * @param ch the channel through which to send the invalidation + * Valid replies: + * fuse_reply_err + * + * @param req request handle * @param ino the inode number - * @param off the offset in the inode where to start invalidating - * or negative to invalidate attributes only - * @param len the amount of cache to invalidate or 0 for all - * @return zero for success, -errno for failure + * @param datasync flag indicating if only data should be flushed + * @param fi file information */ - int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, - off_t off, off_t len); + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); /** - * Notify to invalidate parent attributes and the dentry matching - * parent/name + * Get file system statistics * - * To avoid a deadlock don't call this function from a filesystem operation and - * don't call it with a lock held that can also be held by a filesystem - * operation. + * Valid replies: + * fuse_reply_statfs + * fuse_reply_err * - * @param ch the channel through which to send the invalidation - * @param parent inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure + * @param req request handle + * @param ino the inode number, zero means "undefined" */ - int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, - const char *name, size_t namelen); + void (*statfs) (fuse_req_t req, fuse_ino_t ino); /** - * Notify to invalidate parent attributes and delete the dentry matching - * parent/name if the dentry's inode number matches child (otherwise it - * will invalidate the matching dentry). - * - * To avoid a deadlock don't call this function from a filesystem operation and - * don't call it with a lock held that can also be held by a filesystem - * operation. + * Set an extended attribute * - * @param ch the channel through which to send the notification - * @param parent inode number - * @param child inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure + * Valid replies: + * fuse_reply_err */ - int fuse_lowlevel_notify_delete(struct fuse_chan *ch, - fuse_ino_t parent, fuse_ino_t child, - const char *name, size_t namelen); + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); /** - * Store data to the kernel buffers + * Get an extended attribute * - * Synchronously store data in the kernel buffers belonging to the - * given inode. The stored data is marked up-to-date (no read will be - * performed against it, unless it's invalidated or evicted from the - * cache). + * If size is zero, the size of the value should be sent with + * fuse_reply_xattr. * - * If the stored data overflows the current file size, then the size - * is extended, similarly to a write(2) on the filesystem. + * If the size is non-zero, and the value fits in the buffer, the + * value should be sent with fuse_reply_buf. * - * If this function returns an error, then the store wasn't fully - * completed, but it may have been partially completed. + * If the size is too small for the value, the ERANGE error should + * be sent. * - * @param ch the channel through which to send the invalidation + * Valid replies: + * fuse_reply_buf + * fuse_reply_data + * fuse_reply_xattr + * fuse_reply_err + * + * @param req request handle * @param ino the inode number - * @param offset the starting offset into the file to store to - * @param bufv buffer vector - * @param flags flags controlling the copy - * @return zero for success, -errno for failure + * @param name of the extended attribute + * @param size maximum size of the value to send */ - int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, - off_t offset, struct fuse_bufvec *bufv, - enum fuse_buf_copy_flags flags); + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + /** - * Retrieve data from the kernel buffers + * List extended attribute names * - * Retrieve data in the kernel buffers belonging to the given inode. - * If successful then the retrieve_reply() method will be called with - * the returned data. + * If size is zero, the total size of the attribute list should be + * sent with fuse_reply_xattr. * - * Only present pages are returned in the retrieve reply. Retrieving - * stops when it finds a non-present page and only data prior to that is - * returned. + * 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 this function returns an error, then the retrieve will not be - * completed and no reply will be sent. + * If the size is too small for the list, the ERANGE error should + * be sent. * - * This function doesn't change the dirty state of pages in the kernel - * buffer. For dirty pages the write() method will be called - * regardless of having been retrieved previously. + * Valid replies: + * fuse_reply_buf + * fuse_reply_data + * fuse_reply_xattr + * fuse_reply_err * - * @param ch the channel through which to send the invalidation + * @param req request handle * @param ino the inode number - * @param size the number of bytes to retrieve - * @param offset the starting offset into the file to retrieve from - * @param cookie user data to supply to the reply callback - * @return zero for success, -errno for failure + * @param size maximum size of the list to send */ - int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, - size_t size, off_t offset, void *cookie); - - - /* ----------------------------------------------------------- * - * Utility functions * - * ----------------------------------------------------------- */ + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); /** - * Get the userdata from the request + * Remove an extended attribute + * + * Valid replies: + * fuse_reply_err * * @param req request handle - * @return the user data passed to fuse_lowlevel_new() + * @param ino the inode number + * @param name of the extended attribute */ - void *fuse_req_userdata(fuse_req_t req); + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); /** - * Get the context from the request + * 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 * - * The pointer returned by this function will only be valid for the - * request's lifetime + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_err * * @param req request handle - * @return the context structure + * @param ino the inode number + * @param mask requested access mode */ - const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); /** - * Get the current supplementary group IDs for the specified request + * Create and open a file + * + * If the file does not exist, first create it with the specified + * mode, and then open it. + * + * Open flags (with the exception of O_NOCTTY) are available in + * fi->flags. * - * Similar to the getgroups(2) system call, except the return value is - * always the total number of group IDs, even if it is larger than the - * specified size. + * 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). * - * The current fuse kernel module in linux (as of 2.6.30) doesn't pass - * the group list to userspace, hence this function needs to parse - * "/proc/$TID/task/$TID/status" to get the group IDs. + * 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 for more details. * - * This feature may not be supported on all operating systems. In - * such a case this function will return -ENOSYS. + * 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. + * + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_create + * fuse_reply_err * * @param req request handle - * @param size size of given array - * @param list array of group IDs to be filled in - * @return the total number of supplementary group IDs or -errno on failure + * @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 */ - int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]); + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi); /** - * Callback function for an interrupt + * Test for a POSIX file lock * - * @param req interrupted request - * @param data user data - */ - typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); - - /** - * Register/unregister callback for an interrupt + * Introduced in version 2.6 * - * If an interrupt has already happened, then the callback function is - * called from within this function, hence it's not possible for - * interrupts to be lost. + * Valid replies: + * fuse_reply_lock + * fuse_reply_err * * @param req request handle - * @param func the callback function or NULL for unregister - * @param data user data passed to the callback function + * @param ino the inode number + * @param fi file information + * @param lock the region/type to test */ - void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, - void *data); + void (*getlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock); /** - * Check if a request has already been interrupted + * 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. + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_err * * @param req request handle - * @return 1 if the request has been interrupted, 0 otherwise + * @param ino the inode number + * @param fi file information + * @param lock the region/type to set + * @param sleep locking operation may sleep */ - int fuse_req_interrupted(fuse_req_t req); - - /* ----------------------------------------------------------- * - * Filesystem setup * - * ----------------------------------------------------------- */ - - /* Deprecated, don't use */ - int fuse_lowlevel_is_lib_option(const char *opt); + void (*setlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, + struct flock *lock, int sleep); /** - * Create a low level session + * Map block index within file to block index within device * - * @param args argument vector - * @param op the low level filesystem operations - * @param op_size sizeof(struct fuse_lowlevel_ops) - * @param userdata user data - * @return the created session object, or NULL on failure - */ - struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); - - /* ----------------------------------------------------------- * - * Session interface * - * ----------------------------------------------------------- */ - - /** - * Session operations + * Note: This makes sense only for block device backed filesystems + * mounted with the 'blkdev' option + * + * Introduced in version 2.6 * - * This is used in session creation + * 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 */ - struct fuse_session_ops - { - /** - * Hook to process a request (mandatory) - * - * @param data user data passed to fuse_session_new() - * @param buf buffer containing the raw request - * @param len request length - * @param ch channel on which the request was received - */ - void (*process) (void *data, const char *buf, size_t len, - struct fuse_chan *ch); - - /** - * Hook for session exit and reset (optional) - * - * @param data user data passed to fuse_session_new() - * @param val exited status (1 - exited, 0 - not exited) - */ - void (*exit) (void *data, int val); - - /** - * Hook for querying the current exited status (optional) - * - * @param data user data passed to fuse_session_new() - * @return 1 if exited, 0 if not exited - */ - int (*exited) (void *data); - - /** - * Hook for cleaning up the channel on destroy (optional) - * - * @param data user data passed to fuse_session_new() - */ - void (*destroy) (void *data); - }; + void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, + uint64_t idx); /** - * Create a new session + * Ioctl * - * @param op session operations - * @param data user data - * @return new session object, or NULL on failure + * 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. + * + * Introduced in version 2.8 + * + * 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 */ - struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); + void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned long cmd, void *arg, + struct fuse_file_info *fi, unsigned flags, + const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz); /** - * Assign a channel to a session + * Poll for IO readiness * - * Note: currently only a single channel may be assigned. This may - * change in the future + * Introduced in version 2.8 * - * If a session is destroyed, the assigned channel is also destroyed + * Note: If ph is non-NULL, the client should notify + * when IO readiness events occur by calling + * fuse_lowelevel_notify_poll() with the specified ph. * - * @param se the session - * @param ch the channel + * 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. + * + * 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 fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); + void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, + struct fuse_pollhandle *ph); /** - * Remove a channel from a session + * 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. * - * If the channel is not assigned to a session, then this is a no-op + * 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]). * - * @param ch the channel to remove + * Introduced in version 2.9 + * + * 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 fuse_session_remove_chan(struct fuse_chan *ch); + void (*write_buf) (fuse_req_t req, fuse_ino_t ino, + struct fuse_bufvec *bufv, off_t off, + struct fuse_file_info *fi); /** - * Iterate over the channels assigned to a session + * Callback function for the retrieve request + * + * Introduced in version 2.9 * - * The iterating function needs to start with a NULL channel, and - * after that needs to pass the previously returned channel to the - * function. + * Valid replies: + * fuse_reply_none * - * @param se the session - * @param ch the previous channel, or NULL - * @return the next channel, or NULL if no more channels exist + * @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 */ - struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, - struct fuse_chan *ch); + void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino, + off_t offset, struct fuse_bufvec *bufv); /** - * Process a raw request + * Forget about multiple inodes * - * @param se the session - * @param buf buffer containing the raw request - * @param len request length - * @param ch channel on which the request was received + * See description of the forget function for more + * information. + * + * Introduced in version 2.9 + * + * Valid replies: + * fuse_reply_none + * + * @param req request handle */ - void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, - struct fuse_chan *ch); + void (*forget_multi) (fuse_req_t req, size_t count, + struct fuse_forget_data *forgets); /** - * Process a raw request supplied in a generic buffer + * Acquire, modify or release a BSD file lock * - * This is a more generic version of fuse_session_process(). The - * fuse_buf may contain a memory buffer or a pipe file descriptor. + * 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. * - * @param se the session - * @param buf the fuse_buf containing the request - * @param ch channel on which the request was received + * Introduced in version 2.9 + * + * 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 fuse_session_process_buf(struct fuse_session *se, - const struct fuse_buf *buf, struct fuse_chan *ch); + void (*flock) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, int op); /** - * Receive a raw request supplied in a generic buffer + * 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. * - * This is a more generic version of fuse_chan_recv(). The fuse_buf - * supplied to this function contains a suitably allocated memory - * buffer. This may be overwritten with a file descriptor buffer. + * Introduced in version 2.9 * - * @param se the session - * @param buf the fuse_buf to store the request in - * @param chp pointer to the channel - * @return the actual size of the raw request, or -errno on error + * 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) */ - int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp); + void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, + off_t offset, off_t length, struct fuse_file_info *fi); /** - * Destroy a session + * 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 se the session + * @param req request handle + * @param ino_in the inode number of 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 of 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 fuse_session_destroy(struct fuse_session *se); + 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); +}; + +/** + * Reply with an error code or success + * + * Possible requests: + * all except forget + * + * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, + * removexattr and setlk may send a zero code + * + * @param req request handle + * @param err the positive error value, or zero for success + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_err(fuse_req_t req, int err); +/** + * Don't send reply + * + * Possible requests: + * forget + * + * @param req request handle + */ +void fuse_reply_none(fuse_req_t req); + +/** + * Reply with a directory entry + * + * Possible requests: + * lookup, mknod, mkdir, symlink, link + * + * Side effects: + * increments the lookup count on success + * + * @param req request handle + * @param e the entry parameters + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); + +/** + * Reply with a directory entry and open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * create + * + * Side effects: + * increments the lookup count on success + * + * @param req request handle + * @param e the entry parameters + * @param fi file information + * @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); + +/** + * Reply with attributes + * + * Possible requests: + * getattr, setattr + * + * @param req request handle + * @param attr 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, + const uint64_t timeout); + +/** + * Reply with the contents of a symbolic link + * + * Possible requests: + * readlink + * + * @param req request handle + * @param link symbolic link contents + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_readlink(fuse_req_t req, const char *link); + +/** + * Reply with open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * open, opendir + * + * @param req request handle + * @param fi file information + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); + +/** + * Reply with number of bytes written + * + * Possible requests: + * write + * + * @param req request handle + * @param count the number of bytes written + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_write(fuse_req_t req, size_t count); + +/** + * Reply with data + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param buf buffer containing data + * @param size the size of data in bytes + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); + +/** + * Reply with data copied/moved from buffer(s) + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param bufv buffer vector + * @param flags flags controlling the copy + * @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); + +/** + * Reply with data vector + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param iov the vector containing the data + * @param count the size of vector + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); + +/** + * Reply with filesystem statistics + * + * Possible requests: + * statfs + * + * @param req request handle + * @param stbuf filesystem statistics + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); + +/** + * Reply with needed buffer size + * + * Possible requests: + * getxattr, listxattr + * + * @param req request handle + * @param count the buffer size needed in bytes + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_xattr(fuse_req_t req, size_t count); + +/** + * Reply with file lock information + * + * Possible requests: + * getlk + * + * @param req request handle + * @param lock the lock information + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_lock(fuse_req_t req, const struct flock *lock); + +/** + * Reply with block index + * + * Possible requests: + * bmap + * + * @param req request handle + * @param idx block index within device + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_bmap(fuse_req_t req, uint64_t idx); + +/** + * Reply to ask for data fetch and output buffer preparation. ioctl + * will be retried with the specified input data fetched and output + * buffer prepared. + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param in_iov iovec specifying data to fetch from the caller + * @param in_count number of entries in in_iov + * @param out_iov iovec specifying addresses to write output to + * @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); + +/** + * Reply to finish ioctl + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param result result to be passed to the caller + * @param buf buffer containing output data + * @param size length of output data + */ +int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size); + +/** + * Reply to finish ioctl with iov buffer + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param result result to be passed to the caller + * @param iov the vector containing the data + * @param count the size of vector + */ +int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, + int count); + +/** + * Reply with poll result event mask + * + * @param req request handle + * @param revents poll result event mask + */ +int fuse_reply_poll(fuse_req_t req, unsigned revents); + +/* ----------------------------------------------------------- * + * Notification * + * ----------------------------------------------------------- */ + +/** + * Notify IO readiness event + * + * For more information, please read comment for poll operation. + * + * @param ph poll handle to notify IO readiness event for + */ +int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); + +/** + * Notify to invalidate cache for an inode + * + * @param ch the channel through which to send the invalidation + * @param ino the inode number + * @param off the offset in the inode where to start invalidating + * or negative to invalidate attributes only + * @param len the amount of cache to invalidate or 0 for all + * @return zero for success, -errno for failure + */ +int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, + off_t off, off_t len); + +/** + * Notify to invalidate parent attributes and the dentry matching + * parent/name + * + * To avoid a deadlock don't call this function from a filesystem operation and + * don't call it with a lock held that can also be held by a filesystem + * operation. + * + * @param ch the channel through which to send the invalidation + * @param parent inode number + * @param name file name + * @param namelen strlen() of file name + * @return zero for success, -errno for failure + */ +int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, + const char *name, size_t namelen); + +/** + * Notify to invalidate parent attributes and delete the dentry matching + * parent/name if the dentry's inode number matches child (otherwise it + * will invalidate the matching dentry). + * + * To avoid a deadlock don't call this function from a filesystem operation and + * don't call it with a lock held that can also be held by a filesystem + * operation. + * + * @param ch the channel through which to send the notification + * @param parent inode number + * @param child inode number + * @param name file name + * @param namelen strlen() of file name + * @return zero for success, -errno for failure + */ +int fuse_lowlevel_notify_delete(struct fuse_chan *ch, + fuse_ino_t parent, fuse_ino_t child, + const char *name, size_t namelen); + +/** + * Store data to the kernel buffers + * + * Synchronously store data in the kernel buffers belonging to the + * given inode. The stored data is marked up-to-date (no read will be + * performed against it, unless it's invalidated or evicted from the + * cache). + * + * If the stored data overflows the current file size, then the size + * is extended, similarly to a write(2) on the filesystem. + * + * If this function returns an error, then the store wasn't fully + * completed, but it may have been partially completed. + * + * @param ch the channel through which to send the invalidation + * @param ino the inode number + * @param offset the starting offset into the file to store to + * @param bufv buffer vector + * @param flags flags controlling the copy + * @return zero for success, -errno for failure + */ +int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, + off_t offset, struct fuse_bufvec *bufv, + enum fuse_buf_copy_flags flags); +/** + * Retrieve data from the kernel buffers + * + * Retrieve data in the kernel buffers belonging to the given inode. + * If successful then the retrieve_reply() method will be called with + * the returned data. + * + * Only present pages are returned in the retrieve reply. Retrieving + * stops when it finds a non-present page and only data prior to that is + * returned. + * + * If this function returns an error, then the retrieve will not be + * completed and no reply will be sent. + * + * This function doesn't change the dirty state of pages in the kernel + * buffer. For dirty pages the write() method will be called + * regardless of having been retrieved previously. + * + * @param ch the channel through which to send the invalidation + * @param ino the inode number + * @param size the number of bytes to retrieve + * @param offset the starting offset into the file to retrieve from + * @param cookie user data to supply to the reply callback + * @return zero for success, -errno for failure + */ +int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, + size_t size, off_t offset, void *cookie); + + +/* ----------------------------------------------------------- * + * Utility functions * + * ----------------------------------------------------------- */ + +/** + * Get the userdata from the request + * + * @param req request handle + * @return the user data passed to fuse_lowlevel_new() + */ +void *fuse_req_userdata(fuse_req_t req); + +/** + * Get the context from the request + * + * The pointer returned by this function will only be valid for the + * request's lifetime + * + * @param req request handle + * @return the context structure + */ +const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); + +/** + * Get the current supplementary group IDs for the specified request + * + * Similar to the getgroups(2) system call, except the return value is + * always the total number of group IDs, even if it is larger than the + * specified size. + * + * The current fuse kernel module in linux (as of 2.6.30) doesn't pass + * the group list to userspace, hence this function needs to parse + * "/proc/$TID/task/$TID/status" to get the group IDs. + * + * This feature may not be supported on all operating systems. In + * such a case this function will return -ENOSYS. + * + * @param req request handle + * @param size size of given array + * @param list array of group IDs to be filled in + * @return the total number of supplementary group IDs or -errno on failure + */ +int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]); + +/** + * Callback function for an interrupt + * + * @param req interrupted request + * @param data user data + */ +typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); + +/** + * Register/unregister callback for an interrupt + * + * If an interrupt has already happened, then the callback function is + * called from within this function, hence it's not possible for + * interrupts to be lost. + * + * @param req request handle + * @param func the callback function or NULL for unregister + * @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); + +/** + * Check if a request has already been interrupted + * + * @param req request handle + * @return 1 if the request has been interrupted, 0 otherwise + */ +int fuse_req_interrupted(fuse_req_t req); + +/* ----------------------------------------------------------- * + * Filesystem setup * + * ----------------------------------------------------------- */ + +/* Deprecated, don't use */ +int fuse_lowlevel_is_lib_option(const char *opt); + +/** + * Create a low level session + * + * @param args argument vector + * @param op the low level filesystem operations + * @param op_size sizeof(struct fuse_lowlevel_ops) + * @param userdata user data + * @return the created session object, or NULL on failure + */ +struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); + +/* ----------------------------------------------------------- * + * Session interface * + * ----------------------------------------------------------- */ + +/** + * Session operations + * + * This is used in session creation + */ +struct fuse_session_ops +{ /** - * Exit a session + * Hook to process a request (mandatory) * - * @param se the session + * @param data user data passed to fuse_session_new() + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received */ - void fuse_session_exit(struct fuse_session *se); + void (*process) (void *data, const char *buf, size_t len, + struct fuse_chan *ch); /** - * Reset the exited status of a session + * Hook for session exit and reset (optional) * - * @param se the session + * @param data user data passed to fuse_session_new() + * @param val exited status (1 - exited, 0 - not exited) */ - void fuse_session_reset(struct fuse_session *se); + void (*exit) (void *data, int val); /** - * Query the exited status of a session + * Hook for querying the current exited status (optional) * - * @param se the session + * @param data user data passed to fuse_session_new() * @return 1 if exited, 0 if not exited */ - int fuse_session_exited(struct fuse_session *se); + int (*exited) (void *data); /** - * Get the user data provided to the session + * Hook for cleaning up the channel on destroy (optional) * - * @param se the session - * @return the user data + * @param data user data passed to fuse_session_new() */ - void *fuse_session_data(struct fuse_session *se); + void (*destroy) (void *data); +}; - /** - * Enter a multi-threaded event loop - * - * @param se the session - * @return 0 on success, -1 on error - */ - int fuse_session_loop_mt(struct fuse_session *se, const int threads); +/** + * Create a new session + * + * @param op session operations + * @param data user data + * @return new session object, or NULL on failure + */ +struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); - /* ----------------------------------------------------------- * - * Channel interface * - * ----------------------------------------------------------- */ +/** + * Assign a channel to a session + * + * Note: currently only a single channel may be assigned. This may + * change in the future + * + * If a session is destroyed, the assigned channel is also destroyed + * + * @param se the session + * @param ch the channel + */ +void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); - /** - * Channel operations - * - * This is used in channel creation - */ - struct fuse_chan_ops - { - /** - * Hook for receiving a raw request - * - * @param ch pointer to the channel - * @param buf the buffer to store the request in - * @param size the size of the buffer - * @return the actual size of the raw request, or -1 on error - */ - int (*receive)(struct fuse_chan **chp, char *buf, size_t size); - - /** - * Hook for sending a raw reply - * - * A return value of -ENOENT means, that the request was - * interrupted, and the reply was discarded - * - * @param ch the channel - * @param iov vector of blocks - * @param count the number of blocks in vector - * @return zero on success, -errno on failure - */ - int (*send)(struct fuse_chan *ch, const struct iovec iov[], - size_t count); - - /** - * Destroy the channel - * - * @param ch the channel - */ - void (*destroy)(struct fuse_chan *ch); - }; +/** + * Remove a channel from a session + * + * If the channel is not assigned to a session, then this is a no-op + * + * @param ch the channel to remove + */ +void fuse_session_remove_chan(struct fuse_chan *ch); - /** - * Create a new channel - * - * @param op channel operations - * @param fd file descriptor of the channel - * @param bufsize the minimal receive buffer size - * @param data user data - * @return the new channel object, or NULL on failure - */ - struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data); +/** + * Iterate over the channels assigned to a session + * + * The iterating function needs to start with a NULL channel, and + * after that needs to pass the previously returned channel to the + * function. + * + * @param se the session + * @param ch the previous channel, or NULL + * @return the next channel, or NULL if no more channels exist + */ +struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, + struct fuse_chan *ch); - /** - * Query the file descriptor of the channel - * - * @param ch the channel - * @return the file descriptor passed to fuse_chan_new() - */ - int fuse_chan_fd(struct fuse_chan *ch); +/** + * Process a raw request + * + * @param se the session + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received + */ +void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, + struct fuse_chan *ch); - /** - * Query the minimal receive buffer size - * - * @param ch the channel - * @return the buffer size passed to fuse_chan_new() - */ - size_t fuse_chan_bufsize(struct fuse_chan *ch); +/** + * Process a raw request supplied in a generic buffer + * + * This is a more generic version of fuse_session_process(). The + * fuse_buf may contain a memory buffer or a pipe file descriptor. + * + * @param se the session + * @param buf the fuse_buf containing the request + * @param ch channel on which the request was received + */ +void fuse_session_process_buf(struct fuse_session *se, + const struct fuse_buf *buf, struct fuse_chan *ch); - /** - * Query the user data - * - * @param ch the channel - * @return the user data passed to fuse_chan_new() - */ - void *fuse_chan_data(struct fuse_chan *ch); +/** + * Receive a raw request supplied in a generic buffer + * + * This is a more generic version of fuse_chan_recv(). The fuse_buf + * supplied to this function contains a suitably allocated memory + * buffer. This may be overwritten with a file descriptor buffer. + * + * @param se the session + * @param buf the fuse_buf to store the request in + * @param chp pointer to the channel + * @return the actual size of the raw request, or -errno on error + */ +int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan **chp); - /** - * Query the session to which this channel is assigned - * - * @param ch the channel - * @return the session, or NULL if the channel is not assigned - */ - struct fuse_session *fuse_chan_session(struct fuse_chan *ch); +/** + * Destroy a session + * + * @param se the session + */ +void fuse_session_destroy(struct fuse_session *se); + +/** + * Exit a session + * + * @param se the session + */ +void fuse_session_exit(struct fuse_session *se); + +/** + * Reset the exited status of a session + * + * @param se the session + */ +void fuse_session_reset(struct fuse_session *se); + +/** + * Query the exited status of a session + * + * @param se the session + * @return 1 if exited, 0 if not exited + */ +int fuse_session_exited(struct fuse_session *se); + +/** + * Get the user data provided to the session + * + * @param se the session + * @return the user data + */ +void *fuse_session_data(struct fuse_session *se); + +/** + * Enter a multi-threaded event loop + * + * @param se the session + * @return 0 on success, -1 on error + */ +int fuse_session_loop_mt(struct fuse_session *se, const int threads); +/* ----------------------------------------------------------- * + * Channel interface * + * ----------------------------------------------------------- */ + +/** + * Channel operations + * + * This is used in channel creation + */ +struct fuse_chan_ops +{ /** - * Receive a raw request - * - * A return value of -ENODEV means, that the filesystem was unmounted + * Hook for receiving a raw request * * @param ch pointer to the channel * @param buf the buffer to store the request in * @param size the size of the buffer - * @return the actual size of the raw request, or -errno on error + * @return the actual size of the raw request, or -1 on error */ - int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); + int (*receive)(struct fuse_chan **chp, char *buf, size_t size); /** - * Send a raw reply + * Hook for sending a raw reply * * A return value of -ENOENT means, that the request was * interrupted, and the reply was discarded @@ -1816,18 +1737,94 @@ extern "C" { * @param count the number of blocks in vector * @return zero on success, -errno on failure */ - int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], - size_t count); + int (*send)(struct fuse_chan *ch, const struct iovec iov[], + size_t count); /** - * Destroy a channel + * Destroy the channel * * @param ch the channel */ - void fuse_chan_destroy(struct fuse_chan *ch); + void (*destroy)(struct fuse_chan *ch); +}; -#ifdef __cplusplus -} -#endif +/** + * Create a new channel + * + * @param op channel operations + * @param fd file descriptor of the channel + * @param bufsize the minimal receive buffer size + * @param data user data + * @return the new channel object, or NULL on failure + */ +struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, + size_t bufsize, void *data); + +/** + * Query the file descriptor of the channel + * + * @param ch the channel + * @return the file descriptor passed to fuse_chan_new() + */ +int fuse_chan_fd(struct fuse_chan *ch); + +/** + * Query the minimal receive buffer size + * + * @param ch the channel + * @return the buffer size passed to fuse_chan_new() + */ +size_t fuse_chan_bufsize(struct fuse_chan *ch); + +/** + * Query the user data + * + * @param ch the channel + * @return the user data passed to fuse_chan_new() + */ +void *fuse_chan_data(struct fuse_chan *ch); + +/** + * Query the session to which this channel is assigned + * + * @param ch the channel + * @return the session, or NULL if the channel is not assigned + */ +struct fuse_session *fuse_chan_session(struct fuse_chan *ch); + +/** + * Receive a raw request + * + * A return value of -ENODEV means, that the filesystem was unmounted + * + * @param ch pointer to the channel + * @param buf the buffer to store the request in + * @param size the size of the buffer + * @return the actual size of the raw request, or -errno on error + */ +int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); + +/** + * Send a raw reply + * + * A return value of -ENOENT means, that the request was + * interrupted, and the reply was discarded + * + * @param ch the channel + * @param iov vector of blocks + * @param count the number of blocks in vector + * @return zero on success, -errno on failure + */ +int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + +/** + * Destroy a channel + * + * @param ch the channel + */ +void fuse_chan_destroy(struct fuse_chan *ch); + +EXTERN_C_END #endif /* _FUSE_LOWLEVEL_H_ */ diff --git a/libfuse/include/fuse_opt.h b/libfuse/include/fuse_opt.h index 229c3931..c82eef0d 100644 --- a/libfuse/include/fuse_opt.h +++ b/libfuse/include/fuse_opt.h @@ -9,264 +9,262 @@ #ifndef _FUSE_OPT_H_ #define _FUSE_OPT_H_ +#include "extern_c.h" + /** @file * * This file defines the option parsing interface of FUSE */ -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN + +/** + * Option description + * + * This structure describes a single option, and action associated + * with it, in case it matches. + * + * More than one such match may occur, in which case the action for + * each match is executed. + * + * There are three possible actions in case of a match: + * + * i) An integer (int or unsigned) variable determined by 'offset' is + * set to 'value' + * + * ii) The processing function is called, with 'value' as the key + * + * iii) An integer (any) or string (char *) variable determined by + * 'offset' is set to the value of an option parameter + * + * 'offset' should normally be either set to + * + * - 'offsetof(struct foo, member)' actions i) and iii) + * + * - -1 action ii) + * + * The 'offsetof()' macro is defined in the header. + * + * The template determines which options match, and also have an + * effect on the action. Normally the action is either i) or ii), but + * if a format is present in the template, then action iii) is + * performed. + * + * The types of templates are: + * + * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only + * themselves. Invalid values are "--" and anything beginning + * with "-o" + * + * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or + * the relevant option in a comma separated option list + * + * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) + * which have a parameter + * + * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform + * action iii). + * + * 5) "-x ", etc. Matches either "-xparam" or "-x param" as + * two separate arguments + * + * 6) "-x %s", etc. Combination of 4) and 5) + * + * If the format is "%s", memory is allocated for the string unlike + * with scanf(). + */ +struct fuse_opt +{ + /** Matching template and optional parameter formatting */ + const char *templ; /** - * Option description - * - * This structure describes a single option, and action associated - * with it, in case it matches. - * - * More than one such match may occur, in which case the action for - * each match is executed. - * - * There are three possible actions in case of a match: - * - * i) An integer (int or unsigned) variable determined by 'offset' is - * set to 'value' - * - * ii) The processing function is called, with 'value' as the key - * - * iii) An integer (any) or string (char *) variable determined by - * 'offset' is set to the value of an option parameter - * - * 'offset' should normally be either set to - * - * - 'offsetof(struct foo, member)' actions i) and iii) - * - * - -1 action ii) - * - * The 'offsetof()' macro is defined in the header. - * - * The template determines which options match, and also have an - * effect on the action. Normally the action is either i) or ii), but - * if a format is present in the template, then action iii) is - * performed. - * - * The types of templates are: - * - * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only - * themselves. Invalid values are "--" and anything beginning - * with "-o" - * - * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or - * the relevant option in a comma separated option list - * - * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) - * which have a parameter - * - * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform - * action iii). - * - * 5) "-x ", etc. Matches either "-xparam" or "-x param" as - * two separate arguments - * - * 6) "-x %s", etc. Combination of 4) and 5) - * - * If the format is "%s", memory is allocated for the string unlike - * with scanf(). + * Offset of variable within 'data' parameter of fuse_opt_parse() + * or -1 */ - struct fuse_opt - { - /** Matching template and optional parameter formatting */ - const char *templ; - - /** - * 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; - }; + unsigned long offset; /** - * Key option. In case of a match, the processing function will be - * called with the specified key. + * 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 + * called with the specified key. + */ #define FUSE_OPT_KEY(templ, key) { templ, -1U, key } - /** - * Last option. An array of 'struct fuse_opt' must end with a NULL - * template value - */ +/** + * Last option. An array of 'struct fuse_opt' must end with a NULL + * template value + */ #define FUSE_OPT_END { NULL, 0, 0 } - /** - * Argument list - */ - struct fuse_args - { - /** Argument count */ - int argc; +/** + * Argument list + */ +struct fuse_args +{ + /** 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' - */ +/** + * Initializer for 'struct fuse_args' + */ #define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 } - /** - * Key value passed to the processing function if an option did not - * match any template - */ +/** + * Key value passed to the processing function if an option did not + * match any template + */ #define FUSE_OPT_KEY_OPT -1 - /** - * Key value passed to the processing function for all non-options - * - * Non-options are the arguments beginning with a character other than - * '-' or all arguments after the special '--' option - */ +/** + * Key value passed to the processing function for all non-options + * + * Non-options are the arguments beginning with a character other than + * '-' or all arguments after the special '--' option + */ #define FUSE_OPT_KEY_NONOPT -2 - /** - * Special key value for options to keep - * - * Argument is not passed to processing function, but behave as if the - * processing function returned 1 - */ +/** + * Special key value for options to keep + * + * Argument is not passed to processing function, but behave as if the + * processing function returned 1 + */ #define FUSE_OPT_KEY_KEEP -3 - /** - * Special key value for options to discard - * - * Argument is not passed to processing function, but behave as if the - * processing function returned zero - */ +/** + * Special key value for options to discard + * + * Argument is not passed to processing function, but behave as if the + * processing function returned zero + */ #define FUSE_OPT_KEY_DISCARD -4 - /** - * Processing function - * - * This function is called if - * - option did not match any 'struct fuse_opt' - * - argument is a non-option - * - option did match and offset was set to -1 - * - * The 'arg' parameter will always contain the whole argument or - * option including the parameter if exists. A two-argument option - * ("-x foo") is always converted to single argument option of the - * form "-xfoo" before this function is called. - * - * Options of the form '-ofoo' are passed to this function without the - * '-o' prefix. - * - * The return value of this function determines whether this argument - * is to be inserted into the output argument vector, or discarded. - * - * @param data is the user data passed to the fuse_opt_parse() function - * @param arg is the whole argument or option - * @param key determines why the processing function was called - * @param outargs the current output argument list - * @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); +/** + * Processing function + * + * This function is called if + * - option did not match any 'struct fuse_opt' + * - argument is a non-option + * - option did match and offset was set to -1 + * + * The 'arg' parameter will always contain the whole argument or + * option including the parameter if exists. A two-argument option + * ("-x foo") is always converted to single argument option of the + * form "-xfoo" before this function is called. + * + * Options of the form '-ofoo' are passed to this function without the + * '-o' prefix. + * + * The return value of this function determines whether this argument + * is to be inserted into the output argument vector, or discarded. + * + * @param data is the user data passed to the fuse_opt_parse() function + * @param arg is the whole argument or option + * @param key determines why the processing function was called + * @param outargs the current output argument list + * @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); - /** - * Option parsing function - * - * If 'args' was returned from a previous call to fuse_opt_parse() or - * it was constructed from - * - * A NULL 'args' is equivalent to an empty argument vector - * - * A NULL 'opts' is equivalent to an 'opts' array containing a single - * end marker - * - * A NULL 'proc' is equivalent to a processing function always - * returning '1' - * - * @param args is the input and output argument list - * @param data is the user data - * @param opts is the option description array - * @param proc is the processing function - * @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); +/** + * Option parsing function + * + * If 'args' was returned from a previous call to fuse_opt_parse() or + * it was constructed from + * + * A NULL 'args' is equivalent to an empty argument vector + * + * A NULL 'opts' is equivalent to an 'opts' array containing a single + * end marker + * + * A NULL 'proc' is equivalent to a processing function always + * returning '1' + * + * @param args is the input and output argument list + * @param data is the user data + * @param opts is the option description array + * @param proc is the processing function + * @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); - /** - * Add an option to a comma separated option list - * - * @param opts is a pointer to an option list, may point to a NULL value - * @param opt is the option to add - * @return -1 on allocation error, 0 on success - */ - int fuse_opt_add_opt(char **opts, const char *opt); +/** + * Add an option to a comma separated option list + * + * @param opts is a pointer to an option list, may point to a NULL value + * @param opt is the option to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_add_opt(char **opts, const char *opt); - /** - * Add an option, escaping commas, to a comma separated option list - * - * @param opts is a pointer to an option list, may point to a NULL value - * @param opt is the option to add - * @return -1 on allocation error, 0 on success - */ - int fuse_opt_add_opt_escaped(char **opts, const char *opt); +/** + * Add an option, escaping commas, to a comma separated option list + * + * @param opts is a pointer to an option list, may point to a NULL value + * @param opt is the option to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_add_opt_escaped(char **opts, const char *opt); - /** - * Add an argument to a NULL terminated argument vector - * - * @param args is the structure containing the current argument list - * @param arg is the new argument to add - * @return -1 on allocation error, 0 on success - */ - int fuse_opt_add_arg(struct fuse_args *args, const char *arg); +/** + * Add an argument to a NULL terminated argument vector + * + * @param args is the structure containing the current argument list + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_add_arg(struct fuse_args *args, const char *arg); - /** - * Add an argument at the specified position in a NULL terminated - * argument vector - * - * Adds the argument to the N-th position. This is useful for adding - * options at the beginning of the array which must not come after the - * special '--' option. - * - * @param args is the structure containing the current argument list - * @param pos is the position at which to add the argument - * @param arg is the new argument to add - * @return -1 on allocation error, 0 on success - */ - int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); +/** + * Add an argument at the specified position in a NULL terminated + * argument vector + * + * Adds the argument to the N-th position. This is useful for adding + * options at the beginning of the array which must not come after the + * special '--' option. + * + * @param args is the structure containing the current argument list + * @param pos is the position at which to add the argument + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); - /** - * Free the contents of argument list - * - * The structure itself is not freed - * - * @param args is the structure containing the argument list - */ - void fuse_opt_free_args(struct fuse_args *args); +/** + * Free the contents of argument list + * + * The structure itself is not freed + * + * @param args is the structure containing the argument list + */ +void fuse_opt_free_args(struct fuse_args *args); - /** - * Check if an option matches - * - * @param opts is the option description array - * @param opt is the option to match - * @return 1 if a match is found, 0 if not - */ - int fuse_opt_match(const struct fuse_opt opts[], const char *opt); +/** + * Check if an option matches + * + * @param opts is the option description array + * @param opt is the option to match + * @return 1 if a match is found, 0 if not + */ +int fuse_opt_match(const struct fuse_opt opts[], const char *opt); -#ifdef __cplusplus -} -#endif +EXTERN_C_END #endif /* _FUSE_OPT_H_ */ diff --git a/libfuse/include/ulockmgr.h b/libfuse/include/ulockmgr.h deleted file mode 100644 index ad555799..00000000 --- a/libfuse/include/ulockmgr.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - libulockmgr: Userspace Lock Manager Library - Copyright (C) 2006 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -#include -#include -#include - -/** - * Perform POSIX locking operation - * - * @param fd the file descriptor - * @param cmd the locking command (F_GETFL, F_SETLK or F_SETLKW) - * @param lock the lock parameters - * @param owner the lock owner ID cookie - * @param owner_len length of the lock owner ID cookie - * @return 0 on success -errno on error - */ -int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, - size_t owner_len);