diff options
62 files changed, 1307 insertions, 3464 deletions
@@ -30,7 +30,7 @@ config.* /compile /libtool /INSTALL -/fuse.pc +/*.pc /.pc -/patches +/patches* /m4 @@ -3,9 +3,31 @@ * libfuse: Add missing includes. This allows compiling fuse with musl. Patch by Daniel Thau -2013-07-01 Miklos Szeredi <miklos@szeredi.hu> +2013-07-26 Miklos Szeredi <miklos@szeredi.hu> - * Released 2.9.3 + * Print help on stdout instead of stderr + +2013-07-25 Miklos Szeredi <miklos@szeredi.hu> + + * libfuse: fuse -> fuse3. Allow 2.X and 3.X to coexist. Includes + are now stored under /usr/include/fuse3 and library is named + libfuse3.*. Invoke pkg-config with "fuse3" as the first argument + to build with version 3 of the library. + + * ulockmgr: strip ulockmgr support from this source package and + distribute it separately. It is not needed for the building of + libfuse, only fusexmp_fh. Check ulockmgr library in ./configure + and if not disable remote-lock suport in fusexmp_fh. + +2013-07-24 Miklos Szeredi <miklos@szeredi.hu> + + * libfuse: remove "-D_FILE_OFFSET_BITS=64" from fuse.pc, add + AC_SYS_LARGEFILE to your configure.ac instead. + +2013-06-21 Miklos Szeredi <miklos@szeredi.hu> + + * libfuse: set FD_CLOEXEC also when receiving device fd from + fusermount 2013-06-20 Miklos Szeredi <miklos@szeredi.hu> @@ -18,6 +40,67 @@ cancelling that same worker. This caused a segmenation fault. Reported and tested by Anatol Pomozov +2013-02-20 Miklos Szeredi <miklos@szeredi.hu> + + * libfuse: change the type of fuse_ino_t from 'unsigned long' to + 'uint64_t' + + * libfuse: use O_CLOEXEC flag when opening /dev/fuse device. + Patch by Richard W.M. Jones + + * libfuse: don't force -D_FILE_OFFSET_BITS=64 in pkgconfig file. + Patch by Richard W.M. Jones + +2013-02-19 Miklos Szeredi <miklos@szeredi.hu> + + * fuse_daemonize(): chdir to "/" even if not running in the + background for consistency. Reported by Vladimir Rutsky + +2013-02-18 Miklos Szeredi <miklos@szeredi.hu> + + * fuse_opt_parse(): when storing a newly allocated string for + format "%s", free the previous value stored at that location. + Reported by Marco Schuster + +2013-02-07 Miklos Szeredi <miklos@szeredi.hu> + + * libfuse: add readdirplus support in fuse_lowlevel_ops. Patch by + Feng Shuo + + * libfuse: add poll_events to fuse_file_info. Patch by Enke Chen + + * libfuse: fix fs cleanup. Reported by Eric Wong + + * libfuse: pass security context options to kernel. Patch by + Dalvik Khertel + + * libfuse: remove deprecated features: + - fuse_is_lib_option() + - fuse_invalidate() + - fuse_set_getcontext_func() + - fuse_loop_mt_proc() + - fuse_read_cmd() + - fuse_process_cmd() + - fuse_setup() + - fuse_teardown() + - fuse_exited() + - fuse_lowlevel_is_lib_option() + - fuse_operations.getdir() + - fuse_operations.utime() + - fuse_operations.utime_omit_ok + +2013-02-06 Miklos Szeredi <miklos@szeredi.hu> + + * libfuse: set close-on-exec flag on pipe file descriptors. Patch + by Eric Wong + + * libfuse: add missing INIT flags + +2013-02-05 Miklos Szeredi <miklos@szeredi.hu> + + * libfuse: fix fuse_get_context() in non fuse threads. Reported + by Michael Berlin + 2013-02-04 Miklos Szeredi <miklos@szeredi.hu> * libfuse: fix crash in unlock_path(). Patch by Ratna Manoj @@ -62,6 +145,12 @@ 2012-07-19 Miklos Szeredi <miklos@szeredi.hu> + * Start of 3.0 series. This is going to be a new major version of + the library breaking backward compatibility on the binary level as + well as the source level. + +2012-07-19 Miklos Szeredi <miklos@szeredi.hu> + * Released 2.9.1 2012-07-19 Miklos Szeredi <miklos@szeredi.hu> diff --git a/Makefile.am b/Makefile.am index 8bb0781..10926cc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,12 +5,12 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = @subdirs2@ doc EXTRA_DIST = \ - fuse.pc.in \ + fuse3.pc.in \ README* \ Filesystems \ FAQ pkgconfigdir = @pkgconfigdir@ -pkgconfig_DATA = fuse.pc +pkgconfig_DATA = fuse3.pc $(pkgconfig_DATA): config.status diff --git a/configure.ac b/configure.ac index 8963f2a..0e621d4 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,4 @@ -AC_INIT(fuse, 2.9.3) - +AC_INIT(fuse, 3.0.0-pre0) AC_PREREQ(2.59d) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET @@ -8,7 +7,8 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)]) AC_CONFIG_HEADERS(include/config.h) AC_PROG_LIBTOOL -AC_PROG_CC +AC_PROG_CC_STDC +AC_SYS_LARGEFILE AC_PROG_MKDIR_P AM_PROG_CC_C_O @@ -53,7 +53,7 @@ if test "$enable_mtab" = "no"; then AC_DEFINE(IGNORE_MTAB, 1, [Don't update /etc/mtab]) fi -AC_CHECK_FUNCS([fork setxattr fdatasync splice vmsplice utimensat]) +AC_CHECK_FUNCS([fork setxattr fdatasync splice vmsplice utimensat pipe2]) AC_CHECK_FUNCS([posix_fallocate]) AC_CHECK_MEMBERS([struct stat.st_atim]) AC_CHECK_MEMBERS([struct stat.st_atimespec]) @@ -63,6 +63,11 @@ AC_SEARCH_LIBS(dlopen, [dl]) AC_SEARCH_LIBS(clock_gettime, [rt]) libfuse_libs=$LIBS LIBS= +AC_CHECK_LIB(ulockmgr, ulockmgr_op) +fusexmp_fh_libs=$LIBS +AC_SUBST(fusexmp_fh_libs) +LIBS= + AC_ARG_WITH([libiconv-prefix], [ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [ for dir in `echo "$withval" | tr : ' '`; do @@ -112,7 +117,7 @@ if test "$arch" = linux -a "$cross_compiling" != "yes"; then fi fi -AC_CONFIG_FILES([fuse.pc Makefile lib/Makefile util/Makefile example/Makefile include/Makefile doc/Makefile]) +AC_CONFIG_FILES([fuse3.pc Makefile lib/Makefile util/Makefile example/Makefile include/Makefile doc/Makefile]) AC_OUTPUT if test "$util_linux_ok" = no; then diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..1936cc1 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +html diff --git a/doc/Doxyfile b/doc/Doxyfile index 3926aaf..16ce23a 100644..100755 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -544,7 +544,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = include +INPUT = . ../include ../example ../lib # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -561,7 +561,7 @@ INPUT_ENCODING = UTF-8 # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 -FILE_PATTERNS = *.h +FILE_PATTERNS = *.h *.c *.h *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. @@ -601,7 +601,7 @@ EXCLUDE_SYMBOLS = # directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = . ../example/ ../lib # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp @@ -621,7 +621,7 @@ EXAMPLE_RECURSIVE = NO # directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = +IMAGE_PATH = images/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/doc/Makefile.am b/doc/Makefile.am index ebc9679..bc34a9c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,5 +1,5 @@ ## Process this file with automake to produce Makefile.in -dist_man_MANS = fusermount.1 mount.fuse.8 ulockmgr_server.1 +dist_man_MANS = fusermount.1 mount.fuse.8 EXTRA_DIST = how-fuse-works kernel.txt Doxyfile diff --git a/doc/how-fuse-works b/doc/how-fuse-works index a5febe3..a5febe3 100644..100755 --- a/doc/how-fuse-works +++ b/doc/how-fuse-works diff --git a/doc/images/490px-FUSE_structure.svg.png b/doc/images/490px-FUSE_structure.svg.png Binary files differnew file mode 100644 index 0000000..a4a9731 --- /dev/null +++ b/doc/images/490px-FUSE_structure.svg.png diff --git a/doc/mainpage.dox b/doc/mainpage.dox new file mode 100755 index 0000000..9b1801f --- /dev/null +++ b/doc/mainpage.dox @@ -0,0 +1,92 @@ +/*! +\mainpage FUSE API documentation + +Filesystem in Userspace (FUSE) is a loadable kernel module for Unix-like computer operating systems that lets non-privileged users create their own file systems without editing kernel code. This is achieved by running file system code in user space while the FUSE module provides only a "bridge" to the actual kernel interfaces. + +(c) Wikipedia + +@tableofcontents + + + + + +\section section1 How FUSE works + +@image html 490px-FUSE_structure.svg.png "Structural diagramm of Filesystem in Userspace from http://en.wikipedia.org/wiki/File:FUSE_structure.svg" + +\include how-fuse-works + + + + +\section section2 Kernel + +\include kernel.txt + + + + + +\section section_examples examples + +have a look at the examples listed in the example directory, which can be found here: <a href="files.html">files.html</a>. + +- @ref hello.c - minimal FUSE example featuring fuse_main usage + +- @ref hello_ll.c - FUSE: Filesystem in Userspace + +- @ref null.c - FUSE: Filesystem in Userspace + +- @ref cusexmp.c - CUSE example: Character device in Userspace + +- @ref fioc.c - FUSE fioc: FUSE ioctl example + +- @ref fioclient.c - FUSE fioclient: FUSE ioctl example client + +- @ref fsel.c - FUSE fsel: FUSE select example + +- @ref fselclient.c - FUSE fselclient: FUSE select example client + +- @ref fusexmp.c - FUSE: Filesystem in Userspace + +- @ref fusexmp_fh.c - FUSE: Filesystem in Userspace + + +\section section_links links + +<a href="http://sourceforge.net/apps/mediawiki/fuse/index.php?title=Main_Page">http://sourceforge.net/apps/mediawiki/fuse/index.php?title=Main_Page</a> - the fuse wiki + +<a href="http://en.wikipedia.org/wiki/Filesystem_in_Userspace">http://en.wikipedia.org/wiki/Filesystem_in_Userspace</a> - FUSE on wikipedia + + +\section section_todo todo + +general: + + - fuse_lowlevel.h, describe: + - a channel (or communication channel) is created by fuse_mount(..) + - a fuse session is associated with a channel and a signal handler and runs until the assigned signal handler + shuts the session down, see fuse_session_loop(se) and hello_ll.c + + - http://www.cs.nmsu.edu/~pfeiffer/fuse-tutorial/ + + - http://cinwell.wordpress.com/ + + - http://sourceforge.net/apps/mediawiki/fuse/index.php?title=FuseProtocolSketch + + - http://muratbuffalo.blogspot.de/2011/05/refuse-to-crash-with-re-fuse.html + +examples: + - demonstrate the effect of single vs multithreaded -> fuse_loop fuse_loop_mt + + - add comments and source form all existing examples + + - also add examples form here: http://sourceforge.net/apps/mediawiki/fuse/index.php?title=Main_Page#How_should_threads_be_startedx3f + + - add this new example: http://fuse.996288.n3.nabble.com/Create-multiple-filesystems-in-same-process-td9292.html + + \section section_thanks thanks + - Mark Glines, <mark@glines.org> for his coments on fuse_loop() and fuse_loop_mt(). + - Wikipedia - copied the FUSE introduction from the Filesystem in userspace article. +*/ diff --git a/doc/ulockmgr_server.1 b/doc/ulockmgr_server.1 deleted file mode 100644 index 7b8ab9a..0000000 --- a/doc/ulockmgr_server.1 +++ /dev/null @@ -1,28 +0,0 @@ -.TH ULOCKMGR_SERVER 1 2011\-10\-23 2.8.6 "Filesystem in Userspace (FUSE)" - -.SH NAME -\fBulockmgr_server\fR \- Lock Manager Server for FUSE filesystems - -.SH SYNOPSIS -\fBulockmgr_server\fR - -.SH DESCRIPTION -Filesystem in Userspace (FUSE) is a simple interface for userspace programs to export a virtual filesystem to the Linux kernel. It also aims to provide a secure method for non privileged users to create and mount their own filesystem implementations. -.PP -\fBulockmgr_server\fR is the Userspace Lock Manager Server for FUSE filesystems. - -.SH OPTIONS -\fBulockmgr_server\fR has no options. - -.SH SEE ALSO -\fIfusermount\fR(1), -\fImount\fR(8), -\fImount.fuse\fR(8). - -.SH HOMEPAGE -More information about ulockmgr_server and the FUSE project can be found at <\fIhttp://fuse.sourceforge.net/\fR>. - -.SH AUTHOR -FUSE was written by Miklos Szeredi <\fImiklos@szeredi.hu\fR>. -.PP -This manual page was written by Daniel Baumann <\fIdaniel.baumann@progress\-technologies.net\fR>. diff --git a/example/Makefile.am b/example/Makefile.am index 1c04057..0db537b 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1,12 +1,12 @@ ## Process this file with automake to produce Makefile.in -AM_CPPFLAGS = -I$(top_srcdir)/include -D_FILE_OFFSET_BITS=64 -D_REENTRANT +AM_CPPFLAGS = -I$(top_srcdir)/include -D_REENTRANT noinst_HEADERS = fioc.h noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll fioc fioclient \ fsel fselclient cusexmp -LDADD = ../lib/libfuse.la -fusexmp_fh_LDADD = ../lib/libfuse.la ../lib/libulockmgr.la +LDADD = ../lib/libfuse3.la +fusexmp_fh_LDADD = ../lib/libfuse3.la @fusexmp_fh_libs@ fioclient_CPPFLAGS = fioclient_LDFLAGS = diff --git a/example/cusexmp.c b/example/cusexmp.c index 01fcdf7..8d22075 100644..100755 --- a/example/cusexmp.c +++ b/example/cusexmp.c @@ -6,10 +6,25 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - gcc -Wall cusexmp.c `pkg-config fuse --cflags --libs` -o cusexmp */ -#define FUSE_USE_VERSION 29 +/** @file + * @tableofcontents + * + * cusexmp.c - CUSE example: Character device in Userspace + * + * \section section_compile compiling this example + * + * gcc -Wall cusexmp.c `pkg-config fuse3 --cflags --libs` -o cusexmp + * + * \section section_source the complete source + * \include cusexmp.c + */ + + +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <cuse_lowlevel.h> #include <fuse_opt.h> diff --git a/example/fioc.c b/example/fioc.c index bee40b9..2117ac8 100644..100755 --- a/example/fioc.c +++ b/example/fioc.c @@ -6,10 +6,25 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - gcc -Wall fioc.c `pkg-config fuse --cflags --libs` -o fioc */ -#define FUSE_USE_VERSION 26 +/** @file + * @tableofcontents + * + * fioc.c - FUSE fioc: FUSE ioctl example + * + * \section section_compile compiling this example + * + * gcc -Wall fioc.c `pkg-config fuse3 --cflags --libs` -o fioc + * + * \section section_source the complete source + * \include fioc.c + */ + + +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <fuse.h> #include <stdlib.h> diff --git a/example/fioc.h b/example/fioc.h index ec1a39d..42799aa 100644..100755 --- a/example/fioc.h +++ b/example/fioc.h @@ -7,6 +7,15 @@ See the file COPYING. */ +/** @file + * @tableofcontents + * + * fioc.h - FUSE-ioctl: ioctl support for FUSE + * + * \include fioc.h + */ + + #include <sys/types.h> #include <sys/uio.h> #include <sys/ioctl.h> diff --git a/example/fioclient.c b/example/fioclient.c index 5f05525..a7c0dbe 100644..100755 --- a/example/fioclient.c +++ b/example/fioclient.c @@ -5,10 +5,24 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - - gcc -Wall fioclient.c -o fioclient */ +/** @file + * @tableofcontents + * + * fioclient.c - FUSE fioclient: FUSE ioctl example client + * + * \section section_compile compiling this example + * + * gcc -Wall fioclient.c -o fioclient + * + * \section section_source the complete source + * fioclient.c + * \include fioclient.c + */ + +#include <config.h> + #include <sys/types.h> #include <sys/fcntl.h> #include <sys/stat.h> diff --git a/example/fsel.c b/example/fsel.c index 9cf0221..69202ee 100644..100755 --- a/example/fsel.c +++ b/example/fsel.c @@ -6,10 +6,25 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - gcc -Wall fsel.c `pkg-config fuse --cflags --libs` -o fsel */ -#define FUSE_USE_VERSION 29 +/** @file + * @tableofcontents + * + * fsel.c - FUSE fsel: FUSE select example + * + * \section section_compile compiling this example + * + * gcc -Wall fsel.c `pkg-config fuse3 --cflags --libs` -o fsel + * + * \section section_source the complete source + * \include fsel.c + */ + + +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <fuse.h> #include <unistd.h> diff --git a/example/fselclient.c b/example/fselclient.c index 7c4b837..ac8b7b0 100644..100755 --- a/example/fselclient.c +++ b/example/fselclient.c @@ -6,9 +6,23 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - gcc -Wall fselclient.c -o fselclient */ +/** @file + * @tableofcontents + * + * fselclient.c - FUSE fselclient: FUSE select example client + * + * \section section_compile compiling this example + * + * gcc -Wall fselclient.c -o fselclient + * + * \section section_source the complete source + * \include fselclient.c + */ + +#include <config.h> + #include <sys/select.h> #include <sys/time.h> #include <sys/types.h> diff --git a/example/fusexmp.c b/example/fusexmp.c index dca8a46..6f63ae9 100644..100755 --- a/example/fusexmp.c +++ b/example/fusexmp.c @@ -5,11 +5,23 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - - gcc -Wall fusexmp.c `pkg-config fuse --cflags --libs` -o fusexmp */ -#define FUSE_USE_VERSION 26 +/** @file + * @tableofcontents + * + * fusexmp.c - FUSE: Filesystem in Userspace + * + * \section section_compile compiling this example + * + * gcc -Wall fusexmp.c `pkg-config fuse3 --cflags --libs` -o fusexmp + * + * \section section_source the complete source + * \include fusexmp.c + */ + + +#define FUSE_USE_VERSION 30 #ifdef HAVE_CONFIG_H #include <config.h> diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c index 1ba9dbc..ba6789b 100644..100755 --- a/example/fusexmp_fh.c +++ b/example/fusexmp_fh.c @@ -5,11 +5,22 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - - gcc -Wall fusexmp_fh.c `pkg-config fuse --cflags --libs` -lulockmgr -o fusexmp_fh */ -#define FUSE_USE_VERSION 26 +/** @file + * @tableofcontents + * + * fusexmp_fh.c - FUSE: Filesystem in Userspace + * + * \section section_compile compiling this example + * + * gcc -Wall fusexmp_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr -o fusexmp_fh + * + * \section section_source the complete source + * \include fusexmp_fh.c + */ + +#define FUSE_USE_VERSION 30 #ifdef HAVE_CONFIG_H #include <config.h> @@ -18,7 +29,11 @@ #define _GNU_SOURCE #include <fuse.h> + +#ifdef HAVE_LIBULOCKMGR #include <ulockmgr.h> +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -489,6 +504,7 @@ static int xmp_removexattr(const char *path, const char *name) } #endif /* HAVE_SETXATTR */ +#ifdef HAVE_LIBULOCKMGR static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock) { @@ -497,6 +513,7 @@ static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd, return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, sizeof(fi->lock_owner)); } +#endif static int xmp_flock(const char *path, struct fuse_file_info *fi, int op) { @@ -551,13 +568,10 @@ static struct fuse_operations xmp_oper = { .listxattr = xmp_listxattr, .removexattr = xmp_removexattr, #endif +#ifdef HAVE_LIBULOCKMGR .lock = xmp_lock, - .flock = xmp_flock, - - .flag_nullpath_ok = 1, -#if HAVE_UTIMENSAT - .flag_utime_omit_ok = 1, #endif + .flock = xmp_flock, }; int main(int argc, char *argv[]) diff --git a/example/hello.c b/example/hello.c index bcb6b4c..d26d826 100644..100755 --- a/example/hello.c +++ b/example/hello.c @@ -4,11 +4,38 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - - gcc -Wall hello.c `pkg-config fuse --cflags --libs` -o hello */ -#define FUSE_USE_VERSION 26 +/** @file + * + * hello.c - minimal FUSE example featuring fuse_main usage + * + * \section section_compile compiling this example + * + * gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello + * + * \section section_usage usage + \verbatim + % mkdir mnt + % ./hello mnt # program will vanish into the background + % ls -la mnt + total 4 + drwxr-xr-x 2 root root 0 Jan 1 1970 ./ + drwxrwx--- 1 root vboxsf 4096 Jun 16 23:12 ../ + -r--r--r-- 1 root root 13 Jan 1 1970 hello + % cat mnt/hello + Hello World! + % fusermount -u mnt + \endverbatim + * + * \section section_source the complete source + * \include hello.c + */ + + +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <fuse.h> #include <stdio.h> diff --git a/example/hello_ll.c b/example/hello_ll.c index 1405441..1bf7155 100644..100755 --- a/example/hello_ll.c +++ b/example/hello_ll.c @@ -4,11 +4,42 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - - gcc -Wall hello_ll.c `pkg-config fuse --cflags --libs` -o hello_ll */ -#define FUSE_USE_VERSION 26 +/** @file + * + * hello_ll.c - fuse low level functionality + * + * unlike hello.c this example will stay in the foreground. it also replaced + * the convenience function fuse_main(..) with a more low level approach. + * + * \section section_compile compiling this example + * + * gcc -Wall hello_ll.c `pkg-config fuse3 --cflags --libs` -o hello_ll + * + * \section section_usage usage + \verbatim + % mkdir mnt + % ./hello_ll mnt # program will wait in foreground until you press CTRL+C + in a different shell do: + % ls -la mnt + total 4 + drwxr-xr-x 2 root root 0 Jan 1 1970 ./ + drwxrwx--- 1 root vboxsf 4096 Jun 16 23:12 ../ + -r--r--r-- 1 root root 13 Jan 1 1970 hello + % cat mnt/hello + Hello World! + finally either press ctrl+c or do: + % fusermount -u mnt + \endverbatim + * + * \section section_source the complete source + * \include hello_ll.c + */ + +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <fuse_lowlevel.h> #include <stdio.h> @@ -151,6 +182,7 @@ static struct fuse_lowlevel_ops hello_ll_oper = { .read = hello_ll_read, }; +/*! [doxygen_fuse_lowlevel_usage] */ int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); @@ -167,7 +199,10 @@ int main(int argc, char *argv[]) if (se != NULL) { if (fuse_set_signal_handlers(se) != -1) { fuse_session_add_chan(se, ch); + + /* Block until ctrl+c or fusermount -u */ err = fuse_session_loop(se); + fuse_remove_signal_handlers(se); fuse_session_remove_chan(ch); } @@ -179,3 +214,4 @@ int main(int argc, char *argv[]) return err ? 1 : 0; } +/*! [doxygen_fuse_lowlevel_usage] */ diff --git a/example/null.c b/example/null.c index b72cf4d..1ff1954 100644..100755 --- a/example/null.c +++ b/example/null.c @@ -4,11 +4,24 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. - - gcc -Wall null.c `pkg-config fuse --cflags --libs` -o null */ -#define FUSE_USE_VERSION 26 +/** @file + * + * null.c - FUSE: Filesystem in Userspace + * + * \section section_compile compiling this example + * + * gcc -Wall null.c `pkg-config fuse3 --cflags --libs` -o null + * + * \section section_source the complete source + * \include null.c + */ + + +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <fuse.h> #include <string.h> @@ -8,4 +8,4 @@ Description: Filesystem in Userspace Version: @VERSION@ Libs: -L${libdir} -lfuse -pthread Libs.private: @libfuse_libs@ -Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64 +Cflags: -I${includedir}/fuse3 diff --git a/include/Makefile.am b/include/Makefile.am index 663e164..ffbfafa 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,17 +1,12 @@ ## Process this file with automake to produce Makefile.in -fuseincludedir=$(includedir)/fuse +fuseincludedir=$(includedir)/fuse3 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/include/fuse.h b/include/fuse.h index c657e67..b8a9307 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -13,21 +13,13 @@ * * This file defines the library interface of FUSE * - * IMPORTANT: you should define FUSE_USE_VERSION before including this - * header. To use the newest API define it to 26 (recommended for any - * new application), to use the old API define it to 21 (default) 22 - * or 25, to use the even older 1.X API define it to 11. + * IMPORTANT: you should define FUSE_USE_VERSION before including this header. */ -#ifndef FUSE_USE_VERSION -#define FUSE_USE_VERSION 21 -#endif - #include "fuse_common.h" #include <fcntl.h> #include <time.h> -#include <utime.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/statvfs.h> @@ -44,9 +36,6 @@ extern "C" { /** Handle for a FUSE filesystem */ struct fuse; -/** Structure containing a raw command */ -struct fuse_cmd; - /** Function to add an entry in a readdir() operation * * @param buf the buffer passed to the readdir() operation @@ -58,11 +47,6 @@ struct fuse_cmd; typedef int (*fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off); -/* Used by deprecated getdir() method */ -typedef struct fuse_dirhandle *fuse_dirh_t; -typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, - ino_t ino); - /** * The file system operations: * @@ -86,6 +70,24 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, * is also a snapshot of the relevant wiki pages in the doc/ folder. */ struct fuse_operations { + /** + * Flag indicating that the path need not be calculated for + * the following operations: + * + * read, write, flush, release, fsync, readdir, releasedir, + * fsyncdir, ftruncate, fgetattr, lock, ioctl and poll + * + * If this flag is set then the path will not be calculaged even if the + * file wasn't unlinked. However the path can still be non-NULL if it + * needs to be calculated for some other reason. + */ + unsigned int flag_nopath:1; + + /** + * Reserved flags, don't set + */ + unsigned int flag_reserved:31; + /** Get file attributes. * * Similar to stat(). The 'st_dev' and 'st_blksize' fields are @@ -104,9 +106,6 @@ struct fuse_operations { */ int (*readlink) (const char *, char *, size_t); - /* Deprecated, use readdir() instead */ - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); - /** Create a file node * * This is called for creation of all non-directory, non-symlink @@ -115,7 +114,7 @@ struct fuse_operations { */ int (*mknod) (const char *, mode_t, dev_t); - /** Create a directory + /** 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 @@ -147,12 +146,6 @@ struct fuse_operations { /** 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 @@ -282,16 +275,12 @@ struct fuse_operations { /** 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. + * whole directory is read in a single readdir operation. * * 2) The readdir implementation keeps track of the offsets of the * directory entries. It uses the offset parameter and always @@ -454,43 +443,6 @@ struct fuse_operations { int (*bmap) (const char *, size_t blocksize, uint64_t *idx); /** - * Flag indicating that the filesystem can accept a NULL path - * as the first argument for the following operations: - * - * read, write, flush, release, fsync, readdir, releasedir, - * fsyncdir, ftruncate, fgetattr, lock, ioctl and poll - * - * If this flag is set these operations continue to work on - * unlinked files even if "-ohard_remove" option was specified. - */ - unsigned int flag_nullpath_ok:1; - - /** - * Flag indicating that the path need not be calculated for - * the following operations: - * - * read, write, flush, release, fsync, readdir, releasedir, - * fsyncdir, ftruncate, fgetattr, lock, ioctl and poll - * - * Closely related to flag_nullpath_ok, but if this flag is - * set then the path will not be calculaged even if the file - * wasn't unlinked. However the path can still be non-NULL if - * it needs to be calculated for some other reason. - */ - unsigned int flag_nopath:1; - - /** - * Flag indicating that the filesystem accepts special - * UTIME_NOW and UTIME_OMIT values in its utimens operation. - */ - unsigned int flag_utime_omit_ok:1; - - /** - * Reserved flags, don't set - */ - unsigned int flag_reserved:29; - - /** * Ioctl * * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in @@ -637,6 +589,8 @@ struct fuse_context { * @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 + * + * Example usage, see hello.c */ /* int fuse_main(int argc, char *argv[], const struct fuse_operations *op, @@ -683,6 +637,8 @@ void fuse_destroy(struct fuse *f); * * @param f the FUSE handle * @return 0 if no error occurred, -1 otherwise + * + * See also: fuse_loop() */ int fuse_loop(struct fuse *f); @@ -703,8 +659,24 @@ void fuse_exit(struct fuse *f); * Calling this function requires the pthreads library to be linked to * the application. * + * Note: using fuse_loop() instead of fuse_loop_mt() means you are running in + * single-threaded mode, and that you will not have to worry about reentrancy, + * though you will have to worry about recursive lookups. In single-threaded + * mode, FUSE will wait for one callback to return before calling another. + * + * Enabling multiple threads, by using fuse_loop_mt(), will cause FUSE to make + * multiple simultaneous calls into the various callback functions given by your + * fuse_operations record. + * + * If you are using multiple threads, you can enjoy all the parallel execution + * and interactive response benefits of threads, and you get to enjoy all the + * benefits of race conditions and locking bugs, too. Ensure that any code used + * in the callback funtion of fuse_operations is also thread-safe. + * * @param f the FUSE handle * @return 0 if no error occurred, -1 otherwise + * + * See also: fuse_loop() */ int fuse_loop_mt(struct fuse *f); @@ -746,16 +718,6 @@ int fuse_getgroups(int size, gid_t list[]); 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() @@ -964,93 +926,9 @@ void fuse_register_module(struct fuse_module *mod); fuse_register_module(&mod); \ } - -/* ----------------------------------------------------------- * - * 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, int *multithreaded, - 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); -/* ----------------------------------------------------------- * - * 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/include/fuse_common.h b/include/fuse_common.h index a4d980d..765e0a3 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -1,5 +1,4 @@ -/* - FUSE: Filesystem in Userspace +/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU LGPLv2. @@ -20,19 +19,14 @@ #include <sys/types.h> /** Major version of FUSE library interface */ -#define FUSE_MAJOR_VERSION 2 +#define FUSE_MAJOR_VERSION 3 /** Minor version of FUSE library interface */ -#define FUSE_MINOR_VERSION 9 +#define FUSE_MINOR_VERSION 0 #define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) -/* This interface uses 64 bit off_t */ -#if _FILE_OFFSET_BITS != 64 -#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags! -#endif - #ifdef __cplusplus extern "C" { #endif @@ -40,18 +34,15 @@ extern "C" { /** * Information about open files * - * Changed in version 2.5 + * Changed in version 3.0 */ struct fuse_file_info { /** Open flags. Available in open() and release() */ int flags; - /** Old file handle, don't use */ - unsigned long fh_old; - /** In case of a write operation indicates if this was caused by a writepage */ - int writepage; + unsigned int writepage : 1; /** Can be filled in by open, to use direct I/O on this file. Introduced in version 2.4 */ @@ -85,6 +76,11 @@ struct fuse_file_info { /** Lock owner id. Available in locking operations and flush */ uint64_t lock_owner; + + /** Requested poll events. Available in ->poll. Only set on kernels + which support it. If unsupported, this field is set to zero. + Introduced in version 3.0 */ + uint32_t poll_events; }; /** @@ -101,17 +97,20 @@ struct fuse_file_info { * FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device * FUSE_CAP_IOCTL_DIR: ioctl support on directories */ -#define FUSE_CAP_ASYNC_READ (1 << 0) -#define FUSE_CAP_POSIX_LOCKS (1 << 1) -#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3) -#define FUSE_CAP_EXPORT_SUPPORT (1 << 4) -#define FUSE_CAP_BIG_WRITES (1 << 5) -#define FUSE_CAP_DONT_MASK (1 << 6) -#define FUSE_CAP_SPLICE_WRITE (1 << 7) -#define FUSE_CAP_SPLICE_MOVE (1 << 8) -#define FUSE_CAP_SPLICE_READ (1 << 9) -#define FUSE_CAP_FLOCK_LOCKS (1 << 10) -#define FUSE_CAP_IOCTL_DIR (1 << 11) +#define FUSE_CAP_ASYNC_READ (1 << 0) +#define FUSE_CAP_POSIX_LOCKS (1 << 1) +#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3) +#define FUSE_CAP_EXPORT_SUPPORT (1 << 4) +#define FUSE_CAP_BIG_WRITES (1 << 5) +#define FUSE_CAP_DONT_MASK (1 << 6) +#define FUSE_CAP_SPLICE_WRITE (1 << 7) +#define FUSE_CAP_SPLICE_MOVE (1 << 8) +#define FUSE_CAP_SPLICE_READ (1 << 9) +#define FUSE_CAP_FLOCK_LOCKS (1 << 10) +#define FUSE_CAP_IOCTL_DIR (1 << 11) +#define FUSE_CAP_AUTO_INVAL_DATA (1 << 12) +#define FUSE_CAP_READDIRPLUS (1 << 13) +#define FUSE_CAP_READDIRPLUS_AUTO (1 << 14) /** * Ioctl flags @@ -449,8 +448,15 @@ ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, * Stores session in a global variable. May only be called once per * process until fuse_remove_signal_handlers() is called. * + * Once either of the POSIX signals arrives, the exit_handler() in + * fuse_signals.c is called: + * \snippet fuse_signals.c doxygen_exit_handler + * * @param se the session to exit * @return 0 on success, -1 on failure + * + * See also: + * fuse_remove_signal_handlers() */ int fuse_set_signal_handlers(struct fuse_session *se); @@ -461,6 +467,9 @@ int fuse_set_signal_handlers(struct fuse_session *se); * be called again. * * @param se the same session as given in fuse_set_signal_handlers() + * + * See also: + * fuse_set_signal_handlers() */ void fuse_remove_signal_handlers(struct fuse_session *se); @@ -468,38 +477,26 @@ 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 +#if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30 +# error only API version 30 or greater is supported #endif #ifdef __cplusplus } #endif + +/* + * This interface uses 64 bit off_t. + * + * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags! + */ + +#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus +_Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit"); +#else +struct _fuse_off_t_must_be_64bit_dummy_struct \ + { unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); }; +#endif + #endif /* _FUSE_COMMON_H_ */ diff --git a/include/fuse_common_compat.h b/include/fuse_common_compat.h deleted file mode 100644 index 34440ff..0000000 --- a/include/fuse_common_compat.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -/* 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/include/fuse_compat.h b/include/fuse_compat.h deleted file mode 100644 index e7497a9..0000000 --- a/include/fuse_compat.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -/* 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 (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_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 *, fuse_fill_dir_t, 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 <sys/statfs.h> - -struct fuse_operations_compat22 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_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 *, fuse_fill_dir_t, 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); - -typedef int (*fuse_dirfil_t_compat) (fuse_dirh_t h, const char *name, int type); -struct fuse_operations_compat2 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); - 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 (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); - 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/include/fuse_kernel.h b/include/fuse_kernel.h index c632b58..706d035 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -83,17 +83,23 @@ * * 7.19 * - add FUSE_FALLOCATE + * + * 7.20 + * - add FUSE_AUTO_INVAL_DATA + * + * 7.21 + * - add FUSE_READDIRPLUS + * - send the requested events in POLL request */ #ifndef _LINUX_FUSE_H #define _LINUX_FUSE_H -#include <sys/types.h> -#define __u64 uint64_t -#define __s64 int64_t -#define __u32 uint32_t -#define __s32 int32_t -#define __u16 uint16_t +#ifdef __KERNEL__ +#include <linux/types.h> +#else +#include <stdint.h> +#endif /* * Version negotiation: @@ -119,7 +125,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 19 +#define FUSE_KERNEL_MINOR_VERSION 21 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -128,42 +134,42 @@ userspace works under 64bit kernels */ struct fuse_attr { - __u64 ino; - __u64 size; - __u64 blocks; - __u64 atime; - __u64 mtime; - __u64 ctime; - __u32 atimensec; - __u32 mtimensec; - __u32 ctimensec; - __u32 mode; - __u32 nlink; - __u32 uid; - __u32 gid; - __u32 rdev; - __u32 blksize; - __u32 padding; + uint64_t ino; + uint64_t size; + uint64_t blocks; + uint64_t atime; + uint64_t mtime; + uint64_t ctime; + uint32_t atimensec; + uint32_t mtimensec; + uint32_t ctimensec; + uint32_t mode; + uint32_t nlink; + uint32_t uid; + uint32_t gid; + uint32_t rdev; + uint32_t blksize; + uint32_t padding; }; struct fuse_kstatfs { - __u64 blocks; - __u64 bfree; - __u64 bavail; - __u64 files; - __u64 ffree; - __u32 bsize; - __u32 namelen; - __u32 frsize; - __u32 padding; - __u32 spare[6]; + uint64_t blocks; + uint64_t bfree; + uint64_t bavail; + uint64_t files; + uint64_t ffree; + uint32_t bsize; + uint32_t namelen; + uint32_t frsize; + uint32_t padding; + uint32_t spare[6]; }; struct fuse_file_lock { - __u64 start; - __u64 end; - __u32 type; - __u32 pid; /* tgid */ + uint64_t start; + uint64_t end; + uint32_t type; + uint32_t pid; /* tgid */ }; /** @@ -194,10 +200,21 @@ struct fuse_file_lock { /** * INIT request/reply flags * + * FUSE_ASYNC_READ: asynchronous read requests * FUSE_POSIX_LOCKS: remote locking for POSIX file locks + * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported) + * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." + * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB * FUSE_DONT_MASK: don't apply umask to file mode on create operations + * FUSE_SPLICE_WRITE: kernel supports splice write on the device + * FUSE_SPLICE_MOVE: kernel supports splice move on the device + * FUSE_SPLICE_READ: kernel supports splice read on the device * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks + * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories + * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages + * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) + * FUSE_READDIRPLUS_AUTO: adaptive readdirplus */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -206,7 +223,14 @@ struct fuse_file_lock { #define FUSE_EXPORT_SUPPORT (1 << 4) #define FUSE_BIG_WRITES (1 << 5) #define FUSE_DONT_MASK (1 << 6) +#define FUSE_SPLICE_WRITE (1 << 7) +#define FUSE_SPLICE_MOVE (1 << 8) +#define FUSE_SPLICE_READ (1 << 9) #define FUSE_FLOCK_LOCKS (1 << 10) +#define FUSE_HAS_IOCTL_DIR (1 << 11) +#define FUSE_AUTO_INVAL_DATA (1 << 12) +#define FUSE_DO_READDIRPLUS (1 << 13) +#define FUSE_READDIRPLUS_AUTO (1 << 14) /** * CUSE INIT request/reply flags @@ -313,6 +337,7 @@ enum fuse_opcode { FUSE_NOTIFY_REPLY = 41, FUSE_BATCH_FORGET = 42, FUSE_FALLOCATE = 43, + FUSE_READDIRPLUS = 44, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -334,143 +359,143 @@ enum fuse_notify_code { #define FUSE_COMPAT_ENTRY_OUT_SIZE 120 struct fuse_entry_out { - __u64 nodeid; /* Inode ID */ - __u64 generation; /* Inode generation: nodeid:gen must - be unique for the fs's lifetime */ - __u64 entry_valid; /* Cache timeout for the name */ - __u64 attr_valid; /* Cache timeout for the attributes */ - __u32 entry_valid_nsec; - __u32 attr_valid_nsec; + uint64_t nodeid; /* Inode ID */ + uint64_t generation; /* Inode generation: nodeid:gen must + be unique for the fs's lifetime */ + uint64_t entry_valid; /* Cache timeout for the name */ + uint64_t attr_valid; /* Cache timeout for the attributes */ + uint32_t entry_valid_nsec; + uint32_t attr_valid_nsec; struct fuse_attr attr; }; struct fuse_forget_in { - __u64 nlookup; + uint64_t nlookup; }; struct fuse_forget_one { - __u64 nodeid; - __u64 nlookup; + uint64_t nodeid; + uint64_t nlookup; }; struct fuse_batch_forget_in { - __u32 count; - __u32 dummy; + uint32_t count; + uint32_t dummy; }; struct fuse_getattr_in { - __u32 getattr_flags; - __u32 dummy; - __u64 fh; + uint32_t getattr_flags; + uint32_t dummy; + uint64_t fh; }; #define FUSE_COMPAT_ATTR_OUT_SIZE 96 struct fuse_attr_out { - __u64 attr_valid; /* Cache timeout for the attributes */ - __u32 attr_valid_nsec; - __u32 dummy; + uint64_t attr_valid; /* Cache timeout for the attributes */ + uint32_t attr_valid_nsec; + uint32_t dummy; struct fuse_attr attr; }; #define FUSE_COMPAT_MKNOD_IN_SIZE 8 struct fuse_mknod_in { - __u32 mode; - __u32 rdev; - __u32 umask; - __u32 padding; + uint32_t mode; + uint32_t rdev; + uint32_t umask; + uint32_t padding; }; struct fuse_mkdir_in { - __u32 mode; - __u32 umask; + uint32_t mode; + uint32_t umask; }; struct fuse_rename_in { - __u64 newdir; + uint64_t newdir; }; struct fuse_link_in { - __u64 oldnodeid; + uint64_t oldnodeid; }; struct fuse_setattr_in { - __u32 valid; - __u32 padding; - __u64 fh; - __u64 size; - __u64 lock_owner; - __u64 atime; - __u64 mtime; - __u64 unused2; - __u32 atimensec; - __u32 mtimensec; - __u32 unused3; - __u32 mode; - __u32 unused4; - __u32 uid; - __u32 gid; - __u32 unused5; + uint32_t valid; + uint32_t padding; + uint64_t fh; + uint64_t size; + uint64_t lock_owner; + uint64_t atime; + uint64_t mtime; + uint64_t unused2; + uint32_t atimensec; + uint32_t mtimensec; + uint32_t unused3; + uint32_t mode; + uint32_t unused4; + uint32_t uid; + uint32_t gid; + uint32_t unused5; }; struct fuse_open_in { - __u32 flags; - __u32 unused; + uint32_t flags; + uint32_t unused; }; struct fuse_create_in { - __u32 flags; - __u32 mode; - __u32 umask; - __u32 padding; + uint32_t flags; + uint32_t mode; + uint32_t umask; + uint32_t padding; }; struct fuse_open_out { - __u64 fh; - __u32 open_flags; - __u32 padding; + uint64_t fh; + uint32_t open_flags; + uint32_t padding; }; struct fuse_release_in { - __u64 fh; - __u32 flags; - __u32 release_flags; - __u64 lock_owner; + uint64_t fh; + uint32_t flags; + uint32_t release_flags; + uint64_t lock_owner; }; struct fuse_flush_in { - __u64 fh; - __u32 unused; - __u32 padding; - __u64 lock_owner; + uint64_t fh; + uint32_t unused; + uint32_t padding; + uint64_t lock_owner; }; struct fuse_read_in { - __u64 fh; - __u64 offset; - __u32 size; - __u32 read_flags; - __u64 lock_owner; - __u32 flags; - __u32 padding; + uint64_t fh; + uint64_t offset; + uint32_t size; + uint32_t read_flags; + uint64_t lock_owner; + uint32_t flags; + uint32_t padding; }; #define FUSE_COMPAT_WRITE_IN_SIZE 24 struct fuse_write_in { - __u64 fh; - __u64 offset; - __u32 size; - __u32 write_flags; - __u64 lock_owner; - __u32 flags; - __u32 padding; + uint64_t fh; + uint64_t offset; + uint32_t size; + uint32_t write_flags; + uint64_t lock_owner; + uint32_t flags; + uint32_t padding; }; struct fuse_write_out { - __u32 size; - __u32 padding; + uint32_t size; + uint32_t padding; }; #define FUSE_COMPAT_STATFS_SIZE 48 @@ -480,32 +505,32 @@ struct fuse_statfs_out { }; struct fuse_fsync_in { - __u64 fh; - __u32 fsync_flags; - __u32 padding; + uint64_t fh; + uint32_t fsync_flags; + uint32_t padding; }; struct fuse_setxattr_in { - __u32 size; - __u32 flags; + uint32_t size; + uint32_t flags; }; struct fuse_getxattr_in { - __u32 size; - __u32 padding; + uint32_t size; + uint32_t padding; }; struct fuse_getxattr_out { - __u32 size; - __u32 padding; + uint32_t size; + uint32_t padding; }; struct fuse_lk_in { - __u64 fh; - __u64 owner; + uint64_t fh; + uint64_t owner; struct fuse_file_lock lk; - __u32 lk_flags; - __u32 padding; + uint32_t lk_flags; + uint32_t padding; }; struct fuse_lk_out { @@ -513,179 +538,190 @@ struct fuse_lk_out { }; struct fuse_access_in { - __u32 mask; - __u32 padding; + uint32_t mask; + uint32_t padding; }; struct fuse_init_in { - __u32 major; - __u32 minor; - __u32 max_readahead; - __u32 flags; + uint32_t major; + uint32_t minor; + uint32_t max_readahead; + uint32_t flags; }; struct fuse_init_out { - __u32 major; - __u32 minor; - __u32 max_readahead; - __u32 flags; - __u16 max_background; - __u16 congestion_threshold; - __u32 max_write; + uint32_t major; + uint32_t minor; + uint32_t max_readahead; + uint32_t flags; + uint16_t max_background; + uint16_t congestion_threshold; + uint32_t max_write; }; #define CUSE_INIT_INFO_MAX 4096 struct cuse_init_in { - __u32 major; - __u32 minor; - __u32 unused; - __u32 flags; + uint32_t major; + uint32_t minor; + uint32_t unused; + uint32_t flags; }; struct cuse_init_out { - __u32 major; - __u32 minor; - __u32 unused; - __u32 flags; - __u32 max_read; - __u32 max_write; - __u32 dev_major; /* chardev major */ - __u32 dev_minor; /* chardev minor */ - __u32 spare[10]; + uint32_t major; + uint32_t minor; + uint32_t unused; + uint32_t flags; + uint32_t max_read; + uint32_t max_write; + uint32_t dev_major; /* chardev major */ + uint32_t dev_minor; /* chardev minor */ + uint32_t spare[10]; }; struct fuse_interrupt_in { - __u64 unique; + uint64_t unique; }; struct fuse_bmap_in { - __u64 block; - __u32 blocksize; - __u32 padding; + uint64_t block; + uint32_t blocksize; + uint32_t padding; }; struct fuse_bmap_out { - __u64 block; + uint64_t block; }; struct fuse_ioctl_in { - __u64 fh; - __u32 flags; - __u32 cmd; - __u64 arg; - __u32 in_size; - __u32 out_size; + uint64_t fh; + uint32_t flags; + uint32_t cmd; + uint64_t arg; + uint32_t in_size; + uint32_t out_size; }; struct fuse_ioctl_iovec { - __u64 base; - __u64 len; + uint64_t base; + uint64_t len; }; struct fuse_ioctl_out { - __s32 result; - __u32 flags; - __u32 in_iovs; - __u32 out_iovs; + int32_t result; + uint32_t flags; + uint32_t in_iovs; + uint32_t out_iovs; }; struct fuse_poll_in { - __u64 fh; - __u64 kh; - __u32 flags; - __u32 padding; + uint64_t fh; + uint64_t kh; + uint32_t flags; + uint32_t events; }; struct fuse_poll_out { - __u32 revents; - __u32 padding; + uint32_t revents; + uint32_t padding; }; struct fuse_notify_poll_wakeup_out { - __u64 kh; + uint64_t kh; }; struct fuse_fallocate_in { - __u64 fh; - __u64 offset; - __u64 length; - __u32 mode; - __u32 padding; + uint64_t fh; + uint64_t offset; + uint64_t length; + uint32_t mode; + uint32_t padding; }; struct fuse_in_header { - __u32 len; - __u32 opcode; - __u64 unique; - __u64 nodeid; - __u32 uid; - __u32 gid; - __u32 pid; - __u32 padding; + uint32_t len; + uint32_t opcode; + uint64_t unique; + uint64_t nodeid; + uint32_t uid; + uint32_t gid; + uint32_t pid; + uint32_t padding; }; struct fuse_out_header { - __u32 len; - __s32 error; - __u64 unique; + uint32_t len; + int32_t error; + uint64_t unique; }; struct fuse_dirent { - __u64 ino; - __u64 off; - __u32 namelen; - __u32 type; + uint64_t ino; + uint64_t off; + uint32_t namelen; + uint32_t type; char name[]; }; #define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) -#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1)) +#define FUSE_DIRENT_ALIGN(x) \ + (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) #define FUSE_DIRENT_SIZE(d) \ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) +struct fuse_direntplus { + struct fuse_entry_out entry_out; + struct fuse_dirent dirent; +}; + +#define FUSE_NAME_OFFSET_DIRENTPLUS \ + offsetof(struct fuse_direntplus, dirent.name) +#define FUSE_DIRENTPLUS_SIZE(d) \ + FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen) + struct fuse_notify_inval_inode_out { - __u64 ino; - __s64 off; - __s64 len; + uint64_t ino; + int64_t off; + int64_t len; }; struct fuse_notify_inval_entry_out { - __u64 parent; - __u32 namelen; - __u32 padding; + uint64_t parent; + uint32_t namelen; + uint32_t padding; }; struct fuse_notify_delete_out { - __u64 parent; - __u64 child; - __u32 namelen; - __u32 padding; + uint64_t parent; + uint64_t child; + uint32_t namelen; + uint32_t padding; }; struct fuse_notify_store_out { - __u64 nodeid; - __u64 offset; - __u32 size; - __u32 padding; + uint64_t nodeid; + uint64_t offset; + uint32_t size; + uint32_t padding; }; struct fuse_notify_retrieve_out { - __u64 notify_unique; - __u64 nodeid; - __u64 offset; - __u32 size; - __u32 padding; + uint64_t notify_unique; + uint64_t nodeid; + uint64_t offset; + uint32_t size; + uint32_t padding; }; /* Matches the size of fuse_write_in */ struct fuse_notify_retrieve_in { - __u64 dummy1; - __u64 offset; - __u32 size; - __u32 dummy2; - __u64 dummy3; - __u64 dummy4; + uint64_t dummy1; + uint64_t offset; + uint32_t size; + uint32_t dummy2; + uint64_t dummy3; + uint64_t dummy4; }; #endif /* _LINUX_FUSE_H */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 2036717..595f061 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -44,7 +44,7 @@ extern "C" { #define FUSE_ROOT_ID 1 /** Inode number type */ -typedef unsigned long fuse_ino_t; +typedef uint64_t fuse_ino_t; /** Request pointer type */ typedef struct fuse_req *fuse_req_t; @@ -88,7 +88,7 @@ struct fuse_entry_param { * it as an error. * */ - unsigned long generation; + uint64_t generation; /** Inode attributes. * @@ -122,7 +122,7 @@ struct fuse_ctx { }; struct fuse_forget_data { - uint64_t ino; + fuse_ino_t ino; uint64_t nlookup; }; @@ -233,7 +233,7 @@ struct fuse_lowlevel_ops { * @param ino the inode number * @param nlookup the number of lookups to forget */ - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup); /** * Get file attributes @@ -600,6 +600,9 @@ struct fuse_lowlevel_ops { * * fi->fh will contain the value set by the opendir method, or * will be undefined if the opendir method didn't set any value. + * + * Returning a directory entry from readdir() does not affect + * its lookup count. * * Valid replies: * fuse_reply_buf @@ -1016,6 +1019,36 @@ struct fuse_lowlevel_ops { */ void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi); + + /** + * Read directory with attributes + * + * Send a buffer filled using fuse_add_direntry_plus(), with size not + * exceeding the requested size. Send an empty buffer on end of + * stream. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * In contrast to readdir() (which does not affect the lookup + * counts), the lookup count of every entry returned by + * readdirplus() is increased by one. + * + * Introduced in version 3.0 + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_data + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size maximum number of bytes to send + * @param off offset to continue reading the directory stream + * @param fi file information + */ + void (*readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); }; /** @@ -1150,6 +1183,11 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); * Possible requests: * read, readdir, getxattr, listxattr * + * Side effects: + * when used to return data from a readdirplus() (but not readdir()) + * call, increments the lookup count of each returned entry by one + * on success. + * * @param req request handle * @param bufv buffer vector * @param flags flags controlling the copy @@ -1252,6 +1290,34 @@ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, off_t off); /** + * Add a directory entry to the buffer with the attributes + * + * Buffer needs to be large enough to hold the entry. If it's not, + * then the entry is not filled in but the size of the entry is still + * returned. The caller can check this by comparing the bufsize + * parameter with the returned entry size. If the entry size is + * larger than the buffer size, the operation failed. + * + * From the 'stbuf' argument the st_ino field and bits 12-15 of the + * st_mode field are used. The other fields are ignored. + * + * Note: offsets do not necessarily represent physical offsets, and + * could be any marker, that enables the implementation to find a + * specific point in the directory stream. + * + * @param req request handle + * @param buf the point where the new entry will be added to the buffer + * @param bufsize remaining size of the buffer + * @param name the name of the entry + * @param e the directory entry + * @param off the offset of the next entry + * @return the space needed for the entry + */ +size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, + const char *name, + const struct fuse_entry_param *e, off_t off); + +/** * Reply to ask for data fetch and output buffer preparation. ioctl * will be retried with the specified input data fetched and output * buffer prepared. @@ -1491,9 +1557,6 @@ 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 * @@ -1502,6 +1565,9 @@ int fuse_lowlevel_is_lib_option(const char *opt); * @param op_size sizeof(struct fuse_lowlevel_ops) * @param userdata user data * @return the created session object, or NULL on failure + * + * Example: See hello_ll.c: + * \snippet hello_ll.c doxygen_fuse_lowlevel_usage */ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, @@ -1512,61 +1578,8 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, * ----------------------------------------------------------- */ /** - * 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); - -/** * 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 @@ -1575,7 +1588,7 @@ struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); /** - * Remove a channel from a session + * Remove the channel from a session * * If the channel is not assigned to a session, then this is a no-op * @@ -1584,35 +1597,17 @@ void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); void fuse_session_remove_chan(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 + * Return channel assigned to the session * * @param se the session - * @param buf buffer containing the raw request - * @param len request length - * @param ch channel on which the request was received + * @return the channel */ -void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, - struct fuse_chan *ch); +struct fuse_chan *fuse_session_chan(struct fuse_session *se); /** * 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. + * 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 @@ -1624,17 +1619,16 @@ void fuse_session_process_buf(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 + * 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 + * @param ch 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); + struct fuse_chan *ch); /** * Destroy a session @@ -1644,7 +1638,10 @@ int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, void fuse_session_destroy(struct fuse_session *se); /** - * Exit a session + * Exit a session. + * + * This function is invoked by the POSIX signal handlers, when registered using: + * * fuse_set_signal_handlers() * * @param se the session */ @@ -1666,15 +1663,11 @@ void fuse_session_reset(struct fuse_session *se); int fuse_session_exited(struct fuse_session *se); /** - * Get the user data provided to the session + * Enter a single threaded, blocking event loop. * - * @param se the session - * @return the user data - */ -void *fuse_session_data(struct fuse_session *se); - -/** - * Enter a single threaded event loop + * Using POSIX signals this event loop can be exited but the session + * needs to be configued by issuing: + * fuse_set_signal_handlers() first. * * @param se the session * @return 0 on success, -1 on error @@ -1694,56 +1687,6 @@ int fuse_session_loop_mt(struct fuse_session *se); * ----------------------------------------------------------- */ /** - * 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); - -/** * Query the file descriptor of the channel * * @param ch the channel @@ -1752,84 +1695,12 @@ struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, 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); -/* ----------------------------------------------------------- * - * 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/include/fuse_lowlevel_compat.h b/include/fuse_lowlevel_compat.h deleted file mode 100644 index 8de220b..0000000 --- a/include/fuse_lowlevel_compat.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -/* 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 <sys/statfs.h> - -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/include/fuse_opt.h b/include/fuse_opt.h index add0a30..20653b1 100644 --- a/include/fuse_opt.h +++ b/include/fuse_opt.h @@ -70,8 +70,9 @@ extern "C" { * * 6) "-x %s", etc. Combination of 4) and 5) * - * If the format is "%s", memory is allocated for the string unlike - * with scanf(). + * If the format is "%s", memory is allocated for the string unlike with + * scanf(). The previous value (if non-NULL) stored at the this location is + * freed. */ struct fuse_opt { /** Matching template and optional parameter formatting */ diff --git a/include/old/fuse.h b/include/old/fuse.h deleted file mode 100644 index 3db0945..0000000 --- a/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 <fuse.h>', not '#include - <fuse/fuse.h>'. -*/ - -#include "fuse/fuse.h" diff --git a/include/ulockmgr.h b/include/ulockmgr.h deleted file mode 100644 index ad55579..0000000 --- a/include/ulockmgr.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - libulockmgr: Userspace Lock Manager Library - Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu> - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -#include <stdint.h> -#include <fcntl.h> -#include <sys/types.h> - -/** - * 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); diff --git a/lib/Makefile.am b/lib/Makefile.am index 87c0522..2ad0f15 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,9 +1,9 @@ ## Process this file with automake to produce Makefile.in AM_CPPFLAGS = -I$(top_srcdir)/include -DFUSERMOUNT_DIR=\"$(bindir)\" \ - -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=26 + -D_REENTRANT -DFUSE_USE_VERSION=30 -lib_LTLIBRARIES = libfuse.la libulockmgr.la +lib_LTLIBRARIES = libfuse3.la if BSD mount_source = mount_bsd.c @@ -17,10 +17,9 @@ else iconv_source = endif -libfuse_la_SOURCES = \ +libfuse3_la_SOURCES = \ fuse.c \ fuse_i.h \ - fuse_kern_chan.c \ fuse_loop.c \ fuse_loop_mt.c \ fuse_lowlevel.c \ @@ -36,14 +35,11 @@ libfuse_la_SOURCES = \ $(iconv_source) \ $(mount_source) -libfuse_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 2:9:3 \ +libfuse3_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 0:0:0 \ -Wl,--version-script,$(srcdir)/fuse_versionscript if NETBSD -libfuse_la_LIBADD = -lperfuse -lpuffs +libfuse3_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/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c index 402cf4b..fbaa873 100644 --- a/lib/cuse_lowlevel.c +++ b/lib/cuse_lowlevel.c @@ -7,11 +7,11 @@ See the file COPYING.LIB. */ +#include "config.h" #include "cuse_lowlevel.h" #include "fuse_kernel.h" #include "fuse_i.h" #include "fuse_opt.h" -#include "fuse_misc.h" #include <stdio.h> #include <string.h> @@ -170,12 +170,12 @@ struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, 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); + se = fuse_lowlevel_new(args, &lop, sizeof(lop), userdata); if (!se) { free(cd); return NULL; } - ll = se->data; + ll = se->f; ll->cuse_data = cd; return se; @@ -200,7 +200,7 @@ void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *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); + size_t bufsize = f->bufsize; struct cuse_lowlevel_ops *clop = req_clop(req); (void) nodeid; @@ -313,7 +313,7 @@ struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], goto err_se; } - ch = fuse_kern_chan_new(fd); + ch = fuse_chan_new(fd); if (!ch) { close(fd); goto err_se; @@ -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 <stdio.h> @@ -83,7 +81,6 @@ struct fuse_fs { struct fuse_operations op; struct fuse_module *m; void *user_data; - int compat; int debug; }; @@ -146,8 +143,6 @@ struct fuse { struct fuse_config conf; int intr_installed; struct fuse_fs *fs; - int nullpath_ok; - int utime_omit_ok; struct lock_queue_element *lockq; int pagesize; struct list_head partial_slabs; @@ -208,12 +203,6 @@ struct fuse_dh { fuse_ino_t nodeid; }; -/* old dir handle */ -struct fuse_dirhandle { - fuse_fill_dir_t filler; - void *buf; -}; - struct fuse_context_i { struct fuse_context ctx; fuse_req_t req; @@ -1104,10 +1093,13 @@ static void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid, 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 %llu (w)\n", + msg, (unsigned long long) wnode->nodeid); + } else { + fprintf(stderr, "%s %llu\n", + msg, (unsigned long long) nodeid); + } } } @@ -1182,7 +1174,7 @@ static int get_path_nullok(struct fuse *f, fuse_ino_t nodeid, char **path) *path = NULL; } else { err = get_path_common(f, nodeid, NULL, path, NULL); - if (err == -ENOENT && f->nullpath_ok) + if (err == -ENOENT) err = 0; } @@ -1464,129 +1456,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, const char *path, - struct fuse_file_info *fi) -{ - if (!fs->compat || fs->compat >= 22) - return fs->op.release(path, fi); - else - return ((struct fuse_operations_compat2 *) &fs->op) - ->release(path, 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, const char *path, - struct fuse_file_info *fi) -{ - return fs->op.release(path, 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, struct stat *buf) { fuse_get_context()->private_data = fs->user_data; @@ -1696,7 +1565,7 @@ int fuse_fs_release(struct fuse_fs *fs, const char *path, fi->flush ? "+flush" : "", (unsigned long long) fi->fh, fi->flags); - return fuse_compat_release(fs, path, fi); + return fs->op.release(path, fi); } else { return 0; } @@ -1713,10 +1582,10 @@ 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", + fprintf(stderr, " opendir[%llu] flags: 0x%x %s\n", (unsigned long long) fi->fh, fi->flags, path); return err; @@ -1736,10 +1605,10 @@ 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", + fprintf(stderr, " open[%llu] flags: 0x%x %s\n", (unsigned long long) fi->fh, fi->flags, path); return err; @@ -1958,7 +1827,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; @@ -1981,20 +1850,6 @@ int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, } } -static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type, - ino_t ino) -{ - int res; - struct stat stbuf; - - memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_mode = type << 12; - stbuf.st_ino = ino; - - res = dh->filler(dh->buf, name, &stbuf, 0); - return res ? -ENOMEM : 0; -} - int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, fuse_fill_dir_t filler, off_t off, struct fuse_file_info *fi) @@ -2007,16 +1862,6 @@ int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, (unsigned long long) off); return fs->op.readdir(path, buf, filler, off, fi); - } else if (fs->op.getdir) { - struct fuse_dirhandle dh; - - if (fs->debug) - fprintf(stderr, "getdir[%llu]\n", - (unsigned long long) fi->fh); - - dh.filler = filler; - dh.buf = buf; - return fs->op.getdir(path, &dh, fill_dir_old); } else { return -ENOSYS; } @@ -2154,16 +1999,6 @@ int fuse_fs_utimens(struct fuse_fs *fs, const char *path, 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; } @@ -2324,8 +2159,9 @@ int fuse_fs_poll(struct fuse_fs *fs, const char *path, int res; if (fs->debug) - fprintf(stderr, "poll[%llu] ph: %p\n", - (unsigned long long) fi->fh, ph); + fprintf(stderr, "poll[%llu] ph: %p, events 0x%x\n", + (unsigned long long) fi->fh, ph, + fi->poll_events); res = fs->op.poll(path, fi, ph, reventsp); @@ -2487,8 +2323,8 @@ static int lookup_path(struct fuse *f, fuse_ino_t nodeid, } set_stat(f, e->ino, &e->attr); if (f->conf.debug) - fprintf(stderr, " NODEID: %lu\n", - (unsigned long) e->ino); + fprintf(stderr, " NODEID: %llu\n", + (unsigned long long) e->ino); } } return res; @@ -2496,9 +2332,12 @@ static int lookup_path(struct fuse *f, fuse_ino_t nodeid, static struct fuse_context_i *fuse_get_context_internal(void) { - struct fuse_context_i *c; + return (struct fuse_context_i *) pthread_getspecific(fuse_context_key); +} - c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); +static struct fuse_context_i *fuse_create_context(struct fuse *f) +{ + struct fuse_context_i *c = fuse_get_context_internal(); if (c == NULL) { c = (struct fuse_context_i *) calloc(1, sizeof(struct fuse_context_i)); @@ -2511,7 +2350,11 @@ static struct fuse_context_i *fuse_get_context_internal(void) abort(); } pthread_setspecific(fuse_context_key, c); + } else { + memset(c, 0, sizeof(*c)); } + c->ctx.fuse = f; + return c; } @@ -2551,10 +2394,9 @@ static void fuse_delete_context_key(void) static struct fuse *req_fuse_prepare(fuse_req_t req) { - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse_context_i *c = fuse_create_context(req_fuse(req)); 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; @@ -2598,10 +2440,8 @@ void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *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(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; + fuse_create_context(f); conn->want |= FUSE_CAP_EXPORT_SUPPORT; fuse_fs_init(f->fs, conn); } @@ -2619,10 +2459,8 @@ void fuse_fs_destroy(struct fuse_fs *fs) static void fuse_lib_destroy(void *data) { 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_create_context(f); fuse_fs_destroy(f->fs); f->fs = NULL; } @@ -2692,8 +2530,7 @@ static void do_forget(struct fuse *f, fuse_ino_t ino, uint64_t nlookup) forget_node(f, ino, nlookup); } -static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, - unsigned long nlookup) +static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) { do_forget(req_fuse(req), ino, nlookup); fuse_reply_none(req); @@ -2796,7 +2633,7 @@ static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, attr->st_size); } #ifdef HAVE_UTIMENSAT - if (!err && f->utime_omit_ok && + if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) { struct timespec tv[2]; @@ -3079,14 +2916,8 @@ static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path, { struct node *node; int unlink_hidden = 0; - const char *compatpath; - if (path != NULL || f->nullpath_ok || f->conf.nopath) - compatpath = path; - else - compatpath = "-"; - - fuse_fs_release(f->fs, compatpath, fi); + fuse_fs_release(f->fs, path, fi); pthread_mutex_lock(&f->lock); node = get_node(f, ino); @@ -3312,7 +3143,6 @@ static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; memset(fi, 0, sizeof(struct fuse_file_info)); fi->fh = dh->fh; - fi->fh_old = dh->fh; return dh; } @@ -3517,16 +3347,11 @@ static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info fi; struct fuse_dh *dh = get_dirhandle(llfi, &fi); char *path; - const char *compatpath; get_path_nullok(f, ino, &path); - if (path != NULL || f->nullpath_ok || f->conf.nopath) - compatpath = path; - else - compatpath = "-"; fuse_prepare_interrupt(f, req, &d); - fuse_fs_releasedir(f->fs, compatpath, &fi); + fuse_fs_releasedir(f->fs, path, &fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); @@ -4184,90 +4009,29 @@ int fuse_notify_poll(struct fuse_pollhandle *ph) return fuse_lowlevel_notify_poll(ph); } -static void free_cmd(struct fuse_cmd *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); -} - -int fuse_exited(struct fuse *f) -{ - return fuse_session_exited(f->se); -} - struct fuse_session *fuse_get_session(struct fuse *f) { 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 *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; -} - 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 fuse_chan *ch = fuse_session_chan(se); struct pollfd fds = { .fd = fuse_chan_fd(ch), .events = POLLIN }; - - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } + struct fuse_buf fbuf = { + .mem = NULL, + }; 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); @@ -4283,14 +4047,14 @@ static int fuse_session_loop_remember(struct fuse *f) else break; } else if (res > 0) { - res = fuse_session_receive_buf(se, &fbuf, &tmpch); + res = fuse_session_receive_buf(se, &fbuf, ch); if (res == -EINTR) continue; if (res <= 0) break; - fuse_session_process_buf(se, &fbuf, tmpch); + fuse_session_process_buf(se, &fbuf, ch); } else { timeout = fuse_clean_cache(f); curr_time(&now); @@ -4298,7 +4062,7 @@ static int fuse_session_loop_remember(struct fuse *f) } } - free(buf); + free(fbuf.mem); fuse_session_reset(se); return res < 0 ? -1 : 0; } @@ -4314,13 +4078,6 @@ int fuse_loop(struct fuse *f) return fuse_session_loop(f->se); } -int fuse_invalidate(struct fuse *f, const char *path) -{ - (void) f; - (void) path; - return -EINVAL; -} - void fuse_exit(struct fuse *f) { fuse_session_exit(f->se); @@ -4328,36 +4085,31 @@ void fuse_exit(struct fuse *f) struct fuse_context *fuse_get_context(void) { - return &fuse_get_context_internal()->ctx; -} + struct fuse_context_i *c = fuse_get_context_internal(); -/* - * 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; + if (c) + return &c->ctx; + else + return NULL; } -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); + struct fuse_context_i *c = fuse_get_context_internal(); + if (!c) + return -EINVAL; + + return fuse_req_getgroups(c->req, size, list); } int fuse_interrupted(void) { - return fuse_req_interrupted(fuse_get_context_internal()->req); -} + struct fuse_context_i *c = fuse_get_context_internal(); -void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) -{ - (void) func; - /* no-op */ + if (c) + return fuse_req_interrupted(c->req); + else + return 0; } enum { @@ -4402,7 +4154,7 @@ static const struct fuse_opt fuse_lib_opts[] = { static void fuse_lib_help(void) { - fprintf(stderr, + printf( " -o hard_remove immediate removal (don't hide files)\n" " -o use_ino let filesystem set inode numbers\n" " -o readdir_ino try to fill in d_ino in readdir\n" @@ -4428,7 +4180,7 @@ static void fuse_lib_help(void) static void fuse_lib_help_modules(void) { struct fuse_module *m; - fprintf(stderr, "\nModule options:\n"); + printf("\nModule options:\n"); pthread_mutex_lock(&fuse_context_lock); for (m = fuse_modules; m; m = m->next) { struct fuse_fs *fs = NULL; @@ -4436,7 +4188,7 @@ static void fuse_lib_help_modules(void) struct fuse_args args = FUSE_ARGS_INIT(0, NULL); if (fuse_opt_add_arg(&args, "") != -1 && fuse_opt_add_arg(&args, "-h") != -1) { - fprintf(stderr, "\n[%s]\n", m->name); + printf("\n[%s]\n", m->name); newfs = m->factory(&args, &fs); assert(newfs == NULL); } @@ -4459,12 +4211,6 @@ static int fuse_lib_opt_proc(void *data, const char *arg, int key, return 1; } -int fuse_is_lib_option(const char *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; @@ -4517,9 +4263,7 @@ static int fuse_push_module(struct fuse *f, const char *module, } newfs->m = m; f->fs = newfs; - f->nullpath_ok = newfs->op.flag_nullpath_ok && f->nullpath_ok; f->conf.nopath = newfs->op.flag_nopath && f->conf.nopath; - f->utime_omit_ok = newfs->op.flag_utime_omit_ok && f->utime_omit_ok; return 0; } @@ -4589,9 +4333,9 @@ 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) +struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, + const struct fuse_operations *op, + size_t op_size, void *user_data) { struct fuse *f; struct node *root; @@ -4611,11 +4355,8 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, if (!fs) goto out_free; - fs->compat = compat; f->fs = fs; - f->nullpath_ok = fs->op.flag_nullpath_ok; f->conf.nopath = fs->op.flag_nopath; - f->utime_omit_ok = fs->op.flag_utime_omit_ok; /* Oh f**k, this is ugly! */ if (!fs->op.lock) { @@ -4663,12 +4404,7 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, f->conf.readdir_ino = 1; #endif - 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); + f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f); if (f->se == NULL) { if (f->conf.help) fuse_lib_help_modules(); @@ -4678,9 +4414,7 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, fuse_session_add_chan(f->se, ch); if (f->conf.debug) { - fprintf(stderr, "nullpath_ok: %i\n", f->nullpath_ok); fprintf(stderr, "nopath: %i\n", f->conf.nopath); - fprintf(stderr, "utime_omit_ok: %i\n", f->utime_omit_ok); } /* Trace topmost layer by default */ @@ -4729,10 +4463,9 @@ out_free_name_table: 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); + if (f->fs->m) + fuse_put_module(f->fs->m); + free(f->fs); free(f->conf.modules); out_free: free(f); @@ -4742,13 +4475,6 @@ 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); -} - void fuse_destroy(struct fuse *f) { size_t i; @@ -4757,10 +4483,7 @@ void fuse_destroy(struct fuse *f) fuse_restore_intr_signal(f->conf.intr_signal); if (f->fs) { - struct fuse_context_i *c = fuse_get_context_internal(); - - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; + fuse_create_context(f); for (i = 0; i < f->id_table.size; i++) { struct node *node; @@ -4799,19 +4522,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; -} - /* called with fuse_context_lock held or during initialization (before main() has been called) */ void fuse_register_module(struct fuse_module *mod) @@ -4823,72 +4533,3 @@ void fuse_register_module(struct fuse_module *mod) mod->next = fuse_modules; fuse_modules = mod; } - -#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"); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index fa37156..5823743 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -13,21 +13,20 @@ struct fuse_chan; struct fuse_ll; struct fuse_session { - struct fuse_session_ops op; - - 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 *data; + struct fuse_ll *f; volatile int exited; struct fuse_chan *ch; }; +struct fuse_chan { + struct fuse_session *se; + + int fd; +}; + + struct fuse_req { struct fuse_ll *f; uint64_t unique; @@ -71,6 +70,10 @@ struct fuse_ll { int no_splice_write; int no_splice_move; int no_splice_read; + int auto_inval_data; + int no_auto_inval_data; + int no_readdirplus; + int no_readdirplus_auto; struct fuse_lowlevel_ops op; int got_init; struct cuse_data *cuse_data; @@ -85,28 +88,35 @@ struct fuse_ll { int broken_splice_nonblock; uint64_t notify_ctr; struct fuse_notify_req notify_list; + size_t bufsize; }; -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, - const struct fuse_operations *op, - size_t op_size, void *user_data, int compat); - -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); - -void fuse_kern_unmount_compat22(const char *mountpoint); int fuse_chan_clearfd(struct fuse_chan *ch); +void fuse_chan_close(struct fuse_chan *ch); + +/** + * Create a new session + * + * @return new session object, or NULL on failure + */ +struct fuse_session *fuse_session_new(void); + +/** + * Create a new channel + * + * @param op channel operations + * @param fd file descriptor of the channel + * @return the new channel object, or NULL on failure + */ +struct fuse_chan *fuse_chan_new(int fd); + +/** + * 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); void fuse_kern_unmount(const char *mountpoint, int fd); int fuse_kern_mount(const char *mountpoint, struct fuse_args *args); @@ -115,16 +125,6 @@ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count); void fuse_free_req(fuse_req_t req); - -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, - 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/lib/fuse_kern_chan.c b/lib/fuse_kern_chan.c deleted file mode 100644 index 4a9beb8..0000000 --- a/lib/fuse_kern_chan.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB -*/ - -#include "fuse_lowlevel.h" -#include "fuse_kernel.h" -#include "fuse_i.h" - -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <assert.h> - -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; -} - -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; -} - -static void fuse_kern_chan_destroy(struct fuse_chan *ch) -{ - int fd = fuse_chan_fd(ch); - - if (fd != -1) - close(fd); -} - -#define MIN_BUFSIZE 0x21000 - -struct fuse_chan *fuse_kern_chan_new(int fd) -{ - struct fuse_chan_ops op = { - .receive = fuse_kern_chan_receive, - .send = fuse_kern_chan_send, - .destroy = fuse_kern_chan_destroy, - }; - size_t bufsize = getpagesize() + 0x1000; - bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; - return fuse_chan_new(&op, fd, bufsize, NULL); -} diff --git a/lib/fuse_loop.c b/lib/fuse_loop.c index b7b4ca4..fb6d8a6 100644 --- a/lib/fuse_loop.c +++ b/lib/fuse_loop.c @@ -6,6 +6,7 @@ See the file COPYING.LIB */ +#include "config.h" #include "fuse_lowlevel.h" #include <stdio.h> @@ -15,32 +16,23 @@ 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 *) malloc(bufsize); - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } + struct fuse_chan *ch = fuse_session_chan(se); + struct fuse_buf fbuf = { + .mem = NULL, + }; 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); + res = fuse_session_receive_buf(se, &fbuf, ch); if (res == -EINTR) continue; if (res <= 0) break; - fuse_session_process_buf(se, &fbuf, tmpch); + fuse_session_process_buf(se, &fbuf, ch); } - free(buf); + free(fbuf.mem); fuse_session_reset(se); return res < 0 ? -1 : 0; } diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 82e3001..8f4dceb 100644..100755 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -6,6 +6,7 @@ See the file COPYING.LIB. */ +#include "config.h" #include "fuse_lowlevel.h" #include "fuse_misc.h" #include "fuse_kernel.h" @@ -28,7 +29,7 @@ struct fuse_worker { struct fuse_worker *next; pthread_t thread_id; size_t bufsize; - char *buf; + struct fuse_buf fbuf; struct fuse_mt *mt; }; @@ -70,15 +71,10 @@ static void *fuse_do_work(void *data) while (!fuse_session_exited(mt->se)) { int isforget = 0; - 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); + res = fuse_session_receive_buf(mt->se, &w->fbuf, mt->prevch); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (res == -EINTR) continue; @@ -100,8 +96,8 @@ static void *fuse_do_work(void *data) * This disgusting hack is needed so that zillions of threads * are not created on a burst of FORGET messages */ - if (!(fbuf.flags & FUSE_BUF_IS_FD)) { - struct fuse_in_header *in = fbuf.mem; + if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) { + struct fuse_in_header *in = w->fbuf.mem; if (in->opcode == FUSE_FORGET || in->opcode == FUSE_BATCH_FORGET) @@ -114,7 +110,7 @@ static void *fuse_do_work(void *data) fuse_loop_start_thread(mt); pthread_mutex_unlock(&mt->lock); - fuse_session_process_buf(mt->se, &fbuf, ch); + fuse_session_process_buf(mt->se, &w->fbuf, mt->prevch); pthread_mutex_lock(&mt->lock); if (!isforget) @@ -130,7 +126,7 @@ static void *fuse_do_work(void *data) pthread_mutex_unlock(&mt->lock); pthread_detach(w->thread_id); - free(w->buf); + free(w->fbuf.mem); free(w); return NULL; } @@ -184,18 +180,11 @@ static int fuse_loop_start_thread(struct fuse_mt *mt) return -1; } memset(w, 0, sizeof(struct fuse_worker)); - w->bufsize = fuse_chan_bufsize(mt->prevch); - w->buf = malloc(w->bufsize); + w->fbuf.mem = NULL; 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; } @@ -212,7 +201,7 @@ static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) pthread_mutex_lock(&mt->lock); list_del_worker(w); pthread_mutex_unlock(&mt->lock); - free(w->buf); + free(w->fbuf.mem); free(w); } @@ -224,7 +213,7 @@ int fuse_session_loop_mt(struct fuse_session *se) memset(&mt, 0, sizeof(struct fuse_mt)); mt.se = se; - mt.prevch = fuse_session_next_chan(se, NULL); + mt.prevch = fuse_session_chan(se); mt.error = 0; mt.numworker = 0; mt.numavail = 0; diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 8853346..2b8df06 100644..100755 --- a/lib/fuse_lowlevel.c +++ b/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 <stdio.h> #include <stdlib.h> @@ -156,6 +154,82 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) return req; } +static int fuse_chan_recv(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan *ch) +{ + struct fuse_ll *f = se->f; + int err; + ssize_t res; + + if (!buf->mem) { + buf->mem = malloc(f->bufsize); + if (!buf->mem) { + fprintf(stderr, + "fuse: failed to allocate read buffer\n"); + return -ENOMEM; + } + } + +restart: + res = read(fuse_chan_fd(ch), buf->mem, f->bufsize); + 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; + } + + buf->size = res; + + return res; +} + +static int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count) +{ + 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; +} + +void fuse_chan_close(struct fuse_chan *ch) +{ + int fd = fuse_chan_fd(ch); + if (fd != -1) + close(fd); +} + static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch, struct iovec *iov, int count) @@ -242,13 +316,13 @@ int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) return res; } -size_t fuse_dirent_size(size_t namelen) +static size_t fuse_dirent_size(size_t 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) +static 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; @@ -304,8 +378,6 @@ int fuse_reply_err(fuse_req_t req, int err) void fuse_reply_none(fuse_req_t req) { - if (req->ch) - fuse_chan_send(req->ch, NULL, 0); fuse_free_req(req); } @@ -342,6 +414,25 @@ static void fill_entry(struct fuse_entry_out *arg, convert_stat(&e->attr, &arg->attr); } +size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, + const char *name, + const struct fuse_entry_param *e, off_t off) +{ + struct fuse_entry_out *argp; + size_t entsize; + + (void) req; + entsize = FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + + fuse_dirent_size(strlen(name))); + if (entsize <= bufsize && buf){ + argp = (struct fuse_entry_out *)buf; + memset(argp, 0, sizeof(*argp)); + fill_entry(argp, e); + fuse_add_dirent(buf + sizeof(*argp), name, &(e->attr), off); + } + return entsize; +} + static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f) { @@ -486,6 +577,31 @@ static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp) } #ifdef HAVE_SPLICE +#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC) +static int fuse_pipe(int fds[2]) +{ + int rv = pipe(fds); + + if (rv == -1) + return rv; + + if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 || + fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 || + fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 || + fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) { + close(fds[0]); + close(fds[1]); + rv = -1; + } + return rv; +} +#else +static int fuse_pipe(int fds[2]) +{ + return pipe2(fds, O_CLOEXEC | O_NONBLOCK); +} +#endif + static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_ll *f) { struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); @@ -496,20 +612,12 @@ static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_ll *f) if (llp == NULL) return NULL; - res = pipe(llp->pipe); + res = fuse_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; - } - /* *the default size is 16 pages on linux */ @@ -1036,7 +1144,6 @@ static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) if (arg->getattr_flags & FUSE_GETATTR_FH) { memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; fip = &fi; } } @@ -1062,7 +1169,6 @@ static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi_store, 0, sizeof(fi_store)); fi = &fi_store; fi->fh = arg->fh; - fi->fh_old = fi->fh; } arg->valid &= FUSE_SET_ATTR_MODE | @@ -1225,7 +1331,6 @@ static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; if (req->f->conn.proto_minor >= 9) { fi.lock_owner = arg->lock_owner; fi.flags = arg->flags; @@ -1243,8 +1348,7 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; - fi.writepage = arg->write_flags & 1; + fi.writepage = (arg->write_flags & 1) != 0; if (req->f->conn.proto_minor < 9) { param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE; @@ -1274,7 +1378,6 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg, memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; fi.writepage = arg->write_flags & 1; if (req->f->conn.proto_minor < 9) { @@ -1313,7 +1416,6 @@ static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; fi.flush = 1; if (req->f->conn.proto_minor >= 7) fi.lock_owner = arg->lock_owner; @@ -1332,7 +1434,6 @@ static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; fi.fh = arg->fh; - fi.fh_old = fi.fh; if (req->f->conn.proto_minor >= 8) { fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; fi.lock_owner = arg->lock_owner; @@ -1355,7 +1456,6 @@ static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; if (req->f->op.fsync) req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); @@ -1384,7 +1484,6 @@ static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; if (req->f->op.readdir) req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); @@ -1392,6 +1491,20 @@ static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) fuse_reply_err(req, ENOSYS); } +static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + struct fuse_read_in *arg = (struct fuse_read_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + + if (req->f->op.readdirplus) + req->f->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); +} + static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { struct fuse_release_in *arg = (struct fuse_release_in *) inarg; @@ -1400,7 +1513,6 @@ static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; fi.fh = arg->fh; - fi.fh_old = fi.fh; if (req->f->op.releasedir) req->f->op.releasedir(req, nodeid, &fi); @@ -1415,7 +1527,6 @@ static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; if (req->f->op.fsyncdir) req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); @@ -1670,7 +1781,6 @@ static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 && !(flags & FUSE_IOCTL_32BIT)) { @@ -1697,7 +1807,7 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - fi.fh_old = fi.fh; + fi.poll_events = arg->events; if (req->f->op.poll) { struct fuse_pollhandle *ph = NULL; @@ -1738,7 +1848,7 @@ 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); + size_t bufsize = f->bufsize; (void) nodeid; if (f->debug) { @@ -1790,6 +1900,12 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.capable |= FUSE_CAP_DONT_MASK; if (arg->flags & FUSE_FLOCK_LOCKS) f->conn.capable |= FUSE_CAP_FLOCK_LOCKS; + if (arg->flags & FUSE_AUTO_INVAL_DATA) + f->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA; + if (arg->flags & FUSE_DO_READDIRPLUS) + f->conn.capable |= FUSE_CAP_READDIRPLUS; + if (arg->flags & FUSE_READDIRPLUS_AUTO) + f->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO; } else { f->conn.async_read = 0; f->conn.max_readahead = 0; @@ -1820,6 +1936,13 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.want |= FUSE_CAP_FLOCK_LOCKS; if (f->big_writes) f->conn.want |= FUSE_CAP_BIG_WRITES; + if (f->auto_inval_data) + f->conn.want |= FUSE_CAP_AUTO_INVAL_DATA; + if (f->op.readdirplus && !f->no_readdirplus) { + f->conn.want |= FUSE_CAP_READDIRPLUS; + if (!f->no_readdirplus_auto) + f->conn.want |= FUSE_CAP_READDIRPLUS_AUTO; + } if (bufsize < FUSE_MIN_READ_BUFFER) { fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", @@ -1841,7 +1964,12 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.want &= ~FUSE_CAP_SPLICE_WRITE; if (f->no_splice_move) f->conn.want &= ~FUSE_CAP_SPLICE_MOVE; - + if (f->no_auto_inval_data) + f->conn.want &= ~FUSE_CAP_AUTO_INVAL_DATA; + if (f->no_readdirplus) + f->conn.want &= ~FUSE_CAP_READDIRPLUS; + if (f->no_readdirplus_auto) + f->conn.want &= ~FUSE_CAP_READDIRPLUS_AUTO; if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ)) outarg.flags |= FUSE_ASYNC_READ; if (f->conn.want & FUSE_CAP_POSIX_LOCKS) @@ -1856,6 +1984,12 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) outarg.flags |= FUSE_DONT_MASK; if (f->conn.want & FUSE_CAP_FLOCK_LOCKS) outarg.flags |= FUSE_FLOCK_LOCKS; + if (f->conn.want & FUSE_CAP_AUTO_INVAL_DATA) + outarg.flags |= FUSE_AUTO_INVAL_DATA; + if (f->conn.want & FUSE_CAP_READDIRPLUS) + outarg.flags |= FUSE_DO_READDIRPLUS; + if (f->conn.want & FUSE_CAP_READDIRPLUS_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) { @@ -1989,7 +2123,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2013,7 +2147,7 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2040,7 +2174,7 @@ int fuse_lowlevel_notify_delete(struct fuse_chan *ch, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2074,7 +2208,7 @@ int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2156,7 +2290,7 @@ int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2203,21 +2337,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) { @@ -2287,6 +2406,7 @@ static struct { [FUSE_DESTROY] = { do_destroy, "DESTROY" }, [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, + [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"}, [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, }; @@ -2315,10 +2435,10 @@ static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, return 0; } -static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, - struct fuse_chan *ch) +void fuse_session_process_buf(struct fuse_session *se, + const struct fuse_buf *buf, struct fuse_chan *ch) { - struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_ll *f = se->f; 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 }; @@ -2352,10 +2472,10 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, if (f->debug) { fprintf(stderr, - "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu, pid: %u\n", + "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n", (unsigned long long) in->unique, opname((enum fuse_opcode) in->opcode), in->opcode, - (unsigned long) in->nodeid, buf->size, in->pid); + (unsigned long long) in->nodeid, buf->size, in->pid); } req = fuse_ll_alloc_req(f); @@ -2395,7 +2515,8 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR && - in->opcode != FUSE_NOTIFY_REPLY) + in->opcode != FUSE_NOTIFY_REPLY && + in->opcode != FUSE_READDIRPLUS) goto reply_err; err = ENOSYS; @@ -2453,17 +2574,6 @@ clear_pipe: 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, - }; - - fuse_ll_process_buf(data, &fbuf, ch); -} - enum { KEY_HELP, KEY_VERSION, @@ -2492,6 +2602,13 @@ static const struct fuse_opt fuse_ll_opts[] = { { "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}, + { "auto_inval_data", offsetof(struct fuse_ll, auto_inval_data), 1}, + { "no_auto_inval_data", offsetof(struct fuse_ll, no_auto_inval_data), 1}, + { "readdirplus=no", offsetof(struct fuse_ll, no_readdirplus), 1}, + { "readdirplus=yes", offsetof(struct fuse_ll, no_readdirplus), 0}, + { "readdirplus=yes", offsetof(struct fuse_ll, no_readdirplus_auto), 1}, + { "readdirplus=auto", offsetof(struct fuse_ll, no_readdirplus), 0}, + { "readdirplus=auto", offsetof(struct fuse_ll, no_readdirplus_auto), 0}, FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP), @@ -2502,13 +2619,13 @@ static const struct fuse_opt fuse_ll_opts[] = { static void fuse_ll_version(void) { - fprintf(stderr, "using FUSE kernel interface version %i.%i\n", - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); + printf("using FUSE kernel interface version %i.%i\n", + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } static void fuse_ll_help(void) { - fprintf(stderr, + printf( " -o max_write=N set maximum size of write requests\n" " -o max_readahead=N set maximum readahead\n" " -o max_background=N set number of maximum background requests\n" @@ -2523,6 +2640,8 @@ static void fuse_ll_help(void) " -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" +" -o [no_]auto_inval_data use automatic kernel cache invalidation logic\n" +" -o readdirplus=S control readdirplus use (yes|no|auto)\n" ); } @@ -2547,14 +2666,8 @@ static int fuse_ll_opt_proc(void *data, const char *arg, int key, return -1; } -int fuse_lowlevel_is_lib_option(const char *opt) -{ - return fuse_opt_match(fuse_ll_opts, opt); -} - -static void fuse_ll_destroy(void *data) +static void fuse_ll_destroy(struct fuse_ll *f) { - struct fuse_ll *f = (struct fuse_ll *) data; struct fuse_ll_pipe *llp; if (f->got_init && !f->got_destroy) { @@ -2570,6 +2683,15 @@ static void fuse_ll_destroy(void *data) free(f); } +void fuse_session_destroy(struct fuse_session *se) +{ + fuse_ll_destroy(se->f); + if (se->ch != NULL) + fuse_chan_destroy(se->ch); + free(se); +} + + static void fuse_ll_pipe_destructor(void *data) { struct fuse_ll_pipe *llp = data; @@ -2577,12 +2699,11 @@ static void fuse_ll_pipe_destructor(void *data) } #ifdef HAVE_SPLICE -static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) +int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan *ch) { - struct fuse_chan *ch = *chp; - struct fuse_ll *f = fuse_session_data(se); - size_t bufsize = buf->size; + struct fuse_ll *f = se->f; + size_t bufsize = buf->size = f->bufsize; struct fuse_ll_pipe *llp; struct fuse_buf tmpbuf; int err; @@ -2666,47 +2787,25 @@ static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, return res; fallback: - res = fuse_chan_recv(chp, buf->mem, bufsize); - if (res <= 0) - return res; - - buf->size = res; - - return res; + return fuse_chan_recv(se, buf, ch); } #else -static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) +int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan *ch) { - (void) se; - - int res = fuse_chan_recv(chp, buf->mem, buf->size); - if (res <= 0) - return res; - - buf->size = res; - - return res; + return fuse_chan_recv(se, buf, ch); } #endif +#define MIN_BUFSIZE 0x21000 -/* - * always call fuse_lowlevel_new_common() internally, to work around a - * misfeature in the FreeBSD runtime linker, which links the old - * version of a symbol to internal references. - */ -struct fuse_session *fuse_lowlevel_new_common(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) { 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"); @@ -2723,6 +2822,9 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, f->conn.max_write = UINT_MAX; f->conn.max_readahead = UINT_MAX; f->atomic_o_trunc = 0; + f->bufsize = getpagesize() + 0x1000; + f->bufsize = f->bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : f->bufsize; + list_init_req(&f->list); list_init_req(&f->interrupts); list_init_nreq(&f->notify_list); @@ -2746,12 +2848,11 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, f->owner = getuid(); f->userdata = userdata; - se = fuse_session_new(&sop, f); + se = fuse_session_new(); if (!se) goto out_key_destroy; - se->receive_buf = fuse_ll_receive_buf; - se->process_buf = fuse_ll_process_buf; + se->f = f; return se; @@ -2764,14 +2865,6 @@ out: return NULL; } - -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); -} - #ifdef linux int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) { @@ -2840,129 +2933,3 @@ 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, - 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/lib/fuse_misc.h b/lib/fuse_misc.h index eedf0e0..8b76775 100644 --- a/lib/fuse_misc.h +++ b/lib/fuse_misc.h @@ -6,20 +6,8 @@ See the file COPYING.LIB */ -#include "config.h" #include <pthread.h> -/* - Versioned symbols cannot be used in some cases because it - - confuse the dynamic linker in uClibc - - not supported on MacOSX (in MachO binary format) -*/ -#if (!defined(__UCLIBC__) && !defined(__APPLE__)) -#define FUSE_SYMVER(x) __asm__(x) -#else -#define FUSE_SYMVER(x) -#endif - #ifndef USE_UCLIBC #define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL) #else diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index f6dbe71..be5d644 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -6,105 +6,10 @@ See the file COPYING.LIB. */ -#include "fuse_i.h" -#include "fuse_misc.h" +#include "config.h" +#include "fuse.h" #include "fuse_lowlevel.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> -#include <assert.h> - -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; - - (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); -} - -static int mt_session_exited(void *data) -{ - 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); - - assert(size >= sizeof(cmd)); - - cmd = fuse_read_cmd(pd->f); - if (cmd == NULL) - return 0; - - *(struct fuse_cmd **) buf = 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_session_destroy(se); - return res; -} - int fuse_loop_mt(struct fuse *f) { if (f == NULL) @@ -118,5 +23,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/lib/fuse_opt.c b/lib/fuse_opt.c index a2118ce..bd7a6ee 100644 --- a/lib/fuse_opt.c +++ b/lib/fuse_opt.c @@ -6,6 +6,7 @@ See the file COPYING.LIB */ +#include "config.h" #include "fuse_opt.h" #include "fuse_misc.h" @@ -92,13 +93,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) { @@ -211,11 +205,13 @@ static int process_opt_param(void *var, const char *format, const char *param, { assert(format[0] == '%'); if (format[1] == 's') { + char **s = var; char *copy = strdup(param); if (!copy) return alloc_failed(); - *(char **) var = copy; + free(*s); + *s = copy; } else { if (sscanf(param, format, var) != 1) { fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); @@ -421,6 +417,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/lib/fuse_session.c b/lib/fuse_session.c index 6e11068..e919e73 100644 --- a/lib/fuse_session.c +++ b/lib/fuse_session.c @@ -6,10 +6,9 @@ See the file COPYING.LIB */ +#include "config.h" #include "fuse_i.h" #include "fuse_misc.h" -#include "fuse_common_compat.h" -#include "fuse_lowlevel_compat.h" #include <stdio.h> #include <stdlib.h> @@ -17,31 +16,15 @@ #include <assert.h> #include <errno.h> -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 *fuse_session_new(void) { 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; return se; } @@ -64,89 +47,34 @@ void fuse_session_remove_chan(struct fuse_chan *ch) } } -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; -} - -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); -} - -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); - } -} - -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) +struct fuse_chan *fuse_session_chan(struct fuse_session *se) { - 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; - } - - return res; + return se->ch; } - -void fuse_session_destroy(struct fuse_session *se) +int fuse_chan_clearfd(struct fuse_chan *ch) { - if (se->op.destroy) - se->op.destroy(se->data); - if (se->ch != NULL) - fuse_chan_destroy(se->ch); - free(se); + int fd = ch->fd; + ch->fd = -1; + return fd; } void fuse_session_exit(struct fuse_session *se) { - 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; } int fuse_session_exited(struct fuse_session *se) { - 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->exited; } -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 *fuse_chan_new(int fd) { struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); if (ch == NULL) { @@ -155,86 +83,24 @@ static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, } memset(ch, 0, sizeof(*ch)); - ch->op = *op; ch->fd = fd; - ch->bufsize = bufsize; - ch->data = data; - ch->compat = compat; 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); -} - -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); -} - int fuse_chan_fd(struct fuse_chan *ch) { return ch->fd; } -int fuse_chan_clearfd(struct fuse_chan *ch) -{ - int fd = ch->fd; - ch->fd = -1; - return fd; -} - -size_t fuse_chan_bufsize(struct fuse_chan *ch) -{ - return ch->bufsize; -} - -void *fuse_chan_data(struct fuse_chan *ch) -{ - return ch->data; -} - struct fuse_session *fuse_chan_session(struct fuse_chan *ch) { 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); -} - -int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size) -{ - int res; - - 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); -} - void fuse_chan_destroy(struct fuse_chan *ch) { fuse_session_remove_chan(ch); - if (ch->op.destroy) - ch->op.destroy(ch); + fuse_chan_close(ch); free(ch); } - -#ifndef __FreeBSD__ -FUSE_SYMVER(".symver fuse_chan_new_compat24,fuse_chan_new@FUSE_2.4"); -#endif diff --git a/lib/fuse_signals.c b/lib/fuse_signals.c index 88ac39e..c78c62d 100644..100755 --- a/lib/fuse_signals.c +++ b/lib/fuse_signals.c @@ -6,6 +6,7 @@ See the file COPYING.LIB */ +#include "config.h" #include "fuse_lowlevel.h" #include <stdio.h> @@ -14,12 +15,14 @@ static struct fuse_session *fuse_instance; +/*! [doxygen_exit_handler] */ static void exit_handler(int sig) { (void) sig; if (fuse_instance) fuse_session_exit(fuse_instance); } +/*! [doxygen_exit_handler] */ static int set_one_signal_handler(int sig, void (*handler)(int)) { diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 8d91887..08dafbd 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -1,38 +1,11 @@ -FUSE_2.2 { +FUSE_3.0 { 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; @@ -48,18 +21,8 @@ FUSE_2.4 { fuse_session_exited; fuse_session_loop; fuse_session_loop_mt; - fuse_session_new; - fuse_session_next_chan; - fuse_session_process; + fuse_session_chan; 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; @@ -69,45 +32,23 @@ FUSE_2.5 { 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_add_direntry_plus; 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; @@ -148,15 +89,7 @@ FUSE_2.7 { 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; @@ -177,11 +110,6 @@ FUSE_2.8 { 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; @@ -196,12 +124,8 @@ FUSE_2.9 { 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/lib/helper.c b/lib/helper.c index b644012..e5550c9 100644 --- a/lib/helper.c +++ b/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 <stdio.h> #include <stdlib.h> @@ -59,30 +58,26 @@ static const struct fuse_opt fuse_helper_opts[] = { 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"); + printf("usage: %s mountpoint [options]\n\n", progname); + printf("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" - ); + printf("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); + printf("FUSE library version: %s\n", PACKAGE_VERSION); } static int fuse_helper_opt_proc(void *data, const char *arg, int key, @@ -211,12 +206,13 @@ int fuse_daemonize(int foreground) if (nullfd > 2) close(nullfd); } + } else { + (void) chdir("/"); } return 0; } -static struct fuse_chan *fuse_mount_common(const char *mountpoint, - struct fuse_args *args) +struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) { struct fuse_chan *ch; int fd; @@ -231,23 +227,18 @@ static struct fuse_chan *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; - ch = fuse_kern_chan_new(fd); + ch = fuse_chan_new(fd); if (!ch) fuse_kern_unmount(mountpoint, fd); return ch; } -struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) -{ - return fuse_mount_common(mountpoint, args); -} - -static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) +void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) { if (mountpoint) { int fd = ch ? fuse_chan_clearfd(ch) : -1; @@ -257,19 +248,9 @@ static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) } } -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) -{ - fuse_unmount_common(mountpoint, ch); -} - -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, - int compat) +static struct fuse *fuse_setup(int argc, char *argv[], + const struct fuse_operations *op, size_t op_size, + char **mountpoint, int *multithreaded, void *user_data) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_chan *ch; @@ -281,13 +262,13 @@ struct fuse *fuse_setup_common(int argc, char *argv[], if (res == -1) return NULL; - ch = fuse_mount_common(*mountpoint, &args); + ch = fuse_mount(*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 = fuse_new(ch, &args, op, op_size, user_data); fuse_opt_free_args(&args); if (fuse == NULL) goto err_unmount; @@ -300,13 +281,10 @@ struct fuse *fuse_setup_common(int argc, char *argv[], if (res == -1) goto err_unmount; - if (fd) - *fd = fuse_chan_fd(ch); - return fuse; err_unmount: - fuse_unmount_common(*mountpoint, ch); + fuse_unmount(*mountpoint, ch); if (fuse) fuse_destroy(fuse); err_free: @@ -314,40 +292,26 @@ err_free: 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); -} - -static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) +static void fuse_teardown(struct fuse *fuse, char *mountpoint) { struct fuse_session *se = fuse_get_session(fuse); - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + struct fuse_chan *ch = fuse_session_chan(se); fuse_remove_signal_handlers(se); - fuse_unmount_common(mountpoint, ch); + fuse_unmount(mountpoint, ch); fuse_destroy(fuse); free(mountpoint); } -void fuse_teardown(struct fuse *fuse, char *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) +int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, + size_t op_size, void *user_data) { struct fuse *fuse; char *mountpoint; int multithreaded; int res; - fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, - &multithreaded, NULL, user_data, compat); + fuse = fuse_setup(argc, argv, op, op_size, &mountpoint, + &multithreaded, user_data); if (fuse == NULL) return 1; @@ -356,125 +320,15 @@ static int fuse_main_common(int argc, char *argv[], else res = fuse_loop(fuse); - fuse_teardown_common(fuse, mountpoint); + fuse_teardown(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); -} - -#undef fuse_main -int fuse_main(void); -int fuse_main(void) -{ - fprintf(stderr, "fuse_main(): This function does not exist\n"); - return -1; -} - 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/lib/modules/iconv.c b/lib/modules/iconv.c index 89b22e4..7438ecb 100644 --- a/lib/modules/iconv.c +++ b/lib/modules/iconv.c @@ -6,7 +6,9 @@ See the file COPYING.LIB */ -#define FUSE_USE_VERSION 26 +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <fuse.h> #include <stdio.h> @@ -631,7 +633,6 @@ static const struct fuse_operations iconv_oper = { .flock = iconv_flock, .bmap = iconv_bmap, - .flag_nullpath_ok = 1, .flag_nopath = 1, }; @@ -649,7 +650,7 @@ static void iconv_help(void) char *charmap = strdup(nl_langinfo(CODESET)); setlocale(LC_CTYPE, old); free(old); - fprintf(stderr, + printf( " -o from_code=CHARSET original encoding of file names (default: UTF-8)\n" " -o to_code=CHARSET new encoding of the file names (default: %s)\n", charmap); diff --git a/lib/modules/subdir.c b/lib/modules/subdir.c index 76a53fa..eb56d36 100644 --- a/lib/modules/subdir.c +++ b/lib/modules/subdir.c @@ -6,7 +6,9 @@ See the file COPYING.LIB */ -#define FUSE_USE_VERSION 26 +#define FUSE_USE_VERSION 30 + +#include <config.h> #include <fuse.h> #include <stdio.h> @@ -614,7 +616,6 @@ static const struct fuse_operations subdir_oper = { .flock = subdir_flock, .bmap = subdir_bmap, - .flag_nullpath_ok = 1, .flag_nopath = 1, }; @@ -629,7 +630,7 @@ static const struct fuse_opt subdir_opts[] = { static void subdir_help(void) { - fprintf(stderr, + printf( " -o subdir=DIR prepend this directory to all paths (mandatory)\n" " -o [no]rellinks transform absolute symlinks to relative\n"); } diff --git a/lib/mount.c b/lib/mount.c index 0f767c8..fb9231a 100644 --- a/lib/mount.c +++ b/lib/mount.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 <stdio.h> @@ -98,6 +97,10 @@ static const struct fuse_opt fuse_mount_opts[] = { 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), @@ -124,7 +127,7 @@ static const struct fuse_opt fuse_mount_opts[] = { static void mount_help(void) { - fprintf(stderr, + printf( " -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" @@ -291,9 +294,6 @@ void fuse_kern_unmount(const char *mountpoint, int fd) int res; int pid; - if (!mountpoint) - return; - if (fd != -1) { struct pollfd pfd; @@ -337,11 +337,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) { @@ -409,17 +404,15 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo, waitpid(pid, NULL, 0); /* bury zombie */ } + if (rv >= 0) + fcntl(rv, F_SETFD, FD_CLOEXEC); + 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); -} +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, const char *mnt_opts) @@ -457,7 +450,7 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, return -2; } - fd = open(devname, O_RDWR); + fd = open(devname, O_RDWR | O_CLOEXEC); if (fd == -1) { if (errno == ENODEV || errno == ENOENT) fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n"); @@ -466,6 +459,8 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, devname, strerror(errno)); return -1; } + if (!O_CLOEXEC) + fcntl(fd, F_SETFD, FD_CLOEXEC); snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); @@ -635,6 +630,3 @@ out: 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"); diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c index 3aec3e3..8f3acf0 100644 --- a/lib/mount_bsd.c +++ b/lib/mount_bsd.c @@ -6,6 +6,7 @@ See the file COPYING.LIB. */ +#include "config.h" #include "fuse_i.h" #include "fuse_misc.h" #include "fuse_opt.h" @@ -101,9 +102,7 @@ static const struct fuse_opt fuse_mount_opts[] = { static void mount_help(void) { - fprintf(stderr, - " -o allow_root allow access to root\n" - ); + printf(" -o allow_root allow access to root\n"); system(FUSERMOUNT_PROG " --help"); fputc('\n', stderr); } @@ -387,5 +386,3 @@ out: free(mo.kernel_opts); return res; } - -FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2"); diff --git a/lib/mount_util.c b/lib/mount_util.c index 3cad2e6..87e3888 100644 --- a/lib/mount_util.c +++ b/lib/mount_util.c @@ -6,6 +6,7 @@ See the file COPYING.LIB. */ +#include "config.h" #include "mount_util.h" #include <stdio.h> #include <unistd.h> diff --git a/lib/ulockmgr.c b/lib/ulockmgr.c deleted file mode 100644 index b875c50..0000000 --- a/lib/ulockmgr.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - libulockmgr: Userspace Lock Manager Library - Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu> - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB -*/ - -/* #define DEBUG 1 */ - -#include "ulockmgr.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <pthread.h> -#include <errno.h> -#include <assert.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/wait.h> - -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/test/stracedecode.c b/test/stracedecode.c index 27b883c..940438a 100644 --- a/test/stracedecode.c +++ b/test/stracedecode.c @@ -41,6 +41,7 @@ static struct { [FUSE_INTERRUPT] = { "INTERRUPT" }, [FUSE_BMAP] = { "BMAP" }, [FUSE_DESTROY] = { "DESTROY" }, + [FUSE_READDIRPLUS] = { "READDIRPLUS" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) diff --git a/util/.gitignore b/util/.gitignore index 4a58d8e..961b59b 100644 --- a/util/.gitignore +++ b/util/.gitignore @@ -1,5 +1,4 @@ fusermount -ulockmgr_server fuse_ioslave mount.fuse mount_util.c diff --git a/util/Makefile.am b/util/Makefile.am index 059d5fc..a489d28 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -1,7 +1,6 @@ ## Process this file with automake to produce Makefile.in -AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -bin_PROGRAMS = fusermount ulockmgr_server +bin_PROGRAMS = fusermount noinst_PROGRAMS = mount.fuse # we re-use mount_util.c from the library, but do want to keep ourself @@ -16,10 +15,6 @@ mount_util.c: $(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 \ diff --git a/util/fusermount.c b/util/fusermount.c index 4fc72ed..e7dbca6 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -1159,16 +1159,15 @@ static int send_fd(int sock_fd, int fd) static void usage(void) { - fprintf(stderr, - "%s: [options] mountpoint\n" - "Options:\n" - " -h print help\n" - " -V print version\n" - " -o opt[,opt...] mount options\n" - " -u unmount\n" - " -q quiet\n" - " -z lazy unmount\n", - progname); + printf("%s: [options] mountpoint\n" + "Options:\n" + " -h print help\n" + " -V print version\n" + " -o opt[,opt...] mount options\n" + " -u unmount\n" + " -q quiet\n" + " -z lazy unmount\n", + progname); exit(1); } diff --git a/util/mount.fuse.c b/util/mount.fuse.c index 6df8c03..363b12b 100644 --- a/util/mount.fuse.c +++ b/util/mount.fuse.c @@ -6,6 +6,8 @@ See the file COPYING. */ +#include <config.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/util/ulockmgr_server.c b/util/ulockmgr_server.c deleted file mode 100644 index baef45d..0000000 --- a/util/ulockmgr_server.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - ulockmgr_server: Userspace Lock Manager Server - Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu> - - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. -*/ - -/* #define DEBUG 1 */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <dirent.h> -#include <pthread.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/wait.h> - -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; -} |