From ec46077fb57d6b347edf99e7a46e59696cedf12b Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Tue, 18 Feb 2020 20:53:33 -0500 Subject: [PATCH] checkpoint --- libfuse/ChangeLog | 3547 ---------------- libfuse/Makefile | 9 +- libfuse/NEWS | 303 -- libfuse/README.NFS | 33 - libfuse/README.md | 108 - libfuse/fuse.pc.in | 11 - libfuse/include/Makefile.am | 17 - libfuse/include/cuse_lowlevel.h | 87 - libfuse/include/fuse.h | 123 +- libfuse/include/fuse_chan.h | 22 + libfuse/include/fuse_common.h | 19 +- libfuse/include/fuse_common_compat.h | 2 + libfuse/include/fuse_compat.h | 196 - libfuse/include/fuse_lowlevel.h | 3198 +++++++------- libfuse/include/fuse_lowlevel_compat.h | 13 +- libfuse/lib/Makefile.am | 42 - libfuse/lib/buffer.c | 476 +-- libfuse/lib/cuse_lowlevel.c | 371 -- libfuse/lib/fuse.c | 5330 +++++++++++------------- libfuse/lib/fuse_chan.c | 248 ++ libfuse/lib/fuse_dev.c | 56 + libfuse/lib/fuse_dev.h | 40 + libfuse/lib/fuse_i.h | 158 +- libfuse/lib/fuse_kern_chan.c | 103 - libfuse/lib/fuse_loop.c | 46 - libfuse/lib/fuse_loop_mt.c | 359 +- libfuse/lib/fuse_lowlevel.c | 3816 +++++++---------- libfuse/lib/fuse_mt.c | 110 +- libfuse/lib/fuse_opt.c | 580 +-- libfuse/lib/fuse_session.c | 231 +- libfuse/lib/fuse_signals.c | 70 +- libfuse/lib/fuse_versionscript | 207 - libfuse/lib/helper.c | 572 +-- libfuse/lib/mount_bsd.c | 590 +-- libfuse/lib/mount_generic.c | 983 +++-- libfuse/lib/mount_util.c | 545 ++- libfuse/lib/mount_util.h | 1 - libfuse/lib/sys.c | 48 + libfuse/lib/sys.h | 4 + libfuse/lib/ulockmgr.c | 694 +-- libfuse/util/fusermount.c | 2107 +++++----- libfuse/util/mount.mergerfs.c | 388 +- libfuse/util/mount_util.c | 545 ++- src/config.cpp | 2 +- src/fuse_init.cpp | 2 +- src/option_parser.cpp | 2 +- 46 files changed, 9985 insertions(+), 16429 deletions(-) delete mode 100644 libfuse/ChangeLog delete mode 100644 libfuse/NEWS delete mode 100644 libfuse/README.NFS delete mode 100644 libfuse/README.md delete mode 100644 libfuse/fuse.pc.in delete mode 100644 libfuse/include/Makefile.am delete mode 100644 libfuse/include/cuse_lowlevel.h create mode 100644 libfuse/include/fuse_chan.h delete mode 100644 libfuse/include/fuse_compat.h delete mode 100644 libfuse/lib/Makefile.am delete mode 100644 libfuse/lib/cuse_lowlevel.c create mode 100644 libfuse/lib/fuse_chan.c create mode 100644 libfuse/lib/fuse_dev.c create mode 100644 libfuse/lib/fuse_dev.h delete mode 100644 libfuse/lib/fuse_kern_chan.c delete mode 100644 libfuse/lib/fuse_loop.c delete mode 100644 libfuse/lib/fuse_versionscript create mode 100644 libfuse/lib/sys.c create mode 100644 libfuse/lib/sys.h diff --git a/libfuse/ChangeLog b/libfuse/ChangeLog deleted file mode 100644 index 8371584e..00000000 --- a/libfuse/ChangeLog +++ /dev/null @@ -1,3547 +0,0 @@ -FUSE 2.9.7 (2016-06-20) -======================= - -* Added SELinux support. -* Fixed race-condition when session is terminated right after starting - a FUSE file system. - -FUSE 2.9.6 (2016-04-23) -======================= - -* Tarball now includes documentation. -* Shared-object version has now been bumped correctly. - -FUSE 2.9.5 (2016-01-14) -======================= - -* New maintainer: Nikolaus Rath . Many thanks to - Miklos Szeredi for bringing FUSE to where it is - now! - -* fix warning in mount.c:receive_fd(). Reported by Albert Berger - -* fix possible memory leak. Reported by Jose R. Guzman - -FUSE 2.9.4 (2015-05-22) -======================= - -* fix exec environment for mount and umount. Found by Tavis Ormandy - (CVE-2015-3202). - -* fix fuse_remove_signal_handlers() to properly restore the default - signal handler. Reported by: Chris Johnson - -* highlevel API: fix directory file handle passed to ioctl() method. - Reported by Eric Biggers - -* libfuse: document deadlock avoidance for fuse_notify_inval_entry() - and fuse_notify_delete() - -* fusermount, libfuse: send value as unsigned in "user_id=" and - "group_id=" options. Uids/gids larger than 2147483647 would result - in EINVAL when mounting the filesystem. This also needs a fix in - the kernel. - -* Initilaize stat buffer passed to ->getattr() and ->fgetattr() to - zero in all cases. Reported by Daniel Iwan - -* libfuse: Add missing includes. This allows compiling fuse with - musl. Patch by Daniel Thau - - -Older Versions (before 2013-01-01) -================================== - - -2013-06-20 Miklos Szeredi - - * libfuse: fix multiple close of device fd. Reported by Dan - Greenfield - -2013-03-19 Miklos Szeredi - - * libfuse: fix thread cancel race. Exiting a worker my race with - cancelling that same worker. This caused a segmenation - fault. Reported and tested by Anatol Pomozov - -2013-02-04 Miklos Szeredi - - * libfuse: fix crash in unlock_path(). Patch by Ratna Manoj - - * libfuse: fix the 'remember' option. The lru list was not - initialized for the "/" path. This resulted in remove_node_lru() - crashing on LOOKUP-DOTDOT. Patch by Madan Valluri - - * libfuse: configure: detect new util-linux - - * libfuse: Use AC_CONFIG_HEADERS instead of AM_CONFIG_HEADER. - Patch by Anatol Pomozov - - * libfuse: rename ./configure.in to ./configure.ac. Patch by - Anatol Pomozov - -2012-10-01 Miklos Szeredi - - * Released 2.9.2 - -2012-10-01 Miklos Szeredi - - * Fix deadlock in libfuse. Running "svn update" on a fuse - filesystem could deadlock because of a bug in the way the paths - are locked. Reported by Kazuaki Anami - -2012-08-23 Miklos Szeredi - - * Fix missing config.h in buffer.c. Reported by Matthew Gabeler-Lee - -2012-08-14 Miklos Szeredi - - * Not unhashing the name in forget (commit on 2011-12-09) broke - the forget logic in a subtle way, resulting in "fuse internal - error: node NNN not found" and causing the filesystem daemon to - abort. Fix by incrementing the node refcount if nlookup goes from - zero to one. Reported by Kyle Lippincott - -2012-08-13 Miklos Szeredi - - * Fix linking against GNU libiconv. Patch by Natanael Copa - -2012-07-19 Miklos Szeredi - - * Released 2.9.1 - -2012-07-19 Miklos Szeredi - - * Fix crash caused by freeing a stack address. Reported by Itay - Perl - -2012-07-04 Miklos Szeredi - - * Fix install of mount.fuse from out-of-tree build. Patch by - Olivier Blin - - * Fix build with automake >= 1.12.1. Patch by Olivier Blin - -2012-04-24 Miklos Szeredi - - * Add fallocate operation. Only works on linux kernels 3.5 or - later. Patch by Anatol Pomozov - -2012-05-16 Miklos Szeredi - - * Linking to a library that uses threads requires the application - to be linked with -pthreads otherwise some pthread functions will - be linked to stubs in glibc. So move -pthread from Libs.private - to Libs in fuse.pc. Reported by Werner Fink - - * Fix the compile command in the examples. Reported by Luciano - Dalle Ore - -2012-04-20 Miklos Szeredi - - * Released 2.9.0 - -2012-04-20 Miklos Szeredi - - * Add missing fuse_fs_flock to fuse_versionscript - -2012-04-10 Miklos Szeredi - - * Check protocol version before sending notifications and return - -ENOSYS if a particular notification is not supported. - - * Add 'flag_utime_omit_ok' flag to fuse_operations. If the - filesystem sets this flag then ->utimens() will receive UTIME_OMIT - and UTIME_NOW values as specified in utimensat(2). - -2012-01-27 Miklos Szeredi - - * Interpret octal escape codes in options. Requested by Jan - Engelhardt - -2012-01-26 Miklos Szeredi - - * Add man pages for fusermount, mount.fuse and ulockmgr_server. - Lifted from the Debian package. The man pages were written by - Daniel Baumann and Bastien Roucaries - -2012-01-13 Miklos Szeredi - - * Disable symbol versions on MacOSX. Patch by Anatol Pomozov - -2012-01-02 Miklos Szeredi - - * Remove unnecessary mutex unlock at the end of multithreaded - event loop. - -2011-12-09 Miklos Szeredi - - * Fix hang in wait_on_path(). Reported by Ville Silventoinen - - * Don't unhash name in FORGET. This resulted in ENOENT being - returned for unlinked but still open files if the kernel sent a - FORGET request for the parent directory. - - * Free request in fuse_reply_data(). - -2011-12-08 Miklos Szeredi - - * Fix build if FUSE_NODE_SLAB is not defined. Patch by Emmanuel - Dreyfus - - * Check for availability of utimensat() function. Patch by - Emmanuel Dreyfus - -2011-12-07 Miklos Szeredi - - * Add fuse_lowlevel_notify_delete() which tells the kernel that a - file or directory is deleted. Patch by John Muir - -2011-12-06 Miklos Szeredi - - * Update retrieve_reply() method - -2011-12-05 Miklos Szeredi - - * Low level API: lock argument of fuse_reply_lock should have a - 'const' qualifier. Reported by Shachar Sharon - - * Add support for ioctl on directories. Reported by Antonio SJ - Musumeci - -2011-10-13 Miklos Szeredi - - * Reply to request with ENOMEM in case of failure to allocate - request structure. Otherwise the task issuing the request will - just freeze up until the filesystem daemon is killed. Reported by - Stephan Kulow - -2011-09-23 Miklos Szeredi - - * Replace daemon() function with fork(). Patch by Anatol Pomozov - -2011-08-26 Miklos Szeredi - - * If configured with --disable-mtab then don't call mount(8) from - libfuse to update the mtab. Reported by: James Sierp - -2011-08-24 Miklos Szeredi - - * Use LRU list for cleaning up the cache if the "remember=T" - option was given. Patch by therealneworld@gmail.com - -2011-07-06 Miklos Szeredi - - * Add ->flock() operation to low and high level interfaces. This - fixes problems with emulating flock() with POSIX locking. - Reported by Sebastian Pipping. As with lock/setlk/getlk most - filesystems don't need to implement this, as the kernel takes care - of file locking. The only reason to implement locking operations - is for network filesystems which want file locking to work between - clients. - -2011-07-02 Sebastian Pipping - - * Make xmp_utimens of examples "fusexmp" and "fusexmp_fh" - not follow symlinks as other layers do that already. - -2011-06-02 Miklos Szeredi - - * Add "remember" option. This works similar to "noforget" except - that eventually the node will be allowed to expire from the cache. - Patch by therealneworld@gmail.com - -2011-05-27 Miklos Szeredi - - * Check if splice/vmsplice are supported - -2011-05-26 Miklos Szeredi - - * Remove -lrt -ldl from fuse.pc for dynamic linking since - libfuse.so is already linked with these libraries. Reported by: - Nikolaus Rath - -2011-05-20 Miklos Szeredi - - * Cleaner build output. Patch by Reuben Hawkins - -2011-05-19 Miklos Szeredi - - * Disable splice by default, add "splice_read", "splice_write" and - "splice_move" options. Keep the "no_splice_*" variants, which can - disable splice even if the filesystem explicitly enables it. - -2011-04-15 Max Krasnyansky - * Added support for "auto_unmount" option which unmounts the - filesystem automatically on process exit (or crash). - -2011-03-30 Miklos Szeredi - - * Patches by Laszlo Papp fixing various issues found by the - Coverity checker - -2011-03-11 Miklos Szeredi - - * In case of failure to add to /etc/mtab don't umount. Reported - by Marc Deslauriers - -2011-02-02 Miklos Szeredi - - * libfuse: In fuse_session_loop_mt() don't pause when exiting the - worker threads. The pause() was added in 2.2.1 to prevent - segfault on pthread_cancel() on an exited, detached thread. Now - worker threads are not detached and pthread_cancel() should work - fine even after the thread exited. Reported by Boris Protopopov - -2011-01-31 Miklos Szeredi - - * fusermount: chdir to / before performing mount/umount - - * fusermount: only allow mount and umount if util-linux supports - --no-canonicalize - -2010-12-16 Miklos Szeredi - - * Highlevel lib: allow hash tables to shrink - - * Highlevel lib: add slab allocation for node cache. This will - allow the memory used by the filesystem to grow and shrink - depending on how many inodes are currently cached. - -2010-12-13 Miklos Szeredi - - * Highlevel lib: use dynamically resized hash table for looking up - by name and node ID. - -2010-12-07 Miklos Szeredi - - * Allow batching of forget requests. This allows forget requests - to be processed faster and doesn't require a modification to fuse - filesystems. Reported by Terje Malmedal - - * Add ->forget_multi() operation to the lowlevel API. The - filesystem may implement this to process multiple forget requests - in one call - - * Fix the ambiguity of ioctl ABI on the kernel/userspace boundary - for 32bit vs. 64bit userspace - -2010-11-10 Miklos Szeredi - - * Add new write_buf() method to the highlevel API. Similarly to - the lowlevel write_buf() method, this allows implementing zero - copy writes. - - * Add a new read_buf() method to the highlevel API. This allows - returning a generic buffer from the read method, which in turn - allows zero copy reads. - - * In fusexmp_fh implement the ->read_buf() and ->write_buf() - methods. Leave the ->read() and ->write() implementations for - reference, even though they are not necessary. - -2010-11-08 Miklos Szeredi - - * Fix check for read-only fs in mtab update - - * Open /dev/null for write instead of read for redirecting stdout - and stderr - - * If umount(8) supports --fake and --no-canonicalize (util-linux-ng - version 2.18 or later), and umount(2) supports the - UMOUNT_NOFOLLOW flag (linux kernel version 2.6.35 or later) then, - "fusermount -u" will call the umount(2) system call and use - "umount --fake ..." to update /etc/mtab - - * Added --disable-legacy-umount option to configure. This - disables the runtime checking of umount(8) version. When built - with this option then "fusermount -u" will fail if umount(8) - doesn't support the --fake and --no-canonicalize options. - - * Fix fuse_buf_copy() if already at the end of the buffers - - * Add new ->write_buf() method to low level interface. This - allows passig a generic buffer, either containing a memory buffer - or a file descriptor. This allows implementing zero copy writes. - - * Add fuse_session_receive_buf() and fuse_session_process_buf() - which may be used in event loop implementations to replace - fuse_chan_recv() and fuse_session_process() respectively. - - * Remove unnecessary restoring of current working directory in - "fusermount -u" - - * Add ctx->pid to debug output - - * Fix st_nlink value in high level lib if file is unlinked but - still open - - * libfuse: add store request. Request data to be stored in the - kernel buffers for a given inode. - - * libfuse: add retrieve request. Retrieve data stored in the - kernel buffers for a given inode. - -2010-10-14 Miklos Szeredi - - * Use LTLIBICONV when linking libfuse. This fixes building against - uclibc + libiconv. Patch by Natanael Copa - -2010-10-05 Miklos Szeredi - - * Add missing argument check in ulockmgr.c to prevent calling - ulockmgr_server with illegal arguments. This would cause an ever - growing list of ulockmgr_server processes with an endless list of - open files which finally exceeds the open file handle limit. - Patch by Markus Ammer - -2010-09-28 Miklos Szeredi - - * Fix ambiguous symbol version for fuse_chan_new. - fuse_versionscript included fuse_chan_new in both FUSE_2.4 and - FUSE_2.6. Remove the FUSE_2.4, which is invalid. - -2010-09-28 Miklos Szeredi - - * Fix option escaping for fusermount. If the "fsname=" option - contained a comma then the option parser in fusermount was - confused (Novell bugzilla #641480). Fix by escaping commas when - passing them over to fusermount. Reported by Jan Engelhardt - -2010-08-27 Miklos Szeredi - - * Add NetBSD support. Patch from Emmanuel Dreyfus - -2010-07-12 Miklos Szeredi - - * libfuse: add buffer interface. Add a generic buffer interface - for use with I/O. Buffer vectors are supplied and each buffer in - the vector may be a memory pointer or a file descriptor. - - * The fuse_reply_fd() interface is converted to using buffers. - -2010-06-23 Miklos Szeredi - - * Make the number of max background requests and congestion - threshold tunable. New options are "max_background" and - "congestion_threshold". Only effective on linux kernel versions - 2.6.32 or greater. Patch by Csaba Henk - -2010-06-17 Miklos Szeredi - - * Add fuse_reply_fd() reply function to the low level interface. - On linux version 2.6.35 or greater this will use splice() to move - data directly from a file descriptor to the fuse device without - needing to go though a userspace buffer. With the - FUSE_REPLY_FD_MOVE flag the kernel will attempt to move the data - directly into the filesystem's cache. On earlier kernels it will - fall back to an intermediate buffer. The options - "no_splice_write" and "no_splice_move" can be used to disable - splicing and moving respectively. - -2010-06-15 Miklos Szeredi - - * Fix out-of-source build. Patch by Jörg Faschingbauer - - * Add a "nopath" option and flag, indicating that path argument - need not be calculated for the following operations: read, write, - flush, release, fsync, readdir, releasedir, fsyncdir, ftruncate, - fgetattr, lock, ioctl and poll. - -2010-05-10 Miklos Szeredi - - * Remove "chmod root" from install of fusermount. Reported by - Lucas C. Villa Real - -2010-04-26 Miklos Szeredi - - * Released 2.8.4 - -2010-04-26 Miklos Szeredi - - * Fix checking for symlinks in umount from /tmp. Reported by Al - Viro - - * Fix umounting if /tmp is a symlink. Reported by Franco Broi - -2010-02-18 Miklos Szeredi - - * Fix definition of FUSE_OPT_END for C++. Reported by Tim - Bruylants - -2010-02-03 Miklos Szeredi - - * Fix stack alignment for clone() - -2010-02-01 Miklos Szeredi - - * Released 2.8.3 - -2010-02-01 Miklos Szeredi - - * Using "--no-canonicalize" with umount(8) conflicts with the race - fix, sinceit assumes the supplied path is absolute, while the race - fix relies on the path being relative to the current directory. - Reported by Tom Rindborg - -2010-01-26 Miklos Szeredi - - * Released 2.8.2 - -2010-01-21 Miklos Szeredi - - * Fix race if two "fusermount -u" instances are run in parallel. - Reported by Dan Rosenberg - - * Make sure that the path to be unmounted doesn't refer to a - symlink - -2010-01-14 Miklos Szeredi - - * Fix compile error on FreeBSD. Patch by Jay Sullivan - -2009-12-17 Miklos Szeredi - - * Use '--no-canonicalize' option of mount(8) (available in - util-linux-ng version 2.17 or greater) to avoid calling - readling(2) on the newly mounted filesystem before the mount - procedure is finished. This has caused a deadlock if "audit" was - enabled in the kernel. Also use '--no-canonicalize' for umount to - avoid touching the mounted filesystem. - -2009-09-11 Miklos Szeredi - - * Released 2.8.1 - -2009-08-25 Miklos Szeredi - - * Fix missing versioned symbol fuse_get_context@FUSE_2.2 - -2009-08-18 Miklos Szeredi - - * Released 2.8.0 - -2009-08-18 Miklos Szeredi - - * Add missing fuse_session_data to versionscript - - * Make sure all global symbols are prefixed with "fuse_" or "cuse_" - -2009-07-16 Miklos Szeredi - - * Clarify how the protocol version should be negotiated between - kernel and userspace. Notably libfuse didn't correctly handle the - case when the supported major versions didn't match - - * Add missing pthread link for libulockmgr. Patch by Petr Salinger - -2009-07-02 Miklos Szeredi - - * The context is extended with a 'umask' field. The umask is sent - for mknod, mkdir and create requests by linux kernel version - 2.6.31 or later, otherwise the umask is set to zero. Also - introduce a new feature flag: FUSE_CAP_DONT_MASK. If the kernel - supports this feature, then this flag will be set in conn->capable - in the ->init() method. If the filesystem sets this flag in in - conn->want, then the create modes will not be masked. - - * Add low level interfaces for lookup cache and attribute - invalidation. This feature is available in linux kernels 2.6.31 - or later. Patch by John Muir - - * Kernel interface version is now 7.12 - - * fusermount: Do not silently ignore command line arguments. - Patch by Sebastian Harl - -2009-06-19 Miklos Szeredi - - * Released 2.8.0-pre3 - -2009-06-19 Miklos Szeredi - - * Add fuse_getgroups (high level lib) and fuse_req_getgroups (low - level lib) functions to query the supplementary group IDs for the - current request. Currently this is implemented on Linux by - reading from the /proc filesystem. - -2009-06-18 Miklos Szeredi - - * Add "noforget" option to high level lib to prevent ESTALE errors - on NFS exported filesystems. This result in paths being cached - forever, resulting in ever growing memory usage. Use with care. - - * Add "no_remote_lock" option to disable remote file locking even - if the filesystem implements it. With this option locking - primitives (flock, lockf, fcntl(F_SETLK)) will still work, but - will ignore remotely locked files. - - * CUSE patches from Tejun Heo: - - * Unrestricted ioctl support left some debris. Clean them up: - o No reason to pass around pointer to flags. Pass flags directly. - o Clean up comment and prototype parameter names. - o fuse_lib_ioctl() didn't reply when get_path() failed. Fix it. - o Remove unused variables {in|out}_iov from fuse_lib_ioctl(). - - * Add fuse_reply_ioctl_iov() - - * Move fuse_session, fuse_req and fuse_ll definitions to fuse_i.h - and make send_reply_iov() and fuse_setup_common() global (also in - fuse_i.h). These will be used by CUSE support. - - * Restructure fuse_ll_process() - - * Implement libfuse side of CUSE support. CUSE uses subset of FUSE - operations as dir operations don't make sense for CUSE where one - instance implements single character device. - - CUSE support comes with its own cuse_lowevel_ops and related - initialization and helper functions. Except for initialization, it - usage is basically identical to FUSE. - - This patch also adds example/cusexmp.c which can create a character - device with name and device number specified on command line. The - created device itself is pretty boring. It's a bit bucket supporting - read, write and access via ioctl. - -2009-06-16 Miklos Szeredi - - * Add missing fuse_reply_bmap to versionscript. Debian - Bug#531329. Reported by Goswin Brederlow - -2009-05-27 Miklos Szeredi - - * Don't call forget_node() if the lookup was negative and write() - for the reply returned ENOENT. Reported by John Haxby - -2009-05-25 Miklos Szeredi - - * Add FUSE_CAP_EXPORT_SUPPORT to fuse_common.h - -2009-05-08 Miklos Szeredi - - * Fix missing newlines in some printfs - - * Fix 'make install-strip'. Reported by Dominick Layfield - -2009-01-05 Miklos Szeredi - - * Released 2.8.0-pre2 - -2008-12-08 Miklos Szeredi - - * Implement poll support. Patch by Tejun Heo - - * Add missing setattr flags to . - - * Only pass valid flags to ->setattr(). - -2008-12-05 Miklos Szeredi - - * Implement ioctl support. On high level interface only - "restricted" ioctls are supported (which are defined with the - _IO(), _IOR(), _IOW() or _IOWR() macros). Unrestricted ioctls - will only be allwed to CUSE (Character Device in Userspace) - servers. Patch by Tejun Heo - -2008-11-28 Miklos Szeredi - - * If open sets fi->nonseekable, libfuse will tell the kernel that - the file is not seekable. Patch by Tejun Heo - -2008-11-19 Miklos Szeredi - - * lowlevel lib: fix deadlock if fuse_reply_* is called from the - interrupt handling function. Reported by Tero Marttila - -2008-10-16 Miklos Szeredi - - * Allow commas in options to be escaped with a backslash - - * Add new function: fuse_opt_add_opt_escaped() - - * Add missing fuse_reply_bmap() to the version script - -2008-10-14 Miklos Szeredi - - * Pass current file flags to read and write operations - -2008-07-24 Miklos Szeredi - - * Clean up debug output in highlevel lib - -2008-07-10 Miklos Szeredi - - * Released 2.8.0-pre1 - -2008-06-27 Miklos Szeredi - - * Fix handling of (no)suid and (no)dev options if filesystem is - mounted from /etc/fstab or via mount(8). Reported by Jan Ondrej. - - * Skip calling mount(8) if /etc/mtab doesn't exist or if it's on a - read-only filesystem. This works around issues with certain mount - implementations. Reported by Szabolcs Szakacsits. - -2008-06-16 Miklos Szeredi - - * Remove fuse kernel module sources. Linux 2.6.27 will support - NFS exporting. - -2008-06-10 Miklos Szeredi - - * Fix theoretical infinite loops in libfuse. Reported by Szabolcs - Szakacsits - - * Fix missing include for PATH_MAX. Reported by - Szabolcs Szakacsits - -2008-05-23 Miklos Szeredi - - * Fix mounting over symlink. Reported by Szabolcs Szakacsits - -2008-05-09 Miklos Szeredi - - * Don't allow bigger than 4kB writes by default on 2.6.26 and - later kernels, so that filesystems not expecting this are not - broken on a kernel upgrade. Provide a 'big_writes' mount option - to enable this feature. In future API revisions this may become - the default. - -2008-04-09 Miklos Szeredi - - * Update warning message for missing newline at end of fuse.conf - - * Update debug message for successful operation to not include the - string "error:" - -2008-04-08 Miklos Szeredi - - * Update error message for missing mountpoint parameter. Reported - by Allen Pulsifer - -2008-04-04 Miklos Szeredi - - * Print library version information to debug output - - * Highlevel lib: don't limit paths to 4095 characters - -2008-03-25 Miklos Szeredi - - * Fix memory leaks on mount. Patch by Szabolcs Szakacsits - -2008-03-19 Miklos Szeredi - - * Fix missing pthread_mutex_destroy in error path of - fuse_lib_opendir(). Patch by Szabolcs Szakacsits - -2008-03-07 Miklos Szeredi - - * Add queuing on contention to per-node lock algorithm, to avoid - starvation. - - * Only enable cancelation when reading a request, otherwise - cancellation could happen with a mutex held, which could hang the - process on umount - -2008-02-08 Miklos Szeredi - - * Block SIGCHLD when executing mount and umount - - * fusexmp_fh: avoid unnecessary seeking in readdir - - * Update kernel interface to 7.9: - - * Support receiving file handle from kernel in GETATTR request - - * Allow operations with a NULL path argument, if the filesystem - supports it - - * Add support atomic open(O_TRUNC) - - * Support the st_blksize field in struct stat - - * If the "FUSE_THREAD_STACK" environment is set, initialize the - stack size of threads by this value. Patch by Florin Malita - - * Add per-node locking, instead of a global tree lock to protect - the path from changing during operations. Original patch by - Rodrigo Castro - -2008-02-03 Csaba Henk - - * lib/mount_bsd.c: - - string formatting fixes - - exit if mounting has failed - (in FreeBSD a mount failure is not critical per se, as the daemon - still could be mounted externally, but waiting for such an event - is more confusing than fruitful) - - ditch the kvm(8) stuff and simply use forced unmount which just - won't block - - prettify option specifications - - add "-onosync_unmount" kernel option - -2008-01-07 Csaba Henk - - * lib/mount_bsd.c: - - refine device closing in a race-free way - - add support for "-osubtype" on FreeBSD - - * makeconf.sh: make it work under FreeBSD - -2008-01-03 Csaba Henk - - * lib/mount_bsd.c: close device before unmount - (cf. lib/mount.c rev. 1.43) and fix some warnings - -2007-12-23 Miklos Szeredi - - * Fix './configure --disable-static'. Patch from Ismail Dönmez - -2007-12-17 Miklos Szeredi - - * Released 2.7.2 - -2007-12-12 Miklos Szeredi - - * Fix kernel module compile for 2.6.24 - - * Invalidate attributes of parent directory after create(), since - the modification time changes. Invalidate attributes on rename, - since some filesystems may update st_ctime. Reported by Szabolcs - Szakacsits - - * Fix NFS exporting to handle 64bit node IDs - - * Disable old symbol versions if __UCLIBC__ is defined. If a - symbol in a library has multiple versions, the runtime linker in - uClibc seems to randomly choose between them. - - * Remove erroneous 'fuse_opt_insert_arg@FUSE_2_5' from - fuse_version_script. fuse_opt_free_args() was added in fuse-2.6. - - * Close fuse device file descriptor before calling umount(), - preventing a deadlock when umount is synchronous. Reported by - Szabolcs Szakacsits - -2007-11-12 Miklos Szeredi - - * 'fusermount -u' did not umount the filesystem if /etc/mtab was a - symlink. This bug was introduced in 2.7.1 by "Don't call - /bin/[u]mount if /etc/mtab is a symlink". Found by robertsong. - -2007-10-16 Miklos Szeredi - - * Released 2.7.1 - -2007-10-16 Miklos Szeredi - - * Clarify licence version to be "LGPLv2" for the library - - * kernel fixes: - - * After mount set nlink attribute for the root inode to 1 - - * Fix wake up of task waiting for a reserved request - - * Fix allowing setattr, listxattr and statfs for other users - -2007-09-18 Miklos Szeredi - - * Add missing context initialization in fuse_fs_chmod(). Bug - found by "iohead" - - * Fix kernel module compilation for 2.6.23. Based on patch by - Marian Marinov - -2007-09-04 Philippe Elie - - * lib/fuse_lowlevel.c: fix a fuse_req leak in do_forget() - -2007-07-31 Miklos Szeredi - - * Work around hotplug issue, that it calls filesystem with file - descriptors 0, 1 and 2 not open. Tracked down by Leif Johnson - -2007-07-25 Miklos Szeredi - - * Don't call /bin/[u]mount if /etc/mtab is a symlink. Reported by - Tomas M - - * Also don't touch /etc/mtab if it is within the mounted - filesystem. Suggested by Jeffrey Law - -2007-07-12 Miklos Szeredi - - * Reset args->argc in fuse_opt_free_args(). Patch by Lucas - C. Villa Real - -2007-07-02 Miklos Szeredi - - * Released 2.7.0 - -2007-07-02 Miklos Szeredi - - * Accept a NULL "op" for fuse_main(), etc. This is useful if - filesystem is only invoking fuse to print a help message, or - version. Fixes RedHat bugzilla #217343 - -2007-06-22 Miklos Szeredi - - * lib: fix locking when loading a filesystem module - -2007-06-21 Miklos Szeredi - - * Add fs subtype support to mount.fuse - -2007-06-20 Miklos Szeredi - - * Add fs subtype support to libfuse and fusermount - -2007-06-19 Miklos Szeredi - - * kernel: sync with mainline (2.6.22) - -2007-06-18 Miklos Szeredi - - * Send debug output to stderr instead of stdout. Patch by Jan - Engelhardt - -2007-06-03 Miklos Szeredi - - * libulockmgr: Work around a kernel bug in recv(), causing it to - sometimes return zero even if data was available on the socket. - -2007-05-29 Miklos Szeredi - - * lib: optimization: store parent pointer in node instead of - parent id - -2007-05-25 Miklos Szeredi - - * lib: don't create new thread for each FORGET request. FORGET - messages sometimes caused so many threads to be created, that - process virtual memory space ran out. Reported by Chris AtLee - -2007-05-24 Miklos Szeredi - - * lib: fix memory leak on thread creation failure in multithreaded - event loop. Found by Chris AtLee - -2007-05-23 Miklos Szeredi - - * lowlevel lib: add fuse_reply_iov function, which is similar to - fuse_reply_buf, but accepts a vector of buffers. Patch by Roger - Willcocks - -2007-05-21 Miklos Szeredi - - * Fix Oops or error if a regular file is created with mknod(2) on - a fuse filesystem. Kernels 2.6.18 onward are affected. Thanks to - J. Cameijo Cerdeira for the report - -2007-05-11 Csaba Henk - - * libfuse: fix return value of fuse_loop()/fuse_loop_mt(). - Error reported by Csaba Henk, fix by Miklos Szeredi - - * libfuse: fix unlock in flush - - * libfuse: do unlocking on RELEASE+FLUSH - -2007-05-03 Miklos Szeredi - - * Released 2.7.0-rc1 - -2007-05-02 Miklos Szeredi - - * kernel: sync with mainline: - - * Use invalidate_mapping_pages() if available - - * Fix BUG when invalid file type is supplied in mount. Patch by - Timo Savola - -2007-04-27 Miklos Szeredi - - * libfuse: call umount(8) directly instead of fusermount if - possible - - * Clean up init script, make it LSB compliant - -2007-04-26 Miklos Szeredi - - * In multithreaded loop, use a semaphore instead of SIGHUP to wake - up the main thread on umount. This is more elegant, and works - even if signals are blocked. - -2007-04-25 Miklos Szeredi - - * Improve mounting support in libfuse: - - check non-empty mountpoint - - only fall back to fusermount when necessary - -2007-04-23 Miklos Szeredi - - * Don't chdir to "/" in foreground mode, it causes more trouble - than it's worth - -2007-04-18 Miklos Szeredi - - * Replace utils/mount.fuse "sh" script with a "C" program - -2007-04-15 Miklos Szeredi - - * Add -lulockmgr to compilation comment in fusexmp_fh.c - -2007-04-05 Miklos Szeredi - - * Check for iconv. Patch by Csaba Henk - - * Add direct umounting - - * Use "fusectl" as the device for the fusectl filesystem. Debian - Bug#417945. Reported by Laurent Bonnaud - -2007-04-01 Csaba Henk - - * Fix some FreeBSD related macros. - -2007-03-30 Miklos Szeredi - - * Add support for direct mounting by libfuse. Fall back on - calling fusermount if it doesn't work - -2007-03-14 Miklos Szeredi - - * Released 2.7.0-pre1 - -2007-03-05 Miklos Szeredi - - * Correctly handle O_APPEND in direct IO mode. Reported by Greg - Bruno - - * mount.fuse should use /bin/bash. Debian Bug#413403. Reported - by Thomas Weinbrenner - -2007-02-26 Miklos Szeredi - - * Fix detection of installed fuse in init script. Reported and - fix suggested by Davide Canova - -2007-02-05 Miklos Szeredi - - * Fix 2.6.9 RHEL kernels, which have compatibility mutex.h, but - don't define mutex_destroy(), bummer. Patch from Phil Schwan - -2007-02-04 Miklos Szeredi - - * Compile fuseblk for kernels which don't have an option to turn - off the block layer (CONFIG_BLOCK). Reported by Szakacsits - Szabolcs - -2007-02-03 Miklos Szeredi - - * Add filesystem stacking support to high level API. Filesystem - modules can be built into libfuse or loaded from shared object - (.so) files - - * Add 'subdir' and 'iconv' built in modules - - * lib/fuse.c: Fix locking for the reply code in create and open - -2007-02-02 Miklos Szeredi - - * kernel: make it compile on "strange" kernels which have emulated - mutexes via but no i_mutex. Reported by Tomasz - Mateja - -2007-01-28 Miklos Szeredi - - * kernel: fix BUG in control filesystem if it is umounted and - mounted again, while some fuse filesystems are present. - Bugreport from Florent Mertens - - * kernel: sync with mainline, support 2.6.20 - -2007-01-22 Miklos Szeredi - - * lib/Makefile.am: actually link libfuse against libfuse_libs - -2007-01-19 Miklos Szeredi - - * Build fix for 2.6.16 vanila and 2.6.15 FC5 kernels. Patch from - Ian Abbott - -2007-01-18 Miklos Szeredi - - * Fix abort in fuse_new() compatibility API for opts == NULL case. - Novell bugzilla #233870. Patch from Takashi Iwai. - -2007-01-13 Miklos Szeredi - - * Fix option parsing in mount.fuse. Patch from Jens M. Noedler - -2007-01-02 Miklos Szeredi - - * Fix unaligned access in file desctriptor passing in libfuse, - fusermount and ulockmgr. Debian bug ID: 404904. Reported and - tested by Sebastian Fontius - -2006-12-16 Miklos Szeredi - - * kernel: don't keep unreferenced inodes in the icache. - -2006-12-15 Miklos Szeredi - - * fusermount: Fix detection of fuseblk. Reported by Szakacsits - Szabolcs - - * lib: Fix use after free in fuse_flush(). Reported by Ron - Lindman - -2006-12-10 Miklos Szeredi - - * mount.fuse: add "setuid=USER" option which does a "su - USER" - for the filesystem - - * fusermount: use "/bin/mount -f" to add entry to /etc/mtab, and - "/bin/umount" to remove entry from /etc/mtab. This gets rid of - the ugly code dealing with mtab, as well as a possible race - between fusermount and mount trying to modify /etc/mtab at the - same time - - * Fix "buffer size too small: 4" warning for users of the - fuse_loop_mt_proc() function. - -2006-12-04 Miklos Szeredi - - * Fix warnings with gcc-4.1 on 64bit archs. Report from - Harshavardhana - - * Add extra warning options, and fix resulting warnings - - * Really fix fuse_teardown problem - -2006-12-02 Miklos Szeredi - - * Add -lrt to fuse.pc (if needed) to fix static linking against - libfuse. Reported by Szakacsits Szabolcs - -2006-12-01 Miklos Szeredi - - * Released 2.6.1 - -2006-11-30 Miklos Szeredi - - * Fix API version 21 and 22 compatibility for fuse_teardown. - Reported by Bgs - -2006-11-29 Miklos Szeredi - - * fusermount: Print a more helpful message in case the kernel - doesn't support the 'fuseblk' filesystem type. This has been - biting ntfs-3g users. Reported by Yura Pakhuchiy - - * kernel: fix build problem for "make -C ...". Reported by - Stephen Bryant - -2006-11-19 Miklos Szeredi - - * Fix bug in certain error paths of lookup routines. The request - object was reused for sending FORGET, which is illegal. This bug - could cause an Oops in linux-2.6.18 or in fuse-2.6.0, and might - silently corrupt memory in earlier versions. Report and test - program by Russ Cox - -2006-11-11 Miklos Szeredi - - * Print an error if an incompatible kernel interface version is - detected in INIT. This will only show if filesystem is started - with -d or -f - - * Fix order of fuse_destroy()/fuse_unmount() in error cleanup of - fuse_setup_common(). Reported by Szakacsits Szabolcs - -2006-11-06 Miklos Szeredi - - * Fix recursive locking in fuse_create(). Thanks to Takuya - Ishibashi for the bug report - -2006-10-28 Miklos Szeredi - - * Fix automake problem. Patch from Nix - -2006-10-26 Miklos Szeredi - - * Fix mount.fuse to use /bin/sh instead of /bin/bash, which is not - always available on embedded systems. Patch from Paul Smith - - * Fix util/Makefile.am, so that failure to run update-rc.d or - device creation doesn't cause make to fail. Reported by Paul - Smith - -2006-10-21 Miklos Szeredi - - * Released 2.6.0 - -2006-10-18 Miklos Szeredi - - * fusermount: don't try to create a lock file if /etc/mtab is a - symlink. Report and patch from Alexei Sheplyakov (debian bug - #393693) - -2006-10-17 Miklos Szeredi - - * Minor changes, sync with mainline tree - -2006-10-16 Miklos Szeredi - - * Released 2.6.0-rc3 - -2006-10-15 Miklos Szeredi - - * kernel: cleanups - -2006-10-13 Miklos Szeredi - - * kernel: Fix compilation on patched 2.6.18 (fc6) and 2.6.19. - Report from David Shaw - - * lib: Fix lost error on renaming a file. Report from David Shaw - - * lib: Fix lost error on hiding open files (renaming to - .fuse_hiddenXXXX) - - * kernel: Fix a rare hang on SMP/32bit on heavy filesystem - activity. The cause of the bug was that some calls to - i_size_write() were not protected by a lock, and hence - i_size_seqcount could become corrupted. This caused subsequent - calls to i_size_read() to spin forever. This is a long standing - bug was probably introduced in version 2.2, and thought to be - related to NFS exporting (it's not). It was reported by various - people, but Dana Henriksen has finally helped me to track it down, - so big thanks to him - - * kernel: Protect against truncation of a swapfile - -2006-10-10 Miklos Szeredi - - * kernel: Check for signature of super_operations->umount_begin(). - Ubuntu kernel 2.6.17 seems to use the new signature found in - 2.6.18. Thanks to Florent Mertens for the report - -2006-10-08 Miklos Szeredi - - * Make sure inode numers wrap around at 2^32. This is needed on - dual 64bit/32bit architectures, because 32bit applications using - the non-largefile interface would otherwise break (EOVERFLOW error - would be returned by the stat() system call family) - - * ulockmgr: handle the case, when a locking operation fails - because no more file desctriptors are available in - ulockmgr_server. Also work around a Linux kernel bug (known to - exist for all Linux kernel versions <= 2.6.18) which may cause - sent file descriptors to be lost in the above case - - * ulockmgr: optimize file descriptor use - - * restore needed cpp flags to util/Makefile.am - - * Install udev rules as 99-fuse.rules instead of 60-fuse.rules - - * Minor clean up of udev rules - - * Add a synchronous DESTROY message to kernel interface. This is - invoked from umount, when the final instance of the filesystem is - released. It is only sent for filesystems mounted with the - 'blkdev' option for security reasons. - - * If the DESTROY message is received, call the filesystem's - ->destroy() method. In this case it's not called from session - destruction as it would be otherwise. - -2006-10-01 Miklos Szeredi - - * Released 2.6.0-rc2 - -2006-10-01 Miklos Szeredi - - * Add support for FLUSH+RELEASE operation for FreeBSD. Original - patch by Csaba Henk - - * Add init script to insert fuse module and mount the control - filesystem. The script is installed as /etc/init.d/fuse and on - debian based systems (where update-rc.d is available) symlinks - from /etc/rc*.d/ are also installed. - - * Include '#define FUSE_USE_VERSION=XX' into examples so they - become more self contained. - -2006-09-30 Miklos Szeredi - - * API changes: - - * Move lock_owner from a separate argument into fuse_file_info - - * Add a flag to fuse_file_info indicating (1) a highlevel lock - operation (unlock all) was initiated by a flush, (2) a lowlevel - release operation should perform a flush as well. - - * fusermount: revert modprobe change (2006-08-18) since it - doesn't work reliably with udev - - * Add support for block device backed filesystems. This mode is - selected with the 'blkdev' option, which is privileged. - - * Add support for the bmap (FIBMAP ioctl) operation on block - device backed filesystems. This allows swapon and lilo to work on - such filesystems. - - * kernel changes: - - * Drop support for kernels earlier than 2.6.9. Kernel module from - previous (2.5.x) release can be used with library from this - release - - * In fuse_dentry_revalidate() use dget_parent() instead of - dereferencing d_parent, since there's no protection against parent - changing and going away - - * Protect nlookup from concurrent updates - - * In lookup if a directory alias exists but is unused, - then get rid of it, otherwise return -EBUSY. - - * In mkdir if a directory alias exists, return success, but leave - dentry negative. In reality this could happen if a remote rename - immediately followed the mkdir. - - * Don't BUG in fuse_iget() if multiple retries are needed to get a - good inode. This could happen if several lookups are racing for - the same inode. - -2006-09-29 Miklos Szeredi - - * Fix compilation on 2.6.9. Report from Troy Ayers - -2006-09-27 Miklos Szeredi - - * Fix Oops in fuse_readpages(). Reported by David Shaw - -2006-09-24 Csaba Henk - - * Add support for nanosec times on FreeBSD - - * Fix FreeBSD compatibility issues - -2006-09-23 Miklos Szeredi - - * Fix one more compatibility bug. Thanks to Ricardo Correia - - * Fix utimens compilation with uClibc. Patch from Jamie Guinan - -2006-09-22 Miklos Szeredi - - * Fixed several compatibility bugs in low level interface. - Reported by Ricardo Correia - - * Add workaround for ARM caching bug - -2006-09-16 Miklos Szeredi - - * Rename new utimes() method to more logical utimens() - -2006-09-14 Miklos Szeredi - - * Fuse tried to unlink already unlinked hidden files. Bug - reported by Milan Svoboda - -2006-09-10 Miklos Szeredi - - * Released 2.6.0-rc1 - -2006-09-10 Miklos Szeredi - - * kernel: Fix unlock on close for kernels < 2.6.18 - - * Add ulockmgr library & server. This can be used for handling - file locking requests either directly from libfuse or over a - network, etc. This first version is not optimized and the number - of file descriptors it uses may get out of hand - -2006-09-07 Miklos Szeredi - - * lib: Add interrupt support to high level library, which may be - enabled with the 'intr' mount option. - - * When an operation is interrupted the thread handling that - operation will receive SIGUSR1 (or other signal specified with the - 'intr_signal=N' option). The library installs a no-op signal - handler for this signal, unless there's already a handler - installed. - - * The filesystem may query interrupt status (regardless of 'intr') - with the fuse_interrupted() function. - - * mount.fuse: initialize $HOME if not set. Report from Sven Goldt - -2006-09-03 Miklos Szeredi - - * lib: Multithreaded loop now allows unlimited number of threads. - This is needed for locking operations which may block - indefinitely. Also the kernel now doesn't limit the number of - outstanding requests so the library shouldn't do so either. - -2006-09-01 Miklos Szeredi - - * Fix recursive lock bug in interrupt handling - - * Add utimes() method to highlevel interface, which supports - setting times with nanosecond resolution - -2006-08-18 Miklos Szeredi - - * kernel: fix page leak if fuse_readpages() failed in it's - initialization. Bug found and original patch from Alexander - Zarochentsev - - * For linux kernels >=2.6.18 (2.6.19 if using the fuse module from - the kernel tree) the statfs method will receive the path within - the filesystem on which the stat(v)fs syscall was called - - * fusermount: try to modprobe fuse module if invoked by root and - unable to open device. This is needed with udev, since the device - node will be created only when the module is inserted, hence - module autoloading won't work. Reported by Szakacsits Szabolcs - -2006-07-30 Miklos Szeredi - - * fusermount: if selinux is active, restore the original file's - security context in unmount_rename(). Redhat bugzilla id 188561. - Patch from Yves Perrenoud - - * Add POSIX file locking operation to high level library - - * Initialize context for unlink of hidden files on umount. Bug - reported by Tim Stoakes - -2006-07-14 Miklos Szeredi - - * Multiple release() calls can race with each other, resulting in - the hidden file being deleted before the last release finishes. - Bug found and patch tested by Mark Huijgen - -2006-07-05 Miklos Szeredi - - * fusermount: if /dev/fuse doesn't exist, suggest modprobing fuse; - this makes sense on systems using udev. Reported by Szakacsits - Szabolcs - -2006-06-29 Miklos Szeredi - - * Released 2.6.0-pre3 - -2006-06-29 Miklos Szeredi - - * Support in kernel module for file locking and interruption. The - same functionality is available in official kernels >= 2.6.18 - -2006-06-28 Miklos Szeredi - - * Add POSIX file locking support - - * Add request interruption - -2006-06-06 Miklos Szeredi - - * Add missing pthread_rwlock_destroy(). Patch from Remy Blank - -2006-06-05 Remy Blank - - * lib: canonicalize mount point in fuse_helper_opt_proc() so that - unmounting succeeds even if mount point was relative. - -2006-06-04 Csaba Henk - - * lib: fix emergency umount in helper.c when malloc fails. - (The way it was done would end up in a segfault.) - -2006-06-01 Csaba Henk - - * lib: adjust threading related compiler flags. - Switch to "-pthread" from "-lpthread" as that's the preferred - one on several platforms. Consulted with Terrence Cole and - Miklos Szeredi - -2006-05-08 Miklos Szeredi - - * lib: search fusermount in installation directory (bindir) as - well as in PATH. - -2006-05-03 Miklos Szeredi - - * lib: fix compilation if CLOCK_MONOTONIC is not defined. - Reported by Christian Magnusson - -2006-04-23 Csaba Henk - - * lib: make FreeBSD mount routine recognize if kernel features - backgrounded init and if it does, run the mount util in foreground - (similarly to Linux) - -2006-04-21 Miklos Szeredi - - * kernel: fix fput deadlock fix, the lockless solution could lead - to "VFS: busy inodes after umount..." - - * kernel: fix race between checking and setting file->private_data - for the device. Found by Al Viro - -2006-04-11 Miklos Szeredi - - * kernel: remove request pool, instead allocate requests on - demand. Account the number of background requests, and if they go - over a limit, block the allocation of new requests. - - * kernel: fix deadlock if backgrounded request holds the last - reference to the super block - - * kernel: don't use fuse_reset_request() during direct I/O - -2006-04-06 Csaba Henk - - * lib: Let FreeBSD mount option parsing routine recognize "no" - prefixes for FUSE specific options as well - -2006-04-01 Miklos Szeredi - - * lib: Add missing rwlock initialization. Patch by Ryan Bradetich - -2006-03-17 Miklos Szeredi - - * API changes: - - * fuse_main(), fuse_setup() and fuse_new() have an additionl - user_data parameter - - * fuse_mount() returns a 'struct fuse_chan' pointer instead of a - file descriptor - - * fuse_unmount() receives a 'struct fuse_chan' pointer. It - destroys the given channel - - * fuse_teardown() no longer has a file descriptor parameter - - * new exported functions: fuse_session_remove_chan(), - fuse_get_session(), fuse_daemonize() - - * fuse_chan_recv() may now return a new channel which will be used - to send the reply - -2006-03-16 Miklos Szeredi - - * Released 2.6.0-pre2 - -2006-03-16 Miklos Szeredi - - * Don't unmount if already unmounted. This fixes a problem seen - in the following situation: Lazy unmount a busy filesystem; Mount - a new one in top; When the first finally unmounts, the second also - unmounts. Reported by Franco Broi - -2006-03-15 Miklos Szeredi - - * lowlevel lib: use indirect function calls instead of a - switch/case construct. Besides increased efficiency it helps - maintainability & readability too. Patch from Florin Malita - -2006-03-13 Miklos Szeredi - - * kernel: replace global spinlock with a per-connection spinlock - -2006-03-10 Miklos Szeredi - - * Fix source compatibility breakage for fuse_unmount(). Report - from Yura Pakhuchiy - -2006-03-02 Miklos Szeredi - - * Fix O_ASYNC handling in fuse_dev_release(). From Jeff Dike - -2006-03-01 Miklos Szeredi - - * Add O_ASYNC and O_NONBLOCK support to FUSE device. Patch by - Jeff Dike - - * Renamed fuse_chan_receive() to fuse_chan_recv() and changed - interface to return -errno in case of error. - -2006-03-01 Csaba Henk - - * libfuse: pass device file descriptor to fuse_unmount(), rewrite - FreeBSD implementation so that it uses libc (sysctl backed) instead - of an embdedded script (kmem backed). Adjust the control flow of - hello_ll so that device doesn't get closed before unmount attempt. - -2006-02-25 Miklos Szeredi - - * Lowlevel lib: return all-zero statvfs data if filesystem doesn't - implement method. This is needed on FreeBSD, and nicer on Linux - too. Highlevel lib already did this. Reported by Csaba Henk - - * Fix negative entry handling. There was a bug, that negative - lookups with timeouts (nodeid == 0) returned -EIO. - -2006-02-23 Miklos Szeredi - - * Fix race between RELEASE and UNLINK, which might leave - .fuse_hidden* files around - -2006-02-21 Miklos Szeredi - - * fusexmp_fh: implement flush() method and call close() on the - open file descriptor. This is needed if used on an NFS - filesystem, which buffers data until file is closed. Franco Broi - spotted the situation when 'cp -p' failed to set the modification - time because of this. - -2006-02-20 Miklos Szeredi - - * Released 2.6.0-pre1 - -2006-02-19 Miklos Szeredi - - * libfuse: fix use-after-free bug in interruptred reply_entry(). - Patch from John Muir - - * libfuse: fix wrong symbol versioning for fuse_mount. Debian bug - ID: 352631. Found by Stéphane Rosi - -2006-02-17 Miklos Szeredi - - * Lowlevel lib: Unify fuse_dirent_size() and fuse_add_dirent() - into a single function fuse_add_direntry(). This cleans up the - interface and makes it possible to do stacking. - -2006-02-16 Miklos Szeredi - - * Fix rare race betweeen abort and release caused by failed iget() - in fuse_create_open(). - - * Add 'ac_attr_timeout' option e.g. for filesystems which do their - own attribute caching. - -2006-02-15 Miklos Szeredi - - * Work around FreeBSD runtime linker "feature" which binds an old - version of a symbol to internal references if the symbol has more - than one version. This resulted in infinite recursion in - fuse_lowlevel_new_compat25(). - -2006-02-10 Csaba Henk - - * Refine clock_gettime() querying so that linker options - shall be set as it's appropriate for the target platform. - -2006-02-09 Miklos Szeredi - - * Fix udev rule syntax. Reported by Nix - -2006-02-08 Miklos Szeredi - - * In some cases udev rule seems to be ineffective when installed - as 40-fuse.rules but work as 60-fuse.rules. Reported by John Hunt - -2006-02-03 Miklos Szeredi - - * Fix compilation when build directory is different from source - directory. Reported by Frédéric L. W. Meunier - -2006-02-02 Miklos Szeredi - - * Fix even bigger bug introduced in fix for request_end() on - 2006-01-14. Reported by Gal Rosen - -2006-01-30 Miklos Szeredi - - * highlevel-lib: add 'auto_cache' option. This caches file data - based on modification time and size - -2006-01-20 Miklos Szeredi - - * Sanitize storage type and help message in mount_bsd.c. Patch - from Csaba Henk - - * fuse_opt: add new helper constants FUSE_OPT_KEY_KEEP and - FUSE_OPT_KEY_DISCARD - - * Add options 'max_readahead', 'sync_read' and 'async_read' - - * Kernel ABI version 7.6: - - * Negotiate the 'max_readahead' value and 'async_read' flags with - userspace in the INIT method - - * Add connection info to ->init() methods to both lowlevel and - highlevel API - - * Fall back to synchronous read() behavior if either library or - userspace filesystem is using the old interface version. This is - needed so non-updated filesystems won't be confused by the - different read() behavior - -2006-01-19 Miklos Szeredi - - * lib: if "fsname=" option was given, pass it to fusermount - - * fuse_opt: add new fuse_opt_insert_arg() function, which is - needed by filesystems to implement some argument manipulations - correctly - - * fuse_opt: fix memory leak in handling "--" option - -2006-01-18 Miklos Szeredi - - * kernel: fix detection of case when fuse is not configured into - the kernel either as module or built-in - - * fuse_opt.h: fix incompatibility with C++ compilers by renaming - 'template' structure member to 'templ'. Reported by Takashi Iwai - - * fuse.h: fix compatibility bugs. Patch by Yura Pakhuchiy - - * kernel: support version 2.6.16 (i_sem -> i_mutex) - -2006-01-16 Miklos Szeredi - - * Added (again) asynchronous readpages support - - * Each connection now shows up under /sys/fs/fuse/connections - - * Connection attributes exported to sysfs: 'waiting' number of - waiting requests; 'abort' abort the connection - - * Connection may be aborted through either the sysfs interface or - with 'umount -f mountpoint' - -2006-01-14 Miklos Szeredi - - * Released 2.5.0 - -2006-01-14 Miklos Szeredi - - * kernel: fix a couple of bugs - - * Order of request_end() and fuse_copy_finish() was wrong. - Posthumous note: Franco Broi managed to exploit this, though it - seemed quite impossible - - * request_end() used request pointer after decrementing refcount - - * Clearing ->connected or ->mounted connection flags could race - with setting other bitfields not protected with a lock - -2006-01-10 Miklos Szeredi - - * kernel: add necessary compile flags for 2.4.X/x86_64. - Report from Sean Ziegeler - -2006-01-09 Miklos Szeredi - - * Released 2.5.0-pre2 - -2006-01-09 Miklos Szeredi - - * Applied patch from Csaba Henk, to update mount_bsd to new - fuse_mount() semantics - - * Ignore auto,noauto,... options in mount.fuse. Reported by Frank - Steiner and Don Taber - - * fusermount: add 'dirsync' mount option - -2006-01-07 Miklos Szeredi - - * Improved help reporting and added version reporting to library - -2006-01-06 Miklos Szeredi - - * Change working directory to "/" even if running in the - foreground. Patch from Jonathan Brandmeyer - - * Changed lots of functions to use 'struct fuse_args' instead of - separate argc and argv - - * Added fuse_parse_cmdline(), fuse_set_signal_handlers() and - fuse_remove_signal_handlers() functions, so that it's now pretty - easy to get all the functionality of fuse_main() with a filesystem - using the lowlevel API. - -2006-01-02 Miklos Szeredi - - * mount.fuse: the 'user' option should be ignored. Report and - solution from Mattd. - - * mount.fuse: export PATH in the right place. Report and patch - from Hannes Schweizer - -2005-12-16 Miklos Szeredi - - * Clean up the option parsing interface slightly, by creating an - "argument list" structure, that contains the argument vector and - count - -2005-12-15 Miklos Szeredi - - * fusermount: check if /mnt/mtab is a symlink and don't modify it - in that case - - * kernel: simplify request size limiting. INIT only contains - maximum write size, maximum path component size remains fixed at - 1024 bytes, and maximum xattr size depends on read buffer. - -2005-12-14 Miklos Szeredi - - * Fix readdir() failure on x86_64, of 32bit programs compiled - without largefile support. Bug report and help from Anthony - Kolasny - - * If lookup returns invalid mode, return -EIO instead of creating - a regular file - - * Add current output argument vector to option processing - function - -2005-12-12 Miklos Szeredi - - * Fix stale code in ifdef FreeBSD. Patch from Csaba Henk - -2005-12-09 Miklos Szeredi - - * Released 2.5.0-pre1 - -2005-12-09 Miklos Szeredi - - * libfuse: added option parsing interface, defined in - . - -2005-12-07 Miklos Szeredi - - * Return EIO for file operations (read, write, fsync, flush) on - open files whose inode has become "bad". Inodes will be marked - "bad" if their type changes. Bug report by Csaba Henk - -2005-12-06 Miklos Szeredi - - * Use bigger request buffer size. write() did not work on archs - with > 4k page size, Bug report by Mark Haney - - * ABI version 7.5: - - * Extend INIT reply with data size limits - -2005-12-02 Miklos Szeredi - - * Fix memory leak in fuse_read_cmd()/fuse_process_cmd(). Bug - reported by Vincenzo Ciancia - - * Handle exit-by-umount in fuse_read_cmd() - -2005-11-29 Miklos Szeredi - - * Check if '-msoft-float' option is supported by compiler when - configuring for a 2.4.x kernel. Bug report by Mark Haney - - * In multithreaded loop send a TERM signal to the main thread if - one of the other threads exit. Needed on FreeBSD for a clean exit - on umount. Should not cause any harm on Linux either - -2005-11-28 Miklos Szeredi - - * Fix bug in 32-bit file handle compatibility - -2005-11-27 Miklos Szeredi - - * Block TERM, INT, HUP and QUIT signals in all but the main - thread. According to POSIX it's not specified which thread will - receive these signals. - - * Kernel changes: - - * Check for directory aliasing on mkdir, not just on lookup - - * Check for special node ID values in create+open operation - - * Sync with -mm: readv, writev, aio_read and aio_write methods - added to file operations - - * Cleanups: lookup code, page offset calculation - - * ABI stepped to 7.4, changes: - - * frsize member added to fuse_kstatfs structure - - * added support for negative entry caching: on lowlevel API if - fuse_entry_param::ino is set to zero in reply to a lookup request, - the kernel will cache the dentry for the specified amount of time. - - * libfuse: added 'negative_timeout' option: specifies how much - negative entries should be cached. Default is zero, to be - compatible with prior versions - -2005-11-22 Miklos Szeredi - - * Add detection of mainline FUSE code in running kernel - -2005-11-21 Miklos Szeredi - - * Don't use async cancelation in multithreaded loop. This makes - it more portable to systems where read() is not async cancel safe. - Report from Andriy Gapon - -2005-11-20 Miklos Szeredi - - * Warn if API version 11 compatibility is requested - -2005-11-17 Miklos Szeredi - - * More FreeBSD merge - - * fusermount: don't allow mountpoints with '\n', '\t', or '\\' in - them, because it corrupts /etc/mtab. Found by Thomas Biege - CVE-2005-3531 - - * libfuse: don't use system() to invoke 'fusermount -u ...' - because it breaks mountpoints with spaces in them into multiple - arguments - -2005-11-16 Miklos Szeredi - - * Merge library part of FreeBSD port. Patch by Csaba Henk - -2005-11-11 Miklos Szeredi - - * Use 64bit type for file handle, so the full range supported by - the kernel interface is available to applications - -2005-11-10 Miklos Szeredi - - * Moved mountpoint argument checking from fuse_parse_cmdline() to - fuse_mount() in preparation to FreeBSD merge. - -2005-11-08 Miklos Szeredi - - * Remove unneeded close() from fuse_teardown(). Spotted by Csaba - Henk. - -2005-11-07 Miklos Szeredi - - * Make the statfs change backwards compatible. - -2005-11-06 Miklos Szeredi - - * Change ->statfs() method to use 'struct statvfs' instead of - 'struct statfs'. This makes the API more portable since statvfs() - is defined by POSIX. - -2005-10-28 Miklos Szeredi - - * Add fgetattr() method, which currently will only be called after - a successful call to a create() method. - -2005-10-26 Miklos Szeredi - - * Change kernel ABI version to 7.3 - - * Add ACCESS operation. This is called from the access() system - call if 'default_permissions' mount option is not given, and is - not called on kernels 2.4.* - - * Add atomic CREATE+OPEN operation. This will only work with - 2.6.15 (presumably) or later Linux kernels. - - * Add ftruncate() method. This will only work with 2.6.15 - (presumably) or later Linux kernels. - - * Fix kernel module compile if kernel source and build directories - differ. Report and initial patch by John Eastman - -2005-10-18 Miklos Szeredi - - * lib: optimize buffer reallocation in fill_dir. - -2005-10-17 Miklos Szeredi - - * Released 2.4.1 - -2005-10-14 Miklos Szeredi - - * libfuse: add debug for write result (by Shaun Jackman) and - warnings for too large read/write result - -2005-10-11 Miklos Szeredi - - * Spelling fixes, thanks to Ioannis Barkas - -2005-10-10 Miklos Szeredi - - * fuse_common.h: use extern "C". Thanks to Valient Gough for the - patch - -2005-10-07 Miklos Szeredi - - * highlevel-lib: init() and destroy() methods didn't have an - initialized fuse_context. Bug reported by Tim Stoakes - -2005-10-04 Miklos Szeredi - - * Released 2.4.0 - -2005-10-03 Miklos Szeredi - - * Add documentation to fuse_lowlevel.h - - * API cleanups: - - * Remove definitions of unused FATTR_CTIME / FUSE_SET_ATTR_CTIME - - * Move fuse_mount() and fuse_unmount() to fuse_common.h - - * Change the return type of fuse_reply_none() from int to void. - -2005-09-30 Miklos Szeredi - - * kernel: NFS exporting leaked dentries. Bug found and fixed by - Akshat Aranya. - -2005-09-29 Miklos Szeredi - - * fusermount: fix error message, when unable to open /dev/fuse. - Report by Balázs Pozsár - -2005-09-28 Miklos Szeredi - - * UClibc fixes from Christian Magnusson - -2005-09-27 Miklos Szeredi - - * Added NAME="%k" to util/udev.rules. Fix by Mattias Wadman. - -2005-09-26 Miklos Szeredi - - * Released 2.4.0-rc1 - -2005-09-26 Miklos Szeredi - - * fusermount: allow user umount in the case when /etc/mtab is a - symlink to /proc/mounts. Reported by Balázs Pozsár. - -2005-09-23 Miklos Szeredi - - * Check for special node ID values in lookup and creation - -2005-09-22 Miklos Szeredi - - * Slight optimization in returning EINVAL error in case of an open - with O_DIRECT flag. - -2005-09-20 Miklos Szeredi - - * Remove '--enable-auto-modprobe' configure flag. Module - auto-loading is now handled by the kernel. - -2005-09-15 Miklos Szeredi - - * Install UDEV rule file, so /dev/fuse is created with mode 0666. - Help from Jens M. Noedler. - -2005-09-14 Miklos Szeredi - - * Add memory cleanup on thread exit - -2005-09-13 Miklos Szeredi - - * Set umask to zero in fusexmp and fusexmp_fh, so that - files/directories are created with the requested mode. - -2005-09-12 Miklos Szeredi - - * Don't ignore read error in multithreaded loop - -2005-09-08 Miklos Szeredi - - * Released 2.4.0-pre2 - -2005-09-08 Miklos Szeredi - - * Revert lock and access operations. Postpone these until 2.5. - -2005-09-02 Miklos Szeredi - - * Fix compile warning on 2.6.13 and later - - * Fix compilation on old kernels - -2005-08-19 Miklos Szeredi - - * lib: always refresh directory contents after rewinddir() to - conform to SUS. Bug found by John Muir. - -2005-08-15 Miklos Szeredi - - * Released 2.4.0-pre1 - -2005-08-14 Miklos Szeredi - - * lib: cleaned up (or messed up, depending on your POV) the low - level library API. Hopefully this is close to the final form. - -2005-08-05 Miklos Szeredi - - * fusermount: don't allow empty mountpoint argument, which defeats - automatic umounting in fuse_main(). Bugreport by Václav Jůza - -2005-08-03 Miklos Szeredi - - * fix warnings in fuse.h and fuse_lowlevel.h if -Wshadow compiler - option is used (Paul Alfille). - -2005-08-02 Miklos Szeredi - - * highlevel-lib: added mount options "attr_timeout" and - "entry_timeout". These options control the length of time file - attributes and entries (names) are cached. Both default to 1.0 - second. - - * kernel: correctly handle zero timeout for attributes and entries - -2005-08-01 Miklos Szeredi - - * Added missing symbols to versionscript (Joshua J. Berry) - - * kernel: implement two flags, open can set: 'direct_io' and - 'keep_cache'. These correspond exactly to mount options - 'direct_io' and 'kernel_cache', but allow a per-open setting. - - * Move 'direct_io' and 'kernel_cache' mount option handling to - userspace. For both mount options, if the option is given, then - the respective open flag is set, otherwise the open flag is left - unmodified (so the filesystem can set it). - - * lib (highlevel): make open method optional - -2005-07-28 Miklos Szeredi - - * kernel: invalidate attributes for read/readdir/readlink - operations - - * kernel: detect newer UML kernels - -2005-07-26 Miklos Szeredi - - * Make the installation path of fuse.ko and mount.fuse - configurable through INSTALL_MOD_PATH and MOUNT_FUSE_PATH - environment variables. Requirement and help from Csaba Henk. - -2005-07-22 Miklos Szeredi - - * Fix bug, that causes filesystem requests to hang when unique - request counter becomes negative. This happens after - 2,147,483,648 operations, so most people won't care. Thanks to - Franco Broi for the report and testing. - -2005-07-21 Miklos Szeredi - - * Don't change mtime/ctime/atime to local time on read/write. - Bug reported by Ben Grimm - - * Install fuse_common.h and fuse_lowlevel.h. Report by Christian - Magnusson - - * fusermount: use getopt_long() for option parsing. It allows the - use of '--' to stop argument scanning, so fusermount can now - operate on directories whose names begin with a '-'. Patch by - Adam Connell - -2005-07-15 Miklos Szeredi - - * fusermount: add '-v', '--version' and '--help' options - - * add inode based API - -2005-07-12 Miklos Szeredi - - * lib: don't block signals in worker threads. Problem noticed by - Usarin Heininga - -2005-07-07 Miklos Szeredi - - * lib: don't allow both 'allow_other' and 'allow_root' options to - be given - -2005-07-06 Miklos Szeredi - - * fusermount: check if mountpoint is empty (only '.' and '..' for - directories, and size = 0 for regular files). If "nonempty" - option is given, omit this check. This is useful, so users don't - accidentally hide data (e.g. from backup programs). Thanks to - Frank van Maarseveen for pointing this out. - - * kernel: check if mandatory mount options ('fd', 'rootmode', - 'user_id', 'group_id') are all given - - * lib: simplify 'readdir_ino' handling - - * lib: add mount options 'umask=M', 'uid=N', 'gid=N' - -2005-07-03 Miklos Szeredi - - * kernel: clean up 'direct_io' code - -2005-06-28 Miklos Szeredi - - * Add 'mount.fuse' written by Petr Klima - - * '/dev/fuse' is created by 'make install' if does not yet exist - -2005-06-20 Miklos Szeredi - - * Fix UCLIBC compile error. Patch by Christian Magnusson - -2005-06-08 Miklos Szeredi - - * Enable the auto-loading of the module via access to the - corresponding device file. Patch by Takashi Iwai. - - * Allow mounting a regular file (over a regular file) for - unprivleged users. - - * Do not create temporary device file. Require "/dev/fuse" to - exist, and be readable/writable by the mounting user. - -2005-06-02 Miklos Szeredi - - * Released 2.3.0 - -2005-06-02 Miklos Szeredi - - * Fix serious information leak: if the filesystem returns a short - byte count to a read request, and there are non-zero number of - pages which are not filled at all, these pages will not be zeroed. - Hence the user can read out previous memory contents. Found by - Sven Tantau. - -2005-05-27 Miklos Szeredi - - * Add "readdir_ino" mount option, which tries to fill in the d_ino - field in struct dirent. This mount option is ignored if "use_ino" - is used. It helps some programs (e.g. 'pwd' used over NFS from a - non-Linux OS). Patch by David Shaw. - -2005-05-12 Miklos Szeredi - - * Released 2.3-rc1 - -2005-05-12 Miklos Szeredi - - * File save in krusader and other editors doesn't work with sshfs, - because open() is interrupted by a periodic signal, and open() - restarts forever, without any progress. This could just be fixed - in open(), but the problem is more generic: if signals are - received more often than the filesystem can get the request to - userspace, it will never finish. This is probably only a - theoretical problem, nevertheless I'm removing the possibility to - interrupt requests with anything other than SIGKILL, even before - being sent to userspace. Bugreport by Eduard Czimbalmos. - -2005-05-09 Miklos Szeredi - - * libfuse: add "tree_lock" rwlock, that is locked for write in - rename, unlink and rmdir, and locked for read in all other - operations. This should fix the rename/release race reported by - Valient Gough and others. The solution is very coarse, a finer - grained locking scheme could be implemented, but it would be much - more complex. Let's see whether this is good enough. - -2005-05-09 Miklos Szeredi - - * Released 2.3-pre7 - -2005-05-08 Miklos Szeredi - - * Better fix for out of order FORGET messages. Now the - LOOKUP/FORGET messages are balanced exactly (one FORGET can - balance many lookups), so the order no longer matters. This - changes the kernel ABI slightly, but the library remains backward - compatible. - -2005-05-06 Miklos Szeredi - - * Fix abort for out of order FORGET messages. Again. Spotted by - Franco Broi again. Sorry :) - -2005-04-29 Miklos Szeredi - - * Released 2.3-pre6 - -2005-04-29 Miklos Szeredi - - * Make fusermount work with fuse kernel modules not yet supporting - the "group_id" option (added for the purpose of stricter - permission checking). - -2005-04-28 Miklos Szeredi - - * Check for hard-linked directories in lookup. This could cause - problems in the VFS, which assumes that such objects never exist. - - * Make checking of permission for other users more strict. Now - the same privilege is required for the mount owner as for ptrace - on the process performing the filesystem operation. - -2005-04-23 Miklos Szeredi - - * Released 2.3-pre5 - -2005-04-22 Miklos Szeredi - - * Add -msoft-float to kernel module compile flags for 2.4.X. This - is needed on certain architectures. Report from Chris Kirby - - * Fix buggy behavior of open(..., O_CREAT|O_EXCL) if interrupted. - Reported by David Shaw - - * Remove "allow_root" option from kernel module, and implement - it's functionality in the library - - * Fix Oops caused by premature release of fuse_conn. Clean up - related code, to be more readable - - * Sendfile should not use page cache if "direct_io" mount option - is given - -2005-04-08 Miklos Szeredi - - * Fix Oops in case of nfs export. Spotted by David Shaw - - * Fix another Oops in case of write over nfs with direct_io turned - on. Again spotted by David Shaw - -2005-04-07 Miklos Szeredi - - * Released 2.3-pre4 - -2005-04-07 Miklos Szeredi - - * lib: finalized new readdir() interface, which now supersedes the - getdir() method. - -2005-04-03 Miklos Szeredi - - * Released 2.3-pre3 - -2005-04-03 Miklos Szeredi - - * Implement backward compatibility with version 5 kernel ABI - -2005-04-01 Miklos Szeredi - - * Released 2.3-pre2 - -2005-04-01 Miklos Szeredi - - * kernel: fix dirent offset handling - - * lib: add readdir and releasedir methods - - * lib: use fh field of fuse_file_info in opendir, readdir, - releasedir and fsyncdir methods - - * lib: check kernel API version and bail out of it's old. This - will be properly fixed in the next release - -2005-03-31 Miklos Szeredi - - * Released 2.3-pre1 - -2005-03-31 Miklos Szeredi - - * kernel API: add padding to structures, so 64bit and 32bit - compiler will return the same size - - * kernel API: add offset field to fuse_dirent. This will allow - more sophisticated readdir interface for userspace - - * kernel API: change major number to 6 - - * kernel: fix warnings on 64bit archs - - * kernel: in case of API version mismatch, return ECONNREFUSED - -2005-03-24 Miklos Szeredi - - * kernel: trivial cleanups - -2005-03-21 Miklos Szeredi - - * Add fsyncdir() operation - -2005-03-19 Miklos Szeredi - - * kernel: add locking to background list (fixes previous fix) - -2005-03-18 Miklos Szeredi - - * kernel: fix bug which could cause leave busy inodes after - unmount, and Oops. - -2005-03-08 Miklos Szeredi - - * examples: add -lpthread to link flags to work around valgrind - quirk - - * lib: don't exit threads, so cancelation doesn't cause segfault - -2005-03-04 Miklos Szeredi - - * kernel: fix nasty bug which could cause an Oops under certain - situations. Found by Magnus Johansson - -2005-02-28 Miklos Szeredi - - * libfuse: added opendir() method. This can be used in case - permission checking in getdir() is too late. Thanks to Usarin - Heininga for pointing out this deficiency - - * libfuse: added init() and destroy() methods to fuse_operations - - * kernel: llseek() method for files and directories made explicit - - * kernel: fixed inode leak in NFS export in case of nodeid - wrapping - -2005-02-15 Miklos Szeredi - - * libfuse: clean up some unitialized memory found with valgrind - - * Add -lpthread to Libs in fuse.pc. Valgrind seems to need an - explicitly linked libpthread for applications - -2005-02-10 Miklos Szeredi - - * fusermount: set umask, otherwise /etc/mtab will have - unpredictable permission. Spotted by Jindrich Kolorenc - - * fusermount: set owner and group of /etc/mtab to original values - on unmount - - * libfuse: add 'use_ino' option to help. Patch by Valient Gough - -2005-02-07 Miklos Szeredi - - * Cleaned up directory reading (temporary file is not used) - -2005-02-02 Miklos Szeredi - - * Released 2.2 - -2005-02-02 Miklos Szeredi - - * Fix possible race when operation is interrupted - -2005-01-28 Miklos Szeredi - - * Fix compilation on 2.6.7 - -2005-01-26 Miklos Szeredi - - * Released 2.2-pre6 - -2005-01-26 Miklos Szeredi - - * Fix bug in link() operation which caused the wrong path to be - passed as the first argument. Found by Anton Altaparmakov - -2005-01-21 Miklos Szeredi - - * LIB: fix double reply in readdir operation - - * fusermount: fix uid checking bug. Patch by Adam Connell - - * KERNEL: fix compile on various RedHat patched 2.4 kernels. - Patch by Keshava Gowda - -2005-01-20 Miklos Szeredi - - * KERNEL: provide correct llseek semantics for fuse device (fixes - a bug on Progeny 2.4.20 kernel). Reported by Valient Gough - -2005-01-20 Miklos Szeredi - - * Released 2.2-pre5 (matches kernel 2.6.11-rc1-mm2) - -2005-01-18 Miklos Szeredi - - * KERNEL ABI: remove GETDIR operation, and add OPENDIR, READDIR - and RELEASEDIR. This ends the ugly hack of passing a file - descriptor to the kernel, and actually makes the code simpler. - -2005-01-17 Miklos Szeredi - - * Released 2.2-pre4 - -2005-01-17 Miklos Szeredi - - * fusermount: remove capability setting, which was the cause of - problems for some users. It seems that FS related capabilities - are removed by setfsuid(), so this isn't even needed. - -2005-01-15 Miklos Szeredi - - * fix compilation on 2.4 kernels (reported by Valient Gough) - - * fix failure to unmount bug (found by David Shaw) - - * fusermount: improve parsing of /etc/fuse.conf - -2005-01-13 Miklos Szeredi - - * Remove 'mount_max' and 'user_allow_other' module options. These - are now checked by fusermount, and can be set in /etc/fuse.conf - - * KERNEL: change check for fsid == 0 to capable(CAP_DAC_OVERRIDE) - -2005-01-11 Miklos Szeredi - - * KERNEL: fix possible inode allocation problem, where - sizeof(struct inode) is not aligned (found by Mike Waychison) - - * KERNEL: use new follow_link/put_link methods - - * KERNEL: cosmetic fixes - -2005-01-10 Miklos Szeredi - - * Released 2.2-pre3 - -2005-01-10 Miklos Szeredi - - * Add missing code that was accidently left out - -2005-01-09 Miklos Szeredi - - * Released 2.2-pre2 - -2005-01-09 Miklos Szeredi - - * Change "uid" mount option to "user_id" to avoid confusion with a - mount option "uid" commonly used by many filesystems - -2005-01-09 Miklos Szeredi - - * Released 2.2-pre1 - -2005-01-09 Miklos Szeredi - - * If FUSE is configured in the kernel, don't build it by default - -2005-01-07 Miklos Szeredi - - * Compile fix by Christian Magnusson - -2005-01-05 Miklos Szeredi - - * Fix compilation for 2.6.{0-5} kernels - -2005-01-04 Miklos Szeredi - - * KERNEL: if request is interrupted, still keep reference to used - inode(s) and file, so that FORGET and RELEASE are not sent until - userspace finishes the request. - - * remove /{sys,proc}/fs/fuse/version, and instead add an INIT - request with the same information, which is more flexible, - simpler, works on embedded systems. - -2004-12-16 Miklos Szeredi - - * KERNEL ABI: update interface to make it independent of type - sizes. This will help on 64 bit architectures which can run - legacy 32 bit applications. - - * KERNEL ABI: add "len" field to request headers. This will allow - sending/receiving requests in multiple chunks. - - * KERNEL: handle file type change more intelligently - - * LIB: "-o debug" option should disable backgrounding (fix by - Fabien Reygrobellet) - -2004-12-13 Miklos Szeredi - - * KERNEL: invalidate dentry/attributes if interrupted request - could leave filesystem in an unknown state. - -2004-12-12 Miklos Szeredi - - * KERNEL: lots of cleanups related to avoiding possible deadlocks. - These will cause some regressions, but stability is considered - more important. If any of these features turns out to be - important, it can be readded with the deadlock problems addressed. - - * Make all requests interruptible (only with SIGKILL currently). - This can be used to break any deadlock produced by the userspace - filesystem accessing it's own exported files. The RELEASE request - is special, because if it's interrupted before sending it to - userspace it is still sent, but the reply is not awaited. - - * If request is interrupted before being sent to userspace, and if - it hasn't yet got any side effects, it is always restarted, - regardless of the SA_RESTART flag. This makes these interruptions - transparent to the process. - - * Remove shared-writable mmap support, which was prone to an - out-of-memory deadlock situation - - * Remove INVALIDATE userspace initiated request - - * Make readpages() synchronous. Asynchronous requests are - deadlock prone, since they cannot be interrupted. - - * Add readv/writev support to fuse device operations - - * Remove some printks, which userspace FS can use for a DoS - against syslog - - * Remove 'large_read' mount option from 2.6 in kernel, check it in - fusermount instead - - * LIB: improve compatibility with a fuse.h header installed in - ${prefix}/include which in turn includes the real header. - - * LIB: improve compatibility by defining fuse_main() (which is now - not used), so old configure scripts find it. - -2004-12-10 Miklos Szeredi - - * When mounting on a subdirectory of / don't duplicate slashes at - the beggining of path (spotted by David Shaw) - -2004-12-09 Miklos Szeredi - - * Fix bug causing garbage in mount options (spotted by David Shaw) - -2004-12-07 Miklos Szeredi - - * Add 'writepage' flag to 'fuse_file_info'. - - * More comments in fuse.h - - * Get rid of double underscores - -2004-12-04 Miklos Szeredi - - * Add -D_FILE_OFFSET_BITS=64 to cflags provided by pkg-config - - * helper.c: add -ho option, which only displays the options not - the usage header. This can be used by filesystems which have - their own options. - -2004-12-03 Miklos Szeredi - - * Add source compatibility to 2.1 and 1.1 APIs. To select betwen - versions simply define FUSE_USE_VERSION to 22, 21 or 11 before - including the fuse header - - * Add binary compatibility to 2.1 version of library with symbol - versioning - -2004-12-03 Miklos Szeredi - - * Released 2.1 - -2004-12-01 Miklos Szeredi - - * kernel: clean up writing functions - - * kernel: no allocation on write in direct_io mode - - * move linux/fuse.h to fuse_kernel.h - -2004-11-30 Miklos Szeredi - - * kernel: clean up reading functions - -2004-11-29 Miklos Szeredi - - * kernel: make readpage() uninterruptible - - * kernel: check readonly filesystem flag in fuse_permission - - * lib: don't die if version file not found and new style device - exists - - * lib: add '-r' option, which is short for '-o ro' - - * fusermount: simplify device opening - - * kernel: when direct_io is turend on, copy data directly to - destination without itermediate buffer. More efficient and safer, - since no allocation is done. - - * fusermount: fix warning if fuse module is not loaded - - * kernel: use /dev/fuse on 2.4 too - -2004-11-26 Miklos Szeredi - - * libfuse API change: open, read, write, flush, fsync and release - are passed a 'struct fuse_file_info' pointer containing the open - flags (open and release), and the file handle. Verion changed to - 3.0. - -2004-11-23 Miklos Szeredi - - * More cleanups in the kernel - - * The 10,229 charater device number has been assigned for FUSE - - * Version file checking fix (reported by Christian Magnusson) - - * fusermount: opening the fuse device now doesn't need /sys. - - * Optimize reading by controlling the maximum readahead based on - the 'max_read' mount option - - * fixes for UCLIBC (Christian Magnusson) - -2004-11-19 Miklos Szeredi - - * Cleaned up kernel in preparation for merge into mainline: - - * Use /sys/fs/fuse/version instead of /proc/fs/fuse/version - - * Use real device (/dev/fuse) instead of /proc/fs/fuse/dev - - * __user annotations for sparse - - * allocate individual pages instead of kmalloc in fuse_readdir, - fuse_read and fuse_write. - - * Fix NFS export in case "use_ino" mount option is given - - * Make libfuse and fusermount compatible with future versions - - * fusermount: properly add mount options to /etc/mtab - -2004-11-15 Miklos Szeredi - - * fusermount: do not resolve last component of mountpoint on if it - is '.' or '..'. This new path resolvation is now done on mount as - well as unmount. This enables relative paths to work on unmount. - - * fusermount: parse common mount options like "ro", "rw", etc... - - * Allow module params to be changed through sysfs - -2004-11-14 Miklos Szeredi - - * Released 2.1-pre1 - -2004-11-14 Miklos Szeredi - - * Fix bug in fuse_readpages() causing Oops in certain situations. - Bug found by Vincenzo Ciancia. - - * Fix compilation with kernels versions > 2.6.9. - -2004-11-11 Miklos Szeredi - - * Check kernel interface version in fusermount to prevent - strangeness in case of mismatch. - - * No need to allocate fuse_conn until actual mount happens - - * Fix potential race between umount and fuse_invalidate - - * Check superblock of proc file in addition to inode number - - * Fix race between request_send_noreply() and fuse_dev_release() - -2004-11-10 Miklos Szeredi - - * Separate configure for the kernel directory - - * Don't allow write to return more than 'count' - - * Extend kernel interface for future use - -2004-11-09 Miklos Szeredi - - * Fix 'makeconf.sh' to use autoreconf if available - -2004-11-08 Miklos Szeredi - - * Add ino argument to 'fuse_dirfil_t'. NOTE: This breaks source - compatibility with earlier versions. To compile earier versions - just add '-DFUSE_DIRFIL_COMPAT' compile flag or fix the source. - Do not use the "use_ino" mount flag with filesystems compiled with - FUSE_DIRFIL_COMPAT. - - * Add pkg-config support. To compile a FUSE based filesystem you - can do "gcc -Wall `pkg-config --cflags --libs fuse` myfs.c -o myfs" - or similar. Note, that the PKG_CONFIG_PATH environment variable - usually needs to be set to "/usr/local/lib/pkgconfig". - - * fuse.h is now installed in ${prefix}/include/fuse/ - -2004-11-02 Miklos Szeredi - - * Added "use_ino" mount option. This enables the filesystems to - set the st_ino field on files - -2004-11-01 Miklos Szeredi - - * Fix compile problems with ancient (<=2.4.18) kernels (reported - by Jeremy Smith) - - * Add "allow_root" mount option. Patch by Yaroslav Rastrigin - - * Clear the 'exited' flag when mail loop is finished - -2004-10-28 Miklos Szeredi - - * Make xattr functions work under 2.6 (bug found by Vincenzo - Ciancia) - -2004-10-26 Miklos Szeredi - - * Reset request in fuse_flush() (bugreport by David Shaw) - -2004-10-21 Miklos Szeredi - - * fuse_main() now does not exit on error, rather it returns an - error code - - * Exported __fuse_setup() and __fuse_teardown() functions, which - make it easier to implement a custom event loop. - - * Use daemon() call to background the filesystem after mounting. - This function closes the standard input, output and error and - changes the current working directory to "/". - -2004-10-14 Miklos Szeredi - - * Released 1.9 - -2004-10-09 Miklos Szeredi - - * Don't allow fuse_flush() to be interrupted (bug found by David - Shaw) - -2004-09-27 Miklos Szeredi - - * Add PID to fuse_context. Patch by Steven James - - * Change file handle type to 'unsigned long' in kernel interface - -2004-09-22 Miklos Szeredi - - * A slight API change: fuse_get_context() doesn't need the "fuse" - pointer, but the returned context contains it instead. The - fuse_get() function is not needed anymore, so it's removed. - - * Fix mounting and umounting FUSE filesystem under another FUSE - filesystem by non-root (bug spotted by Valient Gough) - -2004-09-21 Miklos Szeredi - - * Fix deadlock in case of memory allocation failure. Patch by - Christian Magnusson - -2004-09-16 Miklos Szeredi - - * Check memory allocation failures in libfuse - -2004-09-14 Miklos Szeredi - - * Check temporary file creation failure in do_getdir(). Bug - spotted by Terje Oseberg - -2004-09-13 Miklos Szeredi - - * Allow "large_read" option for 2.6 kernels but warn of deprecation - - * Make requests non-interruptible so race with FORGET is avoided. - This is only a temporary solution - - * Support compiling FUSE kernel module on 2.4.x UML kernels - -2004-09-09 Miklos Szeredi - - * Fix bug in case two FORGETs for the same node are executed in - the wrong order. Bug spotted and endured for months by Franco - Broi, and logfile for solution provided by Terje Oseberg - -2004-09-01 Miklos Szeredi - - * Add -D_REENTRANT to the compile flags - - * Add documentation of fuse internals by Terje Oseberg - -2004-08-16 Miklos Szeredi - - * Change release method to be non-interruptible. Fixes bug - causing missing release() call when program which has opened files - is killed (reported by Franco Broi and David Shaw) - -2004-07-29 Miklos Szeredi - - * Add fuse_invalidate() to library API - -2004-07-26 Miklos Szeredi - - * Check permissions in setattr if 'default_permissions' flag is - set. Bug spotted by Damjan Lango - -2004-07-24 Miklos Szeredi - - * 'large_read' mount option removed for 2.6 kernels, since the - default (dynamic read size) is better - - * Extend kernel API with file handles. A file handle is returned - by open, and passed to read, write, flush, fsync and release. - This is currently only used for debug output in the library. - - * Security changes: - - * Change the current directory to the mountpoint before checking - the permissions and mount filesystem on "." - - * By default don't modprobe the fuse module for non-root. The old - behavior can be restored with the '--enable-auto-modprobe' flag of - ./configure - - * By default don't allow shared writable mappings for non-root. - The old behavior can be restored with the 'user_mmap=1' module - parameter - -2004-07-23 Miklos Szeredi - - * Clean up mount option passing to fusermount and to fuse_new() - BEWARE: this changes the userspace API slightly, and the command - line usage of programs using fuse_main() - -2004-07-20 Miklos Szeredi - - * Optimize reading under 2.6 kernels by issuing multiple page - asynchronous read requests - -2004-07-18 Miklos Szeredi - - * Only use redirty_page_for_writepage() for kernels >= 2.6.6 - -2004-07-16 Miklos Szeredi - - * Separate directory entry and inode attribute validity timer - - * New write semaphore to stop page writeback during truncate - - * Fsync now waits for all writes to complete before sending the - request - - * Optimization: if a page is completely written by - fuse_commit_write(), clear the dirty flag and set the uptodate - flag for that page - - * Some memory cleanup at exit - -2004-07-13 Miklos Szeredi - - * Add FUSE_HARD_REMOVE flag, and '-i' option to fuse main, which - disable the "hide if open" behavior of unlink/rename. - - * If temporary buffer allocation fails in raw read, fall back to a - smaller buffer - -2004-07-12 Miklos Szeredi - - * Fix bug in do_open() in libfuse: open count was incremented - after the reply is sent so it could race with unlink/forget and - cause an abort. - -2004-07-08 Miklos Szeredi - - * When performing create or remove operation, refresh the parent's - attributes on next revalidate, as i_nlink (and maybe size/time) - could be inacurate. - - * Use redirty_page_for_writepage() in fuse_writepage() for skipped - pages (2.6 only) - - * Set set_page_dirty address space operation (2.6 only) - -2004-07-06 Miklos Szeredi - - * Minor fix in read: print debug info even if read size is zero - -2004-07-04 Miklos Szeredi - - * Fix race between truncate and writepage (fsx-linux now runs - without error) - -2004-07-02 Miklos Szeredi - - * Fix kernel hang on mkfifo under 2.4 kernels (spotted and patch - by Mattias Wadman) - - * Added option for direct read/write (-r) - - * Fix revalidate time setting for newly created inodes - - * Remove uid==0 check for '-x' option in fusermount (kernel checks - this) - - * fuse_main() only installs handlers for signals (out of INT, HUP, - TERM, PIPE), for which no handler has yet been installed - - * Add module option 'user_allow_other' which if set to non-zero - will allow non root user to specify the 'allow_other' mount option - ('-x' option of fusermount) - - * Fix deadlock between page writeback completion and truncate - (bug found by Valient Gough with the fsx-linux utility) - -2004-07-01 Miklos Szeredi - - * Change passing fuse include dir to 2.6 kernel make system more - robust (fixes compile problems seen on SuSE 9.1 with updated 2.6 - kernel) - -2004-06-30 Miklos Szeredi - - * Acquire inode->i_sem before open and release methods to prevent - concurrent rename or unlink operations. - - * Make __fuse_read_cmd() read only one command. This allows - multiplexing the fuse file descriptor with other event sources - using select() or poll() (patch by Jeff Harris) - - * Export 'exited' flag with __fuse_exited() (patch by Jeff Harris) - -2004-06-27 Miklos Szeredi - - * Fix file offset wrap around at 4G when doing large reads - -2004-06-24 Miklos Szeredi - - * Fix memory leak in open (Valient Gough) - -2004-06-24 Miklos Szeredi - - * Add "close after delete" support to libfuse (patch by Valient - Gough) - - * Cancel all worker threads before exit in multithreaded mode - -2004-06-23 Miklos Szeredi - - * Fix locking bugs - - * Don't send reply to RELEASE - - * Work with newer libtool (1.5a) - - * Check for st_atim member of struct stat - -2004-06-22 Miklos Szeredi - - * No request allocation needed on inode and file release - -2004-06-21 Miklos Szeredi - - * Fix possible inode leak in userspace in case of unfinished - lookup/mknod/mkdir/symlink/link operation. - -2004-06-20 Miklos Szeredi - - * Fix some races and cleanups in fuse_read_super() - -2004-06-19 Miklos Szeredi - - * Requests are allocated at open time - -2004-06-03 Miklos Szeredi - - * Build shared library as well as static (using libtool) - - * Change FUSE_MINOR_VERSION from 1 to 0. I know it's illegal but - there has not been a release with the previous minor number, and I - hope nobody is using it for anything. - - * Change fuse_main(), so that default behavior is to go into - background if mount is successful. '-f' and '-d' options disable - backgrounding. This fixes the "Why does my FUSE daemon hang?" - newbie complaint. - - * Cache ENOSYS (function not implemented) errors on *xattr, flush - and fsync - - * Don't call getdir method from open() only from first readdir(). - Open is sometimes just used to store the current directory - (e.g. find) - -2004-05-18 Miklos Szeredi - - * Added flush() call - -2004-05-04 Miklos Szeredi - - * Extended attributes support for 2.4 (patch by Cody Pisto) - -2004-04-20 Miklos Szeredi - - * Fixed parser with modversions (Mattias Wadman) - -2004-04-19 Miklos Szeredi - - * Added mount option parser to 2.4 build - -2004-04-13 Miklos Szeredi - - * Replaced binary mount data with text options - - * Show FUSE specific mount options in /proc/mounts - - * Check in fuse.h whether _FILE_OFFSET_BITS is set to 64 - -2004-04-09 Miklos Szeredi - - * Check some limits so userspace won't get too big requests - -2004-04-05 Miklos Szeredi - - * Kill compile warning - - * Upgraded user-mount patch for 2.6.5 - -2004-04-02 Miklos Szeredi - - * Add detection of user-mode-linux to configure - -2004-03-31 Miklos Szeredi - - * fixed zero size case for getxattr and listxattr - -2004-03-30 Miklos Szeredi - - * new fusermount flag '-z': lazy unmount, default is not lazy - - * Extended attributes operations added (getxattr, setxattr, - listxattr, removexattr) - -2004-03-25 Miklos Szeredi - - * If filesystem doesn't define a statfs operation, then an - all-zero default statfs is returned instead of ENOSYS - -2004-03-24 Miklos Szeredi - - * Add FS_BINARY_MOUNTDATA filesystem flag for kernels > 2.6.4 - -2004-03-09 Miklos Szeredi - - * Fix for uClinux (Christian Magnusson) - -2004-03-02 Miklos Szeredi - - * fuse_main() adds "-n progname" to the fusermount command line - - * More kernel interface changes: - - * Lookup/getattr return cache timeout values - -2004-02-25 Miklos Szeredi - - * Clean up option parsing in fuse_main() - - * Added fuse_get() function which returns the fuse object created - by fuse_main() - -2004-02-20 Miklos Szeredi - - * removed old way of mounting (fusermount mountpoint program) - - * more kernel interface changes: - - * added nanosecond precision to file times - - * removed interface version from mount data - - * added /proc/fs/fuse/version which contains MAJOR.MINOR - -2004-02-19 Miklos Szeredi - - * statfs library API changed to match other methods. Since this - is not backward compatible FUSE_MAJOR_VERSION is changed to 2 - - * kernel interface changes follow: - - * statfs changed to 64 bits, added 'bavail' field - - * add generation number to lookup result - - * optimized mknod/mkdir/symlink/link (no separate lookup is - needed) - - * rdev size increased to 32 bits for mknod - - * kernel interface version changed to 3.1 - -2004-02-18 Miklos Szeredi - - * user-mount upgraded for 2.6.3 kernel - -2004-02-17 Miklos Szeredi - - * Added user-mount.2.6.2-rc3.patch - - * Add FS_SAFE flag to fuse filesystem - - * fusermount should allow (un)mounting for non-root even if not - suid-root - -2004-02-12 Miklos Szeredi - - * Remove MS_PERMISSION mount flag (that means something else now) - -2004-02-10 Miklos Szeredi - - * Added check for i_size_read/write functions to configure.in - (patch by Valient Gough) - -2004-02-06 Miklos Szeredi - - * Fixed writing >= 2G files - - * Check file size on open (with generic_file_open()) - - * Readpage calls flush_dcache_page() after storing data - - * Use i_size_read/write for accessing inode->i_size - - * Make loopback mount of a fuse file work - -2004-02-04 Miklos Szeredi - - * Released 1.1 - -2004-01-29 Miklos Szeredi - - * Properly check if the inode exists in fuse_invalidate - -2004-01-27 Miklos Szeredi - - * Added -q option for fusermount - - * fuse_unmount() now uses -q option of fusermount, so no error is - printed if the cause of the program exit is that the filesystem - has already been unmounted - - * Fix i_nlink correctness after rmdir/unlink - -2004-01-26 Miklos Szeredi - - * Released 1.1-pre2 - -2004-01-26 Miklos Szeredi - - * Fix typo (thanks Marcos Dione) - - * Compile fixes for 2.4 kernels - -2004-01-23 Miklos Szeredi - - * Fix CONFIG_MODVERSIONS compile on 2.6 - -2004-01-22 Miklos Szeredi - - * Write all pending data before a RELEASE operation - - * Suppress 'Bad file descriptor' warning on exit - - * Replaced fusermount option '-d xxx' with '-n xxx' so it doesn't - get confused with '-d' of fuse_main() (sorry about this change) - - * New fusermount option '-l' which enables big reads. Big reads - are now disabled by default. - - * fuse_main() can accept fusermount arguments after a '--' - -2004-01-19 Miklos Szeredi - - * Support for exporting filesystem over NFS (see README.NFS) - -2004-01-14 Miklos Szeredi - - * Support non-blocking writepage on 2.6. This makes FUSE behave - much more nicely in low-memory situations - - * Fix 32-bit dev handling in getattr and mknod for 2.6 kernels. - (Note: the mknod method does not yet use 32bit device number) - -2004-01-13 Miklos Szeredi - - * Code cleanups - -2004-01-07 Miklos Szeredi - - * Released 1.1-pre1 - -2004-01-06 Miklos Szeredi - - * Integrated 2.6 kernel support patch by Michael Grigoriev - - * Improvements and cleanups for 2.6 kernels - -2004-01-05 Miklos Szeredi - - * Added -d option to fusermount - -2003-12-15 Miklos Szeredi - - * Added major+minor version to library API, and minor version to - kernel API - -2003-12-13 David McNab - - * Implemented fsync support in examples/example.py - - * Implemented 'fsync' and 'statfs' methods in python - interface - -2003-12-12 Miklos Szeredi - - * Make it compile on 2.4.19. - - * Add fsync operation (write file failed on xemacs & vi) - -2003-12-12 David McNab - - * Added distutils support to the python module, as per standard - python development practice - -2003-12-11 Miklos Szeredi - - * Add file locking for mount/unmount (based on patch by Valient - Gough) - -2003-12-11 David McNab - - * Python filesystem - was broken with python2.3, now fixed: - - changed PyTuple_* calls to PySequence_*, because os.lstat - is no longer returning a pure tuple - - changed PyInt_Check() calls to also call PyLong_Check, - to cover for cases (eg os.lstat) where longs are returned - - Added support for file 'release' handling, which IMO is - essential since this signals to a FS that writes to a file - are complete (and therefore the file can now be disposed of - meaningfully at the python filesystem's discretion) - - Added '__init__' handler to base Fuse class, which allows - your Python class to know the mountpoint and mount args, - as attributes myfs.mountpoint, myfs.optlist, myfs.optdict - - * General: - - added 'mount.fuse' script (in util/ dir), which is meant to be - symlinked from /sbin, and which allows FUSE filesystems to - be mounted with the 'mount' command, and listed in fstab; - also, mount arguments get passed to your filesystem - - -2003-11-04 Miklos Szeredi - - * Fix kernel version detection (again). Bugreport by Peter Levart - -2003-11-03 Miklos Szeredi - - * Applied read combining patch by Michael Grigoriev (tested by - Valient Gough and Vincent Wagelaar) - -2003-10-22 Miklos Szeredi - - * Mtab handling fix in fusermount by "Valient Gough" (SF patch - #766443) - -2003-10-13 Miklos Szeredi - - * Error code fixes in kernel module - -2003-10-04 Miklos Szeredi - - * kernel version detection fix - - * fusermount now uses "lazy" umount option - - * fusermount can use modprobe with module-init-tools - -2003-09-08 Miklos Szeredi - - * Integrated caching patch by Michael Grigoriev - - * Added "Filesystems" file with descriptions of projects using - FUSE - - * Added patch by Michael Grigoriev to allow compliation of FUSE - kernel module for 2.6 kernels - -2003-06-02 Miklos Szeredi - - * And another spec-file fix by Achim Settelmeier - -2003-05-26 Miklos Szeredi - - * Spec-file fix by Achim Settelmeier - -2003-03-10 Miklos Szeredi - - * Fix umount oops (found by Samuli Kärkkäinen) - -2003-03-05 Miklos Szeredi - - * Merge of fuse_redhat.spec and fuse.spec by Achim Settelmeier - -2003-03-04 Miklos Szeredi - - * Updated fuse.spec file (Achim Settelmeier) - -2003-02-19 Miklos Szeredi - - * Version 1.0 released - -2003-02-12 Miklos Szeredi - - * SuSE compilation fix by Juan-Mariano de Goyeneche - -2002-12-10 Miklos Szeredi - - * The release() VFS call is now exported to the FUSE interface - -2002-12-05 Miklos Szeredi - - * 64 bit file offset fixes in the fuse kernel module - - * Added function 'fuse_exit()' which can be used to exit the main - loop - -2002-12-03 Miklos Szeredi - - * Added _FILE_OFFSET_BITS=64 define to fuse.h. Note, that this is - an incompatible interface change. - -2002-10-28 Miklos Szeredi - - * Portablility fix (bug reported by C. Chris Erway) - -2002-10-25 Miklos Szeredi - - * Use Mark Glines' fd passing method for default operation instead - of old reexec - -2002-10-22 Miklos Szeredi - - * fix "Stale NFS file handle" bug caused by changes in 2.4.19 - -2002-10-22 Miklos Szeredi - - * fix incompatiblity with Red Hat kernels, with help from Nathan - Thompson-Amato. - -2002-04-18 Mark Glines - - * added an alternative to fuse_mount(), called - fuse_mount_ioslave(), which does not need to reexec the - FUSE program. - * added a small helper util needed by fuse_mount_ioslave(). - -2002-03-16 Mark Glines - - * use struct fuse_statfs everywhere possible to avoid problems - with the headerfiles changing struct statfs member sizes - -2002-03-01 Miklos Szeredi - - * Another RPM spec file for RedHat >= 7 by Ian Pilcher - -2002-01-14 Miklos Szeredi - - * RPM support by Achim Settelmeier - -2002-01-09 Miklos Szeredi - - * Version 0.95 released - -2002-01-09 Miklos Szeredi - - * Revaidate all path components not just the last, this means a - very small performance penalty for being more up-to-date. - -2002-01-08 Miklos Szeredi - - * Update and fix python interface - -2002-01-07 Mark Glines - - * Added statfs() support to kernel, lib, examples, and perl! - -2001-12-26 Miklos Szeredi - - * Better cross compilation support - - * Ported to Compaq IPAQ - -2001-12-20 Miklos Szeredi - - * Added function fuse_get_context() to library API (inspired by - patch from Matt Ryan) - - * Added flags to fusermount and to kernel interface to control - permission checking - - * Integrated fuse_set_operations() into fuse_new() - -2001-12-08 Miklos Szeredi - - * Applied header protection + extern "C" patch by Roland - Bauerschmidt - -2001-12-02 Miklos Szeredi - - * Added perl bindings by Mark Glines - -2001-11-21 Miklos Szeredi - - * Cleaned up way of mounting simple filesystems. - - * fuse_main() helper function added - -2001-11-18 Miklos Szeredi - - * Optimized read/write operations, so that minimal copying of data - is done - -2001-11-14 Miklos Szeredi - - * Python bindings by Jeff Epler added - -2001-11-13 Miklos Szeredi - - * Fixed vfsmount reference leak in fuse_follow_link - - * FS blocksize is set to PAGE_CACHE_SIZE, blksize attribute from - userspace is ignored - -2001-11-09 Miklos Szeredi - - * Started ChangeLog diff --git a/libfuse/Makefile b/libfuse/Makefile index 5157ef17..c5fd2836 100644 --- a/libfuse/Makefile +++ b/libfuse/Makefile @@ -22,11 +22,9 @@ INSTALLMAN1DIR = $(DESTDIR)$(MAN1DIR) SRC = \ lib/buffer.c \ - lib/cuse_lowlevel.c \ - lib/fuse_dirents.c \ lib/fuse.c \ - lib/fuse_kern_chan.c \ - lib/fuse_loop.c \ + lib/fuse_chan.c \ + lib/fuse_dirents.c \ lib/fuse_loop_mt.c \ lib/fuse_lowlevel.c \ lib/fuse_mt.c \ @@ -34,7 +32,8 @@ SRC = \ lib/fuse_session.c \ lib/fuse_signals.c \ lib/helper.c \ - lib/mount.c + lib/mount.c \ + lib/sys.c OBJS = $(SRC:lib/%.c=build/%.o) DEPS = $(SRC:lib/%.c=build/%.d) diff --git a/libfuse/NEWS b/libfuse/NEWS deleted file mode 100644 index 559ee861..00000000 --- a/libfuse/NEWS +++ /dev/null @@ -1,303 +0,0 @@ -What is new in 2.9 - - - Add "zero copy" support for kernel 2.6.35 or newer - - - Make maximum background requests tunable on kernel 2.6.32 or newer - - - Require --no-canonicalize in (u)mount (util-linux version 2.18 or - newer) to fix security problems with fusermount - - - Use dynamically sized hash tables in high level library - - - Memory use of filesystem daemon can shrink more easily - - - Add "auto_unmount" option - - - Add "remember" option - - - Add man pages for fusermount, mount.fuse and ulockmgr_server - - - API changes: - - o Introduce "store" and "retrieve" for accessing kernel buffers on - kernel 2.6.36 or newer - - o Introduce abstract buffer for zero copy operations - - o Allow path calculation to be omitted on certain operations - - o Allow batching forget requests - - o Add "flock" method - - o Add support for ioctl on directories - - o Add delete notification - - o Add fallocate operation (linux kernel 3.5 or newer) - - - Bug fixes and small improvements - -============================================================================ - -What is new in 2.8 - - - More scalable directory tree locking - - - Atomic open(O_TRUNC) support - - - Support big write requests on kernels 2.6.26 and newer - - - Out-of-tree fuse module removed - - - Better NFS exporting support - - - New ioctl and poll requests - - - New CUSE (Character Device in Userspace) interface - - - Allow umask processing in userspace - - - Added cache invalidation notifications - - - Bugfixes and small improvements - -============================================================================ - -What is new in 2.7 - - - Stacking support for the high level API - - - Add filename charset conversion module - - - Improved mounting - -============================================================================ - -What is new in 2.6 - - - Improved read characteristics (asynchronous reads) - - - Support for aborting filesystem connection - - - POSIX file locking support - - - Request interruption support - - - Building module for Linux kernels earlier than 2.6.9 not supported - - - Allow block device based filesystems to support swap files - - - Several bugs fixed, including a rare system hang on SMP - -============================================================================ - -What is new in 2.5 - - - Merge library part of FreeBSD port - - - New atomic create+open, access and ftruncate operations - - - On filesystems implementing the new create+open operation, and - running on Linux kernels 2.6.15 or later, the 'cp' operation will - work correctly when copying read-only files. - - - New option parsing interface added to the library - - - Lots of minor improvements and fixes - -============================================================================ - -What is new in 2.4 - - - Simplify device opening. Now '/dev/fuse' is a requirement - - - Allow module auto-loading if user has access to '/dev/fuse' - - - Allow mounting over a regular file for unprivileged users - - - Allow mounting of arbitrary FUSE filesystems from /etc/fstab - - - New mount options: 'umask=M', 'uid=N', 'gid=N' - - - Check for non-empty mountpoint, and refuse mount by default. New - mount option: 'nonempty' - - - Low level (inode based) API added - - - Allow 'direct_io' and 'keep_cache' options to be set on a - case-by-case basis on open. - - - Add 'attr_timeout' and 'entry_timeout' mount options to the - high-level library. Until now these timeouts were fixed at 1 sec. - - - Some bugfixes - -============================================================================ - -What is new in 2.3 - - - Add new directory related operations: opendir(), readdir(), - releasedir() and fsyncdir() - - - Add init() and destroy() operations which are called before the - event loop is started and after it has exited - - - Update kernel ABI so that on dual architectures (e.g. AMD64) 32bit - binaries work under a 64bit kernel - - - Bugfixes - -============================================================================ - -What is new in 2.2 - -Userspace changes: - - - Add fuse_file_info structure to file operations, this allows the - filesystem to return a file handle in open() which is passed to - read(), write(), flush(), fsync() and release(). - - - Add source compatibility with 2.1 and 1.4 releases - - - Binary compatibility with 2.1 release is retained - -Kernel changes: - - - Make requests interruptible. This prevents the filesystem to go - into an unbreakable deadlock with itself. - - - Make readpages() synchronous. Asynchronous requests are deadlock - prone, since they cannot be interrupted (see above) - - - Remove shared-writeable mapping support, which could deadlock the - machine - - - Remove INVALIDATE userspace initiated request - - - Update ABI to be independent of sizeof(long), so dual-size archs - don't cause problems - - - Remove /sys/fs/fuse/version. Version checking is now done through - the fuse device - - - Replace directory reading method on the kernel interface. Instead - of passing an open file descriptor to the kernel, send data through - the FUSE device, like all other operations. - -============================================================================ - -What is new in 2.1 - -* Bug fixes - -* Improved support for filesystems implementing a custom event-loop - -* Add 'pkg-config' support - -* Kernel module can be compiled separately - -============================================================================ - -What is new in 1.9 - -* Lots of bugs fixed - -* Minor modifications to the library API - -* Improvements to the kernel/userspace interface - -* Mounting by non-root made more secure - -* Build shared library in addition to the static one - -* Consolidated mount options - -* Optimized reading under 2.6 kernels - -* Direct I/O support - -* Support file I/O on deleted files - -* Extended attributes support - -============================================================================ - -What is new in 1.3 - -* Thanks to user bugreports and stress testing with LTP and sfx-linux -a number of bugs were fixed, some quite serious. - -* Fix compile problems with recent SuSE kernles - -============================================================================ - -What is new in 1.2 - -* Fix mount problems on recent 2.6 kernels with SELinux enabled - -* Fixed writing files lager than 2GBytes - -* Other bugfixes - -============================================================================ - -What is new in 1.1 - -* Support for the 2.6 kernels - -* Support for exporting filesystem over NFS in 2.6 kernels - -* Read efficiency improvements: read in 64k blocks instead of 4k -(Michael Grigoriev). Can be turned on with '-l' option of fusermount - -* Lazy automatic unmount - -* Added 'fsync()' VFS call to the FUSE interface - -* Bugfixes - -============================================================================ - -What is new in 1.0 - -* Cleanups and bugfixes - -* Added 'release()' VFS call to the FUSE interface - -* 64 bit file offsets (handling of > 4 GByte files) - -* libfuse is now under LGPL - -* New 'statfs' call (Mark Glines) - -* Cleaned up mount procedure (mostly by Mark Glines) - - NOTE: Binaries linked with with a previous version of libavfs may - not work with the new version of the fusermount program. In such - case recompile the program after installing the new libavfs library. - -* Fix for problems under linux kernel 2.4.19 - -============================================================================ - -What is new in 0.95 - -* Optimized read/write operations. Raw throughput has increased to -about 60Mbyte/s on a Celeron/360 - -* Python bindings by Jeff Epler - -* Perl bindings by Mark Glines - -* Improved multithreaded operation - -* Simplified library interface - -* Bugfixes - -============================================================================ - -What is new in 0.9: - -* Everything diff --git a/libfuse/README.NFS b/libfuse/README.NFS deleted file mode 100644 index f3348d5a..00000000 --- a/libfuse/README.NFS +++ /dev/null @@ -1,33 +0,0 @@ -NFS exporting is supported in Linux kernels 2.6.27 or later. - -You need to add an fsid=NNN option to /etc/exports to make exporting a -FUSE directory work. - -Filesystem support ------------------- - -NFS exporting works to some extent on all fuse filesystems, but not -perfectly. This is due to the stateless nature of the protocol, the -server has no way of knowing whether the client is keeping a reference -to a file or not, and hence that file may be removed from the server's -cache. In that case there has to be a way to look up that object -using the inode number, otherwise an ESTALE error will be returned. - -1) low-level interface - -Filesystems need to implement special lookups for the names "." and -"..". The former may be requested on any inode, including -non-directories, while the latter is only requested for directories. -Otherwise these special lookups should behave identically to ordinary -lookups. - -2) high-level interface - -Because the high-level interface is path based, it is not possible to -delegate looking up by inode to the filesystem. - -To work around this, currently a "noforget" option is provided, which -makes the library remember nodes forever. This will make the NFS -server happy, but also results in an ever growing memory footprint for -the filesystem. For this reason if the filesystem is large (or the -memory is small), then this option is not recommended. diff --git a/libfuse/README.md b/libfuse/README.md deleted file mode 100644 index 2243a12e..00000000 --- a/libfuse/README.md +++ /dev/null @@ -1,108 +0,0 @@ -libfuse -======= - -Warning: unresolved security issue ----------------------------------- - -Be aware that FUSE has an unresolved security bug -([bug #15](https://github.com/libfuse/libfuse/issues/15)): the -permission check for accessing a cached directory is only done once -when the directory entry is first loaded into the cache. Subsequent -accesses will re-use the results of the first check, even if the -directory permissions have since changed, and even if the subsequent -access is made by a different user. - -This bug needs to be fixed in the Linux kernel and has been known -since 2006 but unfortunately no fix has been applied yet. If you -depend on correct permission handling for FUSE file systems, the only -workaround is to completely disable caching of directory -entries. Alternatively, the severity of the bug can be somewhat -reduced by not using the `allow_other` mount option. - - -About ------ - -FUSE (Filesystem in Userspace) is an interface for userspace programs -to export a filesystem to the Linux kernel. The FUSE project consists -of two components: the *fuse* kernel module (maintained in the regular -kernel repositories) and the *libfuse* userspace library (maintained -in this repository). libfuse provides the reference implementation -for communicating with the FUSE kernel module. - -A FUSE file system is typically implemented as a standalone -application that links with libfuse. libfuse provides functions to -mount the file system, unmount it, read requests from the kernel, and -send responses back. libfuse offers two APIs: a "high-level", -synchronous API, and a "low-level" asynchronous API. In both cases, -incoming requests from the kernel are passed to the main program using -callbacks. When using the high-level API, the callbacks may work with -file names and paths instead of inodes, and processing of a request -finishes when the callback function returns. When using the low-level -API, the callbacks must work with inodes and responses must be sent -explicitly using a separate set of API functions. - - -Installation ------------- - - ./configure - make -j8 - make install - -You may also need to add `/usr/local/lib` to `/etc/ld.so.conf` and/or -run *ldconfig*. If you're building from the git repository (instead of -using a release tarball), you also need to run `./makeconf.sh` to -create the `configure` script. - -You'll also need a fuse kernel module (Linux kernels 2.6.14 or later -contain FUSE support). - -For more details see the file `INSTALL` - -Security implications ---------------------- - -If you run `make install`, the *fusermount* program is installed -set-user-id to root. This is done to allow normal users to mount -their own filesystem implementations. - -There must however be some limitations, in order to prevent Bad User from -doing nasty things. Currently those limitations are: - - - The user can only mount on a mountpoint, for which it has write - permission - - - The mountpoint is not a sticky directory which isn't owned by the - user (like /tmp usually is) - - - No other user (including root) can access the contents of the - mounted filesystem (though this can be relaxed by allowing the use - of the `allow_other` and `allow_root` mount options in `fuse.conf`) - - -Building your own filesystem ------------------------------- - -FUSE comes with several example file systems in the `examples` -directory. For example, the *fusexmp* example mirrors the contents of -the root directory under the mountpoint. Start from there and adapt -the code! - -The documentation of the API functions and necessary callbacks is -mostly contained in the files `include/fuse.h` (for the high-level -API) and `include/fuse_lowlevel.h` (for the low-level API). An -autogenerated html version of the API is available in the `doc/html` -directory and at http://libfuse.github.io/doxygen. - - -Getting Help ------------- - -If you need help, please ask on the -mailing list (subscribe at -https://lists.sourceforge.net/lists/listinfo/fuse-devel). - -Please report any bugs on the GitHub issue tracker at -https://github.com/libfuse/main/issues. - diff --git a/libfuse/fuse.pc.in b/libfuse/fuse.pc.in deleted file mode 100644 index 8fdb8415..00000000 --- a/libfuse/fuse.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: fuse -Description: Filesystem in Userspace -Version: @VERSION@ -Libs: -L${libdir} -lfuse -pthread -Libs.private: @libfuse_libs@ -Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64 diff --git a/libfuse/include/Makefile.am b/libfuse/include/Makefile.am deleted file mode 100644 index 663e164c..00000000 --- a/libfuse/include/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -## Process this file with automake to produce Makefile.in - -fuseincludedir=$(includedir)/fuse - -fuseinclude_HEADERS = \ - fuse.h \ - fuse_compat.h \ - fuse_common.h \ - fuse_common_compat.h \ - fuse_lowlevel.h \ - fuse_lowlevel_compat.h \ - fuse_opt.h \ - cuse_lowlevel.h - -include_HEADERS = old/fuse.h ulockmgr.h - -noinst_HEADERS = fuse_kernel.h diff --git a/libfuse/include/cuse_lowlevel.h b/libfuse/include/cuse_lowlevel.h deleted file mode 100644 index e147fa26..00000000 --- a/libfuse/include/cuse_lowlevel.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - CUSE: Character device in Userspace - Copyright (C) 2008-2009 SUSE Linux Products GmbH - Copyright (C) 2008-2009 Tejun Heo - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. - - Read example/cusexmp.c for usages. -*/ - -#ifndef _CUSE_LOWLEVEL_H_ -#define _CUSE_LOWLEVEL_H_ - -#ifndef FUSE_USE_VERSION -#define FUSE_USE_VERSION 29 -#endif - -#include "fuse_lowlevel.h" - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */ - -struct fuse_session; - -struct cuse_info { - unsigned dev_major; - unsigned dev_minor; - unsigned dev_info_argc; - const char **dev_info_argv; - unsigned flags; -}; - -/* - * Most ops behave almost identically to the matching fuse_lowlevel - * ops except that they don't take @ino. - * - * init_done : called after initialization is complete - * read/write : always direct IO, simultaneous operations allowed - * ioctl : might be in unrestricted mode depending on ci->flags - */ -struct cuse_lowlevel_ops { - void (*init) (void *userdata, struct fuse_conn_info *conn); - void (*init_done) (void *userdata); - void (*destroy) (void *userdata); - void (*open) (fuse_req_t req, struct fuse_file_info *fi); - void (*read) (fuse_req_t req, size_t size, off_t off, - struct fuse_file_info *fi); - void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off, - struct fuse_file_info *fi); - void (*flush) (fuse_req_t req, struct fuse_file_info *fi); - void (*release) (fuse_req_t req, struct fuse_file_info *fi); - void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi); - void (*ioctl) (fuse_req_t req, int cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz); - void (*poll) (fuse_req_t req, struct fuse_file_info *fi, - struct fuse_pollhandle *ph); -}; - -struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - void *userdata); - -struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - int *multithreaded, void *userdata); - -void cuse_lowlevel_teardown(struct fuse_session *se); - -int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, void *userdata); - -#ifdef __cplusplus -} -#endif - -#endif /* _CUSE_LOWLEVEL_H_ */ diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index 4931a168..ede50c67 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -9,20 +9,6 @@ #ifndef _FUSE_H_ #define _FUSE_H_ -/** @file - * - * 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. - */ - -#ifndef FUSE_USE_VERSION -#define FUSE_USE_VERSION 21 -#endif - #include "fuse_common.h" #include "fuse_dirents.h" @@ -668,12 +654,11 @@ struct fuse_context { * @param user_data user data supplied in the context during the init() method * @return 0 on success, nonzero on failure */ -/* - int fuse_main(int argc, char *argv[], const struct fuse_operations *op, - void *user_data); -*/ -#define fuse_main(argc, argv, op, user_data) \ - fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) + +int fuse_main(int argc, + char *argv[], + const struct fuse_operations *op, + void *user_data); /* ----------------------------------------------------------- * * More detailed API * @@ -689,7 +674,7 @@ struct fuse_context { * @param user_data user data supplied in the context during the init() method * @return the created FUSE handle */ -struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, +struct fuse *fuse_new(int devfuse_fd, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data); @@ -705,17 +690,6 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, */ void fuse_destroy(struct fuse *f); -/** - * FUSE event loop. - * - * Requests from the kernel are processed, and the appropriate - * operations are called. - * - * @param f the FUSE handle - * @return 0 if no error occurred, -1 otherwise - */ -int fuse_loop(struct fuse *f); - /** * Exit from event loop * @@ -760,26 +734,6 @@ int fuse_loop_mt(struct fuse *f); */ struct fuse_context *fuse_get_context(void); -/** - * Get the current supplementary group IDs for the current request - * - * Similar to the getgroups(2) system call, except the return value is - * always the total number of group IDs, even if it is larger than the - * specified size. - * - * The current fuse kernel module in linux (as of 2.6.30) doesn't pass - * the group list to userspace, hence this function needs to parse - * "/proc/$TID/task/$TID/status" to get the group IDs. - * - * This feature may not be supported on all operating systems. In - * such a case this function will return -ENOSYS. - * - * @param size size of given array - * @param list array of group IDs to be filled in - * @return the total number of supplementary group IDs or -errno on failure - */ -int fuse_getgroups(int size, gid_t list[]); - /** * Check if the current request has already been interrupted * @@ -787,16 +741,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 * @@ -1030,18 +974,12 @@ 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, + char **mountpoint, void *user_data); /** This is the part of fuse_main() after the event loop */ void fuse_teardown(struct fuse *fuse, char *mountpoint); -/** Read a single command. If none are read, return NULL */ -struct fuse_cmd *fuse_read_cmd(struct fuse *f); - -/** Process a single command */ -void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd); - /** Multi threaded event loop, which calls the custom command processor function */ int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data); @@ -1056,53 +994,6 @@ 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/libfuse/include/fuse_chan.h b/libfuse/include/fuse_chan.h new file mode 100644 index 00000000..6df98cec --- /dev/null +++ b/libfuse/include/fuse_chan.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#define FUSE_CHAN_SPLICE_READ (1<<0) +#define FUSE_CHAN_SPLICE_WRITE (1<<1) + +typedef struct fuse_chan_t fuse_chan_t; +struct fuse_chan_t +{ + void *buf; + uint64_t bufsize; + int32_t fd; + int32_t splice_pipe[2]; + uint32_t flags; +}; + +fuse_chan_t *fuse_chan_new(int32_t fd, uint32_t flags); +void fuse_chan_destroy(fuse_chan_t *ch); +int64_t fuse_chan_recv(fuse_chan_t *ch, char *buf, uint64_t size); +int64_t fuse_chan_send(fuse_chan_t *ch, const struct iovec iov[], uint64_t count); diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index 0e62aaaf..9ec78d9e 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -33,8 +33,8 @@ #error Please add -D_FILE_OFFSET_BITS=64 to your compile flags! #endif -#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 -#define FUSE_MAX_MAX_PAGES 256 +#define FUSE_MSG_DEFAULT_PAGES 32 +#define FUSE_MSG_MAX_PAGES 256 #ifdef __cplusplus extern "C" { @@ -206,7 +206,7 @@ struct fuse_conn_info { }; struct fuse_session; -struct fuse_chan; +typedef struct fuse_chan_t fuse_chan_t; struct fuse_pollhandle; /** @@ -219,8 +219,8 @@ struct fuse_pollhandle; * @param args argument vector * @return the communication channel on success, NULL on failure */ -struct fuse_chan *fuse_mount(const char *mountpoint, - struct fuse_args *args); +int fuse_mount(const char *mountpoint, + struct fuse_args *args); /** * Umount a FUSE mountpoint @@ -228,7 +228,8 @@ struct fuse_chan *fuse_mount(const char *mountpoint, * @param mountpoint the mount point path * @param ch the communication channel */ -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); +void fuse_unmount(const char *mountpoint, + int devfuse_fd); /** * Parse common options @@ -247,12 +248,12 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); * * @param args argument vector * @param mountpoint the returned mountpoint, should be freed after use - * @param multithreaded set to 1 unless the '-s' option is present * @param foreground set to 1 if one of the relevant options is present * @return 0 on success, -1 on failure */ -int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground); +int fuse_parse_cmdline(struct fuse_args *args, + char **mountpoint, + int *foreground); /** * Go into the background diff --git a/libfuse/include/fuse_common_compat.h b/libfuse/include/fuse_common_compat.h index 34440ff7..c75e1f1c 100644 --- a/libfuse/include/fuse_common_compat.h +++ b/libfuse/include/fuse_common_compat.h @@ -9,6 +9,8 @@ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ +#include "fuse_opt.h" + struct fuse_file_info_compat { int flags; unsigned long fh; diff --git a/libfuse/include/fuse_compat.h b/libfuse/include/fuse_compat.h deleted file mode 100644 index 509f6896..00000000 --- a/libfuse/include/fuse_compat.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -/* these definitions provide source compatibility to prior versions. - Do not include this file directly! */ - -struct fuse_operations_compat25 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info *); - int (*read) (const char *, char *, size_t, off_t, - struct fuse_file_info *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info *); - int (*statfs) (const char *, struct statvfs *); - int (*flush) (const char *, struct fuse_file_info *); - int (*release) (const char *, struct fuse_file_info *); - int (*fsync) (const char *, int, struct fuse_file_info *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info *); - int (*readdir) (const char *, void *, off_t, - struct fuse_file_info *); - int (*releasedir) (const char *, struct fuse_file_info *); - int (*fsyncdir) (const char *, int, struct fuse_file_info *); - void *(*init) (void); - void (*destroy) (void *); - int (*access) (const char *, int); - int (*create) (const char *, mode_t, struct fuse_file_info *); - int (*ftruncate) (const char *, off_t, struct fuse_file_info *); - int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); -}; - -struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, - const struct fuse_operations_compat25 *op, - size_t op_size); - -int fuse_main_real_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size); - -struct fuse *fuse_setup_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd); - -void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint); - -#if !defined(__FreeBSD__) && !defined(__NetBSD__) -#include - -struct fuse_operations_compat22 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info_compat *); - int (*read) (const char *, char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *, struct fuse_file_info_compat *); - int (*release) (const char *, struct fuse_file_info_compat *); - int (*fsync) (const char *, int, struct fuse_file_info_compat *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info_compat *); - int (*readdir) (const char *, void *, off_t, - struct fuse_file_info_compat *); - int (*releasedir) (const char *, struct fuse_file_info_compat *); - int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *); - void *(*init) (void); - void (*destroy) (void *); -}; - -struct fuse *fuse_new_compat22(int fd, const char *opts, - const struct fuse_operations_compat22 *op, - size_t op_size); - -struct fuse *fuse_setup_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd); - -int fuse_main_real_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size); - -struct fuse_operations_compat2 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); - int (*setxattr) (const char *, const char *, const char *, - size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); -}; - -int fuse_main_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op); - -struct fuse *fuse_new_compat2(int fd, const char *opts, - const struct fuse_operations_compat2 *op); - -struct fuse *fuse_setup_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op, - char **mountpoint, int *multithreaded, int *fd); - -struct fuse_statfs_compat1 { - long block_size; - long blocks; - long blocks_free; - long files; - long files_free; - long namelen; -}; - -struct fuse_operations_compat1 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (struct fuse_statfs_compat1 *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); -}; - -#define FUSE_DEBUG_COMPAT1 (1 << 1) - -struct fuse *fuse_new_compat1(int fd, int flags, - const struct fuse_operations_compat1 *op); - -void fuse_main_compat1(int argc, char *argv[], - const struct fuse_operations_compat1 *op); - -#endif /* __FreeBSD__ || __NetBSD__ */ diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index 7891e233..d8a9c142 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -37,1803 +37,1511 @@ extern "C" { #endif -/* ----------------------------------------------------------- * - * Miscellaneous definitions * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Miscellaneous definitions * + * ----------------------------------------------------------- */ -/** The node ID of the root inode */ + /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 -/** Inode number type */ -typedef uint64_t fuse_ino_t; + /** Inode number type */ + typedef uint64_t fuse_ino_t; -/** Request pointer type */ -typedef struct fuse_req *fuse_req_t; - -/** - * Session - * - * This provides hooks for processing requests, and exiting - */ -struct fuse_session; - -/** - * Channel - * - * A communication channel, providing hooks for sending and receiving - * messages - */ -struct fuse_chan; - -/** Directory entry parameters supplied to fuse_reply_entry() */ -struct fuse_entry_param { - /** Unique inode number - * - * In lookup, zero means negative entry (from version 2.5) - * Returning ENOENT also means negative entry, but by setting zero - * ino the kernel may cache negative entries for entry_timeout - * seconds. - */ - fuse_ino_t ino; - - /** Generation number for this entry. - * - * If the file system will be exported over NFS, the - * ino/generation pairs need to be unique over the file - * system's lifetime (rather than just the mount time). So if - * the file system reuses an inode after it has been deleted, - * it must assign a new, previously unused generation number - * to the inode at the same time. - * - * The generation must be non-zero, otherwise FUSE will treat - * it as an error. - * - */ - uint64_t generation; - - - /** Inode attributes. - * - * Even if attr_timeout == 0, attr must be correct. For example, - * for open(), FUSE uses attr.st_size from lookup() to determine - * how many bytes to request. If this value is not correct, - * incorrect data will be returned. - */ - struct stat attr; - - /** Validity timeout (in seconds) for the attributes */ - double attr_timeout; - - /** Validity timeout (in seconds) for the name */ - double entry_timeout; -}; - -/** Additional context associated with requests */ -struct fuse_ctx { - /** User ID of the calling process */ - uid_t uid; - - /** Group ID of the calling process */ - gid_t gid; - - /** Thread ID of the calling process */ - pid_t pid; - - /** Umask of the calling process (introduced in version 2.8) */ - mode_t umask; -}; - -struct fuse_forget_data { - fuse_ino_t ino; - uint64_t nlookup; -}; - -/* ----------------------------------------------------------- * - * Request methods and replies * - * ----------------------------------------------------------- */ - -/** - * Low level filesystem operations - * - * Most of the methods (with the exception of init and destroy) - * receive a request handle (fuse_req_t) as their first argument. - * This handle must be passed to one of the specified reply functions. - * - * This may be done inside the method invocation, or after the call - * has returned. The request handle is valid until one of the reply - * functions is called. - * - * Other pointer arguments (name, fuse_file_info, etc) are not valid - * after the call has returned, so if they are needed later, their - * contents have to be copied. - * - * The filesystem sometimes needs to handle a return value of -ENOENT - * from the reply function, which means, that the request was - * interrupted, and the reply discarded. For example if - * fuse_reply_open() return -ENOENT means, that the release method for - * this file will not be called. - */ -struct fuse_lowlevel_ops { - /** - * Initialize filesystem - * - * Called before any other filesystem method - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_new() - */ - void (*init) (void *userdata, struct fuse_conn_info *conn); - - /** - * Clean up filesystem - * - * Called on filesystem exit - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_new() - */ - void (*destroy) (void *userdata); - - /** - * Look up a directory entry by name and get its attributes. - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name the name to look up - */ - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Forget about an inode - * - * This function is called when the kernel removes an inode - * from its internal caches. - * - * The inode's lookup count increases by one for every call to - * fuse_reply_entry and fuse_reply_create. The nlookup parameter - * indicates by how much the lookup count should be decreased. - * - * Inodes with a non-zero lookup count may receive request from - * the kernel even after calls to unlink, rmdir or (when - * overwriting an existing file) rename. Filesystems must handle - * such requests properly and it is recommended to defer removal - * of the inode until the lookup count reaches zero. Calls to - * unlink, remdir or rename will be followed closely by forget - * unless the file or directory is open, in which case the - * kernel issues forget only after the release or releasedir - * calls. - * - * Note that if a file system will be exported over NFS the - * inodes lifetime must extend even beyond forget. See the - * generation field in struct fuse_entry_param above. - * - * On unmount the lookup count for all inodes implicitly drops - * to zero. It is not guaranteed that the file system will - * receive corresponding forget messages for the affected - * inodes. - * - * Valid replies: - * fuse_reply_none - * - * @param req request handle - * @param ino the inode number - * @param nlookup the number of lookups to forget - */ - void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup); - - /** - * Get file attributes - * - * Valid replies: - * fuse_reply_attr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi for future use, currently always NULL - */ - void (*getattr) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Set file attributes - * - * In the 'attr' argument only members indicated by the 'to_set' - * bitmask contain valid values. Other members contain undefined - * values. - * - * If the setattr was invoked from the ftruncate() system call - * under Linux kernel versions 2.6.15 or later, the fi->fh will - * contain the value set by the open method or will be undefined - * if the open method didn't set any value. Otherwise (not - * ftruncate call, or kernel version earlier than 2.6.15) the fi - * parameter will be NULL. - * - * Valid replies: - * fuse_reply_attr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param attr the attributes - * @param to_set bit mask of attributes which should be set - * @param fi file information, or NULL - * - * Changed in version 2.5: - * file information filled in for ftruncate - */ - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info *fi); - - /** - * Read symbolic link - * - * Valid replies: - * fuse_reply_readlink - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - */ - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - - /** - * Create file node - * - * Create a regular file, character device, block device, fifo or - * socket node. - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode file type and mode with which to create the new file - * @param rdev the device number (only valid if created file is a device) - */ - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - - /** - * Create a directory - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode with which to create the new file - */ - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - - /** - * Remove a file - * - * If the file's inode's lookup count is non-zero, the file - * system is expected to postpone any removal of the inode - * until the lookup count reaches zero (see description of the - * forget function). - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to remove - */ - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Remove a directory - * - * If the directory's inode's lookup count is non-zero, the - * file system is expected to postpone any removal of the - * inode until the lookup count reaches zero (see description - * of the forget function). - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to remove - */ - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Create a symbolic link - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param link the contents of the symbolic link - * @param parent inode number of the parent directory - * @param name to create - */ - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - - /** Rename a file - * - * If the target exists it should be atomically replaced. If - * the target's inode's lookup count is non-zero, the file - * system is expected to postpone any removal of the inode - * until the lookup count reaches zero (see description of the - * forget function). - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the old parent directory - * @param name old name - * @param newparent inode number of the new parent directory - * @param newname new name - */ - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - - /** - * Create a hard link - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param ino the old inode number - * @param newparent inode number of the new parent directory - * @param newname new name to create - */ - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - - /** - * Open a file - * - * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and - * O_TRUNC) are available in fi->flags. - * - * Filesystem may store an arbitrary file handle (pointer, index, - * etc) in fi->fh, and use this in other all other file operations - * (read, write, flush, release, fsync). - * - * Filesystem may also implement stateless file I/O and not store - * anything in fi->fh. - * - * There are also some flags (direct_io, keep_cache) which the - * filesystem may set in fi, to change the way the file is opened. - * See fuse_file_info structure in for more details. - * - * Valid replies: - * fuse_reply_open - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*open) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Read data - * - * Read should send exactly the number of bytes requested except - * on EOF or error, otherwise the rest of the data will be - * substituted with zeroes. An exception to this is when the file - * has been opened in 'direct_io' mode, in which case the return - * value of the read system call will reflect the return value of - * this operation. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_iov - * fuse_reply_data - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size number of bytes to read - * @param off offset to read from - * @param fi file information - */ - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - - /** - * Write data - * - * Write should return exactly the number of bytes requested - * except on error. An exception to this is when the file has - * been opened in 'direct_io' mode, in which case the return value - * of the write system call will reflect the return value of this - * operation. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * Valid replies: - * fuse_reply_write - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param buf data to write - * @param size number of bytes to write - * @param off offset to write to - * @param fi file information - */ - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi); - - /** - * Flush method - * - * This is called on each close() of the opened file. - * - * Since file descriptors can be duplicated (dup, dup2, fork), for - * one open call there may be many flush calls. - * - * Filesystems shouldn't assume that flush will always be called - * after some writes, or that if will be called at all. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * NOTE: the name of the method is misleading, since (unlike - * fsync) the filesystem is not forced to flush pending writes. - * One reason to flush data, is if the filesystem wants to return - * write errors. - * - * If the filesystem supports file locking operations (setlk, - * getlk) it should remove all locks belonging to 'fi->owner'. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*flush) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Release an open file - * - * Release is called when there are no more references to an open - * file: all file descriptors are closed and all memory mappings - * are unmapped. - * - * For every open call there will be exactly one release call. - * - * The filesystem may reply with an error, but error values are - * not returned to close() or munmap() which triggered the - * release. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * fi->flags will contain the same flags as for open. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*release) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Synchronize file contents - * - * If the datasync parameter is non-zero, then only the user data - * should be flushed, not the meta data. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param datasync flag indicating if only data should be flushed - * @param fi file information - */ - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - - /** - * Open a directory - * - * Filesystem may store an arbitrary file handle (pointer, index, - * etc) in fi->fh, and use this in other all other directory - * stream operations (readdir, releasedir, fsyncdir). - * - * Filesystem may also implement stateless directory I/O and not - * store anything in fi->fh, though that makes it impossible to - * implement standard conforming directory stream operations in - * case the contents of the directory can change between opendir - * and releasedir. - * - * Valid replies: - * fuse_reply_open - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*opendir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Read directory - * - * Send a buffer filled using fuse_add_direntry(), with size not - * exceeding the requested size. Send an empty buffer on end of - * stream. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_data - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size maximum number of bytes to send - * @param off offset to continue reading the directory stream - * @param fi file information - */ - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *llffi); - - void (*readdir_plus)(fuse_req_t req, fuse_ino_t ino, - size_t size, off_t off, - struct fuse_file_info *ffi); - - /** - * Release an open directory - * - * For every opendir call there will be exactly one releasedir - * call. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Synchronize directory contents - * - * If the datasync parameter is non-zero, then only the directory - * contents should be flushed, not the meta data. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param datasync flag indicating if only data should be flushed - * @param fi file information - */ - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - - /** - * Get file system statistics - * - * Valid replies: - * fuse_reply_statfs - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number, zero means "undefined" - */ - void (*statfs) (fuse_req_t req, fuse_ino_t ino); - - /** - * Set an extended attribute - * - * Valid replies: - * fuse_reply_err - */ - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - - /** - * Get an extended attribute - * - * If size is zero, the size of the value should be sent with - * fuse_reply_xattr. - * - * If the size is non-zero, and the value fits in the buffer, the - * value should be sent with fuse_reply_buf. - * - * If the size is too small for the value, the ERANGE error should - * be sent. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_data - * fuse_reply_xattr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param name of the extended attribute - * @param size maximum size of the value to send - */ - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - - /** - * List extended attribute names - * - * If size is zero, the total size of the attribute list should be - * sent with fuse_reply_xattr. - * - * If the size is non-zero, and the null character separated - * attribute list fits in the buffer, the list should be sent with - * fuse_reply_buf. - * - * If the size is too small for the list, the ERANGE error should - * be sent. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_data - * fuse_reply_xattr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size maximum size of the list to send - */ - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - - /** - * Remove an extended attribute - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param name of the extended attribute - */ - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - - /** - * Check file access permissions - * - * This will be called for the access() system call. If the - * 'default_permissions' mount option is given, this method is not - * called. - * - * This method is not called under Linux kernel versions 2.4.x - * - * Introduced in version 2.5 - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param mask requested access mode - */ - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - - /** - * Create and open a file - * - * If the file does not exist, first create it with the specified - * mode, and then open it. - * - * Open flags (with the exception of O_NOCTTY) are available in - * fi->flags. - * - * Filesystem may store an arbitrary file handle (pointer, index, - * etc) in fi->fh, and use this in other all other file operations - * (read, write, flush, release, fsync). - * - * There are also some flags (direct_io, keep_cache) which the - * filesystem may set in fi, to change the way the file is opened. - * See fuse_file_info structure in for more details. - * - * If this method is not implemented or under Linux kernel - * versions earlier than 2.6.15, the mknod() and open() methods - * will be called instead. - * - * Introduced in version 2.5 - * - * Valid replies: - * fuse_reply_create - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode file type and mode with which to create the new file - * @param fi file information - */ - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi); - - /** - * Test for a POSIX file lock - * - * Introduced in version 2.6 - * - * Valid replies: - * fuse_reply_lock - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param lock the region/type to test - */ - void (*getlk) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, struct flock *lock); - - /** - * Acquire, modify or release a POSIX file lock - * - * For POSIX threads (NPTL) there's a 1-1 relation between pid and - * owner, but otherwise this is not always the case. For checking - * lock ownership, 'fi->owner' must be used. The l_pid field in - * 'struct flock' should only be used to fill in this field in - * getlk(). - * - * Note: if the locking methods are not implemented, the kernel - * will still allow file locking to work locally. Hence these are - * only interesting for network filesystems and similar. - * - * Introduced in version 2.6 - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param lock the region/type to set - * @param sleep locking operation may sleep - */ - void (*setlk) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, - struct flock *lock, int sleep); - - /** - * Map block index within file to block index within device - * - * Note: This makes sense only for block device backed filesystems - * mounted with the 'blkdev' option - * - * Introduced in version 2.6 - * - * Valid replies: - * fuse_reply_bmap - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param blocksize unit of block index - * @param idx block index within file - */ - void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, - uint64_t idx); - - /** - * Ioctl - * - * Note: For unrestricted ioctls (not allowed for FUSE - * servers), data in and out areas can be discovered by giving - * iovs and setting FUSE_IOCTL_RETRY in @flags. For - * restricted ioctls, kernel prepares in/out data area - * according to the information encoded in cmd. - * - * Introduced in version 2.8 - * - * Valid replies: - * fuse_reply_ioctl_retry - * fuse_reply_ioctl - * fuse_reply_ioctl_iov - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param cmd ioctl command - * @param arg ioctl argument - * @param fi file information - * @param flags for FUSE_IOCTL_* flags - * @param in_buf data fetched from the caller - * @param in_bufsz number of fetched bytes - * @param out_bufsz maximum size of output data - */ - void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, - struct fuse_file_info *fi, unsigned flags, - const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz); - - /** - * Poll for IO readiness - * - * Introduced in version 2.8 - * - * Note: If ph is non-NULL, the client should notify - * when IO readiness events occur by calling - * fuse_lowelevel_notify_poll() with the specified ph. - * - * Regardless of the number of times poll with a non-NULL ph - * is received, single notification is enough to clear all. - * Notifying more times incurs overhead but doesn't harm - * correctness. - * - * The callee is responsible for destroying ph with - * fuse_pollhandle_destroy() when no longer in use. - * - * Valid replies: - * fuse_reply_poll - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param ph poll handle to be used for notification - */ - void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct fuse_pollhandle *ph); - - /** - * Write data made available in a buffer - * - * This is a more generic version of the ->write() method. If - * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the - * kernel supports splicing from the fuse device, then the - * data will be made available in pipe for supporting zero - * copy data transfer. - * - * buf->count is guaranteed to be one (and thus buf->idx is - * always zero). The write_buf handler must ensure that - * bufv->off is correctly updated (reflecting the number of - * bytes read from bufv->buf[0]). - * - * Introduced in version 2.9 - * - * Valid replies: - * fuse_reply_write - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param bufv buffer containing the data - * @param off offset to write to - * @param fi file information - */ - void (*write_buf) (fuse_req_t req, fuse_ino_t ino, - struct fuse_bufvec *bufv, off_t off, - struct fuse_file_info *fi); - - /** - * Callback function for the retrieve request - * - * Introduced in version 2.9 - * - * Valid replies: - * fuse_reply_none - * - * @param req request handle - * @param cookie user data supplied to fuse_lowlevel_notify_retrieve() - * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve() - * @param offset the offset supplied to fuse_lowlevel_notify_retrieve() - * @param bufv the buffer containing the returned data - */ - void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino, - off_t offset, struct fuse_bufvec *bufv); - - /** - * Forget about multiple inodes - * - * See description of the forget function for more - * information. - * - * Introduced in version 2.9 - * - * Valid replies: - * fuse_reply_none - * - * @param req request handle - */ - void (*forget_multi) (fuse_req_t req, size_t count, - struct fuse_forget_data *forgets); - - /** - * Acquire, modify or release a BSD file lock - * - * Note: if the locking methods are not implemented, the kernel - * will still allow file locking to work locally. Hence these are - * only interesting for network filesystems and similar. - * - * Introduced in version 2.9 - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param op the locking operation, see flock(2) - */ - void (*flock) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, int op); - - /** - * Allocate requested space. If this function returns success then - * subsequent writes to the specified range shall not fail due to the lack - * of free space on the file system storage media. - * - * Introduced in version 2.9 - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param offset starting point for allocated region - * @param length size of allocated region - * @param mode determines the operation to be performed on the given range, - * see fallocate(2) - */ - void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, - off_t offset, off_t length, struct fuse_file_info *fi); + /** Request pointer type */ + typedef struct fuse_req *fuse_req_t; /** - * Copy a range of data from one file to another - * - * Performs an optimized copy between two file descriptors without - * the - * additional cost of transferring data through the FUSE kernel - * module - * to user space (glibc) and then back into the FUSE filesystem - * again. - * - * In case this method is not implemented, glibc falls back to - * reading - * data from the source and writing to the destination. Effectively - * doing an inefficient copy of the data. - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EOPNOTSUPP, - * i.e. all - * future copy_file_range() requests will fail with EOPNOTSUPP - * without - * being send to the filesystem process. - * - * Valid replies: - * fuse_reply_write - * fuse_reply_err + * Session * - * @param req request handle - * @param ino_in the inode number of the source file - * @param off_in starting point from were the data should be read - * @param fi_in file information of the source file - * @param ino_out the inode number of the destination file - * @param off_out starting point where the data should be written - * @param fi_out file information of the destination file - * @param len maximum size of the data to copy - * @param flags passed along with the copy_file_range() syscall + * This provides hooks for processing requests, and exiting */ - void (*copy_file_range)(fuse_req_t req, - fuse_ino_t ino_in, - off_t off_in, - struct fuse_file_info *fi_in, - fuse_ino_t ino_out, - off_t off_out, - struct fuse_file_info *fi_out, - size_t len, - int flags); -}; - -/** - * Reply with an error code or success - * - * Possible requests: - * all except forget - * - * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, - * removexattr and setlk may send a zero code - * - * @param req request handle - * @param err the positive error value, or zero for success - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_err(fuse_req_t req, int err); - -/** - * Don't send reply - * - * Possible requests: - * forget - * - * @param req request handle - */ -void fuse_reply_none(fuse_req_t req); - -/** - * Reply with a directory entry - * - * Possible requests: - * lookup, mknod, mkdir, symlink, link - * - * Side effects: - * increments the lookup count on success - * - * @param req request handle - * @param e the entry parameters - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); - -/** - * Reply with a directory entry and open parameters - * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache - * - * Possible requests: - * create - * - * Side effects: - * increments the lookup count on success - * - * @param req request handle - * @param e the entry parameters - * @param fi file information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, - const struct fuse_file_info *fi); - -/** - * Reply with attributes - * - * Possible requests: - * getattr, setattr - * - * @param req request handle - * @param attr the attributes - * @param attr_timeout validity timeout (in seconds) for the attributes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_attr(fuse_req_t req, const struct stat *attr, - double attr_timeout); - -/** - * Reply with the contents of a symbolic link - * - * Possible requests: - * readlink - * - * @param req request handle - * @param link symbolic link contents - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_readlink(fuse_req_t req, const char *link); - -/** - * Reply with open parameters - * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache - * - * Possible requests: - * open, opendir - * - * @param req request handle - * @param fi file information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); + struct fuse_session; -/** - * Reply with number of bytes written - * - * Possible requests: - * write - * - * @param req request handle - * @param count the number of bytes written - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_write(fuse_req_t req, size_t count); - -/** - * Reply with data - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param buf buffer containing data - * @param size the size of data in bytes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); - -/** - * Reply with data copied/moved from buffer(s) - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param bufv buffer vector - * @param flags flags controlling the copy - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, - enum fuse_buf_copy_flags flags); - -/** - * Reply with data vector - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param iov the vector containing the data - * @param count the size of vector - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); - -/** - * Reply with filesystem statistics - * - * Possible requests: - * statfs - * - * @param req request handle - * @param stbuf filesystem statistics - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); - -/** - * Reply with needed buffer size - * - * Possible requests: - * getxattr, listxattr - * - * @param req request handle - * @param count the buffer size needed in bytes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_xattr(fuse_req_t req, size_t count); - -/** - * Reply with file lock information - * - * Possible requests: - * getlk - * - * @param req request handle - * @param lock the lock information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_lock(fuse_req_t req, const struct flock *lock); - -/** - * Reply with block index - * - * Possible requests: - * bmap - * - * @param req request handle - * @param idx block index within device - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_bmap(fuse_req_t req, uint64_t idx); - -/** - * Reply to ask for data fetch and output buffer preparation. ioctl - * will be retried with the specified input data fetched and output - * buffer prepared. - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param in_iov iovec specifying data to fetch from the caller - * @param in_count number of entries in in_iov - * @param out_iov iovec specifying addresses to write output to - * @param out_count number of entries in out_iov - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_ioctl_retry(fuse_req_t req, - const struct iovec *in_iov, size_t in_count, - const struct iovec *out_iov, size_t out_count); - -/** - * Reply to finish ioctl - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param result result to be passed to the caller - * @param buf buffer containing output data - * @param size length of output data - */ -int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size); - -/** - * Reply to finish ioctl with iov buffer - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param result result to be passed to the caller - * @param iov the vector containing the data - * @param count the size of vector - */ -int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, - int count); + /** + * Channel + * + * A communication channel, providing hooks for sending and receiving + * messages + */ + typedef struct fuse_chan_t fuse_chan_t; + + /** Directory entry parameters supplied to fuse_reply_entry() */ + struct fuse_entry_param { + /** Unique inode number + * + * In lookup, zero means negative entry (from version 2.5) + * Returning ENOENT also means negative entry, but by setting zero + * ino the kernel may cache negative entries for entry_timeout + * seconds. + */ + fuse_ino_t ino; + + /** Generation number for this entry. + * + * If the file system will be exported over NFS, the + * ino/generation pairs need to be unique over the file + * system's lifetime (rather than just the mount time). So if + * the file system reuses an inode after it has been deleted, + * it must assign a new, previously unused generation number + * to the inode at the same time. + * + * The generation must be non-zero, otherwise FUSE will treat + * it as an error. + * + */ + uint64_t generation; + + + /** Inode attributes. + * + * Even if attr_timeout == 0, attr must be correct. For example, + * for open(), FUSE uses attr.st_size from lookup() to determine + * how many bytes to request. If this value is not correct, + * incorrect data will be returned. + */ + struct stat attr; + + /** Validity timeout (in seconds) for the attributes */ + double attr_timeout; + + /** Validity timeout (in seconds) for the name */ + double entry_timeout; + }; + + /** Additional context associated with requests */ + struct fuse_ctx { + /** User ID of the calling process */ + uid_t uid; + + /** Group ID of the calling process */ + gid_t gid; + + /** Thread ID of the calling process */ + pid_t pid; + + /** Umask of the calling process (introduced in version 2.8) */ + mode_t umask; + }; + + struct fuse_forget_data { + fuse_ino_t ino; + uint64_t nlookup; + }; + + /* ----------------------------------------------------------- * + * Request methods and replies * + * ----------------------------------------------------------- */ -/** - * Reply with poll result event mask - * - * @param req request handle - * @param revents poll result event mask - */ -int fuse_reply_poll(fuse_req_t req, unsigned revents); + /** + * Low level filesystem operations + * + * Most of the methods (with the exception of init and destroy) + * receive a request handle (fuse_req_t) as their first argument. + * This handle must be passed to one of the specified reply functions. + * + * This may be done inside the method invocation, or after the call + * has returned. The request handle is valid until one of the reply + * functions is called. + * + * Other pointer arguments (name, fuse_file_info, etc) are not valid + * after the call has returned, so if they are needed later, their + * contents have to be copied. + * + * The filesystem sometimes needs to handle a return value of -ENOENT + * from the reply function, which means, that the request was + * interrupted, and the reply discarded. For example if + * fuse_reply_open() return -ENOENT means, that the release method for + * this file will not be called. + */ + struct fuse_lowlevel_ops { + /** + * Initialize filesystem + * + * Called before any other filesystem method + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ + void (*init) (void *userdata, struct fuse_conn_info *conn); + + /** + * Clean up filesystem + * + * Called on filesystem exit + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ + void (*destroy) (void *userdata); + + /** + * Look up a directory entry by name and get its attributes. + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name the name to look up + */ + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Forget about an inode + * + * This function is called when the kernel removes an inode + * from its internal caches. + * + * The inode's lookup count increases by one for every call to + * fuse_reply_entry and fuse_reply_create. The nlookup parameter + * indicates by how much the lookup count should be decreased. + * + * Inodes with a non-zero lookup count may receive request from + * the kernel even after calls to unlink, rmdir or (when + * overwriting an existing file) rename. Filesystems must handle + * such requests properly and it is recommended to defer removal + * of the inode until the lookup count reaches zero. Calls to + * unlink, remdir or rename will be followed closely by forget + * unless the file or directory is open, in which case the + * kernel issues forget only after the release or releasedir + * calls. + * + * Note that if a file system will be exported over NFS the + * inodes lifetime must extend even beyond forget. See the + * generation field in struct fuse_entry_param above. + * + * On unmount the lookup count for all inodes implicitly drops + * to zero. It is not guaranteed that the file system will + * receive corresponding forget messages for the affected + * inodes. + * + * Valid replies: + * fuse_reply_none + * + * @param req request handle + * @param ino the inode number + * @param nlookup the number of lookups to forget + */ + void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup); + + /** + * Get file attributes + * + * Valid replies: + * fuse_reply_attr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi for future use, currently always NULL + */ + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Set file attributes + * + * In the 'attr' argument only members indicated by the 'to_set' + * bitmask contain valid values. Other members contain undefined + * values. + * + * If the setattr was invoked from the ftruncate() system call + * under Linux kernel versions 2.6.15 or later, the fi->fh will + * contain the value set by the open method or will be undefined + * if the open method didn't set any value. Otherwise (not + * ftruncate call, or kernel version earlier than 2.6.15) the fi + * parameter will be NULL. + * + * Valid replies: + * fuse_reply_attr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param attr the attributes + * @param to_set bit mask of attributes which should be set + * @param fi file information, or NULL + * + * Changed in version 2.5: + * file information filled in for ftruncate + */ + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); + + /** + * Read symbolic link + * + * Valid replies: + * fuse_reply_readlink + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + */ + void (*readlink) (fuse_req_t req, fuse_ino_t ino); + + /** + * Create file node + * + * Create a regular file, character device, block device, fifo or + * socket node. + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode file type and mode with which to create the new file + * @param rdev the device number (only valid if created file is a device) + */ + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); + + /** + * Create a directory + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode with which to create the new file + */ + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + + /** + * Remove a file + * + * If the file's inode's lookup count is non-zero, the file + * system is expected to postpone any removal of the inode + * until the lookup count reaches zero (see description of the + * forget function). + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to remove + */ + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Remove a directory + * + * If the directory's inode's lookup count is non-zero, the + * file system is expected to postpone any removal of the + * inode until the lookup count reaches zero (see description + * of the forget function). + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to remove + */ + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Create a symbolic link + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param link the contents of the symbolic link + * @param parent inode number of the parent directory + * @param name to create + */ + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + + /** Rename a file + * + * If the target exists it should be atomically replaced. If + * the target's inode's lookup count is non-zero, the file + * system is expected to postpone any removal of the inode + * until the lookup count reaches zero (see description of the + * forget function). + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the old parent directory + * @param name old name + * @param newparent inode number of the new parent directory + * @param newname new name + */ + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); + + /** + * Create a hard link + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param ino the old inode number + * @param newparent inode number of the new parent directory + * @param newname new name to create + */ + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); + + /** + * Open a file + * + * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and + * O_TRUNC) are available in fi->flags. + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other file operations + * (read, write, flush, release, fsync). + * + * Filesystem may also implement stateless file I/O and not store + * anything in fi->fh. + * + * There are also some flags (direct_io, keep_cache) which the + * filesystem may set in fi, to change the way the file is opened. + * See fuse_file_info structure in for more details. + * + * Valid replies: + * fuse_reply_open + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Read data + * + * Read should send exactly the number of bytes requested except + * on EOF or error, otherwise the rest of the data will be + * substituted with zeroes. An exception to this is when the file + * has been opened in 'direct_io' mode, in which case the return + * value of the read system call will reflect the return value of + * this operation. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_iov + * fuse_reply_data + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size number of bytes to read + * @param off offset to read from + * @param fi file information + */ + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + + /** + * Write data + * + * Write should return exactly the number of bytes requested + * except on error. An exception to this is when the file has + * been opened in 'direct_io' mode, in which case the return value + * of the write system call will reflect the return value of this + * operation. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * Valid replies: + * fuse_reply_write + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param buf data to write + * @param size number of bytes to write + * @param off offset to write to + * @param fi file information + */ + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + + /** + * Flush method + * + * This is called on each close() of the opened file. + * + * Since file descriptors can be duplicated (dup, dup2, fork), for + * one open call there may be many flush calls. + * + * Filesystems shouldn't assume that flush will always be called + * after some writes, or that if will be called at all. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * NOTE: the name of the method is misleading, since (unlike + * fsync) the filesystem is not forced to flush pending writes. + * One reason to flush data, is if the filesystem wants to return + * write errors. + * + * If the filesystem supports file locking operations (setlk, + * getlk) it should remove all locks belonging to 'fi->owner'. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Release an open file + * + * Release is called when there are no more references to an open + * file: all file descriptors are closed and all memory mappings + * are unmapped. + * + * For every open call there will be exactly one release call. + * + * The filesystem may reply with an error, but error values are + * not returned to close() or munmap() which triggered the + * release. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * fi->flags will contain the same flags as for open. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Synchronize file contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param datasync flag indicating if only data should be flushed + * @param fi file information + */ + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + + /** + * Open a directory + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other directory + * stream operations (readdir, releasedir, fsyncdir). + * + * Filesystem may also implement stateless directory I/O and not + * store anything in fi->fh, though that makes it impossible to + * implement standard conforming directory stream operations in + * case the contents of the directory can change between opendir + * and releasedir. + * + * Valid replies: + * fuse_reply_open + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Read directory + * + * Send a buffer filled using fuse_add_direntry(), with size not + * exceeding the requested size. Send an empty buffer on end of + * stream. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_data + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size maximum number of bytes to send + * @param off offset to continue reading the directory stream + * @param fi file information + */ + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *llffi); + + void (*readdir_plus)(fuse_req_t req, fuse_ino_t ino, + size_t size, off_t off, + struct fuse_file_info *ffi); + + /** + * Release an open directory + * + * For every opendir call there will be exactly one releasedir + * call. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Synchronize directory contents + * + * If the datasync parameter is non-zero, then only the directory + * contents should be flushed, not the meta data. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param datasync flag indicating if only data should be flushed + * @param fi file information + */ + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + + /** + * Get file system statistics + * + * Valid replies: + * fuse_reply_statfs + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number, zero means "undefined" + */ + void (*statfs) (fuse_req_t req, fuse_ino_t ino); + + /** + * Set an extended attribute + * + * Valid replies: + * fuse_reply_err + */ + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + + /** + * Get an extended attribute + * + * If size is zero, the size of the value should be sent with + * fuse_reply_xattr. + * + * If the size is non-zero, and the value fits in the buffer, the + * value should be sent with fuse_reply_buf. + * + * If the size is too small for the value, the ERANGE error should + * be sent. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_data + * fuse_reply_xattr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param name of the extended attribute + * @param size maximum size of the value to send + */ + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + + /** + * List extended attribute names + * + * If size is zero, the total size of the attribute list should be + * sent with fuse_reply_xattr. + * + * If the size is non-zero, and the null character separated + * attribute list fits in the buffer, the list should be sent with + * fuse_reply_buf. + * + * If the size is too small for the list, the ERANGE error should + * be sent. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_data + * fuse_reply_xattr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size maximum size of the list to send + */ + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + + /** + * Remove an extended attribute + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param name of the extended attribute + */ + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + + /** + * Check file access permissions + * + * This will be called for the access() system call. If the + * 'default_permissions' mount option is given, this method is not + * called. + * + * This method is not called under Linux kernel versions 2.4.x + * + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param mask requested access mode + */ + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + + /** + * Create and open a file + * + * If the file does not exist, first create it with the specified + * mode, and then open it. + * + * Open flags (with the exception of O_NOCTTY) are available in + * fi->flags. + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other file operations + * (read, write, flush, release, fsync). + * + * There are also some flags (direct_io, keep_cache) which the + * filesystem may set in fi, to change the way the file is opened. + * See fuse_file_info structure in for more details. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the mknod() and open() methods + * will be called instead. + * + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_create + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode file type and mode with which to create the new file + * @param fi file information + */ + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi); + + /** + * Test for a POSIX file lock + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_lock + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param lock the region/type to test + */ + void (*getlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock); + + /** + * Acquire, modify or release a POSIX file lock + * + * For POSIX threads (NPTL) there's a 1-1 relation between pid and + * owner, but otherwise this is not always the case. For checking + * lock ownership, 'fi->owner' must be used. The l_pid field in + * 'struct flock' should only be used to fill in this field in + * getlk(). + * + * Note: if the locking methods are not implemented, the kernel + * will still allow file locking to work locally. Hence these are + * only interesting for network filesystems and similar. + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param lock the region/type to set + * @param sleep locking operation may sleep + */ + void (*setlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, + struct flock *lock, int sleep); + + /** + * Map block index within file to block index within device + * + * Note: This makes sense only for block device backed filesystems + * mounted with the 'blkdev' option + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_bmap + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param blocksize unit of block index + * @param idx block index within file + */ + void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, + uint64_t idx); + + /** + * Ioctl + * + * Note: For unrestricted ioctls (not allowed for FUSE + * servers), data in and out areas can be discovered by giving + * iovs and setting FUSE_IOCTL_RETRY in @flags. For + * restricted ioctls, kernel prepares in/out data area + * according to the information encoded in cmd. + * + * Introduced in version 2.8 + * + * Valid replies: + * fuse_reply_ioctl_retry + * fuse_reply_ioctl + * fuse_reply_ioctl_iov + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param cmd ioctl command + * @param arg ioctl argument + * @param fi file information + * @param flags for FUSE_IOCTL_* flags + * @param in_buf data fetched from the caller + * @param in_bufsz number of fetched bytes + * @param out_bufsz maximum size of output data + */ + void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, + struct fuse_file_info *fi, unsigned flags, + const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz); + + /** + * Poll for IO readiness + * + * Introduced in version 2.8 + * + * Note: If ph is non-NULL, the client should notify + * when IO readiness events occur by calling + * fuse_lowelevel_notify_poll() with the specified ph. + * + * Regardless of the number of times poll with a non-NULL ph + * is received, single notification is enough to clear all. + * Notifying more times incurs overhead but doesn't harm + * correctness. + * + * The callee is responsible for destroying ph with + * fuse_pollhandle_destroy() when no longer in use. + * + * Valid replies: + * fuse_reply_poll + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param ph poll handle to be used for notification + */ + void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, + struct fuse_pollhandle *ph); + + /** + * Write data made available in a buffer + * + * This is a more generic version of the ->write() method. If + * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the + * kernel supports splicing from the fuse device, then the + * data will be made available in pipe for supporting zero + * copy data transfer. + * + * buf->count is guaranteed to be one (and thus buf->idx is + * always zero). The write_buf handler must ensure that + * bufv->off is correctly updated (reflecting the number of + * bytes read from bufv->buf[0]). + * + * Introduced in version 2.9 + * + * Valid replies: + * fuse_reply_write + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param bufv buffer containing the data + * @param off offset to write to + * @param fi file information + */ + void (*write_buf) (fuse_req_t req, fuse_ino_t ino, + struct fuse_bufvec *bufv, off_t off, + struct fuse_file_info *fi); + + /** + * Callback function for the retrieve request + * + * Introduced in version 2.9 + * + * Valid replies: + * fuse_reply_none + * + * @param req request handle + * @param cookie user data supplied to fuse_lowlevel_notify_retrieve() + * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve() + * @param offset the offset supplied to fuse_lowlevel_notify_retrieve() + * @param bufv the buffer containing the returned data + */ + void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino, + off_t offset, struct fuse_bufvec *bufv); + + /** + * Forget about multiple inodes + * + * See description of the forget function for more + * information. + * + * Introduced in version 2.9 + * + * Valid replies: + * fuse_reply_none + * + * @param req request handle + */ + void (*forget_multi) (fuse_req_t req, size_t count, + struct fuse_forget_data *forgets); + + /** + * Acquire, modify or release a BSD file lock + * + * Note: if the locking methods are not implemented, the kernel + * will still allow file locking to work locally. Hence these are + * only interesting for network filesystems and similar. + * + * Introduced in version 2.9 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param op the locking operation, see flock(2) + */ + void (*flock) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, int op); + + /** + * Allocate requested space. If this function returns success then + * subsequent writes to the specified range shall not fail due to the lack + * of free space on the file system storage media. + * + * Introduced in version 2.9 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param offset starting point for allocated region + * @param length size of allocated region + * @param mode determines the operation to be performed on the given range, + * see fallocate(2) + */ + void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, + off_t offset, off_t length, struct fuse_file_info *fi); -/* ----------------------------------------------------------- * - * Notification * - * ----------------------------------------------------------- */ + /** + * Copy a range of data from one file to another + * + * Performs an optimized copy between two file descriptors without + * the + * additional cost of transferring data through the FUSE kernel + * module + * to user space (glibc) and then back into the FUSE filesystem + * again. + * + * In case this method is not implemented, glibc falls back to + * reading + * data from the source and writing to the destination. Effectively + * doing an inefficient copy of the data. + * + * If this request is answered with an error code of ENOSYS, this is + * treated as a permanent failure with error code EOPNOTSUPP, + * i.e. all + * future copy_file_range() requests will fail with EOPNOTSUPP + * without + * being send to the filesystem process. + * + * Valid replies: + * fuse_reply_write + * fuse_reply_err + * + * @param req request handle + * @param ino_in the inode number of the source file + * @param off_in starting point from were the data should be read + * @param fi_in file information of the source file + * @param ino_out the inode number of the destination file + * @param off_out starting point where the data should be written + * @param fi_out file information of the destination file + * @param len maximum size of the data to copy + * @param flags passed along with the copy_file_range() syscall + */ + void (*copy_file_range)(fuse_req_t req, + fuse_ino_t ino_in, + off_t off_in, + struct fuse_file_info *fi_in, + fuse_ino_t ino_out, + off_t off_out, + struct fuse_file_info *fi_out, + size_t len, + int flags); + }; -/** - * Notify IO readiness event - * - * For more information, please read comment for poll operation. - * - * @param ph poll handle to notify IO readiness event for - */ -int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); + /** + * Reply with an error code or success + * + * Possible requests: + * all except forget + * + * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, + * removexattr and setlk may send a zero code + * + * @param req request handle + * @param err the positive error value, or zero for success + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_err(fuse_req_t req, int err); -/** - * Notify to invalidate cache for an inode - * - * @param ch the channel through which to send the invalidation - * @param ino the inode number - * @param off the offset in the inode where to start invalidating - * or negative to invalidate attributes only - * @param len the amount of cache to invalidate or 0 for all - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, - off_t off, off_t len); + /** + * Don't send reply + * + * Possible requests: + * forget + * + * @param req request handle + */ + void fuse_reply_none(fuse_req_t req); -/** - * Notify to invalidate parent attributes and the dentry matching - * parent/name - * - * To avoid a deadlock don't call this function from a filesystem operation and - * don't call it with a lock held that can also be held by a filesystem - * operation. - * - * @param ch the channel through which to send the invalidation - * @param parent inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, - const char *name, size_t namelen); + /** + * Reply with a directory entry + * + * Possible requests: + * lookup, mknod, mkdir, symlink, link + * + * Side effects: + * increments the lookup count on success + * + * @param req request handle + * @param e the entry parameters + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); -/** - * Notify to invalidate parent attributes and delete the dentry matching - * parent/name if the dentry's inode number matches child (otherwise it - * will invalidate the matching dentry). - * - * To avoid a deadlock don't call this function from a filesystem operation and - * don't call it with a lock held that can also be held by a filesystem - * operation. - * - * @param ch the channel through which to send the notification - * @param parent inode number - * @param child inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_delete(struct fuse_chan *ch, - fuse_ino_t parent, fuse_ino_t child, - const char *name, size_t namelen); + /** + * Reply with a directory entry and open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * create + * + * Side effects: + * increments the lookup count on success + * + * @param req request handle + * @param e the entry parameters + * @param fi file information + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, + const struct fuse_file_info *fi); -/** - * Store data to the kernel buffers - * - * Synchronously store data in the kernel buffers belonging to the - * given inode. The stored data is marked up-to-date (no read will be - * performed against it, unless it's invalidated or evicted from the - * cache). - * - * If the stored data overflows the current file size, then the size - * is extended, similarly to a write(2) on the filesystem. - * - * If this function returns an error, then the store wasn't fully - * completed, but it may have been partially completed. - * - * @param ch the channel through which to send the invalidation - * @param ino the inode number - * @param offset the starting offset into the file to store to - * @param bufv buffer vector - * @param flags flags controlling the copy - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, - off_t offset, struct fuse_bufvec *bufv, - enum fuse_buf_copy_flags flags); -/** - * Retrieve data from the kernel buffers - * - * Retrieve data in the kernel buffers belonging to the given inode. - * If successful then the retrieve_reply() method will be called with - * the returned data. - * - * Only present pages are returned in the retrieve reply. Retrieving - * stops when it finds a non-present page and only data prior to that is - * returned. - * - * If this function returns an error, then the retrieve will not be - * completed and no reply will be sent. - * - * This function doesn't change the dirty state of pages in the kernel - * buffer. For dirty pages the write() method will be called - * regardless of having been retrieved previously. - * - * @param ch the channel through which to send the invalidation - * @param ino the inode number - * @param size the number of bytes to retrieve - * @param offset the starting offset into the file to retrieve from - * @param cookie user data to supply to the reply callback - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, - size_t size, off_t offset, void *cookie); + /** + * Reply with attributes + * + * Possible requests: + * getattr, setattr + * + * @param req request handle + * @param attr the attributes + * @param attr_timeout validity timeout (in seconds) for the attributes + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_attr(fuse_req_t req, const struct stat *attr, + double attr_timeout); + /** + * Reply with the contents of a symbolic link + * + * Possible requests: + * readlink + * + * @param req request handle + * @param link symbolic link contents + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_readlink(fuse_req_t req, const char *link); -/* ----------------------------------------------------------- * - * Utility functions * - * ----------------------------------------------------------- */ + /** + * Reply with open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * open, opendir + * + * @param req request handle + * @param fi file information + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); -/** - * Get the userdata from the request - * - * @param req request handle - * @return the user data passed to fuse_lowlevel_new() - */ -void *fuse_req_userdata(fuse_req_t req); + /** + * Reply with number of bytes written + * + * Possible requests: + * write + * + * @param req request handle + * @param count the number of bytes written + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_write(fuse_req_t req, size_t count); -/** - * Get the context from the request - * - * The pointer returned by this function will only be valid for the - * request's lifetime - * - * @param req request handle - * @return the context structure - */ -const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); + /** + * Reply with data + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param buf buffer containing data + * @param size the size of data in bytes + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); -/** - * Get the current supplementary group IDs for the specified request - * - * Similar to the getgroups(2) system call, except the return value is - * always the total number of group IDs, even if it is larger than the - * specified size. - * - * The current fuse kernel module in linux (as of 2.6.30) doesn't pass - * the group list to userspace, hence this function needs to parse - * "/proc/$TID/task/$TID/status" to get the group IDs. - * - * This feature may not be supported on all operating systems. In - * such a case this function will return -ENOSYS. - * - * @param req request handle - * @param size size of given array - * @param list array of group IDs to be filled in - * @return the total number of supplementary group IDs or -errno on failure - */ -int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]); + /** + * Reply with data copied/moved from buffer(s) + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param bufv buffer vector + * @param flags flags controlling the copy + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, + enum fuse_buf_copy_flags flags); -/** - * Callback function for an interrupt - * - * @param req interrupted request - * @param data user data - */ -typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); + /** + * Reply with data vector + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param iov the vector containing the data + * @param count the size of vector + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); -/** - * Register/unregister callback for an interrupt - * - * If an interrupt has already happened, then the callback function is - * called from within this function, hence it's not possible for - * interrupts to be lost. - * - * @param req request handle - * @param func the callback function or NULL for unregister - * @param data user data passed to the callback function - */ -void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, - void *data); + /** + * Reply with filesystem statistics + * + * Possible requests: + * statfs + * + * @param req request handle + * @param stbuf filesystem statistics + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); -/** - * Check if a request has already been interrupted - * - * @param req request handle - * @return 1 if the request has been interrupted, 0 otherwise - */ -int fuse_req_interrupted(fuse_req_t req); + /** + * Reply with needed buffer size + * + * Possible requests: + * getxattr, listxattr + * + * @param req request handle + * @param count the buffer size needed in bytes + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_xattr(fuse_req_t req, size_t count); -/* ----------------------------------------------------------- * - * Filesystem setup * - * ----------------------------------------------------------- */ + /** + * Reply with file lock information + * + * Possible requests: + * getlk + * + * @param req request handle + * @param lock the lock information + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_lock(fuse_req_t req, const struct flock *lock); -/* Deprecated, don't use */ -int fuse_lowlevel_is_lib_option(const char *opt); + /** + * Reply with block index + * + * Possible requests: + * bmap + * + * @param req request handle + * @param idx block index within device + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_bmap(fuse_req_t req, uint64_t idx); -/** - * Create a low level session - * - * @param args argument vector - * @param op the low level filesystem operations - * @param op_size sizeof(struct fuse_lowlevel_ops) - * @param userdata user data - * @return the created session object, or NULL on failure - */ -struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + /** + * Reply to ask for data fetch and output buffer preparation. ioctl + * will be retried with the specified input data fetched and output + * buffer prepared. + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param in_iov iovec specifying data to fetch from the caller + * @param in_count number of entries in in_iov + * @param out_iov iovec specifying addresses to write output to + * @param out_count number of entries in out_iov + * @return zero for success, -errno for failure to send reply + */ + int fuse_reply_ioctl_retry(fuse_req_t req, + const struct iovec *in_iov, size_t in_count, + const struct iovec *out_iov, size_t out_count); -/* ----------------------------------------------------------- * - * Session interface * - * ----------------------------------------------------------- */ + /** + * Reply to finish ioctl + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param result result to be passed to the caller + * @param buf buffer containing output data + * @param size length of output data + */ + int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size); -/** - * 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); + /** + * Reply to finish ioctl with iov buffer + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param result result to be passed to the caller + * @param iov the vector containing the data + * @param count the size of vector + */ + int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, + int count); -/** - * Assign a channel to a session - * - * Note: currently only a single channel may be assigned. This may - * change in the future - * - * If a session is destroyed, the assigned channel is also destroyed - * - * @param se the session - * @param ch the channel - */ -void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); + /** + * Reply with poll result event mask + * + * @param req request handle + * @param revents poll result event mask + */ + int fuse_reply_poll(fuse_req_t req, unsigned revents); -/** - * Remove a channel from a session - * - * If the channel is not assigned to a session, then this is a no-op - * - * @param ch the channel to remove - */ -void fuse_session_remove_chan(struct fuse_chan *ch); + /* ----------------------------------------------------------- * + * Utility functions * + * ----------------------------------------------------------- */ -/** - * 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); + /** + * Get the userdata from the request + * + * @param req request handle + * @return the user data passed to fuse_lowlevel_new() + */ + void *fuse_req_userdata(fuse_req_t req); -/** - * Process a raw request - * - * @param se the session - * @param buf buffer containing the raw request - * @param len request length - * @param ch channel on which the request was received - */ -void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, - struct fuse_chan *ch); + /** + * Get the context from the request + * + * The pointer returned by this function will only be valid for the + * request's lifetime + * + * @param req request handle + * @return the context structure + */ + const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); -/** - * Process a raw request supplied in a generic buffer - * - * This is a more generic version of fuse_session_process(). The - * fuse_buf may contain a memory buffer or a pipe file descriptor. - * - * @param se the session - * @param buf the fuse_buf containing the request - * @param ch channel on which the request was received - */ -void fuse_session_process_buf(struct fuse_session *se, - const struct fuse_buf *buf, struct fuse_chan *ch); + /** + * Callback function for an interrupt + * + * @param req interrupted request + * @param data user data + */ + typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); -/** - * Receive a raw request supplied in a generic buffer - * - * This is a more generic version of fuse_chan_recv(). The fuse_buf - * supplied to this function contains a suitably allocated memory - * buffer. This may be overwritten with a file descriptor buffer. - * - * @param se the session - * @param buf the fuse_buf to store the request in - * @param chp pointer to the channel - * @return the actual size of the raw request, or -errno on error - */ -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp); + /** + * Register/unregister callback for an interrupt + * + * If an interrupt has already happened, then the callback function is + * called from within this function, hence it's not possible for + * interrupts to be lost. + * + * @param req request handle + * @param func the callback function or NULL for unregister + * @param data user data passed to the callback function + */ + void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, + void *data); -/** - * Destroy a session - * - * @param se the session - */ -void fuse_session_destroy(struct fuse_session *se); + /** + * Check if a request has already been interrupted + * + * @param req request handle + * @return 1 if the request has been interrupted, 0 otherwise + */ + int fuse_req_interrupted(fuse_req_t req); -/** - * Exit a session - * - * @param se the session - */ -void fuse_session_exit(struct fuse_session *se); + /* ----------------------------------------------------------- * + * Filesystem setup * + * ----------------------------------------------------------- */ -/** - * Reset the exited status of a session - * - * @param se the session - */ -void fuse_session_reset(struct fuse_session *se); + /* Deprecated, don't use */ + int fuse_lowlevel_is_lib_option(const char *opt); -/** - * Query the exited status of a session - * - * @param se the session - * @return 1 if exited, 0 if not exited - */ -int fuse_session_exited(struct fuse_session *se); + /** + * Create a low level session + * + * @param args argument vector + * @param op the low level filesystem operations + * @param op_size sizeof(struct fuse_lowlevel_ops) + * @param userdata user data + * @return the created session object, or NULL on failure + */ + struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); + + /* ----------------------------------------------------------- * + * Session interface * + * ----------------------------------------------------------- */ + + void + fuse_ll_process_buf(void *data, + const struct fuse_buf *buf, + fuse_chan_t *ch); + int + fuse_ll_receive_buf(struct fuse_session *se, + struct fuse_buf *buf, + fuse_chan_t *ch); + int + fuse_ll_receive_buf2(struct fuse_buf *buf, + fuse_chan_t *ch); + + int + fuse_ll_receive_buf3(struct fuse_session *se, + struct fuse_buf *buf, + fuse_chan_t *ch); -/** - * Get the user data provided to the session - * - * @param se the session - * @return the user data - */ -void *fuse_session_data(struct fuse_session *se); -/** - * Enter a single threaded event loop - * - * @param se the session - * @return 0 on success, -1 on error - */ -int fuse_session_loop(struct fuse_session *se); + /** + * Session operations + * + * This is used in session creation + */ + struct fuse_session_ops { + /** + * 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); + }; -/** - * Enter a multi-threaded event loop - * - * @param se the session - * @return 0 on success, -1 on error - */ -int fuse_session_loop_mt(struct fuse_session *se, const int threads); + /** + * Create a new session + * + * @param op session operations + * @param data user data + * @return new session object, or NULL on failure + */ + struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); -/* ----------------------------------------------------------- * - * Channel interface * - * ----------------------------------------------------------- */ + /** + * Process a raw request + * + * @param se the session + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received + */ + void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, + fuse_chan_t *ch); -/** - * Channel operations - * - * This is used in channel creation - */ -struct fuse_chan_ops { - /** - * Hook for receiving a raw request - * - * @param ch pointer to the channel - * @param buf the buffer to store the request in - * @param size the size of the buffer - * @return the actual size of the raw request, or -1 on error - */ - int (*receive)(struct fuse_chan **chp, char *buf, size_t size); - - /** - * Hook for sending a raw reply - * - * A return value of -ENOENT means, that the request was - * interrupted, and the reply was discarded - * - * @param ch the channel - * @param iov vector of blocks - * @param count the number of blocks in vector - * @return zero on success, -errno on failure - */ - int (*send)(struct fuse_chan *ch, const struct iovec iov[], - size_t count); - - /** - * Destroy the channel - * - * @param ch the channel - */ - void (*destroy)(struct fuse_chan *ch); -}; - -/** - * 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); + /** + * Process a raw request supplied in a generic buffer + * + * This is a more generic version of fuse_session_process(). The + * fuse_buf may contain a memory buffer or a pipe file descriptor. + * + * @param se the session + * @param buf the fuse_buf containing the request + * @param ch channel on which the request was received + */ + void fuse_session_process_buf(struct fuse_session *se, + const struct fuse_buf *buf, fuse_chan_t *ch); -/** - * Query the file descriptor of the channel - * - * @param ch the channel - * @return the file descriptor passed to fuse_chan_new() - */ -int fuse_chan_fd(struct fuse_chan *ch); + /** + * Receive a raw request supplied in a generic buffer + * + * This is a more generic version of fuse_chan_recv(). The fuse_buf + * supplied to this function contains a suitably allocated memory + * buffer. This may be overwritten with a file descriptor buffer. + * + * @param se the session + * @param buf the fuse_buf to store the request in + * @param chp pointer to the channel + * @return the actual size of the raw request, or -errno on error + */ + int fuse_session_receive_buf(struct fuse_session *se, + struct fuse_buf *buf, + fuse_chan_t *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); + /** + * Destroy a session + * + * @param se the session + */ + void fuse_session_destroy(struct fuse_session *se); -/** - * 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); + /** + * Exit a session + * + * @param se the session + */ + void fuse_session_exit(struct fuse_session *se); -/** - * 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); + /** + * Reset the exited status of a session + * + * @param se the session + */ + void fuse_session_reset(struct fuse_session *se); -/** - * Receive a raw request - * - * A return value of -ENODEV means, that the filesystem was unmounted - * - * @param ch pointer to the channel - * @param buf the buffer to store the request in - * @param size the size of the buffer - * @return the actual size of the raw request, or -errno on error - */ -int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); + /** + * Query the exited status of a session + * + * @param se the session + * @return 1 if exited, 0 if not exited + */ + int fuse_session_exited(struct fuse_session *se); -/** - * 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); + /** + * Get the user data provided to the session + * + * @param se the session + * @return the user data + */ + void *fuse_session_data(struct fuse_session *se); -/** - * Destroy a channel - * - * @param ch the channel - */ -void fuse_chan_destroy(struct fuse_chan *ch); + /** + * Enter a multi-threaded event loop + * + * @param se the session + * @return 0 on success, -1 on error + */ + int fuse_session_loop_mt(struct fuse_session *se, const int threads); -/* ----------------------------------------------------------- * - * Compatibility stuff * - * ----------------------------------------------------------- */ + /* ----------------------------------------------------------- * + * Compatibility stuff * + * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # include "fuse_lowlevel_compat.h" diff --git a/libfuse/include/fuse_lowlevel_compat.h b/libfuse/include/fuse_lowlevel_compat.h index 8de220b9..1231da75 100644 --- a/libfuse/include/fuse_lowlevel_compat.h +++ b/libfuse/include/fuse_lowlevel_compat.h @@ -141,15 +141,4 @@ struct fuse_session *fuse_lowlevel_new_compat(const char *opts, #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); +int fuse_chan_receive(fuse_chan_t *ch, char *buf, size_t size); diff --git a/libfuse/lib/Makefile.am b/libfuse/lib/Makefile.am deleted file mode 100644 index 7c8104a7..00000000 --- a/libfuse/lib/Makefile.am +++ /dev/null @@ -1,42 +0,0 @@ -## Process this file with automake to produce Makefile.in - -AUTOMAKE_OPTIONS = subdir-objects -AM_CPPFLAGS = -I$(top_srcdir)/include -DFUSERMOUNT_DIR=\"$(bindir)\" \ - -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=26 - -lib_LTLIBRARIES = libfuse.la libulockmgr.la - -if BSD -mount_source = mount_bsd.c -else -mount_source = mount.c mount_util.c mount_util.h -endif - -libfuse_la_SOURCES = \ - fuse.c \ - fuse_i.h \ - fuse_kern_chan.c \ - fuse_loop.c \ - fuse_loop_mt.c \ - fuse_lowlevel.c \ - fuse_misc.h \ - fuse_mt.c \ - fuse_opt.c \ - fuse_session.c \ - fuse_signals.c \ - buffer.c \ - cuse_lowlevel.c \ - helper.c \ - $(mount_source) - -libfuse_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 2:9:7 \ - -Wl,--version-script,$(srcdir)/fuse_versionscript - -if NETBSD -libfuse_la_LIBADD = -lperfuse -lpuffs -endif - -libulockmgr_la_SOURCES = ulockmgr.c -libulockmgr_la_LDFLAGS = -pthread -version-number 1:0:1 - -EXTRA_DIST = fuse_versionscript diff --git a/libfuse/lib/buffer.c b/libfuse/lib/buffer.c index 40e426ec..50ed9e7d 100644 --- a/libfuse/lib/buffer.c +++ b/libfuse/lib/buffer.c @@ -18,140 +18,140 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv) { - size_t i; - size_t size = 0; + size_t i; + size_t size = 0; - for (i = 0; i < bufv->count; i++) { - if (bufv->buf[i].size == SIZE_MAX) - size = SIZE_MAX; - else - size += bufv->buf[i].size; - } + for (i = 0; i < bufv->count; i++) { + if (bufv->buf[i].size == SIZE_MAX) + size = SIZE_MAX; + else + size += bufv->buf[i].size; + } - return size; + return size; } static size_t min_size(size_t s1, size_t s2) { - return s1 < s2 ? s1 : s2; + return s1 < s2 ? s1 : s2; } static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len) { - ssize_t res = 0; - size_t copied = 0; - - while (len) { - if (dst->flags & FUSE_BUF_FD_SEEK) { - res = pwrite(dst->fd, src->mem + src_off, len, - dst->pos + dst_off); - } else { - res = write(dst->fd, src->mem + src_off, len); - } - if (res == -1) { - if (!copied) - return -errno; - break; - } - if (res == 0) - break; - - copied += res; - if (!(dst->flags & FUSE_BUF_FD_RETRY)) - break; - - src_off += res; - dst_off += res; - len -= res; - } - - return copied; + ssize_t res = 0; + size_t copied = 0; + + while (len) { + if (dst->flags & FUSE_BUF_FD_SEEK) { + res = pwrite(dst->fd, src->mem + src_off, len, + dst->pos + dst_off); + } else { + res = write(dst->fd, src->mem + src_off, len); + } + if (res == -1) { + if (!copied) + return -errno; + break; + } + if (res == 0) + break; + + copied += res; + if (!(dst->flags & FUSE_BUF_FD_RETRY)) + break; + + src_off += res; + dst_off += res; + len -= res; + } + + return copied; } static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len) { - ssize_t res = 0; - size_t copied = 0; - - while (len) { - if (src->flags & FUSE_BUF_FD_SEEK) { - res = pread(src->fd, dst->mem + dst_off, len, - src->pos + src_off); - } else { - res = read(src->fd, dst->mem + dst_off, len); - } - if (res == -1) { - if (!copied) - return -errno; - break; - } - if (res == 0) - break; - - copied += res; - if (!(src->flags & FUSE_BUF_FD_RETRY)) - break; - - dst_off += res; - src_off += res; - len -= res; - } - - return copied; + ssize_t res = 0; + size_t copied = 0; + + while (len) { + if (src->flags & FUSE_BUF_FD_SEEK) { + res = pread(src->fd, dst->mem + dst_off, len, + src->pos + src_off); + } else { + res = read(src->fd, dst->mem + dst_off, len); + } + if (res == -1) { + if (!copied) + return -errno; + break; + } + if (res == 0) + break; + + copied += res; + if (!(src->flags & FUSE_BUF_FD_RETRY)) + break; + + dst_off += res; + src_off += res; + len -= res; + } + + return copied; } static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len) { - char buf[4096]; - struct fuse_buf tmp = { - .size = sizeof(buf), - .flags = 0, - }; - ssize_t res; - size_t copied = 0; - - tmp.mem = buf; - - while (len) { - size_t this_len = min_size(tmp.size, len); - size_t read_len; - - res = fuse_buf_read(&tmp, 0, src, src_off, this_len); - if (res < 0) { - if (!copied) - return res; - break; - } - if (res == 0) - break; - - read_len = res; - res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len); - if (res < 0) { - if (!copied) - return res; - break; - } - if (res == 0) - break; - - copied += res; - - if (res < this_len) - break; - - dst_off += res; - src_off += res; - len -= res; - } - - return copied; + char buf[4096]; + struct fuse_buf tmp = { + .size = sizeof(buf), + .flags = 0, + }; + ssize_t res; + size_t copied = 0; + + tmp.mem = buf; + + while (len) { + size_t this_len = min_size(tmp.size, len); + size_t read_len; + + res = fuse_buf_read(&tmp, 0, src, src_off, this_len); + if (res < 0) { + if (!copied) + return res; + break; + } + if (res == 0) + break; + + read_len = res; + res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len); + if (res < 0) { + if (!copied) + return res; + break; + } + if (res == 0) + break; + + copied += res; + + if (res < this_len) + break; + + dst_off += res; + src_off += res; + len -= res; + } + + return copied; } #ifdef HAVE_SPLICE @@ -159,64 +159,64 @@ static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len, enum fuse_buf_copy_flags flags) { - int splice_flags = 0; - off_t *srcpos = NULL; - off_t *dstpos = NULL; - off_t srcpos_val; - off_t dstpos_val; - ssize_t res; - size_t copied = 0; - - if (flags & FUSE_BUF_SPLICE_MOVE) - splice_flags |= SPLICE_F_MOVE; - if (flags & FUSE_BUF_SPLICE_NONBLOCK) - splice_flags |= SPLICE_F_NONBLOCK; - - if (src->flags & FUSE_BUF_FD_SEEK) { - srcpos_val = src->pos + src_off; - srcpos = &srcpos_val; - } - if (dst->flags & FUSE_BUF_FD_SEEK) { - dstpos_val = dst->pos + dst_off; - dstpos = &dstpos_val; - } - - while (len) { - res = splice(src->fd, srcpos, dst->fd, dstpos, len, - splice_flags); - if (res == -1) { - if (copied) - break; - - if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE)) - return -errno; - - /* Maybe splice is not supported for this combination */ - return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, - len); - } - if (res == 0) - break; - - copied += res; - if (!(src->flags & FUSE_BUF_FD_RETRY) && - !(dst->flags & FUSE_BUF_FD_RETRY)) { - break; - } - - len -= res; - } - - return copied; + int splice_flags = 0; + off_t *srcpos = NULL; + off_t *dstpos = NULL; + off_t srcpos_val; + off_t dstpos_val; + ssize_t res; + size_t copied = 0; + + if (flags & FUSE_BUF_SPLICE_MOVE) + splice_flags |= SPLICE_F_MOVE; + if (flags & FUSE_BUF_SPLICE_NONBLOCK) + splice_flags |= SPLICE_F_NONBLOCK; + + if (src->flags & FUSE_BUF_FD_SEEK) { + srcpos_val = src->pos + src_off; + srcpos = &srcpos_val; + } + if (dst->flags & FUSE_BUF_FD_SEEK) { + dstpos_val = dst->pos + dst_off; + dstpos = &dstpos_val; + } + + while (len) { + res = splice(src->fd, srcpos, dst->fd, dstpos, len, + splice_flags); + if (res == -1) { + if (copied) + break; + + if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE)) + return -errno; + + /* Maybe splice is not supported for this combination */ + return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, + len); + } + if (res == 0) + break; + + copied += res; + if (!(src->flags & FUSE_BUF_FD_RETRY) && + !(dst->flags & FUSE_BUF_FD_RETRY)) { + break; + } + + len -= res; + } + + return copied; } #else static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len, enum fuse_buf_copy_flags flags) { - (void) flags; + (void) flags; - return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); + return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); } #endif @@ -225,94 +225,94 @@ static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len, enum fuse_buf_copy_flags flags) { - int src_is_fd = src->flags & FUSE_BUF_IS_FD; - int dst_is_fd = dst->flags & FUSE_BUF_IS_FD; - - if (!src_is_fd && !dst_is_fd) { - char *dstmem = dst->mem + dst_off; - char *srcmem = src->mem + src_off; - - if (dstmem != srcmem) { - if (dstmem + len <= srcmem || srcmem + len <= dstmem) - memcpy(dstmem, srcmem, len); - else - memmove(dstmem, srcmem, len); - } - - return len; - } else if (!src_is_fd) { - return fuse_buf_write(dst, dst_off, src, src_off, len); - } else if (!dst_is_fd) { - return fuse_buf_read(dst, dst_off, src, src_off, len); - } else if (flags & FUSE_BUF_NO_SPLICE) { - return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); - } else { - return fuse_buf_splice(dst, dst_off, src, src_off, len, flags); - } + int src_is_fd = src->flags & FUSE_BUF_IS_FD; + int dst_is_fd = dst->flags & FUSE_BUF_IS_FD; + + if (!src_is_fd && !dst_is_fd) { + char *dstmem = dst->mem + dst_off; + char *srcmem = src->mem + src_off; + + if (dstmem != srcmem) { + if (dstmem + len <= srcmem || srcmem + len <= dstmem) + memcpy(dstmem, srcmem, len); + else + memmove(dstmem, srcmem, len); + } + + return len; + } else if (!src_is_fd) { + return fuse_buf_write(dst, dst_off, src, src_off, len); + } else if (!dst_is_fd) { + return fuse_buf_read(dst, dst_off, src, src_off, len); + } else if (flags & FUSE_BUF_NO_SPLICE) { + return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); + } else { + return fuse_buf_splice(dst, dst_off, src, src_off, len, flags); + } } static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv) { - if (bufv->idx < bufv->count) - return &bufv->buf[bufv->idx]; - else - return NULL; + if (bufv->idx < bufv->count) + return &bufv->buf[bufv->idx]; + else + return NULL; } static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len) { - const struct fuse_buf *buf = fuse_bufvec_current(bufv); - - bufv->off += len; - assert(bufv->off <= buf->size); - if (bufv->off == buf->size) { - assert(bufv->idx < bufv->count); - bufv->idx++; - if (bufv->idx == bufv->count) - return 0; - bufv->off = 0; - } - return 1; + const struct fuse_buf *buf = fuse_bufvec_current(bufv); + + bufv->off += len; + assert(bufv->off <= buf->size); + if (bufv->off == buf->size) { + assert(bufv->idx < bufv->count); + bufv->idx++; + if (bufv->idx == bufv->count) + return 0; + bufv->off = 0; + } + return 1; } ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv, enum fuse_buf_copy_flags flags) { - size_t copied = 0; - - if (dstv == srcv) - return fuse_buf_size(dstv); - - for (;;) { - const struct fuse_buf *src = fuse_bufvec_current(srcv); - const struct fuse_buf *dst = fuse_bufvec_current(dstv); - size_t src_len; - size_t dst_len; - size_t len; - ssize_t res; - - if (src == NULL || dst == NULL) - break; - - src_len = src->size - srcv->off; - dst_len = dst->size - dstv->off; - len = min_size(src_len, dst_len); - - res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags); - if (res < 0) { - if (!copied) - return res; - break; - } - copied += res; - - if (!fuse_bufvec_advance(srcv, res) || - !fuse_bufvec_advance(dstv, res)) - break; - - if (res < len) - break; - } - - return copied; + size_t copied = 0; + + if (dstv == srcv) + return fuse_buf_size(dstv); + + for (;;) { + const struct fuse_buf *src = fuse_bufvec_current(srcv); + const struct fuse_buf *dst = fuse_bufvec_current(dstv); + size_t src_len; + size_t dst_len; + size_t len; + ssize_t res; + + if (src == NULL || dst == NULL) + break; + + src_len = src->size - srcv->off; + dst_len = dst->size - dstv->off; + len = min_size(src_len, dst_len); + + res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags); + if (res < 0) { + if (!copied) + return res; + break; + } + copied += res; + + if (!fuse_bufvec_advance(srcv, res) || + !fuse_bufvec_advance(dstv, res)) + break; + + if (res < len) + break; + } + + return copied; } diff --git a/libfuse/lib/cuse_lowlevel.c b/libfuse/lib/cuse_lowlevel.c deleted file mode 100644 index b3a535f1..00000000 --- a/libfuse/lib/cuse_lowlevel.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - CUSE: Character device in Userspace - Copyright (C) 2008 SUSE Linux Products GmbH - Copyright (C) 2008 Tejun Heo - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. -*/ - -#include "cuse_lowlevel.h" -#include "fuse_kernel.h" -#include "fuse_i.h" -#include "fuse_opt.h" -#include "fuse_misc.h" - -#include -#include -#include -#include -#include -#include - -struct cuse_data { - struct cuse_lowlevel_ops clop; - unsigned max_read; - unsigned dev_major; - unsigned dev_minor; - unsigned flags; - unsigned dev_info_len; - char dev_info[]; -}; - -static struct cuse_lowlevel_ops *req_clop(fuse_req_t req) -{ - return &req->f->cuse_data->clop; -} - -static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->open(req, fi); -} - -static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->read(req, size, off, fi); -} - -static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->write(req, buf, size, off, fi); -} - -static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->flush(req, fi); -} - -static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->release(req, fi); -} - -static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi) -{ - (void)ino; - req_clop(req)->fsync(req, datasync, fi); -} - -static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz) -{ - (void)ino; - req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz, - out_bufsz); -} - -static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, struct fuse_pollhandle *ph) -{ - (void)ino; - req_clop(req)->poll(req, fi, ph); -} - -static size_t cuse_pack_info(int argc, const char **argv, char *buf) -{ - size_t size = 0; - int i; - - for (i = 0; i < argc; i++) { - size_t len; - - len = strlen(argv[i]) + 1; - size += len; - if (buf) { - memcpy(buf, argv[i], len); - buf += len; - } - } - - return size; -} - -static struct cuse_data *cuse_prep_data(const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop) -{ - struct cuse_data *cd; - size_t dev_info_len; - - dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, - NULL); - - if (dev_info_len > CUSE_INIT_INFO_MAX) { - fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n", - dev_info_len, CUSE_INIT_INFO_MAX); - return NULL; - } - - cd = calloc(1, sizeof(*cd) + dev_info_len); - if (!cd) { - fprintf(stderr, "cuse: failed to allocate cuse_data\n"); - return NULL; - } - - memcpy(&cd->clop, clop, sizeof(cd->clop)); - cd->max_read = 131072; - cd->dev_major = ci->dev_major; - cd->dev_minor = ci->dev_minor; - cd->dev_info_len = dev_info_len; - cd->flags = ci->flags; - cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info); - - return cd; -} - -struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - void *userdata) -{ - struct fuse_lowlevel_ops lop; - struct cuse_data *cd; - struct fuse_session *se; - struct fuse_ll *ll; - - cd = cuse_prep_data(ci, clop); - if (!cd) - return NULL; - - memset(&lop, 0, sizeof(lop)); - lop.init = clop->init; - lop.destroy = clop->destroy; - lop.open = clop->open ? cuse_fll_open : NULL; - lop.read = clop->read ? cuse_fll_read : NULL; - lop.write = clop->write ? cuse_fll_write : NULL; - lop.flush = clop->flush ? cuse_fll_flush : NULL; - lop.release = clop->release ? cuse_fll_release : NULL; - lop.fsync = clop->fsync ? cuse_fll_fsync : NULL; - lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL; - lop.poll = clop->poll ? cuse_fll_poll : NULL; - - se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata); - if (!se) { - free(cd); - return NULL; - } - ll = se->data; - ll->cuse_data = cd; - - return se; -} - -static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg, - char *dev_info, unsigned dev_info_len) -{ - struct iovec iov[3]; - - iov[1].iov_base = arg; - iov[1].iov_len = sizeof(struct cuse_init_out); - iov[2].iov_base = dev_info; - iov[2].iov_len = dev_info_len; - - return fuse_send_reply_iov_nofree(req, 0, iov, 3); -} - -void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) -{ - struct fuse_init_in *arg = (struct fuse_init_in *) inarg; - struct cuse_init_out outarg; - struct fuse_ll *f = req->f; - struct cuse_data *cd = f->cuse_data; - size_t bufsize = fuse_chan_bufsize(req->ch); - struct cuse_lowlevel_ops *clop = req_clop(req); - - (void) nodeid; - if (f->debug) { - fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor); - fprintf(stderr, "flags=0x%08x\n", arg->flags); - } - f->conn.proto_major = arg->major; - f->conn.proto_minor = arg->minor; - f->conn.capable = 0; - f->conn.want = 0; - - if (arg->major < 7) { - fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); - return; - } - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fprintf(stderr, "cuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - - bufsize -= 4096; - if (bufsize < f->conn.max_write) - f->conn.max_write = bufsize; - - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata, &f->conn); - - memset(&outarg, 0, sizeof(outarg)); - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - outarg.flags = cd->flags; - outarg.max_read = cd->max_read; - outarg.max_write = f->conn.max_write; - outarg.dev_major = cd->dev_major; - outarg.dev_minor = cd->dev_minor; - - if (f->debug) { - fprintf(stderr, " CUSE_INIT: %u.%u\n", - outarg.major, outarg.minor); - fprintf(stderr, " flags=0x%08x\n", outarg.flags); - fprintf(stderr, " max_read=0x%08x\n", outarg.max_read); - fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); - fprintf(stderr, " dev_major=%u\n", outarg.dev_major); - fprintf(stderr, " dev_minor=%u\n", outarg.dev_minor); - fprintf(stderr, " dev_info: %.*s\n", cd->dev_info_len, - cd->dev_info); - } - - cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len); - - if (clop->init_done) - clop->init_done(f->userdata); - - fuse_free_req(req); -} - -struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], - const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, - int *multithreaded, void *userdata) -{ - const char *devname = "/dev/cuse"; - static const struct fuse_opt kill_subtype_opts[] = { - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_END - }; - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_session *se; - struct fuse_chan *ch; - int fd; - int foreground; - int res; - - res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground); - if (res == -1) - goto err_args; - - res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL); - if (res == -1) - goto err_args; - - /* - * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos - * would ensue. - */ - do { - fd = open("/dev/null", O_RDWR); - if (fd > 2) - close(fd); - } while (fd >= 0 && fd <= 2); - - se = cuse_lowlevel_new(&args, ci, clop, userdata); - fuse_opt_free_args(&args); - if (se == NULL) - goto err_args; - - fd = open(devname, O_RDWR); - if (fd == -1) { - if (errno == ENODEV || errno == ENOENT) - fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n"); - else - fprintf(stderr, "cuse: failed to open %s: %s\n", - devname, strerror(errno)); - goto err_se; - } - - ch = fuse_kern_chan_new(fd); - if (!ch) { - close(fd); - goto err_se; - } - - fuse_session_add_chan(se, ch); - - res = fuse_set_signal_handlers(se); - if (res == -1) - goto err_se; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_sig; - - return se; - -err_sig: - fuse_remove_signal_handlers(se); -err_se: - fuse_session_destroy(se); -err_args: - fuse_opt_free_args(&args); - return NULL; -} - -void cuse_lowlevel_teardown(struct fuse_session *se) -{ - fuse_remove_signal_handlers(se); - fuse_session_destroy(se); -} - -int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, - const struct cuse_lowlevel_ops *clop, void *userdata) -{ - struct fuse_session *se; - int multithreaded; - int res; - - se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded, - userdata); - if (se == NULL) - return 1; - - if (multithreaded) - res = fuse_session_loop_mt(se, 0); - else - res = fuse_session_loop(se); - - cuse_lowlevel_teardown(se); - if (res == -1) - return 1; - - return 0; -} diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index 7504b44f..d49a80a2 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -11,14 +11,15 @@ #define _GNU_SOURCE #include "config.h" + +#include "fuse_chan.h" +#include "fuse_common_compat.h" +#include "fuse_dirents.h" #include "fuse_i.h" +#include "fuse_kernel.h" #include "fuse_lowlevel.h" -#include "fuse_opt.h" #include "fuse_misc.h" -#include "fuse_common_compat.h" -#include "fuse_compat.h" -#include "fuse_kernel.h" -#include "fuse_dirents.h" +#include "fuse_opt.h" #include #include @@ -54,73 +55,74 @@ #define NODE_TABLE_MIN_SIZE 8192 -struct fuse_config { - unsigned int uid; - unsigned int gid; - unsigned int umask; - double entry_timeout; - double negative_timeout; - double attr_timeout; - int remember; - int nopath; - int debug; - int use_ino; - int set_mode; - int set_uid; - int set_gid; - int intr; - int intr_signal; - int help; - int threads; +struct fuse_config +{ + unsigned int uid; + unsigned int gid; + unsigned int umask; + double entry_timeout; + double negative_timeout; + double attr_timeout; + int remember; + int nopath; + int debug; + int use_ino; + int set_mode; + int set_uid; + int set_gid; + int intr; + int intr_signal; + int help; + int threads; }; -struct fuse_fs { - struct fuse_operations op; - void *user_data; - int compat; - int debug; +struct fuse_fs +{ + struct fuse_operations op; + void *user_data; + int debug; }; struct lock_queue_element { - struct lock_queue_element *next; - pthread_cond_t cond; - fuse_ino_t nodeid1; - const char *name1; - char **path1; - struct node **wnode1; - fuse_ino_t nodeid2; - const char *name2; - char **path2; - struct node **wnode2; - int err; - bool first_locked : 1; - bool second_locked : 1; - bool done : 1; + struct lock_queue_element *next; + pthread_cond_t cond; + fuse_ino_t nodeid1; + const char *name1; + char **path1; + struct node **wnode1; + fuse_ino_t nodeid2; + const char *name2; + char **path2; + struct node **wnode2; + int err; + bool first_locked : 1; + bool second_locked : 1; + bool done : 1; }; struct node_table { - struct node **array; - size_t use; - size_t size; - size_t split; + struct node **array; + size_t use; + size_t size; + size_t split; }; -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) #define list_entry(ptr, type, member) \ - container_of(ptr, type, member) + container_of(ptr, type, member) struct list_head { - struct list_head *next; - struct list_head *prev; + struct list_head *next; + struct list_head *prev; }; struct node_slab { - struct list_head list; /* must be the first member */ - struct list_head freelist; - int used; + struct list_head list; /* must be the first member */ + struct list_head freelist; + int used; }; struct fuse @@ -146,12 +148,12 @@ struct fuse }; struct lock { - int type; - off_t start; - off_t end; - pid_t pid; - uint64_t owner; - struct lock *next; + int type; + off_t start; + off_t end; + pid_t pid; + uint64_t owner; + struct lock *next; }; struct node @@ -178,9 +180,9 @@ struct node #define TREELOCK_WAIT_OFFSET INT_MIN struct node_lru { - struct node node; - struct list_head lru; - struct timespec forget_time; + struct node node; + struct list_head lru; + struct timespec forget_time; }; struct fuse_dh @@ -191,8 +193,8 @@ struct fuse_dh }; struct fuse_context_i { - struct fuse_context ctx; - fuse_req_t req; + struct fuse_context ctx; + fuse_req_t req; }; static pthread_key_t fuse_context_key; @@ -201,187 +203,187 @@ static int fuse_context_ref; static void init_list_head(struct list_head *list) { - list->next = list; - list->prev = list; + list->next = list; + list->prev = list; } static int list_empty(const struct list_head *head) { - return head->next == head; + return head->next == head; } static void list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } static inline void list_add_head(struct list_head *new, struct list_head *head) { - list_add(new, head, head->next); + list_add(new, head, head->next); } static inline void list_add_tail(struct list_head *new, struct list_head *head) { - list_add(new, head->prev, head); + list_add(new, head->prev, head); } static inline void list_del(struct list_head *entry) { - struct list_head *prev = entry->prev; - struct list_head *next = entry->next; + struct list_head *prev = entry->prev; + struct list_head *next = entry->next; - next->prev = prev; - prev->next = next; + next->prev = prev; + prev->next = next; } static inline int lru_enabled(struct fuse *f) { - return f->conf.remember > 0; + return f->conf.remember > 0; } static struct node_lru *node_lru(struct node *node) { - return (struct node_lru *) node; + return (struct node_lru *) node; } static size_t get_node_size(struct fuse *f) { - if (lru_enabled(f)) - return sizeof(struct node_lru); - else - return sizeof(struct node); + if (lru_enabled(f)) + return sizeof(struct node_lru); + else + return sizeof(struct node); } #ifdef FUSE_NODE_SLAB static struct node_slab *list_to_slab(struct list_head *head) { - return (struct node_slab *) head; + return (struct node_slab *) head; } static struct node_slab *node_to_slab(struct fuse *f, struct node *node) { - return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); + return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); } static int alloc_slab(struct fuse *f) { - void *mem; - struct node_slab *slab; - char *start; - size_t num; - size_t i; - size_t node_size = get_node_size(f); + void *mem; + struct node_slab *slab; + char *start; + size_t num; + size_t i; + size_t node_size = get_node_size(f); - mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (mem == MAP_FAILED) - return -1; + if (mem == MAP_FAILED) + return -1; - slab = mem; - init_list_head(&slab->freelist); - slab->used = 0; - num = (f->pagesize - sizeof(struct node_slab)) / node_size; + slab = mem; + init_list_head(&slab->freelist); + slab->used = 0; + num = (f->pagesize - sizeof(struct node_slab)) / node_size; - start = (char *) mem + f->pagesize - num * node_size; - for (i = 0; i < num; i++) { - struct list_head *n; + start = (char *) mem + f->pagesize - num * node_size; + for (i = 0; i < num; i++) { + struct list_head *n; - n = (struct list_head *) (start + i * node_size); - list_add_tail(n, &slab->freelist); - } - list_add_tail(&slab->list, &f->partial_slabs); + n = (struct list_head *) (start + i * node_size); + list_add_tail(n, &slab->freelist); + } + list_add_tail(&slab->list, &f->partial_slabs); - return 0; + return 0; } static struct node *alloc_node(struct fuse *f) { - struct node_slab *slab; - struct list_head *node; + struct node_slab *slab; + struct list_head *node; - if (list_empty(&f->partial_slabs)) { - int res = alloc_slab(f); - if (res != 0) - return NULL; - } - slab = list_to_slab(f->partial_slabs.next); - slab->used++; - node = slab->freelist.next; - list_del(node); - if (list_empty(&slab->freelist)) { - list_del(&slab->list); - list_add_tail(&slab->list, &f->full_slabs); - } - memset(node, 0, sizeof(struct node)); + if (list_empty(&f->partial_slabs)) { + int res = alloc_slab(f); + if (res != 0) + return NULL; + } + slab = list_to_slab(f->partial_slabs.next); + slab->used++; + node = slab->freelist.next; + list_del(node); + if (list_empty(&slab->freelist)) { + list_del(&slab->list); + list_add_tail(&slab->list, &f->full_slabs); + } + memset(node, 0, sizeof(struct node)); - return (struct node *) node; + return (struct node *) node; } static void free_slab(struct fuse *f, struct node_slab *slab) { - int res; + int res; - list_del(&slab->list); - res = munmap(slab, f->pagesize); - if (res == -1) - fprintf(stderr, "fuse warning: munmap(%p) failed\n", slab); + list_del(&slab->list); + res = munmap(slab, f->pagesize); + if (res == -1) + fprintf(stderr, "fuse warning: munmap(%p) failed\n", slab); } static void free_node_mem(struct fuse *f, struct node *node) { - struct node_slab *slab = node_to_slab(f, node); - struct list_head *n = (struct list_head *) node; + struct node_slab *slab = node_to_slab(f, node); + struct list_head *n = (struct list_head *) node; - slab->used--; - if (slab->used) { - if (list_empty(&slab->freelist)) { - list_del(&slab->list); - list_add_tail(&slab->list, &f->partial_slabs); - } - list_add_head(n, &slab->freelist); - } else { - free_slab(f, slab); - } + slab->used--; + if (slab->used) { + if (list_empty(&slab->freelist)) { + list_del(&slab->list); + list_add_tail(&slab->list, &f->partial_slabs); + } + list_add_head(n, &slab->freelist); + } else { + free_slab(f, slab); + } } #else static struct node *alloc_node(struct fuse *f) { - return (struct node *) calloc(1, get_node_size(f)); + return (struct node *) calloc(1, get_node_size(f)); } static void free_node_mem(struct fuse *f, struct node *node) { - (void) f; - free(node); + (void) f; + free(node); } #endif static size_t id_hash(struct fuse *f, fuse_ino_t ino) { - uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; - uint64_t oldhash = hash % (f->id_table.size / 2); + uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; + uint64_t oldhash = hash % (f->id_table.size / 2); - if (oldhash >= f->id_table.split) - return oldhash; - else - return hash; + if (oldhash >= f->id_table.split) + return oldhash; + else + return hash; } static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) { - size_t hash = id_hash(f, nodeid); - struct node *node; + size_t hash = id_hash(f, nodeid); + struct node *node; - for (node = f->id_table.array[hash]; node != NULL; node = node->id_next) - if (node->nodeid == nodeid) - return node; + for (node = f->id_table.array[hash]; node != NULL; node = node->id_next) + if (node->nodeid == nodeid) + return node; - return NULL; + return NULL; } static @@ -403,22 +405,22 @@ get_node(struct fuse *f, static void curr_time(struct timespec *now); static double diff_timespec(const struct timespec *t1, - const struct timespec *t2); + const struct timespec *t2); static void remove_node_lru(struct node *node) { - struct node_lru *lnode = node_lru(node); - list_del(&lnode->lru); - init_list_head(&lnode->lru); + struct node_lru *lnode = node_lru(node); + list_del(&lnode->lru); + init_list_head(&lnode->lru); } static void set_forget_time(struct fuse *f, struct node *node) { - struct node_lru *lnode = node_lru(node); + struct node_lru *lnode = node_lru(node); - list_del(&lnode->lru); - list_add_tail(&lnode->lru, &f->lru_table); - curr_time(&lnode->forget_time); + list_del(&lnode->lru); + list_add_tail(&lnode->lru, &f->lru_table); + curr_time(&lnode->forget_time); } static @@ -437,266 +439,266 @@ free_node(struct fuse *f_, static void node_table_reduce(struct node_table *t) { - size_t newsize = t->size / 2; - void *newarray; + size_t newsize = t->size / 2; + void *newarray; - if (newsize < NODE_TABLE_MIN_SIZE) - return; + if (newsize < NODE_TABLE_MIN_SIZE) + return; - newarray = realloc(t->array, sizeof(struct node *) * newsize); - if (newarray != NULL) - t->array = newarray; + newarray = realloc(t->array, sizeof(struct node *) * newsize); + if (newarray != NULL) + t->array = newarray; - t->size = newsize; - t->split = t->size / 2; + t->size = newsize; + t->split = t->size / 2; } static void remerge_id(struct fuse *f) { - struct node_table *t = &f->id_table; - int iter; + struct node_table *t = &f->id_table; + int iter; - if (t->split == 0) - node_table_reduce(t); + if (t->split == 0) + node_table_reduce(t); - for (iter = 8; t->split > 0 && iter; iter--) { - struct node **upper; + for (iter = 8; t->split > 0 && iter; iter--) { + struct node **upper; - t->split--; - upper = &t->array[t->split + t->size / 2]; - if (*upper) { - struct node **nodep; + t->split--; + upper = &t->array[t->split + t->size / 2]; + if (*upper) { + struct node **nodep; - for (nodep = &t->array[t->split]; *nodep; - nodep = &(*nodep)->id_next); + for (nodep = &t->array[t->split]; *nodep; + nodep = &(*nodep)->id_next); - *nodep = *upper; - *upper = NULL; - break; - } - } + *nodep = *upper; + *upper = NULL; + break; + } + } } static void unhash_id(struct fuse *f, struct node *node) { - struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; + struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; - for (; *nodep != NULL; nodep = &(*nodep)->id_next) - if (*nodep == node) { - *nodep = node->id_next; - f->id_table.use--; + for (; *nodep != NULL; nodep = &(*nodep)->id_next) + if (*nodep == node) { + *nodep = node->id_next; + f->id_table.use--; - if(f->id_table.use < f->id_table.size / 4) - remerge_id(f); - return; - } + if(f->id_table.use < f->id_table.size / 4) + remerge_id(f); + return; + } } static int node_table_resize(struct node_table *t) { - size_t newsize = t->size * 2; - void *newarray; + size_t newsize = t->size * 2; + void *newarray; - newarray = realloc(t->array, sizeof(struct node *) * newsize); - if (newarray == NULL) - return -1; + newarray = realloc(t->array, sizeof(struct node *) * newsize); + if (newarray == NULL) + return -1; - t->array = newarray; - memset(t->array + t->size, 0, t->size * sizeof(struct node *)); - t->size = newsize; - t->split = 0; + t->array = newarray; + memset(t->array + t->size, 0, t->size * sizeof(struct node *)); + t->size = newsize; + t->split = 0; - return 0; + return 0; } static void rehash_id(struct fuse *f) { - struct node_table *t = &f->id_table; - struct node **nodep; - struct node **next; - size_t hash; - - if (t->split == t->size / 2) - return; - - hash = t->split; - t->split++; - for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { - struct node *node = *nodep; - size_t newhash = id_hash(f, node->nodeid); - - if (newhash != hash) { - next = nodep; - *nodep = node->id_next; - node->id_next = t->array[newhash]; - t->array[newhash] = node; - } else { - next = &node->id_next; - } - } - if (t->split == t->size / 2) - node_table_resize(t); + struct node_table *t = &f->id_table; + struct node **nodep; + struct node **next; + size_t hash; + + if (t->split == t->size / 2) + return; + + hash = t->split; + t->split++; + for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { + struct node *node = *nodep; + size_t newhash = id_hash(f, node->nodeid); + + if (newhash != hash) { + next = nodep; + *nodep = node->id_next; + node->id_next = t->array[newhash]; + t->array[newhash] = node; + } else { + next = &node->id_next; + } + } + if (t->split == t->size / 2) + node_table_resize(t); } static void hash_id(struct fuse *f, struct node *node) { - size_t hash = id_hash(f, node->nodeid); - node->id_next = f->id_table.array[hash]; - f->id_table.array[hash] = node; - f->id_table.use++; + size_t hash = id_hash(f, node->nodeid); + node->id_next = f->id_table.array[hash]; + f->id_table.array[hash] = node; + f->id_table.use++; - if (f->id_table.use >= f->id_table.size / 2) - rehash_id(f); + if (f->id_table.use >= f->id_table.size / 2) + rehash_id(f); } static size_t name_hash(struct fuse *f, fuse_ino_t parent, const char *name) { - uint64_t hash = parent; - uint64_t oldhash; + uint64_t hash = parent; + uint64_t oldhash; - for (; *name; name++) - hash = hash * 31 + (unsigned char) *name; + for (; *name; name++) + hash = hash * 31 + (unsigned char) *name; - hash %= f->name_table.size; - oldhash = hash % (f->name_table.size / 2); - if (oldhash >= f->name_table.split) - return oldhash; - else - return hash; + hash %= f->name_table.size; + oldhash = hash % (f->name_table.size / 2); + if (oldhash >= f->name_table.split) + return oldhash; + else + return hash; } static void unref_node(struct fuse *f, struct node *node); static void remerge_name(struct fuse *f) { - struct node_table *t = &f->name_table; - int iter; + struct node_table *t = &f->name_table; + int iter; - if (t->split == 0) - node_table_reduce(t); + if (t->split == 0) + node_table_reduce(t); - for (iter = 8; t->split > 0 && iter; iter--) { - struct node **upper; + for (iter = 8; t->split > 0 && iter; iter--) { + struct node **upper; - t->split--; - upper = &t->array[t->split + t->size / 2]; - if (*upper) { - struct node **nodep; + t->split--; + upper = &t->array[t->split + t->size / 2]; + if (*upper) { + struct node **nodep; - for (nodep = &t->array[t->split]; *nodep; - nodep = &(*nodep)->name_next); + for (nodep = &t->array[t->split]; *nodep; + nodep = &(*nodep)->name_next); - *nodep = *upper; - *upper = NULL; - break; - } - } + *nodep = *upper; + *upper = NULL; + break; + } + } } static void unhash_name(struct fuse *f, struct node *node) { - if (node->name) { - size_t hash = name_hash(f, node->parent->nodeid, node->name); - struct node **nodep = &f->name_table.array[hash]; - - for (; *nodep != NULL; nodep = &(*nodep)->name_next) - if (*nodep == node) { - *nodep = node->name_next; - node->name_next = NULL; - unref_node(f, node->parent); - if (node->name != node->inline_name) - free(node->name); - node->name = NULL; - node->parent = NULL; - f->name_table.use--; - - if (f->name_table.use < f->name_table.size / 4) - remerge_name(f); - return; - } - fprintf(stderr, - "fuse internal error: unable to unhash node: %llu\n", - (unsigned long long) node->nodeid); - abort(); - } + if (node->name) { + size_t hash = name_hash(f, node->parent->nodeid, node->name); + struct node **nodep = &f->name_table.array[hash]; + + for (; *nodep != NULL; nodep = &(*nodep)->name_next) + if (*nodep == node) { + *nodep = node->name_next; + node->name_next = NULL; + unref_node(f, node->parent); + if (node->name != node->inline_name) + free(node->name); + node->name = NULL; + node->parent = NULL; + f->name_table.use--; + + if (f->name_table.use < f->name_table.size / 4) + remerge_name(f); + return; + } + fprintf(stderr, + "fuse internal error: unable to unhash node: %llu\n", + (unsigned long long) node->nodeid); + abort(); + } } static void rehash_name(struct fuse *f) { - struct node_table *t = &f->name_table; - struct node **nodep; - struct node **next; - size_t hash; - - if (t->split == t->size / 2) - return; - - hash = t->split; - t->split++; - for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { - struct node *node = *nodep; - size_t newhash = name_hash(f, node->parent->nodeid, node->name); - - if (newhash != hash) { - next = nodep; - *nodep = node->name_next; - node->name_next = t->array[newhash]; - t->array[newhash] = node; - } else { - next = &node->name_next; - } - } - if (t->split == t->size / 2) - node_table_resize(t); + struct node_table *t = &f->name_table; + struct node **nodep; + struct node **next; + size_t hash; + + if (t->split == t->size / 2) + return; + + hash = t->split; + t->split++; + for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { + struct node *node = *nodep; + size_t newhash = name_hash(f, node->parent->nodeid, node->name); + + if (newhash != hash) { + next = nodep; + *nodep = node->name_next; + node->name_next = t->array[newhash]; + t->array[newhash] = node; + } else { + next = &node->name_next; + } + } + if (t->split == t->size / 2) + node_table_resize(t); } static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid, const char *name) { - size_t hash = name_hash(f, parentid, name); - struct node *parent = get_node(f, parentid); - if (strlen(name) < sizeof(node->inline_name)) { - strcpy(node->inline_name, name); - node->name = node->inline_name; - } else { - node->name = strdup(name); - if (node->name == NULL) - return -1; - } + size_t hash = name_hash(f, parentid, name); + struct node *parent = get_node(f, parentid); + if (strlen(name) < sizeof(node->inline_name)) { + strcpy(node->inline_name, name); + node->name = node->inline_name; + } else { + node->name = strdup(name); + if (node->name == NULL) + return -1; + } - parent->refctr ++; - node->parent = parent; - node->name_next = f->name_table.array[hash]; - f->name_table.array[hash] = node; - f->name_table.use++; + parent->refctr ++; + node->parent = parent; + node->name_next = f->name_table.array[hash]; + f->name_table.array[hash] = node; + f->name_table.use++; - if (f->name_table.use >= f->name_table.size / 2) - rehash_name(f); + if (f->name_table.use >= f->name_table.size / 2) + rehash_name(f); - return 0; + return 0; } static void delete_node(struct fuse *f, struct node *node) { - if (f->conf.debug) - fprintf(stderr, "DELETE: %llu\n", - (unsigned long long) node->nodeid); + if (f->conf.debug) + fprintf(stderr, "DELETE: %llu\n", + (unsigned long long) node->nodeid); - assert(node->treelock == 0); - unhash_name(f, node); - if (lru_enabled(f)) - remove_node_lru(node); - unhash_id(f, node); - free_node(f, node); + assert(node->treelock == 0); + unhash_name(f, node); + if (lru_enabled(f)) + remove_node_lru(node); + unhash_id(f, node); + free_node(f, node); } static void unref_node(struct fuse *f, struct node *node) { - assert(node->refctr > 0); - node->refctr --; - if (!node->refctr) - delete_node(f, node); + assert(node->refctr > 0); + node->refctr --; + if (!node->refctr) + delete_node(f, node); } static @@ -731,356 +733,356 @@ next_id(struct fuse *f) static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, const char *name) { - size_t hash = name_hash(f, parent, name); - struct node *node; + size_t hash = name_hash(f, parent, name); + struct node *node; - for (node = f->name_table.array[hash]; node != NULL; node = node->name_next) - if (node->parent->nodeid == parent && - strcmp(node->name, name) == 0) - return node; + for (node = f->name_table.array[hash]; node != NULL; node = node->name_next) + if (node->parent->nodeid == parent && + strcmp(node->name, name) == 0) + return node; - return NULL; + return NULL; } static void inc_nlookup(struct node *node) { - if (!node->nlookup) - node->refctr++; - node->nlookup++; + if (!node->nlookup) + node->refctr++; + node->nlookup++; } static struct node *find_node(struct fuse *f, fuse_ino_t parent, const char *name) { - struct node *node; - - pthread_mutex_lock(&f->lock); - if (!name) - node = get_node(f, parent); - else - node = lookup_node(f, parent, name); - if (node == NULL) { - node = alloc_node(f); - if (node == NULL) - goto out_err; - - node->nodeid = next_id(f); - node->generation = f->generation; - if (f->conf.remember) - inc_nlookup(node); - - if (hash_name(f, node, parent, name) == -1) { - free_node(f, node); - node = NULL; - goto out_err; - } - hash_id(f, node); - if (lru_enabled(f)) { - struct node_lru *lnode = node_lru(node); - init_list_head(&lnode->lru); - } - } else if (lru_enabled(f) && node->nlookup == 1) { - remove_node_lru(node); - } - inc_nlookup(node); -out_err: - pthread_mutex_unlock(&f->lock); - return node; + struct node *node; + + pthread_mutex_lock(&f->lock); + if (!name) + node = get_node(f, parent); + else + node = lookup_node(f, parent, name); + if (node == NULL) { + node = alloc_node(f); + if (node == NULL) + goto out_err; + + node->nodeid = next_id(f); + node->generation = f->generation; + if (f->conf.remember) + inc_nlookup(node); + + if (hash_name(f, node, parent, name) == -1) { + free_node(f, node); + node = NULL; + goto out_err; + } + hash_id(f, node); + if (lru_enabled(f)) { + struct node_lru *lnode = node_lru(node); + init_list_head(&lnode->lru); + } + } else if (lru_enabled(f) && node->nlookup == 1) { + remove_node_lru(node); + } + inc_nlookup(node); + out_err: + pthread_mutex_unlock(&f->lock); + return node; } static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name) { - size_t len = strlen(name); + size_t len = strlen(name); - if (s - len <= *buf) { - unsigned pathlen = *bufsize - (s - *buf); - unsigned newbufsize = *bufsize; - char *newbuf; + if (s - len <= *buf) { + unsigned pathlen = *bufsize - (s - *buf); + unsigned newbufsize = *bufsize; + char *newbuf; - while (newbufsize < pathlen + len + 1) { - if (newbufsize >= 0x80000000) - newbufsize = 0xffffffff; - else - newbufsize *= 2; - } + while (newbufsize < pathlen + len + 1) { + if (newbufsize >= 0x80000000) + newbufsize = 0xffffffff; + else + newbufsize *= 2; + } - newbuf = realloc(*buf, newbufsize); - if (newbuf == NULL) - return NULL; + newbuf = realloc(*buf, newbufsize); + if (newbuf == NULL) + return NULL; - *buf = newbuf; - s = newbuf + newbufsize - pathlen; - memmove(s, newbuf + *bufsize - pathlen, pathlen); - *bufsize = newbufsize; - } - s -= len; - strncpy(s, name, len); - s--; - *s = '/'; + *buf = newbuf; + s = newbuf + newbufsize - pathlen; + memmove(s, newbuf + *bufsize - pathlen, pathlen); + *bufsize = newbufsize; + } + s -= len; + strncpy(s, name, len); + s--; + *s = '/'; - return s; + return s; } static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, struct node *end) { - struct node *node; + struct node *node; - if (wnode) { - assert(wnode->treelock == TREELOCK_WRITE); - wnode->treelock = 0; - } + if (wnode) { + assert(wnode->treelock == TREELOCK_WRITE); + wnode->treelock = 0; + } - for (node = get_node(f, nodeid); - node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) { - assert(node->treelock != 0); - assert(node->treelock != TREELOCK_WAIT_OFFSET); - assert(node->treelock != TREELOCK_WRITE); - node->treelock--; - if (node->treelock == TREELOCK_WAIT_OFFSET) - node->treelock = 0; - } + for (node = get_node(f, nodeid); + node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) { + assert(node->treelock != 0); + assert(node->treelock != TREELOCK_WAIT_OFFSET); + assert(node->treelock != TREELOCK_WRITE); + node->treelock--; + if (node->treelock == TREELOCK_WAIT_OFFSET) + node->treelock = 0; + } } static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnodep, bool need_lock) { - unsigned bufsize = 256; - char *buf; - char *s; - struct node *node; - struct node *wnode = NULL; - int err; - - *path = NULL; - - err = -ENOMEM; - buf = malloc(bufsize); - if (buf == NULL) - goto out_err; - - s = buf + bufsize - 1; - *s = '\0'; - - if (name != NULL) { - s = add_name(&buf, &bufsize, s, name); - err = -ENOMEM; - if (s == NULL) - goto out_free; - } - - if (wnodep) { - assert(need_lock); - wnode = lookup_node(f, nodeid, name); - if (wnode) { - if (wnode->treelock != 0) { - if (wnode->treelock > 0) - wnode->treelock += TREELOCK_WAIT_OFFSET; - err = -EAGAIN; - goto out_free; - } - wnode->treelock = TREELOCK_WRITE; - } - } - - for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; - node = node->parent) { - err = -ENOENT; - if (node->name == NULL || node->parent == NULL) - goto out_unlock; - - err = -ENOMEM; - s = add_name(&buf, &bufsize, s, node->name); - if (s == NULL) - goto out_unlock; - - if (need_lock) { - err = -EAGAIN; - if (node->treelock < 0) - goto out_unlock; - - node->treelock++; - } - } - - if (s[0]) - memmove(buf, s, bufsize - (s - buf)); - else - strcpy(buf, "/"); - - *path = buf; - if (wnodep) - *wnodep = wnode; - - return 0; + unsigned bufsize = 256; + char *buf; + char *s; + struct node *node; + struct node *wnode = NULL; + int err; + + *path = NULL; + + err = -ENOMEM; + buf = malloc(bufsize); + if (buf == NULL) + goto out_err; + + s = buf + bufsize - 1; + *s = '\0'; + + if (name != NULL) { + s = add_name(&buf, &bufsize, s, name); + err = -ENOMEM; + if (s == NULL) + goto out_free; + } + + if (wnodep) { + assert(need_lock); + wnode = lookup_node(f, nodeid, name); + if (wnode) { + if (wnode->treelock != 0) { + if (wnode->treelock > 0) + wnode->treelock += TREELOCK_WAIT_OFFSET; + err = -EAGAIN; + goto out_free; + } + wnode->treelock = TREELOCK_WRITE; + } + } + + for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; + node = node->parent) { + err = -ENOENT; + if (node->name == NULL || node->parent == NULL) + goto out_unlock; + + err = -ENOMEM; + s = add_name(&buf, &bufsize, s, node->name); + if (s == NULL) + goto out_unlock; + + if (need_lock) { + err = -EAGAIN; + if (node->treelock < 0) + goto out_unlock; + + node->treelock++; + } + } + + if (s[0]) + memmove(buf, s, bufsize - (s - buf)); + else + strcpy(buf, "/"); + + *path = buf; + if (wnodep) + *wnodep = wnode; + + return 0; out_unlock: - if (need_lock) - unlock_path(f, nodeid, wnode, node); + if (need_lock) + unlock_path(f, nodeid, wnode, node); out_free: - free(buf); + free(buf); out_err: - return err; + return err; } static void queue_element_unlock(struct fuse *f, struct lock_queue_element *qe) { - struct node *wnode; + struct node *wnode; - if (qe->first_locked) { - wnode = qe->wnode1 ? *qe->wnode1 : NULL; - unlock_path(f, qe->nodeid1, wnode, NULL); - qe->first_locked = false; - } - if (qe->second_locked) { - wnode = qe->wnode2 ? *qe->wnode2 : NULL; - unlock_path(f, qe->nodeid2, wnode, NULL); - qe->second_locked = false; - } + if (qe->first_locked) { + wnode = qe->wnode1 ? *qe->wnode1 : NULL; + unlock_path(f, qe->nodeid1, wnode, NULL); + qe->first_locked = false; + } + if (qe->second_locked) { + wnode = qe->wnode2 ? *qe->wnode2 : NULL; + unlock_path(f, qe->nodeid2, wnode, NULL); + qe->second_locked = false; + } } static void queue_element_wakeup(struct fuse *f, struct lock_queue_element *qe) { - int err; - bool first = (qe == f->lockq); - - if (!qe->path1) { - /* Just waiting for it to be unlocked */ - if (get_node(f, qe->nodeid1)->treelock == 0) - pthread_cond_signal(&qe->cond); - - return; - } - - if (!qe->first_locked) { - err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1, - qe->wnode1, true); - if (!err) - qe->first_locked = true; - else if (err != -EAGAIN) - goto err_unlock; - } - if (!qe->second_locked && qe->path2) { - err = try_get_path(f, qe->nodeid2, qe->name2, qe->path2, - qe->wnode2, true); - if (!err) - qe->second_locked = true; - else if (err != -EAGAIN) - goto err_unlock; - } - - if (qe->first_locked && (qe->second_locked || !qe->path2)) { - err = 0; - goto done; - } - - /* - * Only let the first element be partially locked otherwise there could - * be a deadlock. - * - * But do allow the first element to be partially locked to prevent - * starvation. - */ - if (!first) - queue_element_unlock(f, qe); - - /* keep trying */ - return; - -err_unlock: - queue_element_unlock(f, qe); -done: - qe->err = err; - qe->done = true; - pthread_cond_signal(&qe->cond); + int err; + bool first = (qe == f->lockq); + + if (!qe->path1) { + /* Just waiting for it to be unlocked */ + if (get_node(f, qe->nodeid1)->treelock == 0) + pthread_cond_signal(&qe->cond); + + return; + } + + if (!qe->first_locked) { + err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1, + qe->wnode1, true); + if (!err) + qe->first_locked = true; + else if (err != -EAGAIN) + goto err_unlock; + } + if (!qe->second_locked && qe->path2) { + err = try_get_path(f, qe->nodeid2, qe->name2, qe->path2, + qe->wnode2, true); + if (!err) + qe->second_locked = true; + else if (err != -EAGAIN) + goto err_unlock; + } + + if (qe->first_locked && (qe->second_locked || !qe->path2)) { + err = 0; + goto done; + } + + /* + * Only let the first element be partially locked otherwise there could + * be a deadlock. + * + * But do allow the first element to be partially locked to prevent + * starvation. + */ + if (!first) + queue_element_unlock(f, qe); + + /* keep trying */ + return; + + err_unlock: + queue_element_unlock(f, qe); + done: + qe->err = err; + qe->done = true; + pthread_cond_signal(&qe->cond); } static void wake_up_queued(struct fuse *f) { - struct lock_queue_element *qe; + struct lock_queue_element *qe; - for (qe = f->lockq; qe != NULL; qe = qe->next) - queue_element_wakeup(f, qe); + for (qe = f->lockq; qe != NULL; qe = qe->next) + queue_element_wakeup(f, qe); } static void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid, const char *name, bool wr) { - if (f->conf.debug) { - struct node *wnode = NULL; + if (f->conf.debug) { + struct node *wnode = NULL; - if (wr) - wnode = lookup_node(f, nodeid, name); + if (wr) + wnode = lookup_node(f, nodeid, name); - if (wnode) - fprintf(stderr, "%s %li (w)\n", msg, wnode->nodeid); - else - fprintf(stderr, "%s %li\n", msg, nodeid); - } + if (wnode) + fprintf(stderr, "%s %li (w)\n", msg, wnode->nodeid); + else + fprintf(stderr, "%s %li\n", msg, nodeid); + } } static void queue_path(struct fuse *f, struct lock_queue_element *qe) { - struct lock_queue_element **qp; + struct lock_queue_element **qp; - qe->done = false; - qe->first_locked = false; - qe->second_locked = false; - pthread_cond_init(&qe->cond, NULL); - qe->next = NULL; - for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next); - *qp = qe; + qe->done = false; + qe->first_locked = false; + qe->second_locked = false; + pthread_cond_init(&qe->cond, NULL); + qe->next = NULL; + for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next); + *qp = qe; } static void dequeue_path(struct fuse *f, struct lock_queue_element *qe) { - struct lock_queue_element **qp; + struct lock_queue_element **qp; - pthread_cond_destroy(&qe->cond); - for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next); - *qp = qe->next; + pthread_cond_destroy(&qe->cond); + for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next); + *qp = qe->next; } static int wait_path(struct fuse *f, struct lock_queue_element *qe) { - queue_path(f, qe); + queue_path(f, qe); - do { - pthread_cond_wait(&qe->cond, &f->lock); - } while (!qe->done); + do { + pthread_cond_wait(&qe->cond, &f->lock); + } while (!qe->done); - dequeue_path(f, qe); + dequeue_path(f, qe); - return qe->err; + return qe->err; } static int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnode) { - int err; + int err; - pthread_mutex_lock(&f->lock); - err = try_get_path(f, nodeid, name, path, wnode, true); - if (err == -EAGAIN) { - struct lock_queue_element qe = { - .nodeid1 = nodeid, - .name1 = name, - .path1 = path, - .wnode1 = wnode, - }; - debug_path(f, "QUEUE PATH", nodeid, name, !!wnode); - err = wait_path(f, &qe); - debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode); - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + err = try_get_path(f, nodeid, name, path, wnode, true); + if (err == -EAGAIN) { + struct lock_queue_element qe = { + .nodeid1 = nodeid, + .name1 = name, + .path1 = path, + .wnode1 = wnode, + }; + debug_path(f, "QUEUE PATH", nodeid, name, !!wnode); + err = wait_path(f, &qe); + debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode); + } + pthread_mutex_unlock(&f->lock); - return err; + return err; } static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path) { - return get_path_common(f, nodeid, NULL, path, NULL); + return get_path_common(f, nodeid, NULL, path, NULL); } static @@ -1099,8 +1101,8 @@ get_path_nullok(struct fuse *f, { err = get_path_common(f,nodeid,NULL,path,NULL); if((err == -ENOENT) && f->nullpath_ok) - err = 0; - } + err = 0; + } return err; } @@ -1108,13 +1110,13 @@ get_path_nullok(struct fuse *f, static int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path) { - return get_path_common(f, nodeid, name, path, NULL); + return get_path_common(f, nodeid, name, path, NULL); } static int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnode) { - return get_path_common(f, nodeid, name, path, wnode); + return get_path_common(f, nodeid, name, path, wnode); } static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, @@ -1122,20 +1124,20 @@ static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, char **path1, char **path2, struct node **wnode1, struct node **wnode2) { - int err; + int err; - /* FIXME: locking two paths needs deadlock checking */ - err = try_get_path(f, nodeid1, name1, path1, wnode1, true); - if (!err) { - err = try_get_path(f, nodeid2, name2, path2, wnode2, true); - if (err) { - struct node *wn1 = wnode1 ? *wnode1 : NULL; + /* FIXME: locking two paths needs deadlock checking */ + err = try_get_path(f, nodeid1, name1, path1, wnode1, true); + if (!err) { + err = try_get_path(f, nodeid2, name2, path2, wnode2, true); + if (err) { + struct node *wn1 = wnode1 ? *wnode1 : NULL; - unlock_path(f, nodeid1, wn1, NULL); - free(*path1); - } - } - return err; + unlock_path(f, nodeid1, wn1, NULL); + free(*path1); + } + } + return err; } static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, @@ -1143,62 +1145,62 @@ static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, char **path1, char **path2, struct node **wnode1, struct node **wnode2) { - int err; - - pthread_mutex_lock(&f->lock); - err = try_get_path2(f, nodeid1, name1, nodeid2, name2, - path1, path2, wnode1, wnode2); - if (err == -EAGAIN) { - struct lock_queue_element qe = { - .nodeid1 = nodeid1, - .name1 = name1, - .path1 = path1, - .wnode1 = wnode1, - .nodeid2 = nodeid2, - .name2 = name2, - .path2 = path2, - .wnode2 = wnode2, - }; - - debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1); - debug_path(f, " PATH2", nodeid2, name2, !!wnode2); - err = wait_path(f, &qe); - debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1); - debug_path(f, " PATH2", nodeid2, name2, !!wnode2); - } - pthread_mutex_unlock(&f->lock); - - return err; + int err; + + pthread_mutex_lock(&f->lock); + err = try_get_path2(f, nodeid1, name1, nodeid2, name2, + path1, path2, wnode1, wnode2); + if (err == -EAGAIN) { + struct lock_queue_element qe = { + .nodeid1 = nodeid1, + .name1 = name1, + .path1 = path1, + .wnode1 = wnode1, + .nodeid2 = nodeid2, + .name2 = name2, + .path2 = path2, + .wnode2 = wnode2, + }; + + debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1); + debug_path(f, " PATH2", nodeid2, name2, !!wnode2); + err = wait_path(f, &qe); + debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1); + debug_path(f, " PATH2", nodeid2, name2, !!wnode2); + } + pthread_mutex_unlock(&f->lock); + + return err; } static void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, char *path) { - pthread_mutex_lock(&f->lock); - unlock_path(f, nodeid, wnode, NULL); - if (f->lockq) - wake_up_queued(f); - pthread_mutex_unlock(&f->lock); - free(path); + pthread_mutex_lock(&f->lock); + unlock_path(f, nodeid, wnode, NULL); + if (f->lockq) + wake_up_queued(f); + pthread_mutex_unlock(&f->lock); + free(path); } static void free_path(struct fuse *f, fuse_ino_t nodeid, char *path) { - if (path) - free_path_wrlock(f, nodeid, NULL, path); + if (path) + free_path_wrlock(f, nodeid, NULL, path); } static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2, struct node *wnode1, struct node *wnode2, char *path1, char *path2) { - pthread_mutex_lock(&f->lock); - unlock_path(f, nodeid1, wnode1, NULL); - unlock_path(f, nodeid2, wnode2, NULL); - wake_up_queued(f); - pthread_mutex_unlock(&f->lock); - free(path1); - free(path2); + pthread_mutex_lock(&f->lock); + unlock_path(f, nodeid1, wnode1, NULL); + unlock_path(f, nodeid2, wnode2, NULL); + wake_up_queued(f); + pthread_mutex_unlock(&f->lock); + free(path1); + free(path2); } static @@ -1250,291 +1252,168 @@ forget_node(struct fuse *f, static void unlink_node(struct fuse *f, struct node *node) { - if (f->conf.remember) { - assert(node->nlookup > 1); - node->nlookup--; - } - unhash_name(f, node); + if (f->conf.remember) { + assert(node->nlookup > 1); + node->nlookup--; + } + unhash_name(f, node); } static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name) { - struct node *node; + struct node *node; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, name); - if (node != NULL) - unlink_node(f, node); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node != NULL) + unlink_node(f, node); + pthread_mutex_unlock(&f->lock); } static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, fuse_ino_t newdir, const char *newname) { - struct node *node; - struct node *newnode; - int err = 0; + struct node *node; + struct node *newnode; + int err = 0; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, olddir, oldname); - newnode = lookup_node(f, newdir, newname); - if (node == NULL) - goto out; + pthread_mutex_lock(&f->lock); + node = lookup_node(f, olddir, oldname); + newnode = lookup_node(f, newdir, newname); + if (node == NULL) + goto out; - if (newnode != NULL) - unlink_node(f, newnode); + if (newnode != NULL) + unlink_node(f, newnode); - unhash_name(f, node); - if (hash_name(f, node, newdir, newname) == -1) { - err = -ENOMEM; - goto out; - } + unhash_name(f, node); + if (hash_name(f, node, newdir, newname) == -1) { + err = -ENOMEM; + goto out; + } -out: - pthread_mutex_unlock(&f->lock); - return err; + out: + pthread_mutex_unlock(&f->lock); + return err; } static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf) { - if (!f->conf.use_ino) - stbuf->st_ino = nodeid; - if (f->conf.set_mode) - stbuf->st_mode = (stbuf->st_mode & S_IFMT) | - (0777 & ~f->conf.umask); - if (f->conf.set_uid) - stbuf->st_uid = f->conf.uid; - if (f->conf.set_gid) - stbuf->st_gid = f->conf.gid; + if (!f->conf.use_ino) + stbuf->st_ino = nodeid; + if (f->conf.set_mode) + stbuf->st_mode = (stbuf->st_mode & S_IFMT) | + (0777 & ~f->conf.umask); + if (f->conf.set_uid) + stbuf->st_uid = f->conf.uid; + if (f->conf.set_gid) + stbuf->st_gid = f->conf.gid; } static struct fuse *req_fuse(fuse_req_t req) { - return (struct fuse *) fuse_req_userdata(req); + return (struct fuse *) fuse_req_userdata(req); } static void fuse_intr_sighandler(int sig) { - (void) sig; - /* Nothing to do */ + (void) sig; + /* Nothing to do */ } struct fuse_intr_data { - pthread_t id; - pthread_cond_t cond; - int finished; + pthread_t id; + pthread_cond_t cond; + int finished; }; static void fuse_interrupt(fuse_req_t req, void *d_) { - struct fuse_intr_data *d = d_; - struct fuse *f = req_fuse(req); + struct fuse_intr_data *d = d_; + struct fuse *f = req_fuse(req); - if (d->id == pthread_self()) - return; - - pthread_mutex_lock(&f->lock); - while (!d->finished) { - struct timeval now; - struct timespec timeout; + if (d->id == pthread_self()) + return; - pthread_kill(d->id, f->conf.intr_signal); - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec + 1; - timeout.tv_nsec = now.tv_usec * 1000; - pthread_cond_timedwait(&d->cond, &f->lock, &timeout); - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + while (!d->finished) { + struct timeval now; + struct timespec timeout; + + pthread_kill(d->id, f->conf.intr_signal); + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec + 1; + timeout.tv_nsec = now.tv_usec * 1000; + pthread_cond_timedwait(&d->cond, &f->lock, &timeout); + } + pthread_mutex_unlock(&f->lock); } static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { - pthread_mutex_lock(&f->lock); - d->finished = 1; - pthread_cond_broadcast(&d->cond); - pthread_mutex_unlock(&f->lock); - fuse_req_interrupt_func(req, NULL, NULL); - pthread_cond_destroy(&d->cond); + pthread_mutex_lock(&f->lock); + d->finished = 1; + pthread_cond_broadcast(&d->cond); + pthread_mutex_unlock(&f->lock); + fuse_req_interrupt_func(req, NULL, NULL); + pthread_cond_destroy(&d->cond); } static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d) { - d->id = pthread_self(); - pthread_cond_init(&d->cond, NULL); - d->finished = 0; - fuse_req_interrupt_func(req, fuse_interrupt, d); + d->id = pthread_self(); + pthread_cond_init(&d->cond, NULL); + d->finished = 0; + fuse_req_interrupt_func(req, fuse_interrupt, d); } static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_finish_interrupt(f, req, d); + if (f->conf.intr) + fuse_do_finish_interrupt(f, req, d); } static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_prepare_interrupt(req, d); -} - -#if !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); + if (f->conf.intr) + fuse_do_prepare_interrupt(req, d); } -#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; - if (fs->op.getattr) { - if (fs->debug) - fprintf(stderr, "getattr %s\n", path); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getattr) { + if (fs->debug) + fprintf(stderr, "getattr %s\n", path); - return fs->op.getattr(path, buf); - } else { - return -ENOSYS; - } + return fs->op.getattr(path, buf); + } else { + return -ENOSYS; + } } int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fgetattr) { - if (fs->debug) - fprintf(stderr, "fgetattr[%llu] %s\n", - (unsigned long long) fi->fh, path); - - return fs->op.fgetattr(path, buf, fi); - } else if (path && fs->op.getattr) { - if (fs->debug) - fprintf(stderr, "getattr %s\n", path); - - return fs->op.getattr(path, buf); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fgetattr) { + if (fs->debug) + fprintf(stderr, "fgetattr[%llu] %s\n", + (unsigned long long) fi->fh, path); + + return fs->op.fgetattr(path, buf, fi); + } else if (path && fs->op.getattr) { + if (fs->debug) + fprintf(stderr, "getattr %s\n", path); + + return fs->op.getattr(path, buf); + } else { + return -ENOSYS; + } } int @@ -1577,349 +1456,354 @@ fuse_fs_free_hide(struct fuse_fs *fs_, int fuse_fs_unlink(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.unlink) { - if (fs->debug) - fprintf(stderr, "unlink %s\n", path); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.unlink) { + if (fs->debug) + fprintf(stderr, "unlink %s\n", path); - return fs->op.unlink(path); - } else { - return -ENOSYS; - } + return fs->op.unlink(path); + } else { + return -ENOSYS; + } } int fuse_fs_rmdir(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.rmdir) { - if (fs->debug) - fprintf(stderr, "rmdir %s\n", path); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rmdir) { + if (fs->debug) + fprintf(stderr, "rmdir %s\n", path); - return fs->op.rmdir(path); - } else { - return -ENOSYS; - } + return fs->op.rmdir(path); + } else { + return -ENOSYS; + } } int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.symlink) { - if (fs->debug) - fprintf(stderr, "symlink %s %s\n", linkname, path); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.symlink) { + if (fs->debug) + fprintf(stderr, "symlink %s %s\n", linkname, path); - return fs->op.symlink(linkname, path); - } else { - return -ENOSYS; - } + return fs->op.symlink(linkname, path); + } else { + return -ENOSYS; + } } int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.link) { - if (fs->debug) - fprintf(stderr, "link %s %s\n", oldpath, newpath); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.link) { + if (fs->debug) + fprintf(stderr, "link %s %s\n", oldpath, newpath); - return fs->op.link(oldpath, newpath); - } else { - return -ENOSYS; - } + return fs->op.link(oldpath, newpath); + } else { + return -ENOSYS; + } } int fuse_fs_release(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.release) { - if (fs->debug) - fprintf(stderr, "release%s[%llu] flags: 0x%x\n", - fi->flush ? "+flush" : "", - (unsigned long long) fi->fh, fi->flags); - - return fuse_compat_release(fs, path, fi); - } else { - return 0; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.release) { + if (fs->debug) + fprintf(stderr, "release%s[%llu] flags: 0x%x\n", + fi->flush ? "+flush" : "", + (unsigned long long) fi->fh, fi->flags); + + return fs->op.release(path, fi); + } else { + return 0; + } } int fuse_fs_opendir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.opendir) { - int err; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.opendir) { + int err; - if (fs->debug) - fprintf(stderr, "opendir flags: 0x%x %s\n", fi->flags, - path); + if (fs->debug) + fprintf(stderr, "opendir flags: 0x%x %s\n", fi->flags, + path); - err = fuse_compat_opendir(fs, path, fi); + err = fs->op.opendir(path,fi); - if (fs->debug && !err) - fprintf(stderr, " opendir[%lli] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); + if (fs->debug && !err) + fprintf(stderr, " opendir[%lli] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); - return err; - } else { - return 0; - } + return err; + } else { + return 0; + } } int fuse_fs_open(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.open) { - int err; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.open) { + int err; - if (fs->debug) - fprintf(stderr, "open flags: 0x%x %s\n", fi->flags, - path); + if (fs->debug) + fprintf(stderr, "open flags: 0x%x %s\n", fi->flags, + path); - err = fuse_compat_open(fs, path, fi); + err = fs->op.open(path,fi); - if (fs->debug && !err) - fprintf(stderr, " open[%lli] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); + if (fs->debug && !err) + fprintf(stderr, " open[%lli] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); - return err; - } else { - return 0; - } + return err; + } else { + return 0; + } } static void fuse_free_buf(struct fuse_bufvec *buf) { - if (buf != NULL) { - size_t i; + if (buf != NULL) { + size_t i; - for (i = 0; i < buf->count; i++) - free(buf->buf[i].mem); - free(buf); - } + for (i = 0; i < buf->count; i++) + free(buf->buf[i].mem); + free(buf); + } } int fuse_fs_read_buf(struct fuse_fs *fs, const char *path, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.read || fs->op.read_buf) { - int res; - - if (fs->debug) - fprintf(stderr, - "read[%llu] %zu bytes from %llu flags: 0x%x\n", - (unsigned long long) fi->fh, - size, (unsigned long long) off, fi->flags); - - if (fs->op.read_buf) { - res = fs->op.read_buf(path, bufp, size, off, fi); - } else { - struct fuse_bufvec *buf; - void *mem; - - buf = malloc(sizeof(struct fuse_bufvec)); - if (buf == NULL) - return -ENOMEM; - - mem = malloc(size); - if (mem == NULL) { - free(buf); - return -ENOMEM; - } - *buf = FUSE_BUFVEC_INIT(size); - buf->buf[0].mem = mem; - *bufp = buf; - - res = fs->op.read(path, mem, size, off, fi); - if (res >= 0) - buf->buf[0].size = res; - } - - if (fs->debug && res >= 0) - fprintf(stderr, " read[%llu] %zu bytes from %llu\n", - (unsigned long long) fi->fh, - fuse_buf_size(*bufp), - (unsigned long long) off); - if (res >= 0 && fuse_buf_size(*bufp) > (int) size) - fprintf(stderr, "fuse: read too many bytes\n"); - - if (res < 0) - return res; - - return 0; - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.read || fs->op.read_buf) { + int res; + + if (fs->debug) + fprintf(stderr, + "read[%llu] %zu bytes from %llu flags: 0x%x\n", + (unsigned long long) fi->fh, + size, (unsigned long long) off, fi->flags); + + if (fs->op.read_buf) { + res = fs->op.read_buf(path, bufp, size, off, fi); + } else { + struct fuse_bufvec *buf; + void *mem; + + buf = malloc(sizeof(struct fuse_bufvec)); + if (buf == NULL) + return -ENOMEM; + + mem = malloc(size); + if (mem == NULL) { + free(buf); + return -ENOMEM; + } + *buf = FUSE_BUFVEC_INIT(size); + buf->buf[0].mem = mem; + *bufp = buf; + + res = fs->op.read(path, mem, size, off, fi); + if (res >= 0) + buf->buf[0].size = res; + } + + if (fs->debug && res >= 0) + fprintf(stderr, " read[%llu] %zu bytes from %llu\n", + (unsigned long long) fi->fh, + fuse_buf_size(*bufp), + (unsigned long long) off); + if (res >= 0 && fuse_buf_size(*bufp) > (int) size) + fprintf(stderr, "fuse: read too many bytes\n"); + + if (res < 0) + return res; + + return 0; + } else { + return -ENOSYS; + } } int fuse_fs_read(struct fuse_fs *fs, const char *path, char *mem, size_t size, off_t off, struct fuse_file_info *fi) { - int res; - struct fuse_bufvec *buf = NULL; + int res; + struct fuse_bufvec *buf = NULL; - res = fuse_fs_read_buf(fs, path, &buf, size, off, fi); - if (res == 0) { - struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size); + res = fuse_fs_read_buf(fs, path, &buf, size, off, fi); + if (res == 0) { + struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size); - dst.buf[0].mem = mem; - res = fuse_buf_copy(&dst, buf, 0); - } - fuse_free_buf(buf); + dst.buf[0].mem = mem; + res = fuse_buf_copy(&dst, buf, 0); + } + fuse_free_buf(buf); - return res; + return res; } int fuse_fs_write_buf(struct fuse_fs *fs, const char *path, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.write_buf || fs->op.write) { - int res; - size_t size = fuse_buf_size(buf); - - assert(buf->idx == 0 && buf->off == 0); - if (fs->debug) - fprintf(stderr, - "write%s[%llu] %zu bytes to %llu flags: 0x%x\n", - fi->writepage ? "page" : "", - (unsigned long long) fi->fh, - size, - (unsigned long long) off, - fi->flags); - - if (fs->op.write_buf) { - res = fs->op.write_buf(path, buf, off, fi); - } else { - void *mem = NULL; - struct fuse_buf *flatbuf; - struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size); - - if (buf->count == 1 && - !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { - flatbuf = &buf->buf[0]; - } else { - res = -ENOMEM; - mem = malloc(size); - if (mem == NULL) - goto out; - - tmp.buf[0].mem = mem; - res = fuse_buf_copy(&tmp, buf, 0); - if (res <= 0) - goto out_free; - - tmp.buf[0].size = res; - flatbuf = &tmp.buf[0]; - } - - res = fs->op.write(path, flatbuf->mem, flatbuf->size, - off, fi); -out_free: - free(mem); - } -out: - if (fs->debug && res >= 0) - fprintf(stderr, " write%s[%llu] %u bytes to %llu\n", - fi->writepage ? "page" : "", - (unsigned long long) fi->fh, res, - (unsigned long long) off); - if (res > (int) size) - fprintf(stderr, "fuse: wrote too many bytes\n"); - - return res; - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.write_buf || fs->op.write) { + int res; + size_t size = fuse_buf_size(buf); + + assert(buf->idx == 0 && buf->off == 0); + if (fs->debug) + fprintf(stderr, + "write%s[%llu] %zu bytes to %llu flags: 0x%x\n", + fi->writepage ? "page" : "", + (unsigned long long) fi->fh, + size, + (unsigned long long) off, + fi->flags); + + if (fs->op.write_buf) { + res = fs->op.write_buf(path, buf, off, fi); + } else { + void *mem = NULL; + struct fuse_buf *flatbuf; + struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size); + + if (buf->count == 1 && + !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { + flatbuf = &buf->buf[0]; + } else { + res = -ENOMEM; + mem = malloc(size); + if (mem == NULL) + goto out; + + tmp.buf[0].mem = mem; + res = fuse_buf_copy(&tmp, buf, 0); + if (res <= 0) + goto out_free; + + tmp.buf[0].size = res; + flatbuf = &tmp.buf[0]; + } + + res = fs->op.write(path, flatbuf->mem, flatbuf->size, + off, fi); + out_free: + free(mem); + } + out: + if (fs->debug && res >= 0) + fprintf(stderr, " write%s[%llu] %u bytes to %llu\n", + fi->writepage ? "page" : "", + (unsigned long long) fi->fh, res, + (unsigned long long) off); + if (res > (int) size) + fprintf(stderr, "fuse: wrote too many bytes\n"); + + return res; + } else { + return -ENOSYS; + } } int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *mem, size_t size, off_t off, struct fuse_file_info *fi) { - struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size); + struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size); - bufv.buf[0].mem = (void *) mem; + bufv.buf[0].mem = (void *) mem; - return fuse_fs_write_buf(fs, path, &bufv, off, fi); + return fuse_fs_write_buf(fs, path, &bufv, off, fi); } int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsync) { - if (fs->debug) - fprintf(stderr, "fsync[%llu] datasync: %i\n", - (unsigned long long) fi->fh, datasync); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsync) { + if (fs->debug) + fprintf(stderr, "fsync[%llu] datasync: %i\n", + (unsigned long long) fi->fh, datasync); - return fs->op.fsync(path, datasync, fi); - } else { - return -ENOSYS; - } + return fs->op.fsync(path, datasync, fi); + } else { + return -ENOSYS; + } } int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsyncdir) { - if (fs->debug) - fprintf(stderr, "fsyncdir[%llu] datasync: %i\n", - (unsigned long long) fi->fh, datasync); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsyncdir) { + if (fs->debug) + fprintf(stderr, "fsyncdir[%llu] datasync: %i\n", + (unsigned long long) fi->fh, datasync); - return fs->op.fsyncdir(path, datasync, fi); - } else { - return -ENOSYS; - } + return fs->op.fsyncdir(path, datasync, fi); + } else { + return -ENOSYS; + } } int fuse_fs_flush(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.flush) { - if (fs->debug) - fprintf(stderr, "flush[%llu]\n", - (unsigned long long) fi->fh); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.flush) { + if (fs->debug) + fprintf(stderr, "flush[%llu]\n", + (unsigned long long) fi->fh); - return fs->op.flush(path, fi); - } else { - return -ENOSYS; - } + return fs->op.flush(path, fi); + } else { + return -ENOSYS; + } } -int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) +int +fuse_fs_statfs(struct fuse_fs *fs, + const char *path, + struct statvfs *buf) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.statfs) { - if (fs->debug) - fprintf(stderr, "statfs %s\n", path); + fuse_get_context()->private_data = fs->user_data; + + if(fs->debug) + fprintf(stderr, "statfs %s\n", path); + + if(fs->op.statfs == NULL) + { + buf->f_namemax = 255; + buf->f_bsize = 512; + return 0; + } - return fuse_compat_statfs(fs, path, buf); - } else { - buf->f_namemax = 255; - buf->f_bsize = 512; - return 0; - } + return fs->op.statfs(path,buf); } int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.releasedir) { - if (fs->debug) - fprintf(stderr, "releasedir[%llu] flags: 0x%x\n", - (unsigned long long) fi->fh, fi->flags); - - return fs->op.releasedir(path, fi); - } else { - return 0; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.releasedir) { + if (fs->debug) + fprintf(stderr, "releasedir[%llu] flags: 0x%x\n", + (unsigned long long) fi->fh, fi->flags); + + return fs->op.releasedir(path, fi); + } else { + return 0; + } } int @@ -1951,86 +1835,86 @@ fuse_fs_readdir_plus(struct fuse_fs *fs_, int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.create) { - int err; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.create) { + int err; - if (fs->debug) - fprintf(stderr, - "create flags: 0x%x %s 0%o umask=0%03o\n", - fi->flags, path, mode, - fuse_get_context()->umask); + if (fs->debug) + fprintf(stderr, + "create flags: 0x%x %s 0%o umask=0%03o\n", + fi->flags, path, mode, + fuse_get_context()->umask); - err = fs->op.create(path, mode, fi); + err = fs->op.create(path, mode, fi); - if (fs->debug && !err) - fprintf(stderr, " create[%llu] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); + if (fs->debug && !err) + fprintf(stderr, " create[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); - return err; - } else { - return -ENOSYS; - } + return err; + } else { + return -ENOSYS; + } } int fuse_fs_lock(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.lock) { - if (fs->debug) - fprintf(stderr, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n", - (unsigned long long) fi->fh, - (cmd == F_GETLK ? "F_GETLK" : - (cmd == F_SETLK ? "F_SETLK" : - (cmd == F_SETLKW ? "F_SETLKW" : "???"))), - (lock->l_type == F_RDLCK ? "F_RDLCK" : - (lock->l_type == F_WRLCK ? "F_WRLCK" : - (lock->l_type == F_UNLCK ? "F_UNLCK" : - "???"))), - (unsigned long long) lock->l_start, - (unsigned long long) lock->l_len, - (unsigned long long) lock->l_pid); - - return fs->op.lock(path, fi, cmd, lock); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.lock) { + if (fs->debug) + fprintf(stderr, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n", + (unsigned long long) fi->fh, + (cmd == F_GETLK ? "F_GETLK" : + (cmd == F_SETLK ? "F_SETLK" : + (cmd == F_SETLKW ? "F_SETLKW" : "???"))), + (lock->l_type == F_RDLCK ? "F_RDLCK" : + (lock->l_type == F_WRLCK ? "F_WRLCK" : + (lock->l_type == F_UNLCK ? "F_UNLCK" : + "???"))), + (unsigned long long) lock->l_start, + (unsigned long long) lock->l_len, + (unsigned long long) lock->l_pid); + + return fs->op.lock(path, fi, cmd, lock); + } else { + return -ENOSYS; + } } int fuse_fs_flock(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, int op) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.flock) { - if (fs->debug) { - int xop = op & ~LOCK_NB; - - fprintf(stderr, "lock[%llu] %s%s\n", - (unsigned long long) fi->fh, - xop == LOCK_SH ? "LOCK_SH" : - (xop == LOCK_EX ? "LOCK_EX" : - (xop == LOCK_UN ? "LOCK_UN" : "???")), - (op & LOCK_NB) ? "|LOCK_NB" : ""); - } - return fs->op.flock(path, fi, op); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.flock) { + if (fs->debug) { + int xop = op & ~LOCK_NB; + + fprintf(stderr, "lock[%llu] %s%s\n", + (unsigned long long) fi->fh, + xop == LOCK_SH ? "LOCK_SH" : + (xop == LOCK_EX ? "LOCK_EX" : + (xop == LOCK_UN ? "LOCK_UN" : "???")), + (op & LOCK_NB) ? "|LOCK_NB" : ""); + } + return fs->op.flock(path, fi, op); + } else { + return -ENOSYS; + } } int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chown) { - if (fs->debug) - fprintf(stderr, "chown %s %lu %lu\n", path, - (unsigned long) uid, (unsigned long) gid); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chown) { + if (fs->debug) + fprintf(stderr, "chown %s %lu %lu\n", path, + (unsigned long) uid, (unsigned long) gid); - return fs->op.chown(path, uid, gid); - } else { - return -ENOSYS; - } + return fs->op.chown(path, uid, gid); + } else { + return -ENOSYS; + } } int @@ -2049,64 +1933,64 @@ fuse_fs_fchown(struct fuse_fs *fs_, int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.truncate) { - if (fs->debug) - fprintf(stderr, "truncate %s %llu\n", path, - (unsigned long long) size); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.truncate) { + if (fs->debug) + fprintf(stderr, "truncate %s %llu\n", path, + (unsigned long long) size); - return fs->op.truncate(path, size); - } else { - return -ENOSYS; - } + return fs->op.truncate(path, size); + } else { + return -ENOSYS; + } } int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.ftruncate) { - if (fs->debug) - fprintf(stderr, "ftruncate[%llu] %llu\n", - (unsigned long long) fi->fh, - (unsigned long long) size); - - return fs->op.ftruncate(path, size, fi); - } else if (path && fs->op.truncate) { - if (fs->debug) - fprintf(stderr, "truncate %s %llu\n", path, - (unsigned long long) size); - - return fs->op.truncate(path, size); - } else { - return -ENOSYS; - } -} + fuse_get_context()->private_data = fs->user_data; + if (fs->op.ftruncate) { + if (fs->debug) + fprintf(stderr, "ftruncate[%llu] %llu\n", + (unsigned long long) fi->fh, + (unsigned long long) size); + + return fs->op.ftruncate(path, size, fi); + } else if (path && fs->op.truncate) { + if (fs->debug) + fprintf(stderr, "truncate %s %llu\n", path, + (unsigned long long) size); + + return fs->op.truncate(path, size); + } else { + return -ENOSYS; + } +} int fuse_fs_utimens(struct fuse_fs *fs, const char *path, const struct timespec tv[2]) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.utimens) { - if (fs->debug) - fprintf(stderr, "utimens %s %li.%09lu %li.%09lu\n", - path, tv[0].tv_sec, tv[0].tv_nsec, - tv[1].tv_sec, tv[1].tv_nsec); - - return fs->op.utimens(path, tv); - } else if(fs->op.utime) { - struct utimbuf buf; - - if (fs->debug) - fprintf(stderr, "utime %s %li %li\n", path, - tv[0].tv_sec, tv[1].tv_sec); - - buf.actime = tv[0].tv_sec; - buf.modtime = tv[1].tv_sec; - return fs->op.utime(path, &buf); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.utimens) { + if (fs->debug) + fprintf(stderr, "utimens %s %li.%09lu %li.%09lu\n", + path, tv[0].tv_sec, tv[0].tv_nsec, + tv[1].tv_sec, tv[1].tv_nsec); + + return fs->op.utimens(path, tv); + } else if(fs->op.utime) { + struct utimbuf buf; + + if (fs->debug) + fprintf(stderr, "utime %s %li %li\n", path, + tv[0].tv_sec, tv[1].tv_sec); + + buf.actime = tv[0].tv_sec; + buf.modtime = tv[1].tv_sec; + return fs->op.utime(path, &buf); + } else { + return -ENOSYS; + } } int @@ -2124,189 +2008,189 @@ fuse_fs_futimens(struct fuse_fs *fs_, int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.access) { - if (fs->debug) - fprintf(stderr, "access %s 0%o\n", path, mask); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.access) { + if (fs->debug) + fprintf(stderr, "access %s 0%o\n", path, mask); - return fs->op.access(path, mask); - } else { - return -ENOSYS; - } + return fs->op.access(path, mask); + } else { + return -ENOSYS; + } } int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, size_t len) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.readlink) { - if (fs->debug) - fprintf(stderr, "readlink %s %lu\n", path, - (unsigned long) len); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readlink) { + if (fs->debug) + fprintf(stderr, "readlink %s %lu\n", path, + (unsigned long) len); - return fs->op.readlink(path, buf, len); - } else { - return -ENOSYS; - } + return fs->op.readlink(path, buf, len); + } else { + return -ENOSYS; + } } int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, dev_t rdev) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mknod) { - if (fs->debug) - fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n", - path, mode, (unsigned long long) rdev, - fuse_get_context()->umask); - - return fs->op.mknod(path, mode, rdev); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mknod) { + if (fs->debug) + fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n", + path, mode, (unsigned long long) rdev, + fuse_get_context()->umask); + + return fs->op.mknod(path, mode, rdev); + } else { + return -ENOSYS; + } } int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mkdir) { - if (fs->debug) - fprintf(stderr, "mkdir %s 0%o umask=0%03o\n", - path, mode, fuse_get_context()->umask); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mkdir) { + if (fs->debug) + fprintf(stderr, "mkdir %s 0%o umask=0%03o\n", + path, mode, fuse_get_context()->umask); - return fs->op.mkdir(path, mode); - } else { - return -ENOSYS; - } + return fs->op.mkdir(path, mode); + } else { + return -ENOSYS; + } } int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, const char *value, size_t size, int flags) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.setxattr) { - if (fs->debug) - fprintf(stderr, "setxattr %s %s %lu 0x%x\n", - path, name, (unsigned long) size, flags); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.setxattr) { + if (fs->debug) + fprintf(stderr, "setxattr %s %s %lu 0x%x\n", + path, name, (unsigned long) size, flags); - return fs->op.setxattr(path, name, value, size, flags); - } else { - return -ENOSYS; - } + return fs->op.setxattr(path, name, value, size, flags); + } else { + return -ENOSYS; + } } int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, char *value, size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.getxattr) { - if (fs->debug) - fprintf(stderr, "getxattr %s %s %lu\n", - path, name, (unsigned long) size); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getxattr) { + if (fs->debug) + fprintf(stderr, "getxattr %s %s %lu\n", + path, name, (unsigned long) size); - return fs->op.getxattr(path, name, value, size); - } else { - return -ENOSYS; - } + return fs->op.getxattr(path, name, value, size); + } else { + return -ENOSYS; + } } int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.listxattr) { - if (fs->debug) - fprintf(stderr, "listxattr %s %lu\n", - path, (unsigned long) size); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.listxattr) { + if (fs->debug) + fprintf(stderr, "listxattr %s %lu\n", + path, (unsigned long) size); - return fs->op.listxattr(path, list, size); - } else { - return -ENOSYS; - } + return fs->op.listxattr(path, list, size); + } else { + return -ENOSYS; + } } int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, uint64_t *idx) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.bmap) { - if (fs->debug) - fprintf(stderr, "bmap %s blocksize: %lu index: %llu\n", - path, (unsigned long) blocksize, - (unsigned long long) *idx); - - return fs->op.bmap(path, blocksize, idx); - } else { - return -ENOSYS; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.bmap) { + if (fs->debug) + fprintf(stderr, "bmap %s blocksize: %lu index: %llu\n", + path, (unsigned long) blocksize, + (unsigned long long) *idx); + + return fs->op.bmap(path, blocksize, idx); + } else { + return -ENOSYS; + } } int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.removexattr) { - if (fs->debug) - fprintf(stderr, "removexattr %s %s\n", path, name); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.removexattr) { + if (fs->debug) + fprintf(stderr, "removexattr %s %s\n", path, name); - return fs->op.removexattr(path, name); - } else { - return -ENOSYS; - } + return fs->op.removexattr(path, name); + } else { + return -ENOSYS; + } } int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data, uint32_t *out_size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.ioctl) { - if (fs->debug) - fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n", - (unsigned long long) fi->fh, cmd, flags); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.ioctl) { + if (fs->debug) + fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n", + (unsigned long long) fi->fh, cmd, flags); - return fs->op.ioctl(path, cmd, arg, fi, flags, data, out_size); - } else - return -ENOSYS; + return fs->op.ioctl(path, cmd, arg, fi, flags, data, out_size); + } else + return -ENOSYS; } int fuse_fs_poll(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.poll) { - int res; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.poll) { + int res; - if (fs->debug) - fprintf(stderr, "poll[%llu] ph: %p\n", - (unsigned long long) fi->fh, ph); + if (fs->debug) + fprintf(stderr, "poll[%llu] ph: %p\n", + (unsigned long long) fi->fh, ph); - res = fs->op.poll(path, fi, ph, reventsp); + res = fs->op.poll(path, fi, ph, reventsp); - if (fs->debug && !res) - fprintf(stderr, " poll[%llu] revents: 0x%x\n", - (unsigned long long) fi->fh, *reventsp); + if (fs->debug && !res) + fprintf(stderr, " poll[%llu] revents: 0x%x\n", + (unsigned long long) fi->fh, *reventsp); - return res; - } else - return -ENOSYS; + return res; + } else + return -ENOSYS; } int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode, - off_t offset, off_t length, struct fuse_file_info *fi) + off_t offset, off_t length, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fallocate) { - if (fs->debug) - fprintf(stderr, "fallocate %s mode %x, offset: %llu, length: %llu\n", - path, - mode, - (unsigned long long) offset, - (unsigned long long) length); - - return fs->op.fallocate(path, mode, offset, length, fi); - } else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fallocate) { + if (fs->debug) + fprintf(stderr, "fallocate %s mode %x, offset: %llu, length: %llu\n", + path, + mode, + (unsigned long long) offset, + (unsigned long long) length); + + return fs->op.fallocate(path, mode, offset, length, fi); + } else + return -ENOSYS; } ssize_t @@ -2348,16 +2232,16 @@ node_open(const struct node *node_) static void curr_time(struct timespec *now) { - static clockid_t clockid = CLOCK_MONOTONIC; - int res = clock_gettime(clockid, now); - if (res == -1 && errno == EINVAL) { - clockid = CLOCK_REALTIME; - res = clock_gettime(clockid, now); - } - if (res == -1) { - perror("fuse: clock_gettime"); - abort(); - } + static clockid_t clockid = CLOCK_MONOTONIC; + int res = clock_gettime(clockid, now); + if (res == -1 && errno == EINVAL) { + clockid = CLOCK_REALTIME; + res = clock_gettime(clockid, now); + } + if (res == -1) { + perror("fuse: clock_gettime"); + abort(); + } } static @@ -2381,225 +2265,237 @@ static int lookup_path(struct fuse *f, fuse_ino_t nodeid, const char *name, const char *path, struct fuse_entry_param *e, struct fuse_file_info *fi) { - int res; - - memset(e, 0, sizeof(struct fuse_entry_param)); - if (fi) - res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); - else - res = fuse_fs_getattr(f->fs, path, &e->attr); - if (res == 0) { - struct node *node; - - node = find_node(f, nodeid, name); - if (node == NULL) - res = -ENOMEM; - else { - e->ino = node->nodeid; - e->generation = node->generation; - e->entry_timeout = f->conf.entry_timeout; - e->attr_timeout = f->conf.attr_timeout; - pthread_mutex_lock(&f->lock); - update_stat(node, &e->attr); - pthread_mutex_unlock(&f->lock); - set_stat(f, e->ino, &e->attr); - if(f->conf.debug) - fprintf(stderr, - " NODEID: %llu\n" - " GEN: %llu\n", - (unsigned long long)e->ino, - (unsigned long long)e->generation); - } - } - return res; + int res; + + memset(e, 0, sizeof(struct fuse_entry_param)); + if (fi) + res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); + else + res = fuse_fs_getattr(f->fs, path, &e->attr); + if (res == 0) { + struct node *node; + + node = find_node(f, nodeid, name); + if (node == NULL) + res = -ENOMEM; + else { + e->ino = node->nodeid; + e->generation = node->generation; + e->entry_timeout = f->conf.entry_timeout; + e->attr_timeout = f->conf.attr_timeout; + pthread_mutex_lock(&f->lock); + update_stat(node, &e->attr); + pthread_mutex_unlock(&f->lock); + set_stat(f, e->ino, &e->attr); + if(f->conf.debug) + fprintf(stderr, + " NODEID: %llu\n" + " GEN: %llu\n", + (unsigned long long)e->ino, + (unsigned long long)e->generation); + } + } + return res; } static struct fuse_context_i *fuse_get_context_internal(void) { - struct fuse_context_i *c; - - c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); - if (c == NULL) { - c = (struct fuse_context_i *) - calloc(1, sizeof(struct fuse_context_i)); - if (c == NULL) { - /* This is hard to deal with properly, so just - abort. If memory is so low that the - context cannot be allocated, there's not - much hope for the filesystem anyway */ - fprintf(stderr, "fuse: failed to allocate thread specific data\n"); - abort(); - } - pthread_setspecific(fuse_context_key, c); - } - return c; + struct fuse_context_i *c; + + c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); + if (c == NULL) { + c = (struct fuse_context_i *) + calloc(1, sizeof(struct fuse_context_i)); + if (c == NULL) { + /* This is hard to deal with properly, so just + abort. If memory is so low that the + context cannot be allocated, there's not + much hope for the filesystem anyway */ + fprintf(stderr, "fuse: failed to allocate thread specific data\n"); + abort(); + } + pthread_setspecific(fuse_context_key, c); + } + return c; } static void fuse_freecontext(void *data) { - free(data); + free(data); } static int fuse_create_context_key(void) { - int err = 0; - pthread_mutex_lock(&fuse_context_lock); - if (!fuse_context_ref) { - err = pthread_key_create(&fuse_context_key, fuse_freecontext); - if (err) { - fprintf(stderr, "fuse: failed to create thread specific key: %s\n", - strerror(err)); - pthread_mutex_unlock(&fuse_context_lock); - return -1; - } - } - fuse_context_ref++; - pthread_mutex_unlock(&fuse_context_lock); - return 0; + int err = 0; + pthread_mutex_lock(&fuse_context_lock); + if (!fuse_context_ref) { + err = pthread_key_create(&fuse_context_key, fuse_freecontext); + if (err) { + fprintf(stderr, "fuse: failed to create thread specific key: %s\n", + strerror(err)); + pthread_mutex_unlock(&fuse_context_lock); + return -1; + } + } + fuse_context_ref++; + pthread_mutex_unlock(&fuse_context_lock); + return 0; } static void fuse_delete_context_key(void) { - pthread_mutex_lock(&fuse_context_lock); - fuse_context_ref--; - if (!fuse_context_ref) { - free(pthread_getspecific(fuse_context_key)); - pthread_key_delete(fuse_context_key); - } - pthread_mutex_unlock(&fuse_context_lock); + pthread_mutex_lock(&fuse_context_lock); + fuse_context_ref--; + if (!fuse_context_ref) { + free(pthread_getspecific(fuse_context_key)); + pthread_key_delete(fuse_context_key); + } + pthread_mutex_unlock(&fuse_context_lock); } static struct fuse *req_fuse_prepare(fuse_req_t req) { - struct fuse_context_i *c = fuse_get_context_internal(); - const struct fuse_ctx *ctx = fuse_req_ctx(req); - c->req = req; - c->ctx.fuse = req_fuse(req); - c->ctx.uid = ctx->uid; - c->ctx.gid = ctx->gid; - c->ctx.pid = ctx->pid; - c->ctx.umask = ctx->umask; - return c->ctx.fuse; + struct fuse_context_i *c = fuse_get_context_internal(); + const struct fuse_ctx *ctx = fuse_req_ctx(req); + c->req = req; + c->ctx.fuse = req_fuse(req); + c->ctx.uid = ctx->uid; + c->ctx.gid = ctx->gid; + c->ctx.pid = ctx->pid; + c->ctx.umask = ctx->umask; + return c->ctx.fuse; +} + +/* fuse_reply_err() uses non-negated errno values */ +static +inline +void +reply_err(fuse_req_t req_, + int err_) +{ + fuse_reply_err(req_,-err_); } -static inline void reply_err(fuse_req_t req, int err) +static +inline +void +reply_ENOMEM(fuse_req_t req_) { - /* fuse_reply_err() uses non-negated errno values */ - fuse_reply_err(req, -err); + fuse_reply_err(req_,ENOMEM); } static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, int err) { - if (!err) { - struct fuse *f = req_fuse(req); - if (fuse_reply_entry(req, e) == -ENOENT) { - /* Skip forget for negative result */ - if (e->ino != 0) - forget_node(f, e->ino, 1); - } - } else - reply_err(req, err); + if (!err) { + struct fuse *f = req_fuse(req); + if (fuse_reply_entry(req, e) == -ENOENT) { + /* Skip forget for negative result */ + if (e->ino != 0) + forget_node(f, e->ino, 1); + } + } else + reply_err(req, err); } void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn) { - fuse_get_context()->private_data = fs->user_data; - if (!fs->op.write_buf) - conn->want &= ~FUSE_CAP_SPLICE_READ; - if (!fs->op.lock) - conn->want &= ~FUSE_CAP_POSIX_LOCKS; - if (!fs->op.flock) - conn->want &= ~FUSE_CAP_FLOCK_LOCKS; - if (fs->op.init) - fs->user_data = fs->op.init(conn); + fuse_get_context()->private_data = fs->user_data; + if (!fs->op.write_buf) + conn->want &= ~FUSE_CAP_SPLICE_READ; + if (!fs->op.lock) + conn->want &= ~FUSE_CAP_POSIX_LOCKS; + if (!fs->op.flock) + conn->want &= ~FUSE_CAP_FLOCK_LOCKS; + if (fs->op.init) + fs->user_data = fs->op.init(conn); } static void fuse_lib_init(void *data, struct fuse_conn_info *conn) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - conn->want |= FUSE_CAP_EXPORT_SUPPORT; - fuse_fs_init(f->fs, conn); + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + conn->want |= FUSE_CAP_EXPORT_SUPPORT; + fuse_fs_init(f->fs, conn); } void fuse_fs_destroy(struct fuse_fs *fs) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.destroy) - fs->op.destroy(fs->user_data); - free(fs); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.destroy) + fs->op.destroy(fs->user_data); + free(fs); } static void fuse_lib_destroy(void *data) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - fuse_fs_destroy(f->fs); - f->fs = NULL; + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_destroy(f->fs); + f->fs = NULL; } static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - struct node *dot = NULL; - - if (name[0] == '.') { - int len = strlen(name); - - if (len == 1 || (name[1] == '.' && len == 2)) { - pthread_mutex_lock(&f->lock); - if (len == 1) { - if (f->conf.debug) - fprintf(stderr, "LOOKUP-DOT\n"); - dot = get_node_nocheck(f, parent); - if (dot == NULL) { - pthread_mutex_unlock(&f->lock); - reply_entry(req, &e, -ESTALE); - return; - } - dot->refctr++; - } else { - if (f->conf.debug) - fprintf(stderr, "LOOKUP-DOTDOT\n"); - parent = get_node(f, parent)->parent->nodeid; - } - pthread_mutex_unlock(&f->lock); - name = NULL; - } - } - - err = get_path_name(f, parent, name, &path); - if (!err) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "LOOKUP %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = lookup_path(f, parent, name, path, &e, NULL); - if (err == -ENOENT && f->conf.negative_timeout != 0.0) { - e.ino = 0; - e.entry_timeout = f->conf.negative_timeout; - err = 0; - } - fuse_finish_interrupt(f, req, &d); - free_path(f, parent, path); - } - if (dot) { - pthread_mutex_lock(&f->lock); - unref_node(f, dot); - pthread_mutex_unlock(&f->lock); - } - reply_entry(req, &e, err); + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + struct node *dot = NULL; + + if (name[0] == '.') { + int len = strlen(name); + + if (len == 1 || (name[1] == '.' && len == 2)) { + pthread_mutex_lock(&f->lock); + if (len == 1) { + if (f->conf.debug) + fprintf(stderr, "LOOKUP-DOT\n"); + dot = get_node_nocheck(f, parent); + if (dot == NULL) { + pthread_mutex_unlock(&f->lock); + reply_entry(req, &e, -ESTALE); + return; + } + dot->refctr++; + } else { + if (f->conf.debug) + fprintf(stderr, "LOOKUP-DOTDOT\n"); + parent = get_node(f, parent)->parent->nodeid; + } + pthread_mutex_unlock(&f->lock); + name = NULL; + } + } + + err = get_path_name(f, parent, name, &path); + if (!err) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "LOOKUP %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = lookup_path(f, parent, name, path, &e, NULL); + if (err == -ENOENT && f->conf.negative_timeout != 0.0) { + e.ino = 0; + e.entry_timeout = f->conf.negative_timeout; + err = 0; + } + fuse_finish_interrupt(f, req, &d); + free_path(f, parent, path); + } + if (dot) { + pthread_mutex_lock(&f->lock); + unref_node(f, dot); + pthread_mutex_unlock(&f->lock); + } + reply_entry(req, &e, err); } static @@ -2629,75 +2525,75 @@ fuse_lib_forget(fuse_req_t req, static void fuse_lib_forget_multi(fuse_req_t req, size_t count, struct fuse_forget_data *forgets) { - struct fuse *f = req_fuse(req); - size_t i; + struct fuse *f = req_fuse(req); + size_t i; - for (i = 0; i < count; i++) - do_forget(f, forgets[i].ino, forgets[i].nlookup); + for (i = 0; i < count; i++) + do_forget(f, forgets[i].ino, forgets[i].nlookup); - fuse_reply_none(req); + fuse_reply_none(req); } static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct stat buf; - char *path; - int err; - struct node *node; - struct fuse_file_info ffi = {0}; + struct fuse *f = req_fuse_prepare(req); + struct stat buf; + char *path; + int err; + struct node *node; + struct fuse_file_info ffi = {0}; - if(fi == NULL) - { - pthread_mutex_lock(&f->lock); - node = get_node(f,ino); - if(node->is_hidden) - { - fi = &ffi; - fi->fh = node->hidden_fh; - } - pthread_mutex_unlock(&f->lock); - } + if(fi == NULL) + { + pthread_mutex_lock(&f->lock); + node = get_node(f,ino); + if(node->is_hidden) + { + fi = &ffi; + fi->fh = node->hidden_fh; + } + pthread_mutex_unlock(&f->lock); + } - memset(&buf, 0, sizeof(buf)); + memset(&buf, 0, sizeof(buf)); - path = NULL; - err = (((fi == NULL) || (f->fs->op.fgetattr == NULL)) ? - get_path(f,ino,&path) : - get_path_nullok(f,ino,&path)); + path = NULL; + err = (((fi == NULL) || (f->fs->op.fgetattr == NULL)) ? + get_path(f,ino,&path) : + get_path_nullok(f,ino,&path)); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); - err = ((fi == NULL) ? - fuse_fs_getattr(f->fs,path,&buf) : - fuse_fs_fgetattr(f->fs,path,&buf,fi)); + err = ((fi == NULL) ? + fuse_fs_getattr(f->fs,path,&buf) : + fuse_fs_fgetattr(f->fs,path,&buf,fi)); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } - if (!err) { - pthread_mutex_lock(&f->lock); - node = get_node(f, ino); - update_stat(node, &buf); - pthread_mutex_unlock(&f->lock); - set_stat(f, ino, &buf); - fuse_reply_attr(req, &buf, f->conf.attr_timeout); - } else - reply_err(req, err); + if (!err) { + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + update_stat(node, &buf); + pthread_mutex_unlock(&f->lock); + set_stat(f, ino, &buf); + fuse_reply_attr(req, &buf, f->conf.attr_timeout); + } else + reply_err(req, err); } int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chmod) - return fs->op.chmod(path, mode); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chmod) + return fs->op.chmod(path, mode); + else + return -ENOSYS; } int @@ -2837,102 +2733,102 @@ fuse_lib_setattr(fuse_req_t req, static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_access(f->fs, path, mask); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_access(f->fs, path, mask); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - char linkname[PATH_MAX + 1]; - char *path; - int err; - - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - if (!err) { - linkname[PATH_MAX] = '\0'; - fuse_reply_readlink(req, linkname); - } else - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + char linkname[PATH_MAX + 1]; + char *path; + int err; + + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + if (!err) { + linkname[PATH_MAX] = '\0'; + fuse_reply_readlink(req, linkname); + } else + reply_err(req, err); } static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = get_path_name(f, parent, name, &path); - if (!err) { - struct fuse_intr_data d; - - fuse_prepare_interrupt(f, req, &d); - err = -ENOSYS; - if (S_ISREG(mode)) { - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.flags = O_CREAT | O_EXCL | O_WRONLY; - err = fuse_fs_create(f->fs, path, mode, &fi); - if (!err) { - err = lookup_path(f, parent, name, path, &e, - &fi); - fuse_fs_release(f->fs, path, &fi); - } - } - if (err == -ENOSYS) { - err = fuse_fs_mknod(f->fs, path, mode, rdev); - if (!err) - err = lookup_path(f, parent, name, path, &e, - NULL); - } - fuse_finish_interrupt(f, req, &d); - free_path(f, parent, path); - } - reply_entry(req, &e, err); + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = get_path_name(f, parent, name, &path); + if (!err) { + struct fuse_intr_data d; + + fuse_prepare_interrupt(f, req, &d); + err = -ENOSYS; + if (S_ISREG(mode)) { + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = O_CREAT | O_EXCL | O_WRONLY; + err = fuse_fs_create(f->fs, path, mode, &fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, + &fi); + fuse_fs_release(f->fs, path, &fi); + } + } + if (err == -ENOSYS) { + err = fuse_fs_mknod(f->fs, path, mode, rdev); + if (!err) + err = lookup_path(f, parent, name, path, &e, + NULL); + } + fuse_finish_interrupt(f, req, &d); + free_path(f, parent, path); + } + reply_entry(req, &e, err); } static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = get_path_name(f, parent, name, &path); - if (!err) { - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_mkdir(f->fs, path, mode); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free_path(f, parent, path); - } - reply_entry(req, &e, err); + err = get_path_name(f, parent, name, &path); + if (!err) { + struct fuse_intr_data d; + + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_mkdir(f->fs, path, mode); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free_path(f, parent, path); + } + reply_entry(req, &e, err); } static @@ -2976,45 +2872,45 @@ fuse_lib_unlink(fuse_req_t req, static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { - struct fuse *f = req_fuse_prepare(req); - struct node *wnode; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct node *wnode; + char *path; + int err; - err = get_path_wrlock(f, parent, name, &path, &wnode); - if (!err) { - struct fuse_intr_data d; + err = get_path_wrlock(f, parent, name, &path, &wnode); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_rmdir(f->fs, path); - fuse_finish_interrupt(f, req, &d); - if (!err) - remove_node(f, parent, name); - free_path_wrlock(f, parent, wnode, path); - } - reply_err(req, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_rmdir(f->fs, path); + fuse_finish_interrupt(f, req, &d); + if (!err) + remove_node(f, parent, name); + free_path_wrlock(f, parent, wnode, path); + } + reply_err(req, err); } static void fuse_lib_symlink(fuse_req_t req, const char *linkname, fuse_ino_t parent, const char *name) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = get_path_name(f, parent, name, &path); - if (!err) { - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_symlink(f->fs, linkname, path); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free_path(f, parent, path); - } - reply_entry(req, &e, err); + err = get_path_name(f, parent, name, &path); + if (!err) { + struct fuse_intr_data d; + + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_symlink(f->fs, linkname, path); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free_path(f, parent, path); + } + reply_entry(req, &e, err); } static @@ -3064,58 +2960,58 @@ fuse_lib_rename(fuse_req_t req, static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *oldpath; - char *newpath; - int err; - - err = get_path2(f, ino, NULL, newparent, newname, - &oldpath, &newpath, NULL, NULL); - if (!err) { - struct fuse_intr_data d; + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *oldpath; + char *newpath; + int err; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_link(f->fs, oldpath, newpath); - if (!err) - err = lookup_path(f, newparent, newname, newpath, - &e, NULL); - fuse_finish_interrupt(f, req, &d); - free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath); - } - reply_entry(req, &e, err); + err = get_path2(f, ino, NULL, newparent, newname, + &oldpath, &newpath, NULL, NULL); + if (!err) { + struct fuse_intr_data d; + + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_link(f->fs, oldpath, newpath); + if (!err) + err = lookup_path(f, newparent, newname, newpath, + &e, NULL); + fuse_finish_interrupt(f, req, &d); + free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath); + } + reply_entry(req, &e, err); } static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path, struct fuse_file_info *fi) { - struct node *node; - uint64_t fh; - int was_hidden; - const char *compatpath; + struct node *node; + uint64_t fh; + int was_hidden; + const char *compatpath; - fh = 0; - if (path != NULL || f->nullpath_ok || f->conf.nopath) - compatpath = path; - else - compatpath = "-"; + fh = 0; + 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, compatpath, fi); - pthread_mutex_lock(&f->lock); - node = get_node(f, ino); - assert(node->open_count > 0); - node->open_count--; - was_hidden = 0; - if (node->is_hidden && (node->open_count == 0)) { - was_hidden = 1; - node->is_hidden = 0; - fh = node->hidden_fh; - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + assert(node->open_count > 0); + node->open_count--; + was_hidden = 0; + if (node->is_hidden && (node->open_count == 0)) { + was_hidden = 1; + node->is_hidden = 0; + fh = node->hidden_fh; + } + pthread_mutex_unlock(&f->lock); - if(was_hidden) - fuse_fs_free_hide(f->fs,fh); + if(was_hidden) + fuse_fs_free_hide(f->fs,fh); } static @@ -3179,8 +3075,8 @@ fuse_lib_create(fuse_req_t req, static double diff_timespec(const struct timespec *t1, const struct timespec *t2) { - return (t1->tv_sec - t2->tv_sec) + - ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; + return (t1->tv_sec - t2->tv_sec) + + ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; } static @@ -3263,129 +3159,130 @@ fuse_lib_open(fuse_req_t req, static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_bufvec *buf = NULL; - char *path; - int res; + struct fuse *f = req_fuse_prepare(req); + struct fuse_bufvec *buf = NULL; + char *path; + int res; - res = get_path_nullok(f, ino, &path); - if (res == 0) { - struct fuse_intr_data d; + res = get_path_nullok(f, ino, &path); + if (res == 0) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } - if (res == 0) - fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE); - else - reply_err(req, res); + if (res == 0) + fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE); + else + reply_err(req, res); - fuse_free_buf(buf); + fuse_free_buf(buf); } static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int res; + struct fuse *f = req_fuse_prepare(req); + char *path; + int res; - res = get_path_nullok(f, ino, &path); - if (res == 0) { - struct fuse_intr_data d; + res = get_path_nullok(f, ino, &path); + if (res == 0) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_write_buf(f->fs, path, buf, off, fi); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_write_buf(f->fs, path, buf, off, fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } - if (res >= 0) - fuse_reply_write(req, res); - else - reply_err(req, res); + if (res >= 0) + fuse_reply_write(req, res); + else + reply_err(req, res); } static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path_nullok(f, ino, &path); - if (!err) { - struct fuse_intr_data d; + err = get_path_nullok(f, ino, &path); + if (!err) { + struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsync(f->fs, path, datasync, fi); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsync(f->fs, path, datasync, fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, struct fuse_file_info *fi) { - struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; - memset(fi, 0, sizeof(struct fuse_file_info)); - fi->fh = dh->fh; - return dh; -} - -static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *llfi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_dh *dh; - struct fuse_file_info fi; - char *path; - int err; - - dh = (struct fuse_dh *) calloc(1,sizeof(struct fuse_dh)); - if (dh == NULL) { - reply_err(req, -ENOMEM); - return; - } - - fuse_dirents_init(&dh->d); - fuse_mutex_init(&dh->lock); - - llfi->fh = (uintptr_t) dh; - - memset(&fi, 0, sizeof(fi)); - fi.flags = llfi->flags; - - err = get_path(f, ino, &path); - if (!err) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_opendir(f->fs, path, &fi); - fuse_finish_interrupt(f, req, &d); - dh->fh = fi.fh; - llfi->keep_cache = fi.keep_cache; - llfi->cache_readdir = fi.cache_readdir; - } - - if (!err) { - if (fuse_reply_open(req, llfi) == -ENOENT) { - /* The opendir syscall was interrupted, so it - must be cancelled */ - fuse_fs_releasedir(f->fs, path, &fi); - pthread_mutex_destroy(&dh->lock); - free(dh); - } - } else { - reply_err(req, err); - pthread_mutex_destroy(&dh->lock); - free(dh); - } - free_path(f, ino, path); + struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; + memset(fi, 0, sizeof(struct fuse_file_info)); + fi->fh = dh->fh; + return dh; +} + +static +void +fuse_lib_opendir(fuse_req_t req, + fuse_ino_t ino, + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_dh *dh; + struct fuse_file_info fi; + char *path; + int err; + + dh = (struct fuse_dh*)calloc(1,sizeof(struct fuse_dh)); + if(dh == NULL) + return reply_ENOMEM(req); + + fuse_dirents_init(&dh->d); + fuse_mutex_init(&dh->lock); + + llfi->fh = (uintptr_t)dh; + + memset(&fi,0,sizeof(fi)); + fi.flags = llfi->flags; + + err = get_path(f, ino, &path); + if (!err) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_opendir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + dh->fh = fi.fh; + llfi->keep_cache = fi.keep_cache; + llfi->cache_readdir = fi.cache_readdir; + } + + if (!err) { + if (fuse_reply_open(req, llfi) == -ENOENT) { + /* The opendir syscall was interrupted, so it + must be cancelled */ + fuse_fs_releasedir(f->fs, path, &fi); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + } else { + reply_err(req, err); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + free_path(f, ino, path); } static @@ -3567,170 +3464,174 @@ fuse_lib_releasedir(fuse_req_t req_, static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *llfi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_file_info fi; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + char *path; + int err; - get_dirhandle(llfi, &fi); + get_dirhandle(llfi, &fi); - err = get_path_nullok(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + err = get_path_nullok(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - struct statvfs buf; - char *path = NULL; - int err = 0; + struct fuse *f = req_fuse_prepare(req); + struct statvfs buf; + char *path = NULL; + int err = 0; - memset(&buf, 0, sizeof(buf)); - if (ino) - err = get_path(f, ino, &path); + memset(&buf, 0, sizeof(buf)); + if (ino) + err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_statfs(f->fs, path ? path : "/", &buf); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_statfs(f->fs, path ? path : "/", &buf); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } - if (!err) - fuse_reply_statfs(req, &buf); - else - reply_err(req, err); + if (!err) + fuse_reply_statfs(req, &buf); + else + reply_err(req, err); } static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, const char *name, char *value, size_t size) { - int err; - char *path; + int err; + char *path; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_getxattr(f->fs, path, name, value, size); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - return err; + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getxattr(f->fs, path, name, value, size); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + return err; } static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { - struct fuse *f = req_fuse_prepare(req); - int res; - - if (size) { - char *value = (char *) malloc(size); - if (value == NULL) { - reply_err(req, -ENOMEM); - return; - } - res = common_getxattr(f, req, ino, name, value, size); - if (res > 0) - fuse_reply_buf(req, value, res); - else - reply_err(req, res); - free(value); - } else { - res = common_getxattr(f, req, ino, name, NULL, 0); - if (res >= 0) - fuse_reply_xattr(req, res); - else - reply_err(req, res); - } + int res; + struct fuse *f = req_fuse_prepare(req); + + if(size) + { + char *value = (char*)malloc(size); + if(value == NULL) + return reply_ENOMEM(req); + + res = common_getxattr(f, req, ino, name, value, size); + if(res > 0) + fuse_reply_buf(req, value, res); + else + reply_err(req, res); + free(value); + } + else + { + res = common_getxattr(f, req, ino, name, NULL, 0); + if(res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } } static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, char *list, size_t size) { - char *path; - int err; + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_listxattr(f->fs, path, list, size); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - return err; + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_listxattr(f->fs, path, list, size); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + return err; } static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { - struct fuse *f = req_fuse_prepare(req); - int res; - - if (size) { - char *list = (char *) malloc(size); - if (list == NULL) { - reply_err(req, -ENOMEM); - return; - } - res = common_listxattr(f, req, ino, list, size); - if (res > 0) - fuse_reply_buf(req, list, res); - else - reply_err(req, res); - free(list); - } else { - res = common_listxattr(f, req, ino, NULL, 0); - if (res >= 0) - fuse_reply_xattr(req, res); - else - reply_err(req, res); - } + struct fuse *f = req_fuse_prepare(req); + int res; + + if(size) + { + char *list = (char*)malloc(size); + if(list == NULL) + return reply_ENOMEM(req); + + res = common_listxattr(f, req, ino, list, size); + if (res > 0) + fuse_reply_buf(req, list, res); + else + reply_err(req, res); + free(list); + } + else + { + res = common_listxattr(f, req, ino, NULL, 0); + if (res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } } static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_removexattr(f->fs, path, name); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + err = get_path(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_removexattr(f->fs, path, name); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static @@ -3790,292 +3691,292 @@ fuse_lib_copy_file_range(fuse_req_t req_, static struct lock *locks_conflict(struct node *node, const struct lock *lock) { - struct lock *l; + struct lock *l; - for (l = node->locks; l; l = l->next) - if (l->owner != lock->owner && - lock->start <= l->end && l->start <= lock->end && - (l->type == F_WRLCK || lock->type == F_WRLCK)) - break; + for (l = node->locks; l; l = l->next) + if (l->owner != lock->owner && + lock->start <= l->end && l->start <= lock->end && + (l->type == F_WRLCK || lock->type == F_WRLCK)) + break; - return l; + return l; } static void delete_lock(struct lock **lockp) { - struct lock *l = *lockp; - *lockp = l->next; - free(l); + struct lock *l = *lockp; + *lockp = l->next; + free(l); } static void insert_lock(struct lock **pos, struct lock *lock) { - lock->next = *pos; - *pos = lock; + lock->next = *pos; + *pos = lock; } static int locks_insert(struct node *node, struct lock *lock) { - struct lock **lp; - struct lock *newl1 = NULL; - struct lock *newl2 = NULL; - - if (lock->type != F_UNLCK || lock->start != 0 || - lock->end != OFFSET_MAX) { - newl1 = malloc(sizeof(struct lock)); - newl2 = malloc(sizeof(struct lock)); - - if (!newl1 || !newl2) { - free(newl1); - free(newl2); - return -ENOLCK; - } - } - - for (lp = &node->locks; *lp;) { - struct lock *l = *lp; - if (l->owner != lock->owner) - goto skip; - - if (lock->type == l->type) { - if (l->end < lock->start - 1) - goto skip; - if (lock->end < l->start - 1) - break; - if (l->start <= lock->start && lock->end <= l->end) - goto out; - if (l->start < lock->start) - lock->start = l->start; - if (lock->end < l->end) - lock->end = l->end; - goto delete; - } else { - if (l->end < lock->start) - goto skip; - if (lock->end < l->start) - break; - if (lock->start <= l->start && l->end <= lock->end) - goto delete; - if (l->end <= lock->end) { - l->end = lock->start - 1; - goto skip; - } - if (lock->start <= l->start) { - l->start = lock->end + 1; - break; - } - *newl2 = *l; - newl2->start = lock->end + 1; - l->end = lock->start - 1; - insert_lock(&l->next, newl2); - newl2 = NULL; - } - skip: - lp = &l->next; - continue; - - delete: - delete_lock(lp); - } - if (lock->type != F_UNLCK) { - *newl1 = *lock; - insert_lock(lp, newl1); - newl1 = NULL; - } -out: - free(newl1); - free(newl2); - return 0; + struct lock **lp; + struct lock *newl1 = NULL; + struct lock *newl2 = NULL; + + if (lock->type != F_UNLCK || lock->start != 0 || + lock->end != OFFSET_MAX) { + newl1 = malloc(sizeof(struct lock)); + newl2 = malloc(sizeof(struct lock)); + + if (!newl1 || !newl2) { + free(newl1); + free(newl2); + return -ENOLCK; + } + } + + for (lp = &node->locks; *lp;) { + struct lock *l = *lp; + if (l->owner != lock->owner) + goto skip; + + if (lock->type == l->type) { + if (l->end < lock->start - 1) + goto skip; + if (lock->end < l->start - 1) + break; + if (l->start <= lock->start && lock->end <= l->end) + goto out; + if (l->start < lock->start) + lock->start = l->start; + if (lock->end < l->end) + lock->end = l->end; + goto delete; + } else { + if (l->end < lock->start) + goto skip; + if (lock->end < l->start) + break; + if (lock->start <= l->start && l->end <= lock->end) + goto delete; + if (l->end <= lock->end) { + l->end = lock->start - 1; + goto skip; + } + if (lock->start <= l->start) { + l->start = lock->end + 1; + break; + } + *newl2 = *l; + newl2->start = lock->end + 1; + l->end = lock->start - 1; + insert_lock(&l->next, newl2); + newl2 = NULL; + } + skip: + lp = &l->next; + continue; + + delete: + delete_lock(lp); + } + if (lock->type != F_UNLCK) { + *newl1 = *lock; + insert_lock(lp, newl1); + newl1 = NULL; + } + out: + free(newl1); + free(newl2); + return 0; } static void flock_to_lock(struct flock *flock, struct lock *lock) { - memset(lock, 0, sizeof(struct lock)); - lock->type = flock->l_type; - lock->start = flock->l_start; - lock->end = - flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; - lock->pid = flock->l_pid; + memset(lock, 0, sizeof(struct lock)); + lock->type = flock->l_type; + lock->start = flock->l_start; + lock->end = + flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; + lock->pid = flock->l_pid; } static void lock_to_flock(struct lock *lock, struct flock *flock) { - flock->l_type = lock->type; - flock->l_start = lock->start; - flock->l_len = - (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; - flock->l_pid = lock->pid; + flock->l_type = lock->type; + flock->l_start = lock->start; + flock->l_len = + (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; + flock->l_pid = lock->pid; } static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino, const char *path, struct fuse_file_info *fi) { - struct fuse_intr_data d; - struct flock lock; - struct lock l; - int err; - int errlock; - - fuse_prepare_interrupt(f, req, &d); - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - err = fuse_fs_flush(f->fs, path, fi); - errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); - fuse_finish_interrupt(f, req, &d); - - if (errlock != -ENOSYS) { - flock_to_lock(&lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - locks_insert(get_node(f, ino), &l); - pthread_mutex_unlock(&f->lock); - - /* if op.lock() is defined FLUSH is needed regardless - of op.flush() */ - if (err == -ENOSYS) - err = 0; - } - return err; + struct fuse_intr_data d; + struct flock lock; + struct lock l; + int err; + int errlock; + + fuse_prepare_interrupt(f, req, &d); + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + err = fuse_fs_flush(f->fs, path, fi); + errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); + fuse_finish_interrupt(f, req, &d); + + if (errlock != -ENOSYS) { + flock_to_lock(&lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + + /* if op.lock() is defined FLUSH is needed regardless + of op.flush() */ + if (err == -ENOSYS) + err = 0; + } + return err; } static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err = 0; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err = 0; - get_path_nullok(f, ino, &path); - if (fi->flush) { - err = fuse_flush_common(f, req, ino, path, fi); - if (err == -ENOSYS) - err = 0; - } + get_path_nullok(f, ino, &path); + if (fi->flush) { + err = fuse_flush_common(f, req, ino, path, fi); + if (err == -ENOSYS) + err = 0; + } - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, ino, path, fi); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, path, fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); - reply_err(req, err); + reply_err(req, err); } static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - get_path_nullok(f, ino, &path); - err = fuse_flush_common(f, req, ino, path, fi); - free_path(f, ino, path); + get_path_nullok(f, ino, &path); + err = fuse_flush_common(f, req, ino, path, fi); + free_path(f, ino, path); - reply_err(req, err); + reply_err(req, err); } static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int cmd) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path_nullok(f, ino, &path); - if (!err) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_lock(f->fs, path, fi, cmd, lock); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - return err; + err = get_path_nullok(f, ino, &path); + if (!err) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_lock(f->fs, path, fi, cmd, lock); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + return err; } static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock) { - int err; - struct lock l; - struct lock *conflict; - struct fuse *f = req_fuse(req); - - flock_to_lock(lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - conflict = locks_conflict(get_node(f, ino), &l); - if (conflict) - lock_to_flock(conflict, lock); - pthread_mutex_unlock(&f->lock); - if (!conflict) - err = fuse_lock_common(req, ino, fi, lock, F_GETLK); - else - err = 0; - - if (!err) - fuse_reply_lock(req, lock); - else - reply_err(req, err); + int err; + struct lock l; + struct lock *conflict; + struct fuse *f = req_fuse(req); + + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + conflict = locks_conflict(get_node(f, ino), &l); + if (conflict) + lock_to_flock(conflict, lock); + pthread_mutex_unlock(&f->lock); + if (!conflict) + err = fuse_lock_common(req, ino, fi, lock, F_GETLK); + else + err = 0; + + if (!err) + fuse_reply_lock(req, lock); + else + reply_err(req, err); } static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep) { - int err = fuse_lock_common(req, ino, fi, lock, - sleep ? F_SETLKW : F_SETLK); - if (!err) { - struct fuse *f = req_fuse(req); - struct lock l; - flock_to_lock(lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - locks_insert(get_node(f, ino), &l); - pthread_mutex_unlock(&f->lock); - } - reply_err(req, err); + int err = fuse_lock_common(req, ino, fi, lock, + sleep ? F_SETLKW : F_SETLK); + if (!err) { + struct fuse *f = req_fuse(req); + struct lock l; + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + } + reply_err(req, err); } static void fuse_lib_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - err = get_path_nullok(f, ino, &path); - if (err == 0) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_flock(f->fs, path, fi, op); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + err = get_path_nullok(f, ino, &path); + if (err == 0) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_flock(f->fs, path, fi, op); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err; - err = get_path(f, ino, &path); - if (!err) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_bmap(f->fs, path, blocksize, &idx); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - if (!err) - fuse_reply_bmap(req, idx); - else - reply_err(req, err); + err = get_path(f, ino, &path); + if (!err) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_bmap(f->fs, path, blocksize, &idx); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + if (!err) + fuse_reply_bmap(req, idx); + else + reply_err(req, err); } static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, @@ -4083,806 +3984,567 @@ static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz_) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_file_info fi; - char *path, *out_buf = NULL; - int err; - uint32_t out_bufsz = out_bufsz_; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_file_info fi; + char *path, *out_buf = NULL; + int err; + uint32_t out_bufsz = out_bufsz_; - err = -EPERM; - if (flags & FUSE_IOCTL_UNRESTRICTED) - goto err; + err = -EPERM; + if (flags & FUSE_IOCTL_UNRESTRICTED) + goto err; - if (flags & FUSE_IOCTL_DIR) - get_dirhandle(llfi, &fi); - else - fi = *llfi; + if (flags & FUSE_IOCTL_DIR) + get_dirhandle(llfi, &fi); + else + fi = *llfi; - if (out_bufsz) { - err = -ENOMEM; - out_buf = malloc(out_bufsz); - if (!out_buf) - goto err; - } + if (out_bufsz) { + err = -ENOMEM; + out_buf = malloc(out_bufsz); + if (!out_buf) + goto err; + } - assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz); - if (out_buf) - memcpy(out_buf, in_buf, in_bufsz); + assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz); + if (out_buf) + memcpy(out_buf, in_buf, in_bufsz); - err = get_path_nullok(f, ino, &path); - if (err) - goto err; + err = get_path_nullok(f, ino, &path); + if (err) + goto err; - fuse_prepare_interrupt(f, req, &d); + fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags, - out_buf ?: (void *)in_buf, &out_bufsz); + err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags, + out_buf ?: (void *)in_buf, &out_bufsz); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); - fuse_reply_ioctl(req, err, out_buf, out_bufsz); - goto out; -err: - reply_err(req, err); -out: - free(out_buf); + fuse_reply_ioctl(req, err, out_buf, out_bufsz); + goto out; + err: + reply_err(req, err); + out: + free(out_buf); } static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err; - unsigned revents = 0; - - err = get_path_nullok(f, ino, &path); - if (!err) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_poll(f->fs, path, fi, ph, &revents); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - if (!err) - fuse_reply_poll(req, revents); - else - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err; + unsigned revents = 0; + + err = get_path_nullok(f, ino, &path); + if (!err) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_poll(f->fs, path, fi, ph, &revents); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + if (!err) + fuse_reply_poll(req, revents); + else + reply_err(req, err); } static void fuse_lib_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, - off_t offset, off_t length, struct fuse_file_info *fi) + off_t offset, off_t length, struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err; - err = get_path_nullok(f, ino, &path); - if (!err) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fallocate(f->fs, path, mode, offset, length, fi); - fuse_finish_interrupt(f, req, &d); - free_path(f, ino, path); - } - reply_err(req, err); + err = get_path_nullok(f, ino, &path); + if (!err) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fallocate(f->fs, path, mode, offset, length, fi); + fuse_finish_interrupt(f, req, &d); + free_path(f, ino, path); + } + reply_err(req, err); } static int clean_delay(struct fuse *f) { - /* - * This is calculating the delay between clean runs. To - * reduce the number of cleans we are doing them 10 times - * within the remember window. - */ - int min_sleep = 60; - int max_sleep = 3600; - int sleep_time = f->conf.remember / 10; + /* + * This is calculating the delay between clean runs. To + * reduce the number of cleans we are doing them 10 times + * within the remember window. + */ + int min_sleep = 60; + int max_sleep = 3600; + int sleep_time = f->conf.remember / 10; - if (sleep_time > max_sleep) - return max_sleep; - if (sleep_time < min_sleep) - return min_sleep; - return sleep_time; + if (sleep_time > max_sleep) + return max_sleep; + if (sleep_time < min_sleep) + return min_sleep; + return sleep_time; } int fuse_clean_cache(struct fuse *f) { - struct node_lru *lnode; - struct list_head *curr, *next; - struct node *node; - struct timespec now; - - pthread_mutex_lock(&f->lock); - - curr_time(&now); - - for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) { - double age; - - next = curr->next; - lnode = list_entry(curr, struct node_lru, lru); - node = &lnode->node; - - age = diff_timespec(&now, &lnode->forget_time); - if (age <= f->conf.remember) - break; - - assert(node->nlookup == 1); - - /* Don't forget active directories */ - if (node->refctr > 1) - continue; - - node->nlookup = 0; - unhash_name(f, node); - unref_node(f, node); - } - pthread_mutex_unlock(&f->lock); - - return clean_delay(f); -} - -static struct fuse_lowlevel_ops fuse_path_ops = { - .init = fuse_lib_init, - .destroy = fuse_lib_destroy, - .lookup = fuse_lib_lookup, - .forget = fuse_lib_forget, - .forget_multi = fuse_lib_forget_multi, - .getattr = fuse_lib_getattr, - .setattr = fuse_lib_setattr, - .access = fuse_lib_access, - .readlink = fuse_lib_readlink, - .mknod = fuse_lib_mknod, - .mkdir = fuse_lib_mkdir, - .unlink = fuse_lib_unlink, - .rmdir = fuse_lib_rmdir, - .symlink = fuse_lib_symlink, - .rename = fuse_lib_rename, - .link = fuse_lib_link, - .create = fuse_lib_create, - .open = fuse_lib_open, - .read = fuse_lib_read, - .write_buf = fuse_lib_write_buf, - .flush = fuse_lib_flush, - .release = fuse_lib_release, - .fsync = fuse_lib_fsync, - .opendir = fuse_lib_opendir, - .readdir = fuse_lib_readdir, - .readdir_plus = fuse_lib_readdir_plus, - .releasedir = fuse_lib_releasedir, - .fsyncdir = fuse_lib_fsyncdir, - .statfs = fuse_lib_statfs, - .setxattr = fuse_lib_setxattr, - .getxattr = fuse_lib_getxattr, - .listxattr = fuse_lib_listxattr, - .removexattr = fuse_lib_removexattr, - .getlk = fuse_lib_getlk, - .setlk = fuse_lib_setlk, - .flock = fuse_lib_flock, - .bmap = fuse_lib_bmap, - .ioctl = fuse_lib_ioctl, - .poll = fuse_lib_poll, - .fallocate = fuse_lib_fallocate, - .copy_file_range = fuse_lib_copy_file_range, -}; - -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; -} + struct node_lru *lnode; + struct list_head *curr, *next; + struct node *node; + struct timespec now; -static int fuse_session_loop_remember(struct fuse *f) -{ - struct fuse_session *se = f->se; - int res = 0; - struct timespec now; - time_t next_clean; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char *) malloc(bufsize); - struct pollfd fds = { - .fd = fuse_chan_fd(ch), - .events = POLLIN - }; + pthread_mutex_lock(&f->lock); - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } + curr_time(&now); - 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; + for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) { + double age; - curr_time(&now); - if (now.tv_sec < next_clean) - timeout = next_clean - now.tv_sec; - else - timeout = 0; + next = curr->next; + lnode = list_entry(curr, struct node_lru, lru); + node = &lnode->node; - res = poll(&fds, 1, timeout * 1000); - if (res == -1) { - if (errno == -EINTR) - continue; - else - break; - } else if (res > 0) { - res = fuse_session_receive_buf(se, &fbuf, &tmpch); + age = diff_timespec(&now, &lnode->forget_time); + if (age <= f->conf.remember) + break; - if (res == -EINTR) - continue; - if (res <= 0) - break; + assert(node->nlookup == 1); - fuse_session_process_buf(se, &fbuf, tmpch); - } else { - timeout = fuse_clean_cache(f); - curr_time(&now); - next_clean = now.tv_sec + timeout; - } - } + /* Don't forget active directories */ + if (node->refctr > 1) + continue; - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; -} - -int fuse_loop(struct fuse *f) -{ - if (!f) - return -1; - - if (lru_enabled(f)) - return fuse_session_loop_remember(f); - - return fuse_session_loop(f->se); -} + node->nlookup = 0; + unhash_name(f, node); + unref_node(f, node); + } + pthread_mutex_unlock(&f->lock); -int fuse_invalidate(struct fuse *f, const char *path) -{ - (void) f; - (void) path; - return -EINVAL; -} + return clean_delay(f); +} + +static struct fuse_lowlevel_ops fuse_path_ops = + { + .init = fuse_lib_init, + .destroy = fuse_lib_destroy, + .lookup = fuse_lib_lookup, + .forget = fuse_lib_forget, + .forget_multi = fuse_lib_forget_multi, + .getattr = fuse_lib_getattr, + .setattr = fuse_lib_setattr, + .access = fuse_lib_access, + .readlink = fuse_lib_readlink, + .mknod = fuse_lib_mknod, + .mkdir = fuse_lib_mkdir, + .unlink = fuse_lib_unlink, + .rmdir = fuse_lib_rmdir, + .symlink = fuse_lib_symlink, + .rename = fuse_lib_rename, + .link = fuse_lib_link, + .create = fuse_lib_create, + .open = fuse_lib_open, + .read = fuse_lib_read, + .write_buf = fuse_lib_write_buf, + .flush = fuse_lib_flush, + .release = fuse_lib_release, + .fsync = fuse_lib_fsync, + .opendir = fuse_lib_opendir, + .readdir = fuse_lib_readdir, + .readdir_plus = fuse_lib_readdir_plus, + .releasedir = fuse_lib_releasedir, + .fsyncdir = fuse_lib_fsyncdir, + .statfs = fuse_lib_statfs, + .setxattr = fuse_lib_setxattr, + .getxattr = fuse_lib_getxattr, + .listxattr = fuse_lib_listxattr, + .removexattr = fuse_lib_removexattr, + .getlk = fuse_lib_getlk, + .setlk = fuse_lib_setlk, + .flock = fuse_lib_flock, + .bmap = fuse_lib_bmap, + .ioctl = fuse_lib_ioctl, + .poll = fuse_lib_poll, + .fallocate = fuse_lib_fallocate, + .copy_file_range = fuse_lib_copy_file_range, + }; -void fuse_exit(struct fuse *f) +int fuse_exited(struct fuse *f) { - fuse_session_exit(f->se); + return fuse_session_exited(f->se); } -struct fuse_context *fuse_get_context(void) +struct fuse_session* +fuse_get_session(struct fuse *f) { - return &fuse_get_context_internal()->ctx; + return f->se; } -/* - * 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) +void +fuse_exit(struct fuse *f) { - return &fuse_get_context_internal()->ctx; + fuse_session_exit(f->se); } -FUSE_SYMVER(".symver fuse_get_context_compat22,fuse_get_context@FUSE_2.2"); -int fuse_getgroups(int size, gid_t list[]) +struct +fuse_context* +fuse_get_context(void) { - fuse_req_t req = fuse_get_context_internal()->req; - return fuse_req_getgroups(req, size, list); + return &fuse_get_context_internal()->ctx; } int fuse_interrupted(void) { - return fuse_req_interrupted(fuse_get_context_internal()->req); + return fuse_req_interrupted(fuse_get_context_internal()->req); } void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) { - (void) func; - /* no-op */ + (void) func; + /* no-op */ } enum { - KEY_HELP, + KEY_HELP, }; #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } -static const struct fuse_opt fuse_lib_opts[] = { - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_LIB_OPT("debug", debug, 1), - FUSE_LIB_OPT("-d", debug, 1), - FUSE_LIB_OPT("umask=", set_mode, 1), - FUSE_LIB_OPT("umask=%o", umask, 0), - FUSE_LIB_OPT("uid=", set_uid, 1), - FUSE_LIB_OPT("uid=%d", uid, 0), - FUSE_LIB_OPT("gid=", set_gid, 1), - FUSE_LIB_OPT("gid=%d", gid, 0), - FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), - FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), - FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), - FUSE_LIB_OPT("noforget", remember, -1), - FUSE_LIB_OPT("remember=%u", remember, 0), - FUSE_LIB_OPT("nopath", nopath, 1), - FUSE_LIB_OPT("intr", intr, 1), - FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), - FUSE_LIB_OPT("threads=%d", threads, 0), - FUSE_LIB_OPT("use_ino", use_ino, 1), - FUSE_OPT_END -}; +static const struct fuse_opt fuse_lib_opts[] = + { + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_LIB_OPT("debug", debug, 1), + FUSE_LIB_OPT("-d", debug, 1), + FUSE_LIB_OPT("use_ino", use_ino, 1), + FUSE_LIB_OPT("umask=", set_mode, 1), + FUSE_LIB_OPT("umask=%o", umask, 0), + FUSE_LIB_OPT("uid=", set_uid, 1), + FUSE_LIB_OPT("uid=%d", uid, 0), + FUSE_LIB_OPT("gid=", set_gid, 1), + FUSE_LIB_OPT("gid=%d", gid, 0), + FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), + FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), + FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), + FUSE_LIB_OPT("noforget", remember, -1), + FUSE_LIB_OPT("remember=%u", remember, 0), + FUSE_LIB_OPT("nopath", nopath, 1), + FUSE_LIB_OPT("intr", intr, 1), + FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), + FUSE_LIB_OPT("threads=%d", threads, 0), + FUSE_OPT_END + }; static void fuse_lib_help(void) { - fprintf(stderr, -" -o umask=M set file permissions (octal)\n" -" -o uid=N set file owner\n" -" -o gid=N set file group\n" -" -o entry_timeout=T cache timeout for names (1.0s)\n" -" -o negative_timeout=T cache timeout for deleted names (0.0s)\n" -" -o attr_timeout=T cache timeout for attributes (1.0s)\n" -" -o noforget never forget cached inodes\n" -" -o remember=T remember cached inodes for T seconds (0s)\n" -" -o nopath don't supply path if not necessary\n" -" -o intr allow requests to be interrupted\n" -" -o intr_signal=NUM signal to send on interrupt (%i)\n" -" -o threads=NUM number of worker threads. 0 = autodetect.\n" -" Negative values autodetect then divide by\n" -" absolute value. default = 0\n" -"\n", FUSE_DEFAULT_INTR_SIGNAL); + fprintf(stderr, + " -o use_ino let filesystem set inode numbers\n" + " -o umask=M set file permissions (octal)\n" + " -o uid=N set file owner\n" + " -o gid=N set file group\n" + " -o entry_timeout=T cache timeout for names (1.0s)\n" + " -o negative_timeout=T cache timeout for deleted names (0.0s)\n" + " -o attr_timeout=T cache timeout for attributes (1.0s)\n" + " -o noforget never forget cached inodes\n" + " -o remember=T remember cached inodes for T seconds (0s)\n" + " -o nopath don't supply path if not necessary\n" + " -o intr allow requests to be interrupted\n" + " -o intr_signal=NUM signal to send on interrupt (%i)\n" + " -o threads=NUM number of worker threads. 0 = autodetect.\n" + " Negative values autodetect then divide by\n" + " absolute value. default = 0\n" + "\n", FUSE_DEFAULT_INTR_SIGNAL); } static int fuse_lib_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - (void) arg; (void) outargs; + (void) arg; (void) outargs; - if (key == KEY_HELP) { - struct fuse_config *conf = (struct fuse_config *) data; - fuse_lib_help(); - conf->help = 1; - } - - return 1; -} + if (key == KEY_HELP) { + struct fuse_config *conf = (struct fuse_config *) data; + fuse_lib_help(); + conf->help = 1; + } -int fuse_is_lib_option(const char *opt) -{ - return fuse_lowlevel_is_lib_option(opt) || - fuse_opt_match(fuse_lib_opts, opt); + return 1; } static int fuse_init_intr_signal(int signum, int *installed) { - struct sigaction old_sa; + struct sigaction old_sa; - if (sigaction(signum, NULL, &old_sa) == -1) { - perror("fuse: cannot get old signal handler"); - return -1; - } + if (sigaction(signum, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } - if (old_sa.sa_handler == SIG_DFL) { - struct sigaction sa; + if (old_sa.sa_handler == SIG_DFL) { + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = fuse_intr_sighandler; - sigemptyset(&sa.sa_mask); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = fuse_intr_sighandler; + sigemptyset(&sa.sa_mask); - if (sigaction(signum, &sa, NULL) == -1) { - perror("fuse: cannot set interrupt signal handler"); - return -1; - } - *installed = 1; - } - return 0; + if (sigaction(signum, &sa, NULL) == -1) { + perror("fuse: cannot set interrupt signal handler"); + return -1; + } + *installed = 1; + } + return 0; } static void fuse_restore_intr_signal(int signum) { - struct sigaction sa; + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = SIG_DFL; - sigaction(signum, &sa, NULL); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); } struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *user_data) { - struct fuse_fs *fs; + struct fuse_fs *fs; - if (sizeof(struct fuse_operations) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); - op_size = sizeof(struct fuse_operations); - } + if (sizeof(struct fuse_operations) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); + op_size = sizeof(struct fuse_operations); + } - fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); - if (!fs) { - fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); - return NULL; - } + fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); + if (!fs) { + fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); + return NULL; + } - fs->user_data = user_data; - if (op) - memcpy(&fs->op, op, op_size); - return fs; + fs->user_data = user_data; + if (op) + memcpy(&fs->op, op, op_size); + return fs; } static int node_table_init(struct node_table *t) { - t->size = NODE_TABLE_MIN_SIZE; - t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size); - if (t->array == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - t->use = 0; - t->split = 0; + t->size = NODE_TABLE_MIN_SIZE; + t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size); + if (t->array == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + t->use = 0; + t->split = 0; - return 0; + return 0; } static void *fuse_prune_nodes(void *fuse) { - struct fuse *f = fuse; - int sleep_time; + struct fuse *f = fuse; + int sleep_time; - while(1) { - sleep_time = fuse_clean_cache(f); - sleep(sleep_time); - } - return NULL; + while(1) { + sleep_time = fuse_clean_cache(f); + sleep(sleep_time); + } + return NULL; } int fuse_start_cleanup_thread(struct fuse *f) { - if (lru_enabled(f)) - return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f); + if (lru_enabled(f)) + return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f); - return 0; + return 0; } void fuse_stop_cleanup_thread(struct fuse *f) { - if (lru_enabled(f)) { - pthread_mutex_lock(&f->lock); - pthread_cancel(f->prune_thread); - pthread_mutex_unlock(&f->lock); - pthread_join(f->prune_thread, NULL); - } -} - -struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, void *user_data, int compat) -{ - struct fuse *f; - struct node *root; - struct fuse_fs *fs; - struct fuse_lowlevel_ops llop = fuse_path_ops; - - if (fuse_create_context_key() == -1) - goto out; - - f = (struct fuse *) calloc(1, sizeof(struct fuse)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out_delete_context_key; - } - - fs = fuse_fs_new(op, op_size, user_data); - if (!fs) - goto out_free; - - fs->compat = compat; - f->fs = fs; - 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) { - llop.getlk = NULL; - llop.setlk = NULL; - } - - f->conf.entry_timeout = 1.0; - f->conf.attr_timeout = 1.0; - f->conf.negative_timeout = 0.0; - f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; - - f->pagesize = getpagesize(); - init_list_head(&f->partial_slabs); - init_list_head(&f->full_slabs); - init_list_head(&f->lru_table); - - if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, - fuse_lib_opt_proc) == -1) - goto out_free_fs; - - if (compat && compat <= 25) { - if (fuse_sync_compat_args(args) == -1) - goto out_free_fs; - } - - f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); - if (f->se == NULL) { - goto out_free_fs; - } - - fuse_session_add_chan(f->se, ch); - - 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 */ - srand(time(NULL)); - f->fs->debug = f->conf.debug; - f->ctr = 0; - f->generation = rand64(); - if (node_table_init(&f->name_table) == -1) - goto out_free_session; - - if (node_table_init(&f->id_table) == -1) - goto out_free_name_table; - - fuse_mutex_init(&f->lock); - - root = alloc_node(f); - if (root == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_id_table; - } - if (lru_enabled(f)) { - struct node_lru *lnode = node_lru(root); - init_list_head(&lnode->lru); - } - - strcpy(root->inline_name, "/"); - root->name = root->inline_name; - - if (f->conf.intr && - fuse_init_intr_signal(f->conf.intr_signal, - &f->intr_installed) == -1) - goto out_free_root; - - root->parent = NULL; - root->nodeid = FUSE_ROOT_ID; - inc_nlookup(root); - hash_id(f, root); - - return f; - -out_free_root: - free(root); -out_free_id_table: - free(f->id_table.array); -out_free_name_table: - free(f->name_table.array); -out_free_session: - fuse_session_destroy(f->se); -out_free_fs: - /* Horrible compatibility hack to stop the destructor from being - called on the filesystem without init being called first */ - fs->op.destroy = NULL; - fuse_fs_destroy(f->fs); -out_free: - free(f); -out_delete_context_key: - fuse_delete_context_key(); -out: - return NULL; -} - -struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, size_t op_size, - void *user_data) -{ - return fuse_new_common(ch, args, op, op_size, user_data, 0); + if (lru_enabled(f)) { + pthread_mutex_lock(&f->lock); + pthread_cancel(f->prune_thread); + pthread_mutex_unlock(&f->lock); + pthread_join(f->prune_thread, NULL); + } } -void fuse_destroy(struct fuse *f) +struct fuse * +fuse_new_common(int devfuse_fd, struct fuse_args *args, + const struct fuse_operations *op, + size_t op_size, void *user_data) { - size_t i; + struct fuse *f; + struct node *root; + struct fuse_fs *fs; + struct fuse_lowlevel_ops llop = fuse_path_ops; - if (f->conf.intr && f->intr_installed) - fuse_restore_intr_signal(f->conf.intr_signal); + if (fuse_create_context_key() == -1) + goto out; - if (f->fs) { - struct fuse_context_i *c = fuse_get_context_internal(); + f = (struct fuse *) calloc(1, sizeof(struct fuse)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out_delete_context_key; + } - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; + fs = fuse_fs_new(op, op_size, user_data); + if (!fs) + goto out_free; - for (i = 0; i < f->id_table.size; i++) { - struct node *node; + 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; - for (node = f->id_table.array[i]; node != NULL; node = node->id_next) - { - if (node->is_hidden) - fuse_fs_free_hide(f->fs,node->hidden_fh); - } - } - } - for (i = 0; i < f->id_table.size; i++) { - struct node *node; - struct node *next; + /* Oh f**k, this is ugly! */ + if (!fs->op.lock) { + llop.getlk = NULL; + llop.setlk = NULL; + } - for (node = f->id_table.array[i]; node != NULL; node = next) { - next = node->id_next; - free_node(f, node); - f->id_table.use--; - } - } - assert(list_empty(&f->partial_slabs)); - assert(list_empty(&f->full_slabs)); + f->conf.entry_timeout = 1.0; + f->conf.attr_timeout = 1.0; + f->conf.negative_timeout = 0.0; + f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; - free(f->id_table.array); - free(f->name_table.array); - pthread_mutex_destroy(&f->lock); - fuse_session_destroy(f->se); - free(f); - fuse_delete_context_key(); -} + f->pagesize = getpagesize(); + init_list_head(&f->partial_slabs); + init_list_head(&f->full_slabs); + init_list_head(&f->lru_table); -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 (fuse_opt_parse(args, &f->conf, fuse_lib_opts, + fuse_lib_opt_proc) == -1) + goto out_free_fs; - if (ch) - f = fuse_new_common(ch, args, op, op_size, NULL, compat); + f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); + if (f->se == NULL) { + goto out_free_fs; + } - return f; -} + f->se->devfuse_fd = devfuse_fd; -#if !defined(__FreeBSD__) && !defined(__NetBSD__) + 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); + } -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); + /* Trace topmost layer by default */ + srand(time(NULL)); + f->fs->debug = f->conf.debug; + f->ctr = 0; + f->generation = rand64(); + if (node_table_init(&f->name_table) == -1) + goto out_free_session; - if (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; - } + if (node_table_init(&f->id_table) == -1) + goto out_free_name_table; - f = fuse_new_common_compat25(fd, &args, op, op_size, compat); - fuse_opt_free_args(&args); + fuse_mutex_init(&f->lock); - return f; -} + root = alloc_node(f); + if (root == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_id_table; + } + if (lru_enabled(f)) { + struct node_lru *lnode = node_lru(root); + init_list_head(&lnode->lru); + } -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); + strcpy(root->inline_name, "/"); + root->name = root->inline_name; + + if (f->conf.intr && + fuse_init_intr_signal(f->conf.intr_signal, + &f->intr_installed) == -1) + goto out_free_root; + + root->parent = NULL; + root->nodeid = FUSE_ROOT_ID; + inc_nlookup(root); + hash_id(f, root); + + return f; + + out_free_root: + free(root); + out_free_id_table: + free(f->id_table.array); + out_free_name_table: + free(f->name_table.array); + out_free_session: + fuse_session_destroy(f->se); + out_free_fs: + /* Horrible compatibility hack to stop the destructor from being + called on the filesystem without init being called first */ + fs->op.destroy = NULL; + fuse_fs_destroy(f->fs); + out_free: + free(f); + out_delete_context_key: + fuse_delete_context_key(); + out: + return NULL; } -struct fuse *fuse_new_compat2(int fd, const char *opts, - const struct fuse_operations_compat2 *op) +struct fuse *fuse_new(int devfuse_fd, struct fuse_args *args, + const struct fuse_operations *op, size_t op_size, + void *user_data) { - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), - 21); + return fuse_new_common(devfuse_fd, args, op, op_size, user_data); } -struct fuse *fuse_new_compat1(int fd, int flags, - const struct fuse_operations_compat1 *op) +void fuse_destroy(struct fuse *f) { - 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); -} + size_t i; -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"); + if (f->conf.intr && f->intr_installed) + fuse_restore_intr_signal(f->conf.intr_signal); -#endif /* __FreeBSD__ || __NetBSD__ */ + if (f->fs) { + struct fuse_context_i *c = fuse_get_context_internal(); -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); -} + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + + for (i = 0; i < f->id_table.size; i++) { + struct node *node; + + for (node = f->id_table.array[i]; node != NULL; node = node->id_next) + { + if (node->is_hidden) + fuse_fs_free_hide(f->fs,node->hidden_fh); + } + } + } + for (i = 0; i < f->id_table.size; i++) { + struct node *node; + struct node *next; + + for (node = f->id_table.array[i]; node != NULL; node = next) { + next = node->id_next; + free_node(f, node); + f->id_table.use--; + } + } + assert(list_empty(&f->partial_slabs)); + assert(list_empty(&f->full_slabs)); -FUSE_SYMVER(".symver fuse_new_compat25,fuse_new@FUSE_2.5"); + free(f->id_table.array); + free(f->name_table.array); + pthread_mutex_destroy(&f->lock); + fuse_session_destroy(f->se); + free(f); + fuse_delete_context_key(); +} int fuse_config_num_threads(const struct fuse *fuse_) diff --git a/libfuse/lib/fuse_chan.c b/libfuse/lib/fuse_chan.c new file mode 100644 index 00000000..57ca6707 --- /dev/null +++ b/libfuse/lib/fuse_chan.c @@ -0,0 +1,248 @@ +#define _GNU_SOURCE + +#include "fuse_chan.h" +#include "fuse_lowlevel.h" +#include "fuse_kernel.h" +#include "sys.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static const char DEV_FUSE[] = "/dev/fuse"; + +static +void* +aligned_mem(const uint64_t size_) +{ + int rv; + void *mem; + int pagesize; + + pagesize = sys_get_pagesize(); + + rv = posix_memalign(&mem,pagesize,size_); + if(rv == 0) + return mem; + + errno = rv; + return NULL; +} + +static +int +clone_devfuse_fd(const int devfuse_fd_) +{ +#ifdef FUSE_DEV_IOC_CLONE + int rv; + int clone_fd; + + clone_fd = open(DEV_FUSE,O_RDWR|O_CLOEXEC); + if(clone_fd == -1) + return devfuse_fd_; + + rv = ioctl(clone_fd,FUSE_DEV_IOC_CLONE,&devfuse_fd_); + if(rv == -1) + { + perror("fuse: failed to clone /dev/fuse"); + close(clone_fd); + return devfuse_fd_; + } + + return clone_fd; +#else + return devfuse_fd_; +#endif +} + +int +fuse_msg_bufsize(void) +{ + int bufsize; + + bufsize = ((FUSE_MSG_MAX_PAGES + 1) * sys_get_pagesize()); + + return bufsize; +} + +fuse_chan_t* +fuse_chan_new(int32_t devfuse_fd_, + uint32_t flags_) +{ + int rv; + int bufsize; + fuse_chan_t *ch; + + ch = (fuse_chan_t*)calloc(1,sizeof(fuse_chan_t)); + if(ch == NULL) + { + fprintf(stderr, "fuse: failed to allocate channel memory\n"); + return NULL; + } + + bufsize = fuse_msg_bufsize(); + ch->fd = clone_devfuse_fd(devfuse_fd_); + ch->buf = aligned_mem(bufsize); + ch->bufsize = bufsize; + ch->flags = flags_; + if(flags_ & (FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE)) + { + rv = sys_alloc_pipe(ch->splice_pipe,bufsize); + if(rv == -1) + ch->flags &= ~(FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE); + } + + return ch; +} + +static +int64_t +fuse_chan_recv_splice(fuse_chan_t *ch_, + char *buf_, + uint64_t size_) +{ + int64_t rv; + struct iovec iov; + + restart_splice: + rv = splice(ch_->fd,NULL,ch_->splice_pipe[1],NULL,size_,SPLICE_F_MOVE); + switch((rv == -1) ? errno : 0) + { + case 0: + break; + case ENOENT: + case EINTR: + case EAGAIN: + goto restart_splice; + case ENODEV: + return 0; + default: + return -errno; + } + + iov.iov_base = buf_; + iov.iov_len = rv; + restart_vmsplice: + rv = vmsplice(ch_->splice_pipe[0],&iov,1,SPLICE_F_MOVE); + switch((rv == -1) ? errno : 0) + { + case 0: + break; + case ENOENT: + case EINTR: + case EAGAIN: + goto restart_vmsplice; + case ENODEV: + return 0; + default: + return -errno; + } + + return rv; +} + +static +int +fuse_chan_recv_read(fuse_chan_t *ch_, + char *buf_, + uint64_t size_) +{ + int64_t rv; + + restart: + rv = read(ch_->fd,buf_,size_); + switch((rv == -1) ? errno : 0) + { + case 0: + break; + case ENOENT: + case EINTR: + case EAGAIN: + goto restart; + case ENODEV: + return 0; + default: + return -errno; + } + + if(rv < sizeof(struct fuse_in_header)) + { + fprintf(stderr, "fuse: short read on fuse device\n"); + return -EIO; + } + + return rv; +} + +int64_t +fuse_chan_recv(fuse_chan_t *ch_, + char *buf_, + size_t size_) +{ + if(ch_->flags & FUSE_CHAN_SPLICE_READ) + return fuse_chan_recv_splice(ch_,buf_,size_); + return fuse_chan_recv_read(ch_,buf_,size_); +} + +static +int64_t +fuse_chan_send_write(fuse_chan_t *ch_, + const struct iovec iov_[], + size_t count_) +{ + int64_t rv; + + if(iov_ == NULL) + return 0; + + rv = writev(ch_->fd,iov_,count_); + if(rv == -1) + return -errno; + + return rv; +} + +static +int64_t +fuse_chan_send_splice(fuse_chan_t *ch_, + const struct iovec iov_[], + size_t count_) +{ + int64_t rv; + + rv = vmsplice(ch_->splice_pipe[1],iov_,count_,SPLICE_F_MOVE); + if(rv == -1) + return -errno; + + rv = splice(ch_->splice_pipe[0],NULL,ch_->fd,NULL,rv,SPLICE_F_MOVE); + + return rv; +} + +int64_t +fuse_chan_send(fuse_chan_t *ch, + const struct iovec iov[], + size_t count) +{ + if(ch->flags & FUSE_CHAN_SPLICE_WRITE) + return fuse_chan_send_splice(ch,iov,count); + return fuse_chan_send_write(ch,iov,count); +} + +void +fuse_chan_destroy(fuse_chan_t *ch) +{ + close(ch->fd); + if(ch->flags & (FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE)) + { + close(ch->splice_pipe[0]); + close(ch->splice_pipe[1]); + } + free(ch->buf); + free(ch); +} diff --git a/libfuse/lib/fuse_dev.c b/libfuse/lib/fuse_dev.c new file mode 100644 index 00000000..132b387b --- /dev/null +++ b/libfuse/lib/fuse_dev.c @@ -0,0 +1,56 @@ +#include "fuse_dev.h" + +#include +#include +#include + +fuse_dev_t* +fuse_dev_alloc(void) +{ + return calloc(1,sizeof(fuse_dev_t)); +} + +void +fuse_dev_free(fuse_dev_t *fd_) +{ + if(fd_) + free(fd_); +} + +fuse_dev_t* +fuse_dev_clone(fuse_dev_t *fd_) +{ + return fd_; +} + +int64_t +fuse_dev_read(const fuse_dev_t *fd_, + void *buf_, + uint64_t count_) +{ + int64_t rv; + + rv = read(fd_->fd,buf_,count_); + + return rv; +} + +int64_t +fuse_dev_write(const fuse_dev_t *fd_, + const struct iovec *iov_, + int iovcnt_) +{ + int64_t rv; + + rv = writev(fd_->fd,iov_,iovcnt_); + + return rv; +} + +int64_t +fuse_dev_write_splice(const fuse_dev_t* fd_, + const struct iovec *iov_, + int iovcnt_) +{ + +} diff --git a/libfuse/lib/fuse_dev.h b/libfuse/lib/fuse_dev.h new file mode 100644 index 00000000..3004534e --- /dev/null +++ b/libfuse/lib/fuse_dev.h @@ -0,0 +1,40 @@ +/* + ISC License + + Copyright (c) 2020, Antonio SJ Musumeci + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#pragma once + +#include +#include + +typedef struct fuse_dev_s fuse_dev_t; +struct fuse_dev_s +{ + int fd; +}; + +fuse_dev_t* fuse_dev_alloc(void); +void fuse_dev_free(fuse_dev_t *fd); +fuse_dev_t* fuse_dev_clone(fuse_dev_t *fd); + +int64_t fuse_dev_read(const fuse_dev_t *fd, + void *buf, + uint64_t count); + +int64_t fuse_dev_write(const fuse_dev_t *fd, + const struct iovec *iov, + int iovcnt); diff --git a/libfuse/lib/fuse_i.h b/libfuse/lib/fuse_i.h index fa371560..bab87ec8 100644 --- a/libfuse/lib/fuse_i.h +++ b/libfuse/lib/fuse_i.h @@ -9,104 +9,97 @@ #include "fuse.h" #include "fuse_lowlevel.h" -struct fuse_chan; +typedef struct fuse_chan_t fuse_chan_t; 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; - - volatile int exited; - - struct fuse_chan *ch; +struct fuse_session +{ + struct fuse_session_ops op; + void *data; + volatile int exited; + int devfuse_fd; }; -struct fuse_req { - struct fuse_ll *f; - uint64_t unique; - int ctr; - pthread_mutex_t lock; - struct fuse_ctx ctx; - struct fuse_chan *ch; - int interrupted; - unsigned int ioctl_64bit : 1; - union { - struct { - uint64_t unique; - } i; - struct { - fuse_interrupt_func_t func; - void *data; - } ni; - } u; - struct fuse_req *next; - struct fuse_req *prev; +struct fuse_req +{ + struct fuse_ll *f; + uint64_t unique; + int ctr; + pthread_mutex_t lock; + struct fuse_ctx ctx; + fuse_chan_t *ch; + int interrupted; + unsigned int ioctl_64bit : 1; + union { + struct { + uint64_t unique; + } i; + struct { + fuse_interrupt_func_t func; + void *data; + } ni; + } u; + struct fuse_req *next; + struct fuse_req *prev; }; -struct fuse_notify_req { - uint64_t unique; - void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t, - const void *, const struct fuse_buf *); - struct fuse_notify_req *next; - struct fuse_notify_req *prev; +struct fuse_notify_req +{ + uint64_t unique; + void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t, + const void *, const struct fuse_buf *); + struct fuse_notify_req *next; + struct fuse_notify_req *prev; }; -struct fuse_ll { - int debug; - int allow_root; - int atomic_o_trunc; - int no_remote_posix_lock; - int no_remote_flock; - int big_writes; - int splice_write; - int splice_move; - int splice_read; - int no_splice_write; - int no_splice_move; - int no_splice_read; - struct fuse_lowlevel_ops op; - int got_init; - struct cuse_data *cuse_data; - void *userdata; - uid_t owner; - struct fuse_conn_info conn; - struct fuse_req list; - struct fuse_req interrupts; - pthread_mutex_t lock; - int got_destroy; - pthread_key_t pipe_key; - int broken_splice_nonblock; - uint64_t notify_ctr; - struct fuse_notify_req notify_list; +struct fuse_ll +{ + int debug; + int allow_root; + int atomic_o_trunc; + int no_remote_posix_lock; + int no_remote_flock; + int big_writes; + int splice_write; + int splice_move; + int splice_read; + int no_splice_write; + int no_splice_move; + int no_splice_read; + struct fuse_lowlevel_ops op; + int got_init; + void *userdata; + uid_t owner; + struct fuse_conn_info conn; + struct fuse_req list; + struct fuse_req interrupts; + pthread_mutex_t lock; + int got_destroy; + pthread_key_t pipe_key; + int broken_splice_nonblock; + uint64_t notify_ctr; + struct fuse_notify_req notify_list; }; -struct fuse_cmd { - char *buf; - size_t buflen; - struct fuse_chan *ch; +struct fuse_cmd +{ + char *buf; + size_t buflen; + fuse_chan_t *ch; }; -struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, +struct fuse *fuse_new_common(int devfuse_fd, struct fuse_args *args, const struct fuse_operations *op, - size_t op_size, void *user_data, int compat); + size_t op_size, void *user_data); int fuse_sync_compat_args(struct fuse_args *args); -struct fuse_chan *fuse_kern_chan_new(int fd); - struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); void fuse_kern_unmount_compat22(const char *mountpoint); -int fuse_chan_clearfd(struct fuse_chan *ch); +int fuse_chan_clearfd(fuse_chan_t *ch); void fuse_kern_unmount(const char *mountpoint, int fd); int fuse_kern_mount(const char *mountpoint, struct fuse_args *args); @@ -120,11 +113,6 @@ struct fuse *fuse_setup_common(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, char **mountpoint, - int *multithreaded, - int *fd, - void *user_data, - int compat); - -void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg); + void *user_data); int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg); diff --git a/libfuse/lib/fuse_kern_chan.c b/libfuse/lib/fuse_kern_chan.c deleted file mode 100644 index e8448a5f..00000000 --- a/libfuse/lib/fuse_kern_chan.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB -*/ - -#include "fuse_lowlevel.h" -#include "fuse_kernel.h" -#include "fuse_i.h" - -#include -#include -#include -#include - -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); -} - -struct fuse_chan * -fuse_kern_chan_new(int fd_) -{ - long pagesize; - size_t bufsize; - struct fuse_chan_ops op = - { - .receive = fuse_kern_chan_receive, - .send = fuse_kern_chan_send, - .destroy = fuse_kern_chan_destroy, - }; - - pagesize = sysconf(_SC_PAGESIZE); - - bufsize = ((FUSE_MAX_MAX_PAGES * pagesize) + 0x1000); - - return fuse_chan_new(&op, fd_, bufsize, NULL); -} diff --git a/libfuse/lib/fuse_loop.c b/libfuse/lib/fuse_loop.c deleted file mode 100644 index 277080ef..00000000 --- a/libfuse/lib/fuse_loop.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB -*/ - -#include "fuse_lowlevel.h" - -#include -#include -#include - -int fuse_session_loop(struct fuse_session *se) -{ - int res = 0; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char*)calloc(bufsize,1); - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } - - while (!fuse_session_exited(se)) { - struct fuse_chan *tmpch = ch; - struct fuse_buf fbuf = { - .mem = buf, - .size = bufsize, - }; - - res = fuse_session_receive_buf(se, &fbuf, &tmpch); - - if (res == -EINTR) - continue; - if (res <= 0) - break; - - fuse_session_process_buf(se, &fbuf, tmpch); - } - - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; -} diff --git a/libfuse/lib/fuse_loop_mt.c b/libfuse/lib/fuse_loop_mt.c index 6b1ed003..da18a352 100644 --- a/libfuse/lib/fuse_loop_mt.c +++ b/libfuse/lib/fuse_loop_mt.c @@ -6,166 +6,189 @@ See the file COPYING.LIB. */ +#include "fuse_chan.h" +#include "fuse_i.h" +#include "fuse_kernel.h" #include "fuse_lowlevel.h" #include "fuse_misc.h" -#include "fuse_kernel.h" -#include "fuse_i.h" +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include #include #include /* Environment var controlling the thread stack size */ #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" -struct fuse_worker { - struct fuse_worker *prev; - struct fuse_worker *next; - pthread_t thread_id; - size_t bufsize; - char *buf; - struct fuse_mt *mt; +struct fuse_worker +{ + struct fuse_worker *prev; + struct fuse_worker *next; + struct fuse_mt *mt; + pthread_t thread_id; + fuse_chan_t *ch; }; -struct fuse_mt { - struct fuse_session *se; - struct fuse_chan *prevch; - struct fuse_worker main; - sem_t finish; - int exit; - int error; +struct fuse_mt +{ + struct fuse_session *se; + struct fuse_worker main; + sem_t finish; + int exit; + int error; }; -static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next) +static +void +list_add_worker(struct fuse_worker *w, + struct fuse_worker *next) { - struct fuse_worker *prev = next->prev; - w->next = next; - w->prev = prev; - prev->next = w; - next->prev = w; + struct fuse_worker *prev = next->prev; + w->next = next; + w->prev = prev; + prev->next = w; + next->prev = w; } -static void list_del_worker(struct fuse_worker *w) +static +void +list_del_worker(struct fuse_worker *w) { - struct fuse_worker *prev = w->prev; - struct fuse_worker *next = w->next; - prev->next = next; - next->prev = prev; + struct fuse_worker *prev = w->prev; + struct fuse_worker *next = w->next; + prev->next = next; + next->prev = prev; } static int fuse_loop_start_thread(struct fuse_mt *mt); -static void *fuse_do_work(void *data) +static +void* +fuse_do_work(void *data) { - struct fuse_worker *w = (struct fuse_worker *) data; - struct fuse_mt *mt = w->mt; - - while (!fuse_session_exited(mt->se)) { - struct fuse_chan *ch = mt->prevch; - struct fuse_buf fbuf = { - .mem = w->buf, - .size = w->bufsize, - }; - int res; - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - res = fuse_session_receive_buf(mt->se, &fbuf, &ch); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - if (res == -EINTR) - continue; - if (res <= 0) { - if (res < 0) { - fuse_session_exit(mt->se); - mt->error = -1; - } - break; - } - - if (mt->exit) - return NULL; - - fuse_session_process_buf(mt->se, &fbuf, ch); - } - - sem_post(&mt->finish); - - return NULL; + struct fuse_mt *mt; + fuse_chan_t *ch; + struct fuse_worker *w; + + w = (struct fuse_worker*)data; + mt = w->mt; + ch = w->ch; + while(!fuse_session_exited(mt->se)) + { + int res; + struct fuse_buf fbuf = { .mem = ch->buf, .size = ch->bufsize }; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + res = fuse_ll_receive_buf(mt->se,&fbuf,ch); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if(res == -EINTR) + continue; + if(res == 0) + break; + if(res < 0) + { + fuse_session_exit(mt->se); + mt->error = -1; + break; + } + + if(mt->exit) + return NULL; + + fuse_ll_process_buf(mt->se->data,&fbuf,ch); + } + + sem_post(&mt->finish); + + return NULL; } -int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) +int +fuse_start_thread(pthread_t *thread_id, + void *(*func)(void *), + void *arg) { - sigset_t oldset; - sigset_t newset; - int res; - pthread_attr_t attr; - char *stack_size; - - /* Override default stack size */ - pthread_attr_init(&attr); - stack_size = getenv(ENVNAME_THREAD_STACK); - if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size))) - fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size); - - /* Disallow signal reception in worker threads */ - sigemptyset(&newset); - sigaddset(&newset, SIGTERM); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - res = pthread_create(thread_id, &attr, func, arg); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - pthread_attr_destroy(&attr); - if (res != 0) { - fprintf(stderr, "fuse: error creating thread: %s\n", - strerror(res)); - return -1; - } - - return 0; + int res; + sigset_t oldset; + sigset_t newset; + pthread_attr_t attr; + char *stack_size; + + /* Override default stack size */ + pthread_attr_init(&attr); + stack_size = getenv(ENVNAME_THREAD_STACK); + if(stack_size && pthread_attr_setstacksize(&attr,atoi(stack_size))) + fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size); + + /* Disallow signal reception in worker threads */ + sigemptyset(&newset); + sigaddset(&newset, SIGTERM); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGHUP); + sigaddset(&newset, SIGQUIT); + pthread_sigmask(SIG_BLOCK, &newset, &oldset); + res = pthread_create(thread_id, &attr, func, arg); + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + pthread_attr_destroy(&attr); + + if(res != 0) + { + fprintf(stderr, "fuse: error creating thread: %s\n", + strerror(res)); + return -1; + } + + return 0; } -static int fuse_loop_start_thread(struct fuse_mt *mt) +static +int +fuse_loop_start_thread(struct fuse_mt *mt) { - int res; - struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); - if (!w) { - fprintf(stderr, "fuse: failed to allocate worker structure\n"); - return -1; - } - memset(w, 0, sizeof(struct fuse_worker)); - w->bufsize = fuse_chan_bufsize(mt->prevch); - w->buf = calloc(w->bufsize,1); - w->mt = mt; - if (!w->buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(w); - return -1; - } - - res = fuse_start_thread(&w->thread_id, fuse_do_work, w); - if (res == -1) { - free(w->buf); - free(w); - return -1; - } - list_add_worker(w, &mt->main); - - return 0; + int res; + struct fuse_worker *w; + + w = malloc(sizeof(struct fuse_worker)); + if(!w) + { + fprintf(stderr, "fuse: failed to allocate worker structure\n"); + return -1; + } + + memset(w,0,sizeof(struct fuse_worker)); + + w->mt = mt; + w->ch = fuse_chan_new(mt->se->devfuse_fd,FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE); + if(w->ch == NULL) + { + fprintf(stderr, "fuse: failed to allocate fuse channel\n"); + free(w); + return -1; + } + + res = fuse_start_thread(&w->thread_id, fuse_do_work, w); + if(res == -1) + { + free(w); + return -1; + } + + list_add_worker(w,&mt->main); + + return 0; } static void fuse_join_worker(struct fuse_worker *w) { - pthread_join(w->thread_id, NULL); - list_del_worker(w); - free(w->buf); - free(w); + pthread_join(w->thread_id, NULL); + list_del_worker(w); + fuse_chan_destroy(w->ch); + free(w); } static int number_of_threads(void) @@ -178,48 +201,48 @@ static int number_of_threads(void) } int fuse_session_loop_mt(struct fuse_session *se, - const int _threads) + const int threads_) { - int i; - int err; - int threads; - struct fuse_mt mt; - struct fuse_worker *w; - - memset(&mt, 0, sizeof(struct fuse_mt)); - mt.se = se; - mt.prevch = fuse_session_next_chan(se, NULL); - mt.error = 0; - mt.main.thread_id = pthread_self(); - mt.main.prev = mt.main.next = &mt.main; - sem_init(&mt.finish, 0, 0); - - threads = ((_threads > 0) ? _threads : number_of_threads()); - if(_threads < 0) - threads /= -_threads; - if(threads == 0) - threads = 1; - - err = 0; - for(i = 0; (i < threads) && !err; i++) - err = fuse_loop_start_thread(&mt); - - if (!err) { - /* sem_wait() is interruptible */ - while (!fuse_session_exited(se)) - sem_wait(&mt.finish); - - for (w = mt.main.next; w != &mt.main; w = w->next) - pthread_cancel(w->thread_id); - mt.exit = 1; - - while (mt.main.next != &mt.main) - fuse_join_worker(mt.main.next); - - err = mt.error; - } - - sem_destroy(&mt.finish); - fuse_session_reset(se); - return err; + int i; + int err; + int threads; + struct fuse_mt mt; + struct fuse_worker *w; + + memset(&mt, 0, sizeof(struct fuse_mt)); + mt.se = se; + mt.error = 0; + mt.main.thread_id = pthread_self(); + mt.main.prev = mt.main.next = &mt.main; + sem_init(&mt.finish, 0, 0); + + threads = ((threads_ > 0) ? threads_ : number_of_threads()); + if(threads_ < 0) + threads /= -threads_; + if(threads == 0) + threads = 1; + + err = 0; + for(i = 0; (i < threads) && !err; i++) + err = fuse_loop_start_thread(&mt); + + if(!err) + { + /* sem_wait() is interruptible */ + while(!fuse_session_exited(se)) + sem_wait(&mt.finish); + + for(w = mt.main.next; w != &mt.main; w = w->next) + pthread_cancel(w->thread_id); + mt.exit = 1; + + while(mt.main.next != &mt.main) + fuse_join_worker(mt.main.next); + + err = mt.error; + } + + sem_destroy(&mt.finish); + fuse_session_reset(se); + return err; } diff --git a/libfuse/lib/fuse_lowlevel.c b/libfuse/lib/fuse_lowlevel.c index b36dd9f6..55410ad0 100644 --- a/libfuse/lib/fuse_lowlevel.c +++ b/libfuse/lib/fuse_lowlevel.c @@ -9,12 +9,13 @@ #define _GNU_SOURCE #include "config.h" +#include "fuse_chan.h" +#include "fuse_common_compat.h" #include "fuse_i.h" #include "fuse_kernel.h" -#include "fuse_opt.h" -#include "fuse_misc.h" -#include "fuse_common_compat.h" #include "fuse_lowlevel_compat.h" +#include "fuse_misc.h" +#include "fuse_opt.h" #include #include @@ -37,21 +38,22 @@ #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) #define OFFSET_MAX 0x7fffffffffffffffLL -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) -struct fuse_pollhandle { - uint64_t kh; - struct fuse_chan *ch; - struct fuse_ll *f; +struct fuse_pollhandle +{ + uint64_t kh; + fuse_chan_t *ch; + struct fuse_ll *f; }; static size_t pagesize; static __attribute__((constructor)) void fuse_ll_init_pagesize(void) { - pagesize = getpagesize(); + pagesize = getpagesize(); } static @@ -93,216 +95,262 @@ convert_attr(const struct fuse_setattr_in *attr_, ST_CTIM_NSEC_SET(stbuf_,attr_->ctimensec); } -static size_t iov_length(const struct iovec *iov, size_t count) +static +size_t +iov_length(const struct iovec *iov, + size_t count) { - size_t seg; - size_t ret = 0; + size_t seg; + size_t ret = 0; + + for(seg = 0; seg < count; seg++) + ret += iov[seg].iov_len; - for (seg = 0; seg < count; seg++) - ret += iov[seg].iov_len; - return ret; + return ret; } -static void list_init_req(struct fuse_req *req) +static +void +list_init_req(struct fuse_req *req) { - req->next = req; - req->prev = req; + req->next = req; + req->prev = req; } -static void list_del_req(struct fuse_req *req) +static +void +list_del_req(struct fuse_req *req) { - struct fuse_req *prev = req->prev; - struct fuse_req *next = req->next; - prev->next = next; - next->prev = prev; + struct fuse_req *prev = req->prev; + struct fuse_req *next = req->next; + prev->next = next; + next->prev = prev; } -static void list_add_req(struct fuse_req *req, struct fuse_req *next) +static +void +list_add_req(struct fuse_req *req, + struct fuse_req *next) { - struct fuse_req *prev = next->prev; - req->next = next; - req->prev = prev; - prev->next = req; - next->prev = req; + struct fuse_req *prev = next->prev; + req->next = next; + req->prev = prev; + prev->next = req; + next->prev = req; } -static void destroy_req(fuse_req_t req) +static +void +destroy_req(fuse_req_t req) { - pthread_mutex_destroy(&req->lock); - free(req); + pthread_mutex_destroy(&req->lock); + free(req); } -void fuse_free_req(fuse_req_t req) +void +fuse_free_req(fuse_req_t req) { - int ctr; - struct fuse_ll *f = req->f; + int ctr; + struct fuse_ll *f = req->f; - pthread_mutex_lock(&f->lock); - req->u.ni.func = NULL; - req->u.ni.data = NULL; - list_del_req(req); - ctr = --req->ctr; - pthread_mutex_unlock(&f->lock); - if (!ctr) - destroy_req(req); + pthread_mutex_lock(&f->lock); + req->u.ni.func = NULL; + req->u.ni.data = NULL; + list_del_req(req); + ctr = --req->ctr; + pthread_mutex_unlock(&f->lock); + if(!ctr) + destroy_req(req); } -static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) +static +struct fuse_req* +fuse_ll_alloc_req(struct fuse_ll *f) { - struct fuse_req *req; + struct fuse_req *req; - req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); - if (req == NULL) { - fprintf(stderr, "fuse: failed to allocate request\n"); - } else { - req->f = f; - req->ctr = 1; - list_init_req(req); - fuse_mutex_init(&req->lock); - } + req = (struct fuse_req *)calloc(1,sizeof(struct fuse_req)); + if(req == NULL) + { + fprintf(stderr, "fuse: failed to allocate request\n"); + } + else + { + req->f = f; + req->ctr = 1; + list_init_req(req); + fuse_mutex_init(&req->lock); + } - return req; + return req; } +static +int +fuse_send_msg(struct fuse_ll *f, + fuse_chan_t *ch, + struct iovec *iov, + int count) +{ + struct fuse_out_header *out = iov[0].iov_base; + + out->len = iov_length(iov, count); + if(f->debug) { + if(out->unique == 0) { + fprintf(stderr, "NOTIFY: code=%d length=%u\n", + out->error, out->len); + } else if(out->error) { + fprintf(stderr, + " unique: %llu, error: %i (%s), outsize: %i\n", + (unsigned long long) out->unique, out->error, + strerror(-out->error), out->len); + } else { + fprintf(stderr, + " unique: %llu, success, outsize: %i\n", + (unsigned long long) out->unique, out->len); + } + } -static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch, - struct iovec *iov, int count) -{ - struct fuse_out_header *out = iov[0].iov_base; - - out->len = iov_length(iov, count); - if (f->debug) { - if (out->unique == 0) { - fprintf(stderr, "NOTIFY: code=%d length=%u\n", - out->error, out->len); - } else if (out->error) { - fprintf(stderr, - " unique: %llu, error: %i (%s), outsize: %i\n", - (unsigned long long) out->unique, out->error, - strerror(-out->error), out->len); - } else { - fprintf(stderr, - " unique: %llu, success, outsize: %i\n", - (unsigned long long) out->unique, out->len); - } - } - - return fuse_chan_send(ch, iov, count); + return fuse_chan_send(ch,iov,count); } -int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, - int count) +int +fuse_send_reply_iov_nofree(fuse_req_t req, + int error, + struct iovec *iov, + int count) { - struct fuse_out_header out; + struct fuse_out_header out; - if (error <= -1000 || error > 0) { - fprintf(stderr, "fuse: bad error value: %i\n", error); - error = -ERANGE; - } + if(error <= -1000 || error > 0) + { + fprintf(stderr, "fuse: bad error value: %i\n", error); + error = -ERANGE; + } - out.unique = req->unique; - out.error = error; + out.unique = req->unique; + out.error = error; - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(struct fuse_out_header); + iov[0].iov_base = &out; + iov[0].iov_len = sizeof(struct fuse_out_header); - return fuse_send_msg(req->f, req->ch, iov, count); + return fuse_send_msg(req->f, req->ch, iov, count); } -static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, - int count) +static +int +send_reply_iov(fuse_req_t req, + int error, + struct iovec *iov, + int count) { - int res; + int res; + + res = fuse_send_reply_iov_nofree(req,error,iov,count); + fuse_free_req(req); - res = fuse_send_reply_iov_nofree(req, error, iov, count); - fuse_free_req(req); - return res; + return res; } -static int send_reply(fuse_req_t req, int error, const void *arg, - size_t argsize) +static +int +send_reply(fuse_req_t req, + int error, + const void *arg, + size_t argsize) { - struct iovec iov[2]; - int count = 1; - if (argsize) { - iov[1].iov_base = (void *) arg; - iov[1].iov_len = argsize; - count++; - } - return send_reply_iov(req, error, iov, count); + int count; + struct iovec iov[2]; + + count = 1; + if(argsize) + { + iov[1].iov_base = (void *) arg; + iov[1].iov_len = argsize; + count++; + } + + return send_reply_iov(req,error,iov,count); } -int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) +int +fuse_reply_iov(fuse_req_t req, + const struct iovec *iov, + int count) { - int res; - struct iovec *padded_iov; + int res; + struct iovec *padded_iov; - padded_iov = malloc((count + 1) * sizeof(struct iovec)); - if (padded_iov == NULL) - return fuse_reply_err(req, ENOMEM); + padded_iov = malloc((count + 1) * sizeof(struct iovec)); + if(padded_iov == NULL) + return fuse_reply_err(req, ENOMEM); - memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); - count++; + memcpy(padded_iov + 1,iov,count * sizeof(struct iovec)); + count++; - res = send_reply_iov(req, 0, padded_iov, count); - free(padded_iov); + res = send_reply_iov(req,0,padded_iov,count); + free(padded_iov); - return res; + return res; } -size_t fuse_dirent_size(size_t namelen) +size_t +fuse_dirent_size(size_t namelen) { - return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); + return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); } -char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, - off_t off) +char* +fuse_add_dirent(char *buf, + const char *name, + const struct stat *stbuf, + off_t off) { - unsigned namelen = strlen(name); - unsigned entlen = FUSE_NAME_OFFSET + namelen; - unsigned entsize = fuse_dirent_size(namelen); - unsigned padlen = entsize - entlen; - struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + unsigned namelen = strlen(name); + unsigned entlen = FUSE_NAME_OFFSET + namelen; + unsigned entsize = fuse_dirent_size(namelen); + unsigned padlen = entsize - entlen; + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; - dirent->ino = stbuf->st_ino; - dirent->off = off; - dirent->namelen = namelen; - dirent->type = (stbuf->st_mode & 0170000) >> 12; - strncpy(dirent->name, name, namelen); - if (padlen) - memset(buf + entlen, 0, padlen); + dirent->ino = stbuf->st_ino; + dirent->off = off; + dirent->namelen = namelen; + dirent->type = (stbuf->st_mode & 0170000) >> 12; + strncpy(dirent->name, name, namelen); + if(padlen) + memset(buf + entlen, 0, padlen); - return buf + entsize; + return buf + entsize; } size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off) { - size_t entsize; + size_t entsize; - (void) req; - entsize = fuse_dirent_size(strlen(name)); - if (entsize <= bufsize && buf) - fuse_add_dirent(buf, name, stbuf, off); - return entsize; + (void) req; + entsize = fuse_dirent_size(strlen(name)); + if(entsize <= bufsize && buf) + fuse_add_dirent(buf, name, stbuf, off); + return entsize; } static void convert_statfs(const struct statvfs *stbuf, struct fuse_kstatfs *kstatfs) { - kstatfs->bsize = stbuf->f_bsize; - kstatfs->frsize = stbuf->f_frsize; - kstatfs->blocks = stbuf->f_blocks; - kstatfs->bfree = stbuf->f_bfree; - kstatfs->bavail = stbuf->f_bavail; - kstatfs->files = stbuf->f_files; - kstatfs->ffree = stbuf->f_ffree; - kstatfs->namelen = stbuf->f_namemax; + kstatfs->bsize = stbuf->f_bsize; + kstatfs->frsize = stbuf->f_frsize; + kstatfs->blocks = stbuf->f_blocks; + kstatfs->bfree = stbuf->f_bfree; + kstatfs->bavail = stbuf->f_bavail; + kstatfs->files = stbuf->f_files; + kstatfs->ffree = stbuf->f_ffree; + kstatfs->namelen = stbuf->f_namemax; } static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) { - return send_reply(req, 0, arg, argsize); + return send_reply(req, 0, arg, argsize); } int @@ -314,753 +362,504 @@ fuse_reply_err(fuse_req_t req_, void fuse_reply_none(fuse_req_t req) { - if (req->ch) - fuse_chan_send(req->ch, NULL, 0); - fuse_free_req(req); + if(req->ch) + fuse_chan_send(req->ch, NULL, 0); + fuse_free_req(req); } static unsigned long calc_timeout_sec(double t) { - if (t > (double) ULONG_MAX) - return ULONG_MAX; - else if (t < 0.0) - return 0; - else - return (unsigned long) t; + if(t > (double) ULONG_MAX) + return ULONG_MAX; + else if(t < 0.0) + return 0; + else + return (unsigned long) t; } static unsigned int calc_timeout_nsec(double t) { - double f = t - (double) calc_timeout_sec(t); - if (f < 0.0) - return 0; - else if (f >= 0.999999999) - return 999999999; - else - return (unsigned int) (f * 1.0e9); + double f = t - (double) calc_timeout_sec(t); + if(f < 0.0) + return 0; + else if(f >= 0.999999999) + return 999999999; + else + return (unsigned int) (f * 1.0e9); } static void fill_entry(struct fuse_entry_out *arg, const struct fuse_entry_param *e) { - arg->nodeid = e->ino; - arg->generation = e->generation; - arg->entry_valid = calc_timeout_sec(e->entry_timeout); - arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); - arg->attr_valid = calc_timeout_sec(e->attr_timeout); - arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); - convert_stat(&e->attr, &arg->attr); + arg->nodeid = e->ino; + arg->generation = e->generation; + arg->entry_valid = calc_timeout_sec(e->entry_timeout); + arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); + arg->attr_valid = calc_timeout_sec(e->attr_timeout); + arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); + convert_stat(&e->attr, &arg->attr); } static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f) { - arg->fh = f->fh; - if (f->direct_io) - arg->open_flags |= FOPEN_DIRECT_IO; - if (f->keep_cache) - arg->open_flags |= FOPEN_KEEP_CACHE; - if (f->nonseekable) - arg->open_flags |= FOPEN_NONSEEKABLE; - if (f->cache_readdir) - arg->open_flags |= FOPEN_CACHE_DIR; + arg->fh = f->fh; + if(f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if(f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; + if(f->nonseekable) + arg->open_flags |= FOPEN_NONSEEKABLE; + if(f->cache_readdir) + arg->open_flags |= FOPEN_CACHE_DIR; } int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) { - struct fuse_entry_out arg; - size_t size = req->f->conn.proto_minor < 9 ? - FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg); + struct fuse_entry_out arg; + size_t size = req->f->conn.proto_minor < 9 ? + FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg); - /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant - negative entry */ - if (!e->ino && req->f->conn.proto_minor < 4) - return fuse_reply_err(req, ENOENT); + /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant + negative entry */ + if(!e->ino && req->f->conn.proto_minor < 4) + return fuse_reply_err(req, ENOENT); - memset(&arg, 0, sizeof(arg)); - fill_entry(&arg, e); - return send_reply_ok(req, &arg, size); + memset(&arg, 0, sizeof(arg)); + fill_entry(&arg, e); + return send_reply_ok(req, &arg, size); } int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *f) { - char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)]; - size_t entrysize = req->f->conn.proto_minor < 9 ? - FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out); - struct fuse_entry_out *earg = (struct fuse_entry_out *) buf; - struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize); + char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)]; + size_t entrysize = req->f->conn.proto_minor < 9 ? + FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out); + struct fuse_entry_out *earg = (struct fuse_entry_out *) buf; + struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize); - memset(buf, 0, sizeof(buf)); - fill_entry(earg, e); - fill_open(oarg, f); - return send_reply_ok(req, buf, - entrysize + sizeof(struct fuse_open_out)); + memset(buf, 0, sizeof(buf)); + fill_entry(earg, e); + fill_open(oarg, f); + return send_reply_ok(req, buf, + entrysize + sizeof(struct fuse_open_out)); } -int fuse_reply_attr(fuse_req_t req, const struct stat *attr, - double attr_timeout) +int +fuse_reply_attr(fuse_req_t req, + const struct stat *attr, + double attr_timeout) { - struct fuse_attr_out arg; - size_t size = req->f->conn.proto_minor < 9 ? - FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg); + struct fuse_attr_out arg; + size_t size = req->f->conn.proto_minor < 9 ? + FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg); - memset(&arg, 0, sizeof(arg)); - arg.attr_valid = calc_timeout_sec(attr_timeout); - arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); - convert_stat(attr, &arg.attr); + memset(&arg,0,sizeof(arg)); + arg.attr_valid = calc_timeout_sec(attr_timeout); + arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); + convert_stat(attr,&arg.attr); - return send_reply_ok(req, &arg, size); + return send_reply_ok(req,&arg,size); } -int fuse_reply_readlink(fuse_req_t req, const char *linkname) +int +fuse_reply_readlink(fuse_req_t req, + const char *linkname) { - return send_reply_ok(req, linkname, strlen(linkname)); + return send_reply_ok(req,linkname,strlen(linkname)); } int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) { - struct fuse_open_out arg; + struct fuse_open_out arg; - memset(&arg, 0, sizeof(arg)); - fill_open(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_open(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_write(fuse_req_t req, size_t count) { - struct fuse_write_out arg; + struct fuse_write_out arg; - memset(&arg, 0, sizeof(arg)); - arg.size = count; + memset(&arg, 0, sizeof(arg)); + arg.size = count; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) { - return send_reply_ok(req, buf, size); + return send_reply_ok(req, buf, size); } -static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch, +static int fuse_send_data_iov_fallback(struct fuse_ll *f, fuse_chan_t *ch, struct iovec *iov, int iov_count, struct fuse_bufvec *buf, size_t len) { - struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); - void *mbuf; - int res; + struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); + void *mbuf; + int res; - /* Optimize common case */ - if (buf->count == 1 && buf->idx == 0 && buf->off == 0 && - !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { - /* FIXME: also avoid memory copy if there are multiple buffers - but none of them contain an fd */ + /* Optimize common case */ + if(buf->count == 1 && buf->idx == 0 && buf->off == 0 && + !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { + /* FIXME: also avoid memory copy if there are multiple buffers + but none of them contain an fd */ - iov[iov_count].iov_base = buf->buf[0].mem; - iov[iov_count].iov_len = len; - iov_count++; - return fuse_send_msg(f, ch, iov, iov_count); - } + iov[iov_count].iov_base = buf->buf[0].mem; + iov[iov_count].iov_len = len; + iov_count++; + return fuse_send_msg(f, ch, iov, iov_count); + } - res = posix_memalign(&mbuf, pagesize, len); - if (res != 0) - return res; + res = posix_memalign(&mbuf, pagesize, len); + if(res != 0) + return res; - mem_buf.buf[0].mem = mbuf; - res = fuse_buf_copy(&mem_buf, buf, 0); - if (res < 0) { - free(mbuf); - return -res; - } - len = res; + mem_buf.buf[0].mem = mbuf; + res = fuse_buf_copy(&mem_buf, buf, 0); + if(res < 0) { + free(mbuf); + return -res; + } + len = res; - iov[iov_count].iov_base = mbuf; - iov[iov_count].iov_len = len; - iov_count++; - res = fuse_send_msg(f, ch, iov, iov_count); - free(mbuf); + iov[iov_count].iov_base = mbuf; + iov[iov_count].iov_len = len; + iov_count++; + res = fuse_send_msg(f, ch, iov, iov_count); + free(mbuf); - return res; + return res; } struct fuse_ll_pipe { - size_t size; - int can_grow; - int pipe[2]; + size_t size; + int can_grow; + int pipe[2]; }; static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp) { - close(llp->pipe[0]); - close(llp->pipe[1]); - free(llp); + close(llp->pipe[0]); + close(llp->pipe[1]); + free(llp); } -#ifdef HAVE_SPLICE -static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_ll *f) +static void fuse_ll_clear_pipe(struct fuse_ll *f) { - struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); - if (llp == NULL) { - int res; - - llp = malloc(sizeof(struct fuse_ll_pipe)); - if (llp == NULL) - return NULL; - - res = pipe(llp->pipe); - if (res == -1) { - free(llp); - return NULL; - } - - if (fcntl(llp->pipe[0], F_SETFL, O_NONBLOCK) == -1 || - fcntl(llp->pipe[1], F_SETFL, O_NONBLOCK) == -1) { - close(llp->pipe[0]); - close(llp->pipe[1]); - free(llp); - return NULL; - } - - /* - *the default size is 16 pages on linux - */ - llp->size = pagesize * 16; - llp->can_grow = 1; - - pthread_setspecific(f->pipe_key, llp); - } - - return llp; + struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); + if(llp) { + pthread_setspecific(f->pipe_key, NULL); + fuse_ll_pipe_free(llp); + } } -#endif -static void fuse_ll_clear_pipe(struct fuse_ll *f) +static int fuse_send_data_iov(struct fuse_ll *f, fuse_chan_t *ch, + struct iovec *iov, int iov_count, + struct fuse_bufvec *buf, unsigned int flags) { - struct fuse_ll_pipe *llp = pthread_getspecific(f->pipe_key); - if (llp) { - pthread_setspecific(f->pipe_key, NULL); - fuse_ll_pipe_free(llp); - } -} - -#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE) -static int read_back(int fd, char *buf, size_t len) -{ - int res; - - res = read(fd, buf, len); - if (res == -1) { - fprintf(stderr, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno)); - return -EIO; - } - if (res != len) { - fprintf(stderr, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len); - return -EIO; - } - return 0; -} - -static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, - struct iovec *iov, int iov_count, - struct fuse_bufvec *buf, unsigned int flags) -{ - int res; - size_t len = fuse_buf_size(buf); - struct fuse_out_header *out = iov[0].iov_base; - struct fuse_ll_pipe *llp; - int splice_flags; - size_t pipesize; - size_t total_fd_size; - size_t idx; - size_t headerlen; - struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len); - - if (f->broken_splice_nonblock) - goto fallback; - - if (flags & FUSE_BUF_NO_SPLICE) - goto fallback; - - total_fd_size = 0; - for (idx = buf->idx; idx < buf->count; idx++) { - if (buf->buf[idx].flags & FUSE_BUF_IS_FD) { - total_fd_size = buf->buf[idx].size; - if (idx == buf->idx) - total_fd_size -= buf->off; - } - } - if (total_fd_size < 2 * pagesize) - goto fallback; - - if (f->conn.proto_minor < 14 || - !(f->conn.want & FUSE_CAP_SPLICE_WRITE)) - goto fallback; - - llp = fuse_ll_get_pipe(f); - if (llp == NULL) - goto fallback; - - - headerlen = iov_length(iov, iov_count); - - out->len = headerlen + len; - - /* - * Heuristic for the required pipe size, does not work if the - * source contains less than page size fragments - */ - pipesize = pagesize * (iov_count + buf->count + 1) + out->len; - - if (llp->size < pipesize) { - if (llp->can_grow) { - res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize); - if (res == -1) { - llp->can_grow = 0; - goto fallback; - } - llp->size = res; - } - if (llp->size < pipesize) - goto fallback; - } - - - res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK); - if (res == -1) - goto fallback; - - if (res != headerlen) { - res = -EIO; - fprintf(stderr, "fuse: short vmsplice to pipe: %u/%zu\n", res, - headerlen); - goto clear_pipe; - } - - pipe_buf.buf[0].flags = FUSE_BUF_IS_FD; - pipe_buf.buf[0].fd = llp->pipe[1]; - - res = fuse_buf_copy(&pipe_buf, buf, - FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK); - if (res < 0) { - if (res == -EAGAIN || res == -EINVAL) { - /* - * Should only get EAGAIN on kernels with - * broken SPLICE_F_NONBLOCK support (<= - * 2.6.35) where this error or a short read is - * returned even if the pipe itself is not - * full - * - * EINVAL might mean that splice can't handle - * this combination of input and output. - */ - if (res == -EAGAIN) - f->broken_splice_nonblock = 1; - - pthread_setspecific(f->pipe_key, NULL); - fuse_ll_pipe_free(llp); - goto fallback; - } - res = -res; - goto clear_pipe; - } - - if (res != 0 && res < len) { - struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); - void *mbuf; - size_t now_len = res; - /* - * For regular files a short count is either - * 1) due to EOF, or - * 2) because of broken SPLICE_F_NONBLOCK (see above) - * - * For other inputs it's possible that we overflowed - * the pipe because of small buffer fragments. - */ - - res = posix_memalign(&mbuf, pagesize, len); - if (res != 0) - goto clear_pipe; - - mem_buf.buf[0].mem = mbuf; - mem_buf.off = now_len; - res = fuse_buf_copy(&mem_buf, buf, 0); - if (res > 0) { - char *tmpbuf; - size_t extra_len = res; - /* - * Trickiest case: got more data. Need to get - * back the data from the pipe and then fall - * back to regular write. - */ - tmpbuf = malloc(headerlen); - if (tmpbuf == NULL) { - free(mbuf); - res = ENOMEM; - goto clear_pipe; - } - res = read_back(llp->pipe[0], tmpbuf, headerlen); - free(tmpbuf); - if (res != 0) { - free(mbuf); - goto clear_pipe; - } - res = read_back(llp->pipe[0], mbuf, now_len); - if (res != 0) { - free(mbuf); - goto clear_pipe; - } - len = now_len + extra_len; - iov[iov_count].iov_base = mbuf; - iov[iov_count].iov_len = len; - iov_count++; - res = fuse_send_msg(f, ch, iov, iov_count); - free(mbuf); - return res; - } - free(mbuf); - res = now_len; - } - len = res; - out->len = headerlen + len; - - if (f->debug) { - fprintf(stderr, - " unique: %llu, success, outsize: %i (splice)\n", - (unsigned long long) out->unique, out->len); - } - - splice_flags = 0; - if ((flags & FUSE_BUF_SPLICE_MOVE) && - (f->conn.want & FUSE_CAP_SPLICE_MOVE)) - splice_flags |= SPLICE_F_MOVE; - - res = splice(llp->pipe[0], NULL, - fuse_chan_fd(ch), NULL, out->len, splice_flags); - if (res == -1) { - res = -errno; - perror("fuse: splice from pipe"); - goto clear_pipe; - } - if (res != out->len) { - res = -EIO; - fprintf(stderr, "fuse: short splice from pipe: %u/%u\n", - res, out->len); - goto clear_pipe; - } - return 0; - -clear_pipe: - fuse_ll_clear_pipe(f); - return res; - -fallback: - return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); -} -#else -static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, - struct iovec *iov, int iov_count, - struct fuse_bufvec *buf, unsigned int flags) -{ - size_t len = fuse_buf_size(buf); - (void) flags; - - return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); + size_t len = fuse_buf_size(buf); + (void) flags; + + return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); } -#endif int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags) { - struct iovec iov[2]; - struct fuse_out_header out; - int res; + struct iovec iov[2]; + struct fuse_out_header out; + int res; - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(struct fuse_out_header); + iov[0].iov_base = &out; + iov[0].iov_len = sizeof(struct fuse_out_header); - out.unique = req->unique; - out.error = 0; + out.unique = req->unique; + out.error = 0; - res = fuse_send_data_iov(req->f, req->ch, iov, 1, bufv, flags); - if (res <= 0) { - fuse_free_req(req); - return res; - } else { - return fuse_reply_err(req, res); - } + res = fuse_send_data_iov(req->f, req->ch, iov, 1, bufv, flags); + if(res <= 0) { + fuse_free_req(req); + return res; + } else { + return fuse_reply_err(req, res); + } } int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) { - struct fuse_statfs_out arg; - size_t size = req->f->conn.proto_minor < 4 ? - FUSE_COMPAT_STATFS_SIZE : sizeof(arg); + struct fuse_statfs_out arg; + size_t size = req->f->conn.proto_minor < 4 ? + FUSE_COMPAT_STATFS_SIZE : sizeof(arg); - memset(&arg, 0, sizeof(arg)); - convert_statfs(stbuf, &arg.st); + memset(&arg, 0, sizeof(arg)); + convert_statfs(stbuf, &arg.st); - return send_reply_ok(req, &arg, size); + return send_reply_ok(req, &arg, size); } int fuse_reply_xattr(fuse_req_t req, size_t count) { - struct fuse_getxattr_out arg; + struct fuse_getxattr_out arg; - memset(&arg, 0, sizeof(arg)); - arg.size = count; + memset(&arg, 0, sizeof(arg)); + arg.size = count; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_lock(fuse_req_t req, const struct flock *lock) { - struct fuse_lk_out arg; + struct fuse_lk_out arg; - memset(&arg, 0, sizeof(arg)); - arg.lk.type = lock->l_type; - if (lock->l_type != F_UNLCK) { - arg.lk.start = lock->l_start; - if (lock->l_len == 0) - arg.lk.end = OFFSET_MAX; - else - arg.lk.end = lock->l_start + lock->l_len - 1; - } - arg.lk.pid = lock->l_pid; - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + arg.lk.type = lock->l_type; + if(lock->l_type != F_UNLCK) { + arg.lk.start = lock->l_start; + if(lock->l_len == 0) + arg.lk.end = OFFSET_MAX; + else + arg.lk.end = lock->l_start + lock->l_len - 1; + } + arg.lk.pid = lock->l_pid; + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_bmap(fuse_req_t req, uint64_t idx) { - struct fuse_bmap_out arg; + struct fuse_bmap_out arg; - memset(&arg, 0, sizeof(arg)); - arg.block = idx; + memset(&arg, 0, sizeof(arg)); + arg.block = idx; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov, size_t count) { - struct fuse_ioctl_iovec *fiov; - size_t i; + struct fuse_ioctl_iovec *fiov; + size_t i; - fiov = malloc(sizeof(fiov[0]) * count); - if (!fiov) - return NULL; + fiov = malloc(sizeof(fiov[0]) * count); + if(!fiov) + return NULL; - for (i = 0; i < count; i++) { - fiov[i].base = (uintptr_t) iov[i].iov_base; - fiov[i].len = iov[i].iov_len; - } + for (i = 0; i < count; i++) { + fiov[i].base = (uintptr_t) iov[i].iov_base; + fiov[i].len = iov[i].iov_len; + } - return fiov; + return fiov; } int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count) { - struct fuse_ioctl_out arg; - struct fuse_ioctl_iovec *in_fiov = NULL; - struct fuse_ioctl_iovec *out_fiov = NULL; - struct iovec iov[4]; - size_t count = 1; - int res; - - memset(&arg, 0, sizeof(arg)); - arg.flags |= FUSE_IOCTL_RETRY; - arg.in_iovs = in_count; - arg.out_iovs = out_count; - iov[count].iov_base = &arg; - iov[count].iov_len = sizeof(arg); - count++; - - if (req->f->conn.proto_minor < 16) { - if (in_count) { - iov[count].iov_base = (void *)in_iov; - iov[count].iov_len = sizeof(in_iov[0]) * in_count; - count++; - } - - if (out_count) { - iov[count].iov_base = (void *)out_iov; - iov[count].iov_len = sizeof(out_iov[0]) * out_count; - count++; - } - } else { - /* Can't handle non-compat 64bit ioctls on 32bit */ - if (sizeof(void *) == 4 && req->ioctl_64bit) { - res = fuse_reply_err(req, EINVAL); - goto out; - } - - if (in_count) { - in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count); - if (!in_fiov) - goto enomem; - - iov[count].iov_base = (void *)in_fiov; - iov[count].iov_len = sizeof(in_fiov[0]) * in_count; - count++; - } - if (out_count) { - out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count); - if (!out_fiov) - goto enomem; - - iov[count].iov_base = (void *)out_fiov; - iov[count].iov_len = sizeof(out_fiov[0]) * out_count; - count++; - } - } - - res = send_reply_iov(req, 0, iov, count); -out: - free(in_fiov); - free(out_fiov); - - return res; - -enomem: - res = fuse_reply_err(req, ENOMEM); - goto out; + struct fuse_ioctl_out arg; + struct fuse_ioctl_iovec *in_fiov = NULL; + struct fuse_ioctl_iovec *out_fiov = NULL; + struct iovec iov[4]; + size_t count = 1; + int res; + + memset(&arg, 0, sizeof(arg)); + arg.flags |= FUSE_IOCTL_RETRY; + arg.in_iovs = in_count; + arg.out_iovs = out_count; + iov[count].iov_base = &arg; + iov[count].iov_len = sizeof(arg); + count++; + + if(req->f->conn.proto_minor < 16) { + if(in_count) { + iov[count].iov_base = (void *)in_iov; + iov[count].iov_len = sizeof(in_iov[0]) * in_count; + count++; + } + + if(out_count) { + iov[count].iov_base = (void *)out_iov; + iov[count].iov_len = sizeof(out_iov[0]) * out_count; + count++; + } + } else { + /* Can't handle non-compat 64bit ioctls on 32bit */ + if(sizeof(void *) == 4 && req->ioctl_64bit) { + res = fuse_reply_err(req, EINVAL); + goto out; + } + + if(in_count) { + in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count); + if(!in_fiov) + goto enomem; + + iov[count].iov_base = (void *)in_fiov; + iov[count].iov_len = sizeof(in_fiov[0]) * in_count; + count++; + } + if(out_count) { + out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count); + if(!out_fiov) + goto enomem; + + iov[count].iov_base = (void *)out_fiov; + iov[count].iov_len = sizeof(out_fiov[0]) * out_count; + count++; + } + } + + res = send_reply_iov(req, 0, iov, count); + out: + free(in_fiov); + free(out_fiov); + + return res; + + enomem: + res = fuse_reply_err(req, ENOMEM); + goto out; } int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, uint32_t size) { - int count; - struct iovec iov[3]; - struct fuse_ioctl_out arg; + int count; + struct iovec iov[3]; + struct fuse_ioctl_out arg; - arg.result = result; - arg.flags = 0; - arg.in_iovs = 0; - arg.out_iovs = 0; + arg.result = result; + arg.flags = 0; + arg.in_iovs = 0; + arg.out_iovs = 0; - count = 1; - iov[count].iov_base = &arg; - iov[count].iov_len = sizeof(arg); - count++; + count = 1; + iov[count].iov_base = &arg; + iov[count].iov_len = sizeof(arg); + count++; - if(size) - { - iov[count].iov_base = (char*)buf; - iov[count].iov_len = size; - count++; - } + if(size) + { + iov[count].iov_base = (char*)buf; + iov[count].iov_len = size; + count++; + } - return send_reply_iov(req, 0, iov, count); + return send_reply_iov(req, 0, iov, count); } int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count) { - struct iovec *padded_iov; - struct fuse_ioctl_out arg; - int res; + struct iovec *padded_iov; + struct fuse_ioctl_out arg; + int res; - padded_iov = malloc((count + 2) * sizeof(struct iovec)); - if (padded_iov == NULL) - return fuse_reply_err(req, ENOMEM); + padded_iov = malloc((count + 2) * sizeof(struct iovec)); + if(padded_iov == NULL) + return fuse_reply_err(req, ENOMEM); - memset(&arg, 0, sizeof(arg)); - arg.result = result; - padded_iov[1].iov_base = &arg; - padded_iov[1].iov_len = sizeof(arg); + memset(&arg, 0, sizeof(arg)); + arg.result = result; + padded_iov[1].iov_base = &arg; + padded_iov[1].iov_len = sizeof(arg); - memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); + memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); - res = send_reply_iov(req, 0, padded_iov, count + 2); - free(padded_iov); + res = send_reply_iov(req, 0, padded_iov, count + 2); + free(padded_iov); - return res; + return res; } int fuse_reply_poll(fuse_req_t req, unsigned revents) { - struct fuse_poll_out arg; + struct fuse_poll_out arg; - memset(&arg, 0, sizeof(arg)); - arg.revents = revents; + memset(&arg, 0, sizeof(arg)); + arg.revents = revents; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.lookup) - req->f->op.lookup(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.lookup) + req->f->op.lookup(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg; + struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg; - if (req->f->op.forget) - req->f->op.forget(req, nodeid, arg->nlookup); - else - fuse_reply_none(req); + if(req->f->op.forget) + req->f->op.forget(req, nodeid, arg->nlookup); + else + fuse_reply_none(req); } static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_batch_forget_in *arg = (void *) inarg; - struct fuse_forget_one *param = (void *) PARAM(arg); - unsigned int i; + struct fuse_batch_forget_in *arg = (void *) inarg; + struct fuse_forget_one *param = (void *) PARAM(arg); + unsigned int i; - (void) nodeid; + (void) nodeid; - if (req->f->op.forget_multi) { - req->f->op.forget_multi(req, arg->count, - (struct fuse_forget_data *) param); - } else if (req->f->op.forget) { - for (i = 0; i < arg->count; i++) { - struct fuse_forget_one *forget = ¶m[i]; - struct fuse_req *dummy_req; + if(req->f->op.forget_multi) { + req->f->op.forget_multi(req, arg->count, + (struct fuse_forget_data *) param); + } else if(req->f->op.forget) { + for (i = 0; i < arg->count; i++) { + struct fuse_forget_one *forget = ¶m[i]; + struct fuse_req *dummy_req; - dummy_req = fuse_ll_alloc_req(req->f); - if (dummy_req == NULL) - break; + dummy_req = fuse_ll_alloc_req(req->f); + if(dummy_req == NULL) + break; - dummy_req->unique = req->unique; - dummy_req->ctx = req->ctx; - dummy_req->ch = NULL; + dummy_req->unique = req->unique; + dummy_req->ctx = req->ctx; + dummy_req->ch = NULL; - req->f->op.forget(dummy_req, forget->nodeid, - forget->nlookup); - } - fuse_reply_none(req); - } else { - fuse_reply_none(req); - } + req->f->op.forget(dummy_req, forget->nodeid, + forget->nlookup); + } + fuse_reply_none(req); + } else { + fuse_reply_none(req); + } } static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_file_info *fip = NULL; - struct fuse_file_info fi; + struct fuse_file_info *fip = NULL; + struct fuse_file_info fi; - if (req->f->conn.proto_minor >= 9) { - struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg; + if(req->f->conn.proto_minor >= 9) { + struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg; - if (arg->getattr_flags & FUSE_GETATTR_FH) { - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fip = &fi; - } - } + if(arg->getattr_flags & FUSE_GETATTR_FH) { + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fip = &fi; + } + } - if (req->f->op.getattr) - req->f->op.getattr(req, nodeid, fip); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.getattr) + req->f->op.getattr(req, nodeid, fip); + else + fuse_reply_err(req, ENOSYS); } static @@ -1107,308 +906,308 @@ do_setattr(fuse_req_t req_, static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_access_in *arg = (struct fuse_access_in *) inarg; + struct fuse_access_in *arg = (struct fuse_access_in *) inarg; - if (req->f->op.access) - req->f->op.access(req, nodeid, arg->mask); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.access) + req->f->op.access(req, nodeid, arg->mask); + else + fuse_reply_err(req, ENOSYS); } static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) inarg; + (void) inarg; - if (req->f->op.readlink) - req->f->op.readlink(req, nodeid); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.readlink) + req->f->op.readlink(req, nodeid); + else + fuse_reply_err(req, ENOSYS); } static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; - char *name = PARAM(arg); + struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; + char *name = PARAM(arg); - if (req->f->conn.proto_minor >= 12) - req->ctx.umask = arg->umask; - else - name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE; + if(req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else + name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE; - if (req->f->op.mknod) - req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.mknod) + req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev); + else + fuse_reply_err(req, ENOSYS); } static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; + struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; - if (req->f->conn.proto_minor >= 12) - req->ctx.umask = arg->umask; + if(req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; - if (req->f->op.mkdir) - req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.mkdir) + req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); + else + fuse_reply_err(req, ENOSYS); } static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.unlink) - req->f->op.unlink(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.unlink) + req->f->op.unlink(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.rmdir) - req->f->op.rmdir(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.rmdir) + req->f->op.rmdir(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; - char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1; + char *name = (char *) inarg; + char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1; - if (req->f->op.symlink) - req->f->op.symlink(req, linkname, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.symlink) + req->f->op.symlink(req, linkname, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg; - char *oldname = PARAM(arg); - char *newname = oldname + strlen(oldname) + 1; + struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg; + char *oldname = PARAM(arg); + char *newname = oldname + strlen(oldname) + 1; - if (req->f->op.rename) - req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.rename) + req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); + else + fuse_reply_err(req, ENOSYS); } static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_link_in *arg = (struct fuse_link_in *) inarg; + struct fuse_link_in *arg = (struct fuse_link_in *) inarg; - if (req->f->op.link) - req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.link) + req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); + else + fuse_reply_err(req, ENOSYS); } static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_create_in *arg = (struct fuse_create_in *) inarg; + struct fuse_create_in *arg = (struct fuse_create_in *) inarg; - if (req->f->op.create) { - struct fuse_file_info fi; - char *name = PARAM(arg); + if(req->f->op.create) { + struct fuse_file_info fi; + char *name = PARAM(arg); - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - if (req->f->conn.proto_minor >= 12) - req->ctx.umask = arg->umask; - else - name = (char *) inarg + sizeof(struct fuse_open_in); + if(req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else + name = (char *) inarg + sizeof(struct fuse_open_in); - req->f->op.create(req, nodeid, name, arg->mode, &fi); - } else - fuse_reply_err(req, ENOSYS); + req->f->op.create(req, nodeid, name, arg->mode, &fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - struct fuse_file_info fi; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - if (req->f->op.open) - req->f->op.open(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if(req->f->op.open) + req->f->op.open(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); } static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_read_in *arg = (struct fuse_read_in *) inarg; + struct fuse_read_in *arg = (struct fuse_read_in *) inarg; - if (req->f->op.read) { - struct fuse_file_info fi; + if(req->f->op.read) { + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - if (req->f->conn.proto_minor >= 9) { - fi.lock_owner = arg->lock_owner; - fi.flags = arg->flags; - } - req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); - } else - fuse_reply_err(req, ENOSYS); + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + if(req->f->conn.proto_minor >= 9) { + fi.lock_owner = arg->lock_owner; + fi.flags = arg->flags; + } + req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_write_in *arg = (struct fuse_write_in *) inarg; - struct fuse_file_info fi; - char *param; - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.writepage = arg->write_flags & 1; - - if (req->f->conn.proto_minor < 9) { - param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE; - } else { - fi.lock_owner = arg->lock_owner; - fi.flags = arg->flags; - param = PARAM(arg); - } - - if (req->f->op.write) - req->f->op.write(req, nodeid, param, arg->size, - arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + struct fuse_write_in *arg = (struct fuse_write_in *) inarg; + struct fuse_file_info fi; + char *param; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.writepage = arg->write_flags & 1; + + if(req->f->conn.proto_minor < 9) { + param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE; + } else { + fi.lock_owner = arg->lock_owner; + fi.flags = arg->flags; + param = PARAM(arg); + } + + if(req->f->op.write) + req->f->op.write(req, nodeid, param, arg->size, + arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg, const struct fuse_buf *ibuf) { - struct fuse_ll *f = req->f; - struct fuse_bufvec bufv = { - .buf[0] = *ibuf, - .count = 1, - }; - struct fuse_write_in *arg = (struct fuse_write_in *) inarg; - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.writepage = arg->write_flags & 1; - - if (req->f->conn.proto_minor < 9) { - bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE; - bufv.buf[0].size -= sizeof(struct fuse_in_header) + - FUSE_COMPAT_WRITE_IN_SIZE; - assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD)); - } else { - fi.lock_owner = arg->lock_owner; - fi.flags = arg->flags; - if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) - bufv.buf[0].mem = PARAM(arg); - - bufv.buf[0].size -= sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in); - } - if (bufv.buf[0].size < arg->size) { - fprintf(stderr, "fuse: do_write_buf: buffer size too small\n"); - fuse_reply_err(req, EIO); - goto out; - } - bufv.buf[0].size = arg->size; - - req->f->op.write_buf(req, nodeid, &bufv, arg->offset, &fi); - -out: - /* Need to reset the pipe if ->write_buf() didn't consume all data */ - if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) - fuse_ll_clear_pipe(f); + struct fuse_ll *f = req->f; + struct fuse_bufvec bufv = { + .buf[0] = *ibuf, + .count = 1, + }; + struct fuse_write_in *arg = (struct fuse_write_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.writepage = arg->write_flags & 1; + + if(req->f->conn.proto_minor < 9) { + bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE; + bufv.buf[0].size -= sizeof(struct fuse_in_header) + + FUSE_COMPAT_WRITE_IN_SIZE; + assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD)); + } else { + fi.lock_owner = arg->lock_owner; + fi.flags = arg->flags; + if(!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) + bufv.buf[0].mem = PARAM(arg); + + bufv.buf[0].size -= sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in); + } + if(bufv.buf[0].size < arg->size) { + fprintf(stderr, "fuse: do_write_buf: buffer size too small\n"); + fuse_reply_err(req, EIO); + goto out; + } + bufv.buf[0].size = arg->size; + + req->f->op.write_buf(req, nodeid, &bufv, arg->offset, &fi); + + out: + /* Need to reset the pipe if ->write_buf() didn't consume all data */ + if((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) + fuse_ll_clear_pipe(f); } static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg; - struct fuse_file_info fi; + struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.flush = 1; - if (req->f->conn.proto_minor >= 7) - fi.lock_owner = arg->lock_owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.flush = 1; + if(req->f->conn.proto_minor >= 7) + fi.lock_owner = arg->lock_owner; - if (req->f->op.flush) - req->f->op.flush(req, nodeid, &fi); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.flush) + req->f->op.flush(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_release_in *arg = (struct fuse_release_in *) inarg; - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - if (req->f->conn.proto_minor >= 8) { - fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; - fi.lock_owner = arg->lock_owner; - } - if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) { - fi.flock_release = 1; - fi.lock_owner = arg->lock_owner; - } - - if (req->f->op.release) - req->f->op.release(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + struct fuse_release_in *arg = (struct fuse_release_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; + if(req->f->conn.proto_minor >= 8) { + fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; + fi.lock_owner = arg->lock_owner; + } + if(arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) { + fi.flock_release = 1; + fi.lock_owner = arg->lock_owner; + } + + if(req->f->op.release) + req->f->op.release(req, nodeid, &fi); + else + fuse_reply_err(req, 0); } static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; - struct fuse_file_info fi; + struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; - if (req->f->op.fsync) - req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.fsync) + req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - struct fuse_file_info fi; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - if (req->f->op.opendir) - req->f->op.opendir(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if(req->f->op.opendir) + req->f->op.opendir(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); } static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_read_in *arg = (struct fuse_read_in *) inarg; - struct fuse_file_info fi; + struct fuse_read_in *arg = (struct fuse_read_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; - if (req->f->op.readdir) - req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.readdir) + req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } static @@ -1431,594 +1230,586 @@ do_readdir_plus(fuse_req_t req_, static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_release_in *arg = (struct fuse_release_in *) inarg; - struct fuse_file_info fi; + struct fuse_release_in *arg = (struct fuse_release_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; - if (req->f->op.releasedir) - req->f->op.releasedir(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + if(req->f->op.releasedir) + req->f->op.releasedir(req, nodeid, &fi); + else + fuse_reply_err(req, 0); } static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; - struct fuse_file_info fi; + struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; - if (req->f->op.fsyncdir) - req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.fsyncdir) + req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) nodeid; - (void) inarg; + (void) nodeid; + (void) inarg; - if (req->f->op.statfs) - req->f->op.statfs(req, nodeid); - else { - struct statvfs buf = { - .f_namemax = 255, - .f_bsize = 512, - }; - fuse_reply_statfs(req, &buf); - } + if(req->f->op.statfs) + req->f->op.statfs(req, nodeid); + else { + struct statvfs buf = { + .f_namemax = 255, + .f_bsize = 512, + }; + fuse_reply_statfs(req, &buf); + } } static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg; - char *name = PARAM(arg); - char *value = name + strlen(name) + 1; + struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg; + char *name = PARAM(arg); + char *value = name + strlen(name) + 1; - if (req->f->op.setxattr) - req->f->op.setxattr(req, nodeid, name, value, arg->size, - arg->flags); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.setxattr) + req->f->op.setxattr(req, nodeid, name, value, arg->size, + arg->flags); + else + fuse_reply_err(req, ENOSYS); } static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; - if (req->f->op.getxattr) - req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.getxattr) + req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); + else + fuse_reply_err(req, ENOSYS); } static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; - if (req->f->op.listxattr) - req->f->op.listxattr(req, nodeid, arg->size); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.listxattr) + req->f->op.listxattr(req, nodeid, arg->size); + else + fuse_reply_err(req, ENOSYS); } static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.removexattr) - req->f->op.removexattr(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.removexattr) + req->f->op.removexattr(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void convert_fuse_file_lock(struct fuse_file_lock *fl, struct flock *flock) { - memset(flock, 0, sizeof(struct flock)); - flock->l_type = fl->type; - flock->l_whence = SEEK_SET; - flock->l_start = fl->start; - if (fl->end == OFFSET_MAX) - flock->l_len = 0; - else - flock->l_len = fl->end - fl->start + 1; - flock->l_pid = fl->pid; + memset(flock, 0, sizeof(struct flock)); + flock->l_type = fl->type; + flock->l_whence = SEEK_SET; + flock->l_start = fl->start; + if(fl->end == OFFSET_MAX) + flock->l_len = 0; + else + flock->l_len = fl->end - fl->start + 1; + flock->l_pid = fl->pid; } static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; - struct fuse_file_info fi; - struct flock flock; + struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; - convert_fuse_file_lock(&arg->lk, &flock); - if (req->f->op.getlk) - req->f->op.getlk(req, nodeid, &fi, &flock); - else - fuse_reply_err(req, ENOSYS); + convert_fuse_file_lock(&arg->lk, &flock); + if(req->f->op.getlk) + req->f->op.getlk(req, nodeid, &fi, &flock); + else + fuse_reply_err(req, ENOSYS); } static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid, const void *inarg, int sleep) { - struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; - struct fuse_file_info fi; - struct flock flock; - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; - - if (arg->lk_flags & FUSE_LK_FLOCK) { - int op = 0; - - switch (arg->lk.type) { - case F_RDLCK: - op = LOCK_SH; - break; - case F_WRLCK: - op = LOCK_EX; - break; - case F_UNLCK: - op = LOCK_UN; - break; - } - if (!sleep) - op |= LOCK_NB; - - if (req->f->op.flock) - req->f->op.flock(req, nodeid, &fi, op); - else - fuse_reply_err(req, ENOSYS); - } else { - convert_fuse_file_lock(&arg->lk, &flock); - if (req->f->op.setlk) - req->f->op.setlk(req, nodeid, &fi, &flock, sleep); - else - fuse_reply_err(req, ENOSYS); - } + struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; + + if(arg->lk_flags & FUSE_LK_FLOCK) { + int op = 0; + + switch (arg->lk.type) { + case F_RDLCK: + op = LOCK_SH; + break; + case F_WRLCK: + op = LOCK_EX; + break; + case F_UNLCK: + op = LOCK_UN; + break; + } + if(!sleep) + op |= LOCK_NB; + + if(req->f->op.flock) + req->f->op.flock(req, nodeid, &fi, op); + else + fuse_reply_err(req, ENOSYS); + } else { + convert_fuse_file_lock(&arg->lk, &flock); + if(req->f->op.setlk) + req->f->op.setlk(req, nodeid, &fi, &flock, sleep); + else + fuse_reply_err(req, ENOSYS); + } } static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - do_setlk_common(req, nodeid, inarg, 0); + do_setlk_common(req, nodeid, inarg, 0); } static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - do_setlk_common(req, nodeid, inarg, 1); + do_setlk_common(req, nodeid, inarg, 1); } static int find_interrupted(struct fuse_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->list.next; curr != &f->list; curr = curr->next) { - if (curr->unique == req->u.i.unique) { - fuse_interrupt_func_t func; - void *data; - - curr->ctr++; - pthread_mutex_unlock(&f->lock); - - /* Ugh, ugly locking */ - pthread_mutex_lock(&curr->lock); - pthread_mutex_lock(&f->lock); - curr->interrupted = 1; - func = curr->u.ni.func; - data = curr->u.ni.data; - pthread_mutex_unlock(&f->lock); - if (func) - func(curr, data); - pthread_mutex_unlock(&curr->lock); - - pthread_mutex_lock(&f->lock); - curr->ctr--; - if (!curr->ctr) - destroy_req(curr); - - return 1; - } - } - for (curr = f->interrupts.next; curr != &f->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->u.i.unique) - return 1; - } - return 0; + struct fuse_req *curr; + + for (curr = f->list.next; curr != &f->list; curr = curr->next) { + if(curr->unique == req->u.i.unique) { + fuse_interrupt_func_t func; + void *data; + + curr->ctr++; + pthread_mutex_unlock(&f->lock); + + /* Ugh, ugly locking */ + pthread_mutex_lock(&curr->lock); + pthread_mutex_lock(&f->lock); + curr->interrupted = 1; + func = curr->u.ni.func; + data = curr->u.ni.data; + pthread_mutex_unlock(&f->lock); + if(func) + func(curr, data); + pthread_mutex_unlock(&curr->lock); + + pthread_mutex_lock(&f->lock); + curr->ctr--; + if(!curr->ctr) + destroy_req(curr); + + return 1; + } + } + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if(curr->u.i.unique == req->u.i.unique) + return 1; + } + return 0; } static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; - struct fuse_ll *f = req->f; + struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; + struct fuse_ll *f = req->f; - (void) nodeid; - if (f->debug) - fprintf(stderr, "INTERRUPT: %llu\n", - (unsigned long long) arg->unique); + (void) nodeid; + if(f->debug) + fprintf(stderr, "INTERRUPT: %llu\n", + (unsigned long long) arg->unique); - req->u.i.unique = arg->unique; + req->u.i.unique = arg->unique; - pthread_mutex_lock(&f->lock); - if (find_interrupted(f, req)) - destroy_req(req); - else - list_add_req(req, &f->interrupts); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + if(find_interrupted(f, req)) + destroy_req(req); + else + list_add_req(req, &f->interrupts); + pthread_mutex_unlock(&f->lock); } static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->interrupts.next; curr != &f->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->unique) { - req->interrupted = 1; - list_del_req(curr); - free(curr); - return NULL; - } - } - curr = f->interrupts.next; - if (curr != &f->interrupts) { - list_del_req(curr); - list_init_req(curr); - return curr; - } else - return NULL; + struct fuse_req *curr; + + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if(curr->u.i.unique == req->unique) { + req->interrupted = 1; + list_del_req(curr); + free(curr); + return NULL; + } + } + curr = f->interrupts.next; + if(curr != &f->interrupts) { + list_del_req(curr); + list_init_req(curr); + return curr; + } else + return NULL; } static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg; + struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg; - if (req->f->op.bmap) - req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); - else - fuse_reply_err(req, ENOSYS); + if(req->f->op.bmap) + req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); + else + fuse_reply_err(req, ENOSYS); } static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg; - unsigned int flags = arg->flags; - void *in_buf = arg->in_size ? PARAM(arg) : NULL; - struct fuse_file_info fi; - - if (flags & FUSE_IOCTL_DIR && - !(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) { - fuse_reply_err(req, ENOTTY); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 && - !(flags & FUSE_IOCTL_32BIT)) { - req->ioctl_64bit = 1; - } - - if (req->f->op.ioctl) - req->f->op.ioctl(req, nodeid, arg->cmd, - (void *)(uintptr_t)arg->arg, &fi, flags, - in_buf, arg->in_size, arg->out_size); - else - fuse_reply_err(req, ENOSYS); + struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg; + unsigned int flags = arg->flags; + void *in_buf = arg->in_size ? PARAM(arg) : NULL; + struct fuse_file_info fi; + + if(flags & FUSE_IOCTL_DIR && + !(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) { + fuse_reply_err(req, ENOTTY); + return; + } + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + + if(sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 && + !(flags & FUSE_IOCTL_32BIT)) { + req->ioctl_64bit = 1; + } + + if(req->f->op.ioctl) + req->f->op.ioctl(req, nodeid, arg->cmd, + (void *)(uintptr_t)arg->arg, &fi, flags, + in_buf, arg->in_size, arg->out_size); + else + fuse_reply_err(req, ENOSYS); } void fuse_pollhandle_destroy(struct fuse_pollhandle *ph) { - free(ph); + free(ph); } static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg; - struct fuse_file_info fi; + struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; - if (req->f->op.poll) { - struct fuse_pollhandle *ph = NULL; + if(req->f->op.poll) { + struct fuse_pollhandle *ph = NULL; - if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) { - ph = malloc(sizeof(struct fuse_pollhandle)); - if (ph == NULL) { - fuse_reply_err(req, ENOMEM); - return; - } - ph->kh = arg->kh; - ph->ch = req->ch; - ph->f = req->f; - } + if(arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) { + ph = malloc(sizeof(struct fuse_pollhandle)); + if(ph == NULL) { + fuse_reply_err(req, ENOMEM); + return; + } + ph->kh = arg->kh; + ph->ch = req->ch; + ph->f = req->f; + } - req->f->op.poll(req, nodeid, &fi, ph); - } else { - fuse_reply_err(req, ENOSYS); - } + req->f->op.poll(req, nodeid, &fi, ph); + } else { + fuse_reply_err(req, ENOSYS); + } } static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg; - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->f->op.fallocate) - req->f->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi); - else - fuse_reply_err(req, ENOSYS); -} - -static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) -{ - struct fuse_init_in *arg = (struct fuse_init_in *) inarg; - struct fuse_init_out outarg; - struct fuse_ll *f = req->f; - size_t bufsize = fuse_chan_bufsize(req->ch); - - (void) nodeid; - if (f->debug) { - fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); - if (arg->major == 7 && arg->minor >= 6) { - fprintf(stderr, "flags=0x%08x\n", arg->flags); - fprintf(stderr, "max_readahead=0x%08x\n", - arg->max_readahead); - } - } - f->conn.proto_major = arg->major; - f->conn.proto_minor = arg->minor; - f->conn.capable = 0; - f->conn.want = 0; - - memset(&outarg, 0, sizeof(outarg)); - - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - outarg.max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ; - - if (arg->major < 7) { - fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); - return; - } - - if (arg->major > 7) { - /* Wait for a second INIT request with a 7.X version */ - send_reply_ok(req, &outarg, sizeof(outarg)); - return; - } - - if (arg->minor >= 6) { - if (arg->max_readahead < f->conn.max_readahead) - f->conn.max_readahead = arg->max_readahead; - if (arg->flags & FUSE_ASYNC_READ) - f->conn.capable |= FUSE_CAP_ASYNC_READ; - if (arg->flags & FUSE_POSIX_LOCKS) - f->conn.capable |= FUSE_CAP_POSIX_LOCKS; - if (arg->flags & FUSE_ATOMIC_O_TRUNC) - f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC; - if (arg->flags & FUSE_EXPORT_SUPPORT) - f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT; - if (arg->flags & FUSE_BIG_WRITES) - f->conn.capable |= FUSE_CAP_BIG_WRITES; - if (arg->flags & FUSE_DONT_MASK) - f->conn.capable |= FUSE_CAP_DONT_MASK; - if (arg->flags & FUSE_FLOCK_LOCKS) - f->conn.capable |= FUSE_CAP_FLOCK_LOCKS; - if (arg->flags & FUSE_POSIX_ACL) - f->conn.capable |= FUSE_CAP_POSIX_ACL; - if (arg->flags & FUSE_CACHE_SYMLINKS) - f->conn.capable |= FUSE_CAP_CACHE_SYMLINKS; - if (arg->flags & FUSE_ASYNC_DIO) - f->conn.capable |= FUSE_CAP_ASYNC_DIO; - if (arg->flags & FUSE_PARALLEL_DIROPS) - f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; - if (arg->flags & FUSE_MAX_PAGES) - f->conn.capable |= FUSE_CAP_MAX_PAGES; - if (arg->flags & FUSE_WRITEBACK_CACHE) - f->conn.capable |= FUSE_CAP_WRITEBACK_CACHE; - if (arg->flags & FUSE_DO_READDIRPLUS) - f->conn.capable |= FUSE_CAP_READDIR_PLUS; - if (arg->flags & FUSE_READDIRPLUS_AUTO) - f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO; - } else { - f->conn.want &= ~FUSE_CAP_ASYNC_READ; - f->conn.max_readahead = 0; - } - - if (req->f->conn.proto_minor >= 14) { -#ifdef HAVE_SPLICE -#ifdef HAVE_VMSPLICE - f->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; - if (f->splice_write) - f->conn.want |= FUSE_CAP_SPLICE_WRITE; - if (f->splice_move) - f->conn.want |= FUSE_CAP_SPLICE_MOVE; -#endif - f->conn.capable |= FUSE_CAP_SPLICE_READ; - if (f->splice_read) - f->conn.want |= FUSE_CAP_SPLICE_READ; -#endif - } - if (req->f->conn.proto_minor >= 18) - f->conn.capable |= FUSE_CAP_IOCTL_DIR; - - if (f->op.getlk && f->op.setlk && !f->no_remote_posix_lock) - f->conn.want |= FUSE_CAP_POSIX_LOCKS; - if (f->op.flock && !f->no_remote_flock) - f->conn.want |= FUSE_CAP_FLOCK_LOCKS; - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - - bufsize -= 4096; - if (bufsize < f->conn.max_write) - f->conn.max_write = bufsize; - - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata, &f->conn); - - if (f->no_splice_read) - f->conn.want &= ~FUSE_CAP_SPLICE_READ; - if (f->no_splice_write) - f->conn.want &= ~FUSE_CAP_SPLICE_WRITE; - if (f->no_splice_move) - f->conn.want &= ~FUSE_CAP_SPLICE_MOVE; - - if ((arg->flags & FUSE_MAX_PAGES) && (f->conn.want & FUSE_CAP_MAX_PAGES)) - { - outarg.flags |= FUSE_MAX_PAGES; - outarg.max_pages = f->conn.max_pages; - } - - if (f->conn.want & FUSE_CAP_ASYNC_READ) - outarg.flags |= FUSE_ASYNC_READ; - if (f->conn.want & FUSE_CAP_POSIX_LOCKS) - outarg.flags |= FUSE_POSIX_LOCKS; - if (f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) - outarg.flags |= FUSE_ATOMIC_O_TRUNC; - if (f->conn.want & FUSE_CAP_EXPORT_SUPPORT) - outarg.flags |= FUSE_EXPORT_SUPPORT; - if (f->conn.want & FUSE_CAP_BIG_WRITES) - outarg.flags |= FUSE_BIG_WRITES; - if (f->conn.want & FUSE_CAP_DONT_MASK) - outarg.flags |= FUSE_DONT_MASK; - if (f->conn.want & FUSE_CAP_FLOCK_LOCKS) - outarg.flags |= FUSE_FLOCK_LOCKS; - if (f->conn.want & FUSE_CAP_POSIX_ACL) - outarg.flags |= FUSE_POSIX_ACL; - if (f->conn.want & FUSE_CAP_CACHE_SYMLINKS) - outarg.flags |= FUSE_CACHE_SYMLINKS; - if (f->conn.want & FUSE_CAP_ASYNC_DIO) - outarg.flags |= FUSE_ASYNC_DIO; - if (f->conn.want & FUSE_CAP_PARALLEL_DIROPS) - outarg.flags |= FUSE_PARALLEL_DIROPS; - if (f->conn.want & FUSE_CAP_WRITEBACK_CACHE) - outarg.flags |= FUSE_WRITEBACK_CACHE; - if (f->conn.want & FUSE_CAP_READDIR_PLUS) - outarg.flags |= FUSE_DO_READDIRPLUS; - if (f->conn.want & FUSE_CAP_READDIR_PLUS_AUTO) - outarg.flags |= FUSE_READDIRPLUS_AUTO; - - outarg.max_readahead = f->conn.max_readahead; - outarg.max_write = f->conn.max_write; - if (f->conn.proto_minor >= 13) { - if (f->conn.max_background >= (1 << 16)) - f->conn.max_background = (1 << 16) - 1; - if (f->conn.congestion_threshold > f->conn.max_background) - f->conn.congestion_threshold = f->conn.max_background; - if (!f->conn.congestion_threshold) { - f->conn.congestion_threshold = - f->conn.max_background * 3 / 4; - } - - outarg.max_background = f->conn.max_background; - outarg.congestion_threshold = f->conn.congestion_threshold; - } - - if (f->debug) { - fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); - fprintf(stderr, " flags=0x%08x\n", outarg.flags); - fprintf(stderr, " max_readahead=0x%08x\n", - outarg.max_readahead); - fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); - fprintf(stderr, " max_background=%i\n", - outarg.max_background); - fprintf(stderr, " congestion_threshold=%i\n", - outarg.congestion_threshold); - fprintf(stderr, " max_pages=%d\n",outarg.max_pages); - } - - size_t outargsize; - if(arg->minor < 5) - outargsize = FUSE_COMPAT_INIT_OUT_SIZE; - else if(arg->minor < 23) - outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE; - else - outargsize = sizeof(outarg); - - send_reply_ok(req, &outarg, outargsize); + struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + + if(req->f->op.fallocate) + req->f->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) -{ - struct fuse_ll *f = req->f; +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 = req->ch->bufsize; + + (void) nodeid; + if(f->debug) { + fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); + if(arg->major == 7 && arg->minor >= 6) { + fprintf(stderr, "flags=0x%08x\n", arg->flags); + fprintf(stderr, "max_readahead=0x%08x\n", + arg->max_readahead); + } + } + f->conn.proto_major = arg->major; + f->conn.proto_minor = arg->minor; + f->conn.capable = 0; + f->conn.want = 0; + + memset(&outarg, 0, sizeof(outarg)); + + outarg.major = FUSE_KERNEL_VERSION; + outarg.minor = FUSE_KERNEL_MINOR_VERSION; + outarg.max_pages = FUSE_MSG_DEFAULT_PAGES; + + if(arg->major < 7) { + fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", + arg->major, arg->minor); + fuse_reply_err(req, EPROTO); + return; + } + + if(arg->major > 7) { + /* Wait for a second INIT request with a 7.X version */ + send_reply_ok(req, &outarg, sizeof(outarg)); + return; + } + + if(arg->minor >= 6) { + if(arg->max_readahead < f->conn.max_readahead) + f->conn.max_readahead = arg->max_readahead; + if(arg->flags & FUSE_ASYNC_READ) + f->conn.capable |= FUSE_CAP_ASYNC_READ; + if(arg->flags & FUSE_POSIX_LOCKS) + f->conn.capable |= FUSE_CAP_POSIX_LOCKS; + if(arg->flags & FUSE_ATOMIC_O_TRUNC) + f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC; + if(arg->flags & FUSE_EXPORT_SUPPORT) + f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT; + if(arg->flags & FUSE_BIG_WRITES) + f->conn.capable |= FUSE_CAP_BIG_WRITES; + if(arg->flags & FUSE_DONT_MASK) + f->conn.capable |= FUSE_CAP_DONT_MASK; + if(arg->flags & FUSE_FLOCK_LOCKS) + f->conn.capable |= FUSE_CAP_FLOCK_LOCKS; + if(arg->flags & FUSE_POSIX_ACL) + f->conn.capable |= FUSE_CAP_POSIX_ACL; + if(arg->flags & FUSE_CACHE_SYMLINKS) + f->conn.capable |= FUSE_CAP_CACHE_SYMLINKS; + if(arg->flags & FUSE_ASYNC_DIO) + f->conn.capable |= FUSE_CAP_ASYNC_DIO; + if(arg->flags & FUSE_PARALLEL_DIROPS) + f->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; + if(arg->flags & FUSE_MAX_PAGES) + f->conn.capable |= FUSE_CAP_MAX_PAGES; + if(arg->flags & FUSE_WRITEBACK_CACHE) + f->conn.capable |= FUSE_CAP_WRITEBACK_CACHE; + if (arg->flags & FUSE_DO_READDIRPLUS) + f->conn.capable |= FUSE_CAP_READDIR_PLUS; + if (arg->flags & FUSE_READDIRPLUS_AUTO) + f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO; + } else { + f->conn.want &= ~FUSE_CAP_ASYNC_READ; + f->conn.max_readahead = 0; + } + + if(req->f->conn.proto_minor >= 14) + { + f->conn.capable |= (FUSE_CAP_SPLICE_WRITE|FUSE_CAP_SPLICE_MOVE); + if(f->splice_write) + f->conn.want |= FUSE_CAP_SPLICE_WRITE; + if(f->splice_move) + f->conn.want |= FUSE_CAP_SPLICE_MOVE; + f->conn.capable |= FUSE_CAP_SPLICE_READ; + if(f->splice_read) + f->conn.want |= FUSE_CAP_SPLICE_READ; + } + + if(req->f->conn.proto_minor >= 18) + f->conn.capable |= FUSE_CAP_IOCTL_DIR; - (void) nodeid; - (void) inarg; + if(f->op.getlk && f->op.setlk && !f->no_remote_posix_lock) + f->conn.want |= FUSE_CAP_POSIX_LOCKS; + if(f->op.flock && !f->no_remote_flock) + f->conn.want |= FUSE_CAP_FLOCK_LOCKS; - f->got_destroy = 1; - if (f->op.destroy) - f->op.destroy(f->userdata); + if(bufsize < FUSE_MIN_READ_BUFFER) { + fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", + bufsize); + bufsize = FUSE_MIN_READ_BUFFER; + } - send_reply_ok(req, NULL, 0); + bufsize -= 4096; + if(bufsize < f->conn.max_write) + f->conn.max_write = bufsize; + + f->got_init = 1; + if(f->op.init) + f->op.init(f->userdata, &f->conn); + + if(f->no_splice_read) + f->conn.want &= ~FUSE_CAP_SPLICE_READ; + if(f->no_splice_write) + f->conn.want &= ~FUSE_CAP_SPLICE_WRITE; + if(f->no_splice_move) + f->conn.want &= ~FUSE_CAP_SPLICE_MOVE; + + if((arg->flags & FUSE_MAX_PAGES) && (f->conn.want & FUSE_CAP_MAX_PAGES)) + { + outarg.flags |= FUSE_MAX_PAGES; + outarg.max_pages = f->conn.max_pages; + } + + if(f->conn.want & FUSE_CAP_ASYNC_READ) + outarg.flags |= FUSE_ASYNC_READ; + if(f->conn.want & FUSE_CAP_POSIX_LOCKS) + outarg.flags |= FUSE_POSIX_LOCKS; + if(f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) + outarg.flags |= FUSE_ATOMIC_O_TRUNC; + if(f->conn.want & FUSE_CAP_EXPORT_SUPPORT) + outarg.flags |= FUSE_EXPORT_SUPPORT; + if(f->conn.want & FUSE_CAP_BIG_WRITES) + outarg.flags |= FUSE_BIG_WRITES; + if(f->conn.want & FUSE_CAP_DONT_MASK) + outarg.flags |= FUSE_DONT_MASK; + if(f->conn.want & FUSE_CAP_FLOCK_LOCKS) + outarg.flags |= FUSE_FLOCK_LOCKS; + if(f->conn.want & FUSE_CAP_POSIX_ACL) + outarg.flags |= FUSE_POSIX_ACL; + if(f->conn.want & FUSE_CAP_CACHE_SYMLINKS) + outarg.flags |= FUSE_CACHE_SYMLINKS; + if(f->conn.want & FUSE_CAP_ASYNC_DIO) + outarg.flags |= FUSE_ASYNC_DIO; + if(f->conn.want & FUSE_CAP_PARALLEL_DIROPS) + outarg.flags |= FUSE_PARALLEL_DIROPS; + if(f->conn.want & FUSE_CAP_WRITEBACK_CACHE) + outarg.flags |= FUSE_WRITEBACK_CACHE; + if (f->conn.want & FUSE_CAP_READDIR_PLUS) + outarg.flags |= FUSE_DO_READDIRPLUS; + if (f->conn.want & FUSE_CAP_READDIR_PLUS_AUTO) + outarg.flags |= FUSE_READDIRPLUS_AUTO; + + outarg.max_readahead = f->conn.max_readahead; + outarg.max_write = f->conn.max_write; + if(f->conn.proto_minor >= 13) { + if(f->conn.max_background >= (1 << 16)) + f->conn.max_background = (1 << 16) - 1; + if(f->conn.congestion_threshold > f->conn.max_background) + f->conn.congestion_threshold = f->conn.max_background; + if(!f->conn.congestion_threshold) { + f->conn.congestion_threshold = + f->conn.max_background * 3 / 4; + } + + outarg.max_background = f->conn.max_background; + outarg.congestion_threshold = f->conn.congestion_threshold; + } + + if(f->debug) { + fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); + fprintf(stderr, " flags=0x%08x\n", outarg.flags); + fprintf(stderr, " max_readahead=0x%08x\n", + outarg.max_readahead); + fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); + fprintf(stderr, " max_background=%i\n", + outarg.max_background); + fprintf(stderr, " congestion_threshold=%i\n", + outarg.congestion_threshold); + fprintf(stderr, " max_pages=%d\n",outarg.max_pages); + } + + size_t outargsize; + if(arg->minor < 5) + outargsize = FUSE_COMPAT_INIT_OUT_SIZE; + else if(arg->minor < 23) + outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE; + else + outargsize = sizeof(outarg); + + send_reply_ok(req, &outarg, outargsize); } -static void list_del_nreq(struct fuse_notify_req *nreq) +static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_notify_req *prev = nreq->prev; - struct fuse_notify_req *next = nreq->next; - prev->next = next; - next->prev = prev; + struct fuse_ll *f = req->f; + + (void) nodeid; + (void) inarg; + + f->got_destroy = 1; + if(f->op.destroy) + f->op.destroy(f->userdata); + + send_reply_ok(req, NULL, 0); } -static void list_add_nreq(struct fuse_notify_req *nreq, - struct fuse_notify_req *next) +static void list_del_nreq(struct fuse_notify_req *nreq) { - struct fuse_notify_req *prev = next->prev; - nreq->next = next; - nreq->prev = prev; - prev->next = nreq; - next->prev = nreq; + struct fuse_notify_req *prev = nreq->prev; + struct fuse_notify_req *next = nreq->next; + prev->next = next; + next->prev = prev; } static void list_init_nreq(struct fuse_notify_req *nreq) { - nreq->next = nreq; - nreq->prev = nreq; + nreq->next = nreq; + nreq->prev = nreq; } static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid, const void *inarg, const struct fuse_buf *buf) { - struct fuse_ll *f = req->f; - struct fuse_notify_req *nreq; - struct fuse_notify_req *head; + struct fuse_ll *f = req->f; + struct fuse_notify_req *nreq; + struct fuse_notify_req *head; - pthread_mutex_lock(&f->lock); - head = &f->notify_list; - for (nreq = head->next; nreq != head; nreq = nreq->next) { - if (nreq->unique == req->unique) { - list_del_nreq(nreq); - break; - } - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + head = &f->notify_list; + for (nreq = head->next; nreq != head; nreq = nreq->next) { + if(nreq->unique == req->unique) { + list_del_nreq(nreq); + break; + } + } + pthread_mutex_unlock(&f->lock); - if (nreq != head) - nreq->reply(nreq, req, nodeid, inarg, buf); + if(nreq != head) + nreq->reply(nreq, req, nodeid, inarg, buf); } static @@ -2049,262 +1840,20 @@ do_copy_file_range(fuse_req_t req_, arg->flags); } -static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch, - int notify_code, struct iovec *iov, int count) -{ - struct fuse_out_header out; - - if (!f->got_init) - return -ENOTCONN; - - out.unique = 0; - out.error = notify_code; - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(struct fuse_out_header); - - return fuse_send_msg(f, ch, iov, count); -} - -int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph) -{ - if (ph != NULL) { - struct fuse_notify_poll_wakeup_out outarg; - struct iovec iov[2]; - - outarg.kh = ph->kh; - - iov[1].iov_base = &outarg; - iov[1].iov_len = sizeof(outarg); - - return send_notify_iov(ph->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2); - } else { - return 0; - } -} - -int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, - off_t off, off_t len) -{ - struct fuse_notify_inval_inode_out outarg; - struct fuse_ll *f; - struct iovec iov[2]; - - if (!ch) - return -EINVAL; - - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; - - outarg.ino = ino; - outarg.off = off; - outarg.len = len; - - iov[1].iov_base = &outarg; - iov[1].iov_len = sizeof(outarg); - - return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2); -} - -int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, - const char *name, size_t namelen) +struct fuse_retrieve_req { - struct fuse_notify_inval_entry_out outarg; - struct fuse_ll *f; - struct iovec iov[3]; - - if (!ch) - return -EINVAL; - - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; - - outarg.parent = parent; - outarg.namelen = namelen; - outarg.padding = 0; - - iov[1].iov_base = &outarg; - iov[1].iov_len = sizeof(outarg); - iov[2].iov_base = (void *)name; - iov[2].iov_len = namelen + 1; - - return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); -} - -int fuse_lowlevel_notify_delete(struct fuse_chan *ch, - fuse_ino_t parent, fuse_ino_t child, - const char *name, size_t namelen) -{ - struct fuse_notify_delete_out outarg; - struct fuse_ll *f; - struct iovec iov[3]; - - if (!ch) - return -EINVAL; - - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; - - if (f->conn.proto_minor < 18) - return -ENOSYS; - - outarg.parent = parent; - outarg.child = child; - outarg.namelen = namelen; - outarg.padding = 0; - - iov[1].iov_base = &outarg; - iov[1].iov_len = sizeof(outarg); - iov[2].iov_base = (void *)name; - iov[2].iov_len = namelen + 1; - - return send_notify_iov(f, ch, FUSE_NOTIFY_DELETE, iov, 3); -} - -int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, - off_t offset, struct fuse_bufvec *bufv, - enum fuse_buf_copy_flags flags) -{ - struct fuse_out_header out; - struct fuse_notify_store_out outarg; - struct fuse_ll *f; - struct iovec iov[3]; - size_t size = fuse_buf_size(bufv); - int res; - - if (!ch) - return -EINVAL; - - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; - - if (f->conn.proto_minor < 15) - return -ENOSYS; - - out.unique = 0; - out.error = FUSE_NOTIFY_STORE; - - outarg.nodeid = ino; - outarg.offset = offset; - outarg.size = size; - outarg.padding = 0; - - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(out); - iov[1].iov_base = &outarg; - iov[1].iov_len = sizeof(outarg); - - res = fuse_send_data_iov(f, ch, iov, 2, bufv, flags); - if (res > 0) - res = -res; - - return res; -} - -struct fuse_retrieve_req { - struct fuse_notify_req nreq; - void *cookie; + struct fuse_notify_req nreq; + void *cookie; }; -static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, - fuse_req_t req, fuse_ino_t ino, - const void *inarg, - const struct fuse_buf *ibuf) -{ - struct fuse_ll *f = req->f; - struct fuse_retrieve_req *rreq = - container_of(nreq, struct fuse_retrieve_req, nreq); - const struct fuse_notify_retrieve_in *arg = inarg; - struct fuse_bufvec bufv = { - .buf[0] = *ibuf, - .count = 1, - }; - - if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) - bufv.buf[0].mem = PARAM(arg); - - bufv.buf[0].size -= sizeof(struct fuse_in_header) + - sizeof(struct fuse_notify_retrieve_in); - - if (bufv.buf[0].size < arg->size) { - fprintf(stderr, "fuse: retrieve reply: buffer size too small\n"); - fuse_reply_none(req); - goto out; - } - bufv.buf[0].size = arg->size; - - if (req->f->op.retrieve_reply) { - req->f->op.retrieve_reply(req, rreq->cookie, ino, - arg->offset, &bufv); - } else { - fuse_reply_none(req); - } -out: - free(rreq); - if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) - fuse_ll_clear_pipe(f); -} - -int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, - size_t size, off_t offset, void *cookie) -{ - struct fuse_notify_retrieve_out outarg; - struct fuse_ll *f; - struct iovec iov[2]; - struct fuse_retrieve_req *rreq; - int err; - - if (!ch) - return -EINVAL; - - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); - if (!f) - return -ENODEV; - - if (f->conn.proto_minor < 15) - return -ENOSYS; - - rreq = malloc(sizeof(*rreq)); - if (rreq == NULL) - return -ENOMEM; - - pthread_mutex_lock(&f->lock); - rreq->cookie = cookie; - rreq->nreq.unique = f->notify_ctr++; - rreq->nreq.reply = fuse_ll_retrieve_reply; - list_add_nreq(&rreq->nreq, &f->notify_list); - pthread_mutex_unlock(&f->lock); - - outarg.notify_unique = rreq->nreq.unique; - outarg.nodeid = ino; - outarg.offset = offset; - outarg.size = size; - - iov[1].iov_base = &outarg; - iov[1].iov_len = sizeof(outarg); - - err = send_notify_iov(f, ch, FUSE_NOTIFY_RETRIEVE, iov, 2); - if (err) { - pthread_mutex_lock(&f->lock); - list_del_nreq(&rreq->nreq); - pthread_mutex_unlock(&f->lock); - free(rreq); - } - - return err; -} - void *fuse_req_userdata(fuse_req_t req) { - return req->f->userdata; + return req->f->userdata; } const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) { - return &req->ctx; + return &req->ctx; } /* @@ -2315,7 +1864,7 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req); const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req) { - return fuse_req_ctx(req); + return fuse_req_ctx(req); } #ifndef __NetBSD__ FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4"); @@ -2325,30 +1874,31 @@ FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4"); void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data) { - pthread_mutex_lock(&req->lock); - pthread_mutex_lock(&req->f->lock); - req->u.ni.func = func; - req->u.ni.data = data; - pthread_mutex_unlock(&req->f->lock); - if (req->interrupted && func) - func(req, data); - pthread_mutex_unlock(&req->lock); + pthread_mutex_lock(&req->lock); + pthread_mutex_lock(&req->f->lock); + req->u.ni.func = func; + req->u.ni.data = data; + pthread_mutex_unlock(&req->f->lock); + if(req->interrupted && func) + func(req,data); + pthread_mutex_unlock(&req->lock); } int fuse_req_interrupted(fuse_req_t req) { - int interrupted; + int interrupted; - pthread_mutex_lock(&req->f->lock); - interrupted = req->interrupted; - pthread_mutex_unlock(&req->f->lock); + pthread_mutex_lock(&req->f->lock); + interrupted = req->interrupted; + pthread_mutex_unlock(&req->f->lock); - return interrupted; + return interrupted; } -static struct { - void (*func)(fuse_req_t, fuse_ino_t, const void *); - const char *name; +static struct +{ + void (*func)(fuse_req_t, fuse_ino_t, const void *); + const char *name; } fuse_ll_ops[] = { [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, @@ -2394,405 +1944,312 @@ static struct { [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" }, - [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) -static const char *opname(enum fuse_opcode opcode) -{ - if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) - return "???"; - else - return fuse_ll_ops[opcode].name; -} - -static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, - struct fuse_bufvec *src) -{ - int res = fuse_buf_copy(dst, src, 0); - if (res < 0) { - fprintf(stderr, "fuse: copy from pipe: %s\n", strerror(-res)); - return res; - } - if (res < fuse_buf_size(dst)) { - fprintf(stderr, "fuse: copy from pipe: short read\n"); - return -1; - } - return 0; -} - -static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, - struct fuse_chan *ch) -{ - struct fuse_ll *f = (struct fuse_ll *) data; - const size_t write_header_size = sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in); - struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 }; - struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size); - struct fuse_in_header *in; - const void *inarg; - struct fuse_req *req; - void *mbuf = NULL; - int err; - int res; - - if (buf->flags & FUSE_BUF_IS_FD) { - if (buf->size < tmpbuf.buf[0].size) - tmpbuf.buf[0].size = buf->size; - - mbuf = malloc(tmpbuf.buf[0].size); - if (mbuf == NULL) { - fprintf(stderr, "fuse: failed to allocate header\n"); - goto clear_pipe; - } - tmpbuf.buf[0].mem = mbuf; - - res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); - if (res < 0) - goto clear_pipe; - - in = mbuf; - } else { - in = buf->mem; - } - - if (f->debug) { - fprintf(stderr, - "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu, pid: %u\n", - (unsigned long long) in->unique, - opname((enum fuse_opcode) in->opcode), in->opcode, - (unsigned long) in->nodeid, buf->size, in->pid); - } - - req = fuse_ll_alloc_req(f); - if (req == NULL) { - struct fuse_out_header out = { - .unique = in->unique, - .error = -ENOMEM, - }; - struct iovec iov = { - .iov_base = &out, - .iov_len = sizeof(struct fuse_out_header), - }; - - fuse_send_msg(f, ch, &iov, 1); - goto clear_pipe; - } - - req->unique = in->unique; - req->ctx.uid = in->uid; - req->ctx.gid = in->gid; - req->ctx.pid = in->pid; - req->ch = ch; - - err = EIO; - if (!f->got_init) { - enum fuse_opcode expected; - - expected = f->cuse_data ? CUSE_INIT : FUSE_INIT; - if (in->opcode != expected) - goto reply_err; - } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) - goto reply_err; - - err = EACCES; - if (f->allow_root && - in->uid != f->owner && - in->uid != 0 && - in->opcode != FUSE_INIT && - in->opcode != FUSE_READ && - in->opcode != FUSE_WRITE && - in->opcode != FUSE_FSYNC && - in->opcode != FUSE_RELEASE && - in->opcode != FUSE_READDIR && - in->opcode != FUSE_READDIRPLUS && - in->opcode != FUSE_FSYNCDIR && - in->opcode != FUSE_RELEASEDIR && - in->opcode != FUSE_NOTIFY_REPLY) - goto reply_err; - - err = ENOSYS; - if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) - goto reply_err; - if (in->opcode != FUSE_INTERRUPT) { - struct fuse_req *intr; - pthread_mutex_lock(&f->lock); - intr = check_interrupt(f, req); - list_add_req(req, &f->list); - pthread_mutex_unlock(&f->lock); - if (intr) - fuse_reply_err(intr, EAGAIN); - } - - if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size && - (in->opcode != FUSE_WRITE || !f->op.write_buf) && - in->opcode != FUSE_NOTIFY_REPLY) { - void *newmbuf; - - err = ENOMEM; - newmbuf = realloc(mbuf, buf->size); - if (newmbuf == NULL) - goto reply_err; - mbuf = newmbuf; - - tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size); - tmpbuf.buf[0].mem = mbuf + write_header_size; - - res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); - err = -res; - if (res < 0) - goto reply_err; - - in = mbuf; - } - - inarg = (void *) &in[1]; - if (in->opcode == FUSE_WRITE && f->op.write_buf) - do_write_buf(req, in->nodeid, inarg, buf); - else if (in->opcode == FUSE_NOTIFY_REPLY) - do_notify_reply(req, in->nodeid, inarg, buf); - else - fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); - -out_free: - free(mbuf); - return; - -reply_err: - fuse_reply_err(req, err); -clear_pipe: - if (buf->flags & FUSE_BUF_IS_FD) - fuse_ll_clear_pipe(f); - goto out_free; -} - -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); +static +const +char* +opname(enum fuse_opcode opcode) +{ + if(opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) + return "???"; + else + return fuse_ll_ops[opcode].name; +} + +static +int +fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, + struct fuse_bufvec *src) +{ + int res = fuse_buf_copy(dst,src,0); + + if(res < 0) + { + fprintf(stderr, "fuse: copy from pipe: %s\n", strerror(-res)); + return res; + } + + if(res < fuse_buf_size(dst)) + { + fprintf(stderr, "fuse: copy from pipe: short read\n"); + return -1; + } + + return 0; +} + +void +fuse_ll_process_buf(void *data, + const struct fuse_buf *buf, + fuse_chan_t *ch) +{ + struct fuse_ll *f = (struct fuse_ll *) data; + const size_t write_header_size = sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in); + struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 }; + struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size); + struct fuse_in_header *in; + const void *inarg; + struct fuse_req *req; + void *mbuf = NULL; + int err; + int res; + + if(buf->flags & FUSE_BUF_IS_FD) { + if(buf->size < tmpbuf.buf[0].size) + tmpbuf.buf[0].size = buf->size; + + mbuf = malloc(tmpbuf.buf[0].size); + if(mbuf == NULL) { + fprintf(stderr, "fuse: failed to allocate header\n"); + goto clear_pipe; + } + tmpbuf.buf[0].mem = mbuf; + + res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); + if(res < 0) + goto clear_pipe; + + in = mbuf; + } else { + in = buf->mem; + } + + if(f->debug) { + fprintf(stderr, + "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu, pid: %u\n", + (unsigned long long) in->unique, + opname((enum fuse_opcode) in->opcode), in->opcode, + (unsigned long) in->nodeid, buf->size, in->pid); + } + + req = fuse_ll_alloc_req(f); + if(req == NULL) { + struct fuse_out_header out = { + .unique = in->unique, + .error = -ENOMEM, + }; + struct iovec iov = { + .iov_base = &out, + .iov_len = sizeof(struct fuse_out_header), + }; + + fuse_send_msg(f, ch, &iov, 1); + goto clear_pipe; + } + + req->unique = in->unique; + req->ctx.uid = in->uid; + req->ctx.gid = in->gid; + req->ctx.pid = in->pid; + req->ch = ch; + + err = EIO; + if(!f->got_init) + { + if(in->opcode != FUSE_INIT) + goto reply_err; + } + else if(in->opcode == FUSE_INIT) + { + goto reply_err; + } + + err = EACCES; + if(f->allow_root && in->uid != f->owner && in->uid != 0 && + in->opcode != FUSE_INIT && in->opcode != FUSE_READ && + in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && + in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && + in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR && + in->opcode != FUSE_NOTIFY_REPLY) + goto reply_err; + + err = ENOSYS; + if(in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) + goto reply_err; + if(in->opcode != FUSE_INTERRUPT) { + struct fuse_req *intr; + pthread_mutex_lock(&f->lock); + intr = check_interrupt(f, req); + list_add_req(req, &f->list); + pthread_mutex_unlock(&f->lock); + if(intr) + fuse_reply_err(intr, EAGAIN); + } + + if((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size && + (in->opcode != FUSE_WRITE || !f->op.write_buf) && + in->opcode != FUSE_NOTIFY_REPLY) { + void *newmbuf; + + err = ENOMEM; + newmbuf = realloc(mbuf, buf->size); + if(newmbuf == NULL) + goto reply_err; + mbuf = newmbuf; + + tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size); + tmpbuf.buf[0].mem = mbuf + write_header_size; + + res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); + err = -res; + if(res < 0) + goto reply_err; + + in = mbuf; + } + + inarg = (void *) &in[1]; + if(in->opcode == FUSE_WRITE && f->op.write_buf) + do_write_buf(req, in->nodeid, inarg, buf); + else if(in->opcode == FUSE_NOTIFY_REPLY) + do_notify_reply(req, in->nodeid, inarg, buf); + else + fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); + + out_free: + free(mbuf); + return; + + reply_err: + fuse_reply_err(req, err); + clear_pipe: + if(buf->flags & FUSE_BUF_IS_FD) + fuse_ll_clear_pipe(f); + goto out_free; } enum { - KEY_HELP, - KEY_VERSION, + KEY_HELP, + KEY_VERSION, }; -static const struct fuse_opt fuse_ll_opts[] = { - { "debug", offsetof(struct fuse_ll, debug), 1 }, - { "-d", offsetof(struct fuse_ll, debug), 1 }, - { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, - { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, - { "max_background=%u", offsetof(struct fuse_ll, conn.max_background), 0 }, - { "congestion_threshold=%u", - offsetof(struct fuse_ll, conn.congestion_threshold), 0 }, - { "no_remote_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, - { "no_remote_lock", offsetof(struct fuse_ll, no_remote_flock), 1}, - { "no_remote_flock", offsetof(struct fuse_ll, no_remote_flock), 1}, - { "no_remote_posix_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, - { "splice_write", offsetof(struct fuse_ll, splice_write), 1}, - { "no_splice_write", offsetof(struct fuse_ll, no_splice_write), 1}, - { "splice_move", offsetof(struct fuse_ll, splice_move), 1}, - { "no_splice_move", offsetof(struct fuse_ll, no_splice_move), 1}, - { "splice_read", offsetof(struct fuse_ll, splice_read), 1}, - { "no_splice_read", offsetof(struct fuse_ll, no_splice_read), 1}, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END -}; +static const struct fuse_opt fuse_ll_opts[] = + { + { "debug", offsetof(struct fuse_ll, debug), 1 }, + { "-d", offsetof(struct fuse_ll, debug), 1 }, + { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, + { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, + { "max_background=%u", offsetof(struct fuse_ll, conn.max_background), 0 }, + { "congestion_threshold=%u", + offsetof(struct fuse_ll, conn.congestion_threshold), 0 }, + { "no_remote_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, + { "no_remote_lock", offsetof(struct fuse_ll, no_remote_flock), 1}, + { "no_remote_flock", offsetof(struct fuse_ll, no_remote_flock), 1}, + { "no_remote_posix_lock", offsetof(struct fuse_ll, no_remote_posix_lock), 1}, + { "splice_write", offsetof(struct fuse_ll, splice_write), 1}, + { "no_splice_write", offsetof(struct fuse_ll, no_splice_write), 1}, + { "splice_move", offsetof(struct fuse_ll, splice_move), 1}, + { "no_splice_move", offsetof(struct fuse_ll, no_splice_move), 1}, + { "splice_read", offsetof(struct fuse_ll, splice_read), 1}, + { "no_splice_read", offsetof(struct fuse_ll, no_splice_read), 1}, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END + }; -static void fuse_ll_version(void) +static +void +fuse_ll_version(void) { - fprintf(stderr, "using FUSE kernel interface version %i.%i\n", - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); + fprintf(stderr, "using FUSE kernel interface version %i.%i\n", + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } -static void fuse_ll_help(void) +static +void +fuse_ll_help(void) { - fprintf(stderr, -" -o max_readahead=N set maximum readahead\n" -" -o max_background=N set number of maximum background requests\n" -" -o congestion_threshold=N set kernel's congestion threshold\n" -" -o no_remote_lock disable remote file locking\n" -" -o no_remote_flock disable remote file locking (BSD)\n" -" -o no_remote_posix_lock disable remove file locking (POSIX)\n" -" -o [no_]splice_write use splice to write to the fuse device\n" -" -o [no_]splice_move move data while splicing to the fuse device\n" -" -o [no_]splice_read use splice to read from the fuse device\n" -); + fprintf(stderr, + " -o max_readahead=N set maximum readahead\n" + " -o max_background=N set number of maximum background requests\n" + " -o congestion_threshold=N set kernel's congestion threshold\n" + " -o no_remote_lock disable remote file locking\n" + " -o no_remote_flock disable remote file locking (BSD)\n" + " -o no_remote_posix_lock disable remove file locking (POSIX)\n" + " -o [no_]splice_write use splice to write to the fuse device\n" + " -o [no_]splice_move move data while splicing to the fuse device\n" + " -o [no_]splice_read use splice to read from the fuse device\n" + ); } static int fuse_ll_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - (void) data; (void) outargs; + (void) data; (void) outargs; - switch (key) { - case KEY_HELP: - fuse_ll_help(); - break; + switch (key) { + case KEY_HELP: + fuse_ll_help(); + break; - case KEY_VERSION: - fuse_ll_version(); - break; + case KEY_VERSION: + fuse_ll_version(); + break; - default: - fprintf(stderr, "fuse: unknown option `%s'\n", arg); - } + default: + fprintf(stderr, "fuse: unknown option `%s'\n", arg); + } - return -1; + return -1; } -int fuse_lowlevel_is_lib_option(const char *opt) +int +fuse_lowlevel_is_lib_option(const char *opt) { - return fuse_opt_match(fuse_ll_opts, opt); + return fuse_opt_match(fuse_ll_opts, opt); } -static void fuse_ll_destroy(void *data) +static +void +fuse_ll_destroy(void *data) { - struct fuse_ll *f = (struct fuse_ll *) data; - struct fuse_ll_pipe *llp; + struct fuse_ll *f = (struct fuse_ll*)data; + struct fuse_ll_pipe *llp; + + if(f->got_init && !f->got_destroy) + { + if(f->op.destroy) + f->op.destroy(f->userdata); + } + + llp = pthread_getspecific(f->pipe_key); + if(llp != NULL) + fuse_ll_pipe_free(llp); - if (f->got_init && !f->got_destroy) { - if (f->op.destroy) - f->op.destroy(f->userdata); - } - llp = pthread_getspecific(f->pipe_key); - if (llp != NULL) - fuse_ll_pipe_free(llp); - pthread_key_delete(f->pipe_key); - pthread_mutex_destroy(&f->lock); - free(f->cuse_data); - free(f); + pthread_key_delete(f->pipe_key); + pthread_mutex_destroy(&f->lock); + + free(f); } static void fuse_ll_pipe_destructor(void *data) { - struct fuse_ll_pipe *llp = data; - fuse_ll_pipe_free(llp); -} - -#ifdef HAVE_SPLICE -static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) -{ - struct fuse_chan *ch = *chp; - struct fuse_ll *f = fuse_session_data(se); - size_t bufsize = buf->size; - struct fuse_ll_pipe *llp; - struct fuse_buf tmpbuf; - int err; - int res; - - if (f->conn.proto_minor < 14 || !(f->conn.want & FUSE_CAP_SPLICE_READ)) - goto fallback; - - llp = fuse_ll_get_pipe(f); - if (llp == NULL) - goto fallback; - - if (llp->size < bufsize) { - if (llp->can_grow) { - res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize); - if (res == -1) { - llp->can_grow = 0; - goto fallback; - } - llp->size = res; - } - if (llp->size < bufsize) - goto fallback; - } - - res = splice(fuse_chan_fd(ch), NULL, llp->pipe[1], NULL, bufsize, 0); - err = errno; - - if (fuse_session_exited(se)) - return 0; - - if (res == -1) { - if (err == ENODEV) { - fuse_session_exit(se); - return 0; - } - if (err != EINTR && err != EAGAIN) - perror("fuse: splice from device"); - return -err; - } - - if (res < sizeof(struct fuse_in_header)) { - fprintf(stderr, "short splice from fuse device\n"); - return -EIO; - } - - tmpbuf = (struct fuse_buf) { - .size = res, - .flags = FUSE_BUF_IS_FD, - .fd = llp->pipe[0], - }; - - /* - * Don't bother with zero copy for small requests. - * fuse_loop_mt() needs to check for FORGET so this more than - * just an optimization. - */ - if (res < sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in) + pagesize) { - struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 }; - struct fuse_bufvec dst = { .buf[0] = *buf, .count = 1 }; - - res = fuse_buf_copy(&dst, &src, 0); - if (res < 0) { - fprintf(stderr, "fuse: copy from pipe: %s\n", - strerror(-res)); - fuse_ll_clear_pipe(f); - return res; - } - if (res < tmpbuf.size) { - fprintf(stderr, "fuse: copy from pipe: short read\n"); - fuse_ll_clear_pipe(f); - return -EIO; - } - buf->size = tmpbuf.size; - return buf->size; - } - - *buf = tmpbuf; - - return res; - -fallback: - res = fuse_chan_recv(chp, buf->mem, bufsize); - if (res <= 0) - return res; - - buf->size = res; - - return res; -} -#else -static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) -{ - (void) se; - - int res = fuse_chan_recv(chp, buf->mem, buf->size); - if (res <= 0) - return res; - - buf->size = res; - - return res; + struct fuse_ll_pipe *llp = data; + fuse_ll_pipe_free(llp); +} + +int +fuse_ll_receive_buf(struct fuse_session *se, + struct fuse_buf *buf, + fuse_chan_t *ch) +{ + (void) se; + + int res = fuse_chan_recv(ch, buf->mem, buf->size); + if(res <= 0) + return res; + + buf->size = res; + + return res; } -#endif /* @@ -2804,66 +2261,62 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata) { - int err; - struct fuse_ll *f; - struct fuse_session *se; - struct fuse_session_ops sop = { - .process = fuse_ll_process, - .destroy = fuse_ll_destroy, - }; - - if (sizeof(struct fuse_lowlevel_ops) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); - op_size = sizeof(struct fuse_lowlevel_ops); - } - - f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out; - } - - f->conn.max_write = UINT_MAX; - f->conn.max_readahead = UINT_MAX; - list_init_req(&f->list); - list_init_req(&f->interrupts); - list_init_nreq(&f->notify_list); - f->notify_ctr = 1; - fuse_mutex_init(&f->lock); - - err = pthread_key_create(&f->pipe_key, fuse_ll_pipe_destructor); - if (err) { - fprintf(stderr, "fuse: failed to create thread specific key: %s\n", - strerror(err)); - goto out_free; - } - - if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) - goto out_key_destroy; - - if (f->debug) - fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); - - memcpy(&f->op, op, op_size); - f->owner = getuid(); - f->userdata = userdata; - - se = fuse_session_new(&sop, f); - if (!se) - goto out_key_destroy; - - se->receive_buf = fuse_ll_receive_buf; - se->process_buf = fuse_ll_process_buf; - - return se; - -out_key_destroy: - pthread_key_delete(f->pipe_key); -out_free: - pthread_mutex_destroy(&f->lock); - free(f); -out: - return NULL; + int err; + struct fuse_ll *f; + struct fuse_session *se; + struct fuse_session_ops sop = { + .destroy = fuse_ll_destroy, + }; + + if(sizeof(struct fuse_lowlevel_ops) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); + op_size = sizeof(struct fuse_lowlevel_ops); + } + + f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); + if(f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out; + } + + f->conn.max_write = UINT_MAX; + f->conn.max_readahead = UINT_MAX; + list_init_req(&f->list); + list_init_req(&f->interrupts); + list_init_nreq(&f->notify_list); + f->notify_ctr = 1; + fuse_mutex_init(&f->lock); + + err = pthread_key_create(&f->pipe_key, fuse_ll_pipe_destructor); + if(err) { + fprintf(stderr, "fuse: failed to create thread specific key: %s\n", + strerror(err)); + goto out_free; + } + + if(fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) + goto out_key_destroy; + + if(f->debug) + fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); + + memcpy(&f->op, op, op_size); + f->owner = getuid(); + f->userdata = userdata; + + se = fuse_session_new(&sop, f); + if(!se) + goto out_key_destroy; + + return se; + + out_key_destroy: + pthread_key_delete(f->pipe_key); + out_free: + pthread_mutex_destroy(&f->lock); + free(f); + out: + return NULL; } @@ -2871,174 +2324,105 @@ 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[]) -{ - char *buf; - size_t bufsize = 1024; - char path[128]; - int ret; - int fd; - unsigned long pid = req->ctx.pid; - char *s; - - sprintf(path, "/proc/%lu/task/%lu/status", pid, pid); - -retry: - buf = malloc(bufsize); - if (buf == NULL) - return -ENOMEM; - - ret = -EIO; - fd = open(path, O_RDONLY); - if (fd == -1) - goto out_free; - - ret = read(fd, buf, bufsize); - close(fd); - if (ret == -1) { - ret = -EIO; - goto out_free; - } - - if (ret == bufsize) { - free(buf); - bufsize *= 4; - goto retry; - } - - ret = -EIO; - s = strstr(buf, "\nGroups:"); - if (s == NULL) - goto out_free; - - s += 8; - ret = 0; - while (1) { - char *end; - unsigned long val = strtoul(s, &end, 0); - if (end == s) - break; - - s = end; - if (ret < size) - list[ret] = val; - ret++; - } - -out_free: - free(buf); - return ret; -} -#else /* linux */ -/* - * This is currently not implemented on other than Linux... - */ -int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) -{ - return -ENOSYS; + return fuse_lowlevel_new_common(args, op, op_size, userdata); } -#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; + arg->fh = f->fh; + if(f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if(f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; } static void convert_statfs_compat(const struct statfs *compatbuf, struct statvfs *buf) { - buf->f_bsize = compatbuf->f_bsize; - buf->f_blocks = compatbuf->f_blocks; - buf->f_bfree = compatbuf->f_bfree; - buf->f_bavail = compatbuf->f_bavail; - buf->f_files = compatbuf->f_files; - buf->f_ffree = compatbuf->f_ffree; - buf->f_namemax = compatbuf->f_namelen; + buf->f_bsize = compatbuf->f_bsize; + buf->f_blocks = compatbuf->f_blocks; + buf->f_bfree = compatbuf->f_bfree; + buf->f_bavail = compatbuf->f_bavail; + buf->f_files = compatbuf->f_files; + buf->f_ffree = compatbuf->f_ffree; + buf->f_namemax = compatbuf->f_namelen; } int fuse_reply_open_compat(fuse_req_t req, const struct fuse_file_info_compat *f) { - struct fuse_open_out arg; + struct fuse_open_out arg; - memset(&arg, 0, sizeof(arg)); - fill_open_compat(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_open_compat(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf) { - struct statvfs newbuf; + struct statvfs newbuf; - memset(&newbuf, 0, sizeof(newbuf)); - convert_statfs_compat(stbuf, &newbuf); + memset(&newbuf, 0, sizeof(newbuf)); + convert_statfs_compat(stbuf, &newbuf); - return fuse_reply_statfs(req, &newbuf); + return fuse_reply_statfs(req, &newbuf); } struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat *op, + size_t op_size, void *userdata) { - struct fuse_session *se; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + struct fuse_session *se; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (opts && - (fuse_opt_add_arg(&args, "") == -1 || - fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, - op_size, userdata); - fuse_opt_free_args(&args); + if(opts && + (fuse_opt_add_arg(&args, "") == -1 || + fuse_opt_add_arg(&args, "-o") == -1 || + fuse_opt_add_arg(&args, opts) == -1)) { + fuse_opt_free_args(&args); + return NULL; + } + se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, + op_size, userdata); + fuse_opt_free_args(&args); - return se; + return se; } struct fuse_ll_compat_conf { - unsigned max_read; - int set_max_read; + unsigned max_read; + int set_max_read; }; static const struct fuse_opt fuse_ll_opts_compat[] = { - { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, - { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END + { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, + { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END }; int fuse_sync_compat_args(struct fuse_args *args) { - struct fuse_ll_compat_conf conf; + struct fuse_ll_compat_conf conf; - memset(&conf, 0, sizeof(conf)); - if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) - return -1; + memset(&conf, 0, sizeof(conf)); + if(fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) + return -1; - if (fuse_opt_insert_arg(args, 1, "-osync_read")) - return -1; + if(fuse_opt_insert_arg(args, 1, "-osync_read")) + return -1; - if (conf.set_max_read) { - char tmpbuf[64]; + if(conf.set_max_read) { + char tmpbuf[64]; - sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); - if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) - return -1; - } - return 0; + sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); + if(fuse_opt_insert_arg(args, 1, tmpbuf) == -1) + return -1; + } + return 0; } FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4"); @@ -3049,22 +2433,22 @@ FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4"); int fuse_sync_compat_args(struct fuse_args *args) { - (void) args; - return 0; + (void) args; + return 0; } #endif /* __FreeBSD__ || __NetBSD__ */ struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata) { - if (fuse_sync_compat_args(args) == -1) - return NULL; + if(fuse_sync_compat_args(args) == -1) + return NULL; - return fuse_lowlevel_new_common(args, - (const struct fuse_lowlevel_ops *) op, - op_size, userdata); + return fuse_lowlevel_new_common(args, + (const struct fuse_lowlevel_ops *) op, + op_size, userdata); } FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5"); diff --git a/libfuse/lib/fuse_mt.c b/libfuse/lib/fuse_mt.c index 6cc30344..ec795b3e 100644 --- a/libfuse/lib/fuse_mt.c +++ b/libfuse/lib/fuse_mt.c @@ -16,109 +16,17 @@ #include #include -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_config_num_threads(f)); - fuse_session_destroy(se); - return res; -} - int fuse_loop_mt(struct fuse *f) { - if (f == NULL) - return -1; + if (f == NULL) + return -1; - int res = fuse_start_cleanup_thread(f); - if (res) - return -1; + int res = fuse_start_cleanup_thread(f); + if (res) + return -1; - res = fuse_session_loop_mt(fuse_get_session(f), - fuse_config_num_threads(f)); - fuse_stop_cleanup_thread(f); - return res; + res = fuse_session_loop_mt(fuse_get_session(f), + fuse_config_num_threads(f)); + fuse_stop_cleanup_thread(f); + return res; } - -FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@"); diff --git a/libfuse/lib/fuse_opt.c b/libfuse/lib/fuse_opt.c index a2118ced..af7abf8d 100644 --- a/libfuse/lib/fuse_opt.c +++ b/libfuse/lib/fuse_opt.c @@ -15,411 +15,411 @@ #include struct fuse_opt_context { - void *data; - const struct fuse_opt *opt; - fuse_opt_proc_t proc; - int argctr; - int argc; - char **argv; - struct fuse_args outargs; - char *opts; - int nonopt; + void *data; + const struct fuse_opt *opt; + fuse_opt_proc_t proc; + int argctr; + int argc; + char **argv; + struct fuse_args outargs; + char *opts; + int nonopt; }; void fuse_opt_free_args(struct fuse_args *args) { - if (args) { - if (args->argv && args->allocated) { - int i; - for (i = 0; i < args->argc; i++) - free(args->argv[i]); - free(args->argv); - } - args->argc = 0; - args->argv = NULL; - args->allocated = 0; - } + if (args) { + if (args->argv && args->allocated) { + int i; + for (i = 0; i < args->argc; i++) + free(args->argv[i]); + free(args->argv); + } + args->argc = 0; + args->argv = NULL; + args->allocated = 0; + } } static int alloc_failed(void) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; } int fuse_opt_add_arg(struct fuse_args *args, const char *arg) { - char **newargv; - char *newarg; - - assert(!args->argv || args->allocated); - - newarg = strdup(arg); - if (!newarg) - return alloc_failed(); - - newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); - if (!newargv) { - free(newarg); - return alloc_failed(); - } - - args->argv = newargv; - args->allocated = 1; - args->argv[args->argc++] = newarg; - args->argv[args->argc] = NULL; - return 0; + char **newargv; + char *newarg; + + assert(!args->argv || args->allocated); + + newarg = strdup(arg); + if (!newarg) + return alloc_failed(); + + newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); + if (!newargv) { + free(newarg); + return alloc_failed(); + } + + args->argv = newargv; + args->allocated = 1; + args->argv[args->argc++] = newarg; + args->argv[args->argc] = NULL; + return 0; } static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos, const char *arg) { - assert(pos <= args->argc); - if (fuse_opt_add_arg(args, arg) == -1) - return -1; - - if (pos != args->argc - 1) { - char *newarg = args->argv[args->argc - 1]; - memmove(&args->argv[pos + 1], &args->argv[pos], - sizeof(char *) * (args->argc - pos - 1)); - args->argv[pos] = newarg; - } - return 0; + assert(pos <= args->argc); + if (fuse_opt_add_arg(args, arg) == -1) + return -1; + + if (pos != args->argc - 1) { + char *newarg = args->argv[args->argc - 1]; + memmove(&args->argv[pos + 1], &args->argv[pos], + sizeof(char *) * (args->argc - pos - 1)); + args->argv[pos] = newarg; + } + return 0; } int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) { - return fuse_opt_insert_arg_common(args, pos, arg); + return fuse_opt_insert_arg_common(args, pos, arg); } int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg); int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg) { - return fuse_opt_insert_arg_common(args, pos, arg); + return fuse_opt_insert_arg_common(args, pos, arg); } static int next_arg(struct fuse_opt_context *ctx, const char *opt) { - if (ctx->argctr + 1 >= ctx->argc) { - fprintf(stderr, "fuse: missing argument after `%s'\n", opt); - return -1; - } - ctx->argctr++; - return 0; + if (ctx->argctr + 1 >= ctx->argc) { + fprintf(stderr, "fuse: missing argument after `%s'\n", opt); + return -1; + } + ctx->argctr++; + return 0; } static int add_arg(struct fuse_opt_context *ctx, const char *arg) { - return fuse_opt_add_arg(&ctx->outargs, arg); + return fuse_opt_add_arg(&ctx->outargs, arg); } static int add_opt_common(char **opts, const char *opt, int esc) { - unsigned oldlen = *opts ? strlen(*opts) : 0; - char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1); - - if (!d) - return alloc_failed(); - - *opts = d; - if (oldlen) { - d += oldlen; - *d++ = ','; - } - - for (; *opt; opt++) { - if (esc && (*opt == ',' || *opt == '\\')) - *d++ = '\\'; - *d++ = *opt; - } - *d = '\0'; - - return 0; + unsigned oldlen = *opts ? strlen(*opts) : 0; + char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1); + + if (!d) + return alloc_failed(); + + *opts = d; + if (oldlen) { + d += oldlen; + *d++ = ','; + } + + for (; *opt; opt++) { + if (esc && (*opt == ',' || *opt == '\\')) + *d++ = '\\'; + *d++ = *opt; + } + *d = '\0'; + + return 0; } int fuse_opt_add_opt(char **opts, const char *opt) { - return add_opt_common(opts, opt, 0); + return add_opt_common(opts, opt, 0); } int fuse_opt_add_opt_escaped(char **opts, const char *opt) { - return add_opt_common(opts, opt, 1); + return add_opt_common(opts, opt, 1); } static int add_opt(struct fuse_opt_context *ctx, const char *opt) { - return add_opt_common(&ctx->opts, opt, 1); + return add_opt_common(&ctx->opts, opt, 1); } static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key, int iso) { - if (key == FUSE_OPT_KEY_DISCARD) - return 0; - - if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { - int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); - if (res == -1 || !res) - return res; - } - if (iso) - return add_opt(ctx, arg); - else - return add_arg(ctx, arg); + if (key == FUSE_OPT_KEY_DISCARD) + return 0; + + if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { + int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); + if (res == -1 || !res) + return res; + } + if (iso) + return add_opt(ctx, arg); + else + return add_arg(ctx, arg); } static int match_template(const char *t, const char *arg, unsigned *sepp) { - int arglen = strlen(arg); - const char *sep = strchr(t, '='); - sep = sep ? sep : strchr(t, ' '); - if (sep && (!sep[1] || sep[1] == '%')) { - int tlen = sep - t; - if (sep[0] == '=') - tlen ++; - if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { - *sepp = sep - t; - return 1; - } - } - if (strcmp(t, arg) == 0) { - *sepp = 0; - return 1; - } - return 0; + int arglen = strlen(arg); + const char *sep = strchr(t, '='); + sep = sep ? sep : strchr(t, ' '); + if (sep && (!sep[1] || sep[1] == '%')) { + int tlen = sep - t; + if (sep[0] == '=') + tlen ++; + if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { + *sepp = sep - t; + return 1; + } + } + if (strcmp(t, arg) == 0) { + *sepp = 0; + return 1; + } + return 0; } static const struct fuse_opt *find_opt(const struct fuse_opt *opt, const char *arg, unsigned *sepp) { - for (; opt && opt->templ; opt++) - if (match_template(opt->templ, arg, sepp)) - return opt; - return NULL; + for (; opt && opt->templ; opt++) + if (match_template(opt->templ, arg, sepp)) + return opt; + return NULL; } int fuse_opt_match(const struct fuse_opt *opts, const char *opt) { - unsigned dummy; - return find_opt(opts, opt, &dummy) ? 1 : 0; + unsigned dummy; + return find_opt(opts, opt, &dummy) ? 1 : 0; } static int process_opt_param(void *var, const char *format, const char *param, const char *arg) { - assert(format[0] == '%'); - if (format[1] == 's') { - char *copy = strdup(param); - if (!copy) - return alloc_failed(); - - *(char **) var = copy; - } else { - if (sscanf(param, format, var) != 1) { - fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); - return -1; - } - } - return 0; + assert(format[0] == '%'); + if (format[1] == 's') { + char *copy = strdup(param); + if (!copy) + return alloc_failed(); + + *(char **) var = copy; + } else { + if (sscanf(param, format, var) != 1) { + fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); + return -1; + } + } + return 0; } static int process_opt(struct fuse_opt_context *ctx, const struct fuse_opt *opt, unsigned sep, const char *arg, int iso) { - if (opt->offset == -1U) { - if (call_proc(ctx, arg, opt->value, iso) == -1) - return -1; - } else { - void *var = ctx->data + opt->offset; - if (sep && opt->templ[sep + 1]) { - const char *param = arg + sep; - if (opt->templ[sep] == '=') - param ++; - if (process_opt_param(var, opt->templ + sep + 1, - param, arg) == -1) - return -1; - } else - *(int *)var = opt->value; - } - return 0; + if (opt->offset == -1U) { + if (call_proc(ctx, arg, opt->value, iso) == -1) + return -1; + } else { + void *var = ctx->data + opt->offset; + if (sep && opt->templ[sep + 1]) { + const char *param = arg + sep; + if (opt->templ[sep] == '=') + param ++; + if (process_opt_param(var, opt->templ + sep + 1, + param, arg) == -1) + return -1; + } else + *(int *)var = opt->value; + } + return 0; } static int process_opt_sep_arg(struct fuse_opt_context *ctx, const struct fuse_opt *opt, unsigned sep, const char *arg, int iso) { - int res; - char *newarg; - char *param; + int res; + char *newarg; + char *param; - if (next_arg(ctx, arg) == -1) - return -1; + if (next_arg(ctx, arg) == -1) + return -1; - param = ctx->argv[ctx->argctr]; - newarg = malloc(sep + strlen(param) + 1); - if (!newarg) - return alloc_failed(); + param = ctx->argv[ctx->argctr]; + newarg = malloc(sep + strlen(param) + 1); + if (!newarg) + return alloc_failed(); - memcpy(newarg, arg, sep); - strcpy(newarg + sep, param); - res = process_opt(ctx, opt, sep, newarg, iso); - free(newarg); + memcpy(newarg, arg, sep); + strcpy(newarg + sep, param); + res = process_opt(ctx, opt, sep, newarg, iso); + free(newarg); - return res; + return res; } static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) { - unsigned sep; - const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); - if (opt) { - for (; opt; opt = find_opt(opt + 1, arg, &sep)) { - int res; - if (sep && opt->templ[sep] == ' ' && !arg[sep]) - res = process_opt_sep_arg(ctx, opt, sep, arg, - iso); - else - res = process_opt(ctx, opt, sep, arg, iso); - if (res == -1) - return -1; - } - return 0; - } else - return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); + unsigned sep; + const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); + if (opt) { + for (; opt; opt = find_opt(opt + 1, arg, &sep)) { + int res; + if (sep && opt->templ[sep] == ' ' && !arg[sep]) + res = process_opt_sep_arg(ctx, opt, sep, arg, + iso); + else + res = process_opt(ctx, opt, sep, arg, iso); + if (res == -1) + return -1; + } + return 0; + } else + return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); } static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) { - char *s = opts; - char *d = s; - int end = 0; - - while (!end) { - if (*s == '\0') - end = 1; - if (*s == ',' || end) { - int res; - - *d = '\0'; - res = process_gopt(ctx, opts, 1); - if (res == -1) - return -1; - d = opts; - } else { - if (s[0] == '\\' && s[1] != '\0') { - s++; - if (s[0] >= '0' && s[0] <= '3' && - s[1] >= '0' && s[1] <= '7' && - s[2] >= '0' && s[2] <= '7') { - *d++ = (s[0] - '0') * 0100 + - (s[1] - '0') * 0010 + - (s[2] - '0'); - s += 2; - } else { - *d++ = *s; - } - } else { - *d++ = *s; - } - } - s++; - } - - return 0; + char *s = opts; + char *d = s; + int end = 0; + + while (!end) { + if (*s == '\0') + end = 1; + if (*s == ',' || end) { + int res; + + *d = '\0'; + res = process_gopt(ctx, opts, 1); + if (res == -1) + return -1; + d = opts; + } else { + if (s[0] == '\\' && s[1] != '\0') { + s++; + if (s[0] >= '0' && s[0] <= '3' && + s[1] >= '0' && s[1] <= '7' && + s[2] >= '0' && s[2] <= '7') { + *d++ = (s[0] - '0') * 0100 + + (s[1] - '0') * 0010 + + (s[2] - '0'); + s += 2; + } else { + *d++ = *s; + } + } else { + *d++ = *s; + } + } + s++; + } + + return 0; } static int process_option_group(struct fuse_opt_context *ctx, const char *opts) { - int res; - char *copy = strdup(opts); - - if (!copy) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - res = process_real_option_group(ctx, copy); - free(copy); - return res; + int res; + char *copy = strdup(opts); + + if (!copy) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + res = process_real_option_group(ctx, copy); + free(copy); + return res; } static int process_one(struct fuse_opt_context *ctx, const char *arg) { - if (ctx->nonopt || arg[0] != '-') - return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); - else if (arg[1] == 'o') { - if (arg[2]) - return process_option_group(ctx, arg + 2); - else { - if (next_arg(ctx, arg) == -1) - return -1; - - return process_option_group(ctx, - ctx->argv[ctx->argctr]); - } - } else if (arg[1] == '-' && !arg[2]) { - if (add_arg(ctx, arg) == -1) - return -1; - ctx->nonopt = ctx->outargs.argc; - return 0; - } else - return process_gopt(ctx, arg, 0); + if (ctx->nonopt || arg[0] != '-') + return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); + else if (arg[1] == 'o') { + if (arg[2]) + return process_option_group(ctx, arg + 2); + else { + if (next_arg(ctx, arg) == -1) + return -1; + + return process_option_group(ctx, + ctx->argv[ctx->argctr]); + } + } else if (arg[1] == '-' && !arg[2]) { + if (add_arg(ctx, arg) == -1) + return -1; + ctx->nonopt = ctx->outargs.argc; + return 0; + } else + return process_gopt(ctx, arg, 0); } static int opt_parse(struct fuse_opt_context *ctx) { - if (ctx->argc) { - if (add_arg(ctx, ctx->argv[0]) == -1) - return -1; - } - - for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) - if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) - return -1; - - if (ctx->opts) { - if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || - fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) - return -1; - } - - /* If option separator ("--") is the last argument, remove it */ - if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc && - strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) { - free(ctx->outargs.argv[ctx->outargs.argc - 1]); - ctx->outargs.argv[--ctx->outargs.argc] = NULL; - } - - return 0; + if (ctx->argc) { + if (add_arg(ctx, ctx->argv[0]) == -1) + return -1; + } + + for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) + if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) + return -1; + + if (ctx->opts) { + if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || + fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) + return -1; + } + + /* If option separator ("--") is the last argument, remove it */ + if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc && + strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) { + free(ctx->outargs.argv[ctx->outargs.argc - 1]); + ctx->outargs.argv[--ctx->outargs.argc] = NULL; + } + + return 0; } int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc) { - int res; - struct fuse_opt_context ctx = { - .data = data, - .opt = opts, - .proc = proc, - }; - - if (!args || !args->argv || !args->argc) - return 0; - - ctx.argc = args->argc; - ctx.argv = args->argv; - - res = opt_parse(&ctx); - if (res != -1) { - struct fuse_args tmp = *args; - *args = ctx.outargs; - ctx.outargs = tmp; - } - free(ctx.opts); - fuse_opt_free_args(&ctx.outargs); - return res; + int res; + struct fuse_opt_context ctx = { + .data = data, + .opt = opts, + .proc = proc, + }; + + if (!args || !args->argv || !args->argc) + return 0; + + ctx.argc = args->argc; + ctx.argv = args->argv; + + res = opt_parse(&ctx); + if (res != -1) { + struct fuse_args tmp = *args; + *args = ctx.outargs; + ctx.outargs = tmp; + } + free(ctx.opts); + fuse_opt_free_args(&ctx.outargs); + return res; } /* This symbol version was mistakenly added to the version script */ diff --git a/libfuse/lib/fuse_session.c b/libfuse/lib/fuse_session.c index 6e110683..504958d0 100644 --- a/libfuse/lib/fuse_session.c +++ b/libfuse/lib/fuse_session.c @@ -6,235 +6,66 @@ See the file COPYING.LIB */ -#include "fuse_i.h" -#include "fuse_misc.h" +#include "fuse_chan.h" #include "fuse_common_compat.h" +#include "fuse_i.h" +#include "fuse_kernel.h" #include "fuse_lowlevel_compat.h" +#include "fuse_misc.h" +#include +#include #include #include #include -#include -#include - -struct fuse_chan { - struct fuse_chan_ops op; - - struct fuse_session *se; - - int fd; - - size_t bufsize; - - void *data; - - int compat; -}; +#include +#include struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) { - struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); - if (se == NULL) { - fprintf(stderr, "fuse: failed to allocate session\n"); - return NULL; - } - - memset(se, 0, sizeof(*se)); - se->op = *op; - se->data = data; - - return se; -} - -void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) -{ - assert(se->ch == NULL); - assert(ch->se == NULL); - se->ch = ch; - ch->se = se; -} - -void fuse_session_remove_chan(struct fuse_chan *ch) -{ - struct fuse_session *se = ch->se; - if (se) { - assert(se->ch == ch); - se->ch = NULL; - ch->se = NULL; - } -} - -struct fuse_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; -} + struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); + if (se == NULL) { + fprintf(stderr, "fuse: failed to allocate session\n"); + 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); -} + memset(se, 0, sizeof(*se)); + se->op = *op; + se->data = data; -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); - } + return se; } -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) -{ - 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; -} - - void fuse_session_destroy(struct fuse_session *se) { - if (se->op.destroy) - se->op.destroy(se->data); - if (se->ch != NULL) - fuse_chan_destroy(se->ch); - free(se); + if (se->op.destroy) + se->op.destroy(se->data); + free(se); } void fuse_session_exit(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 1); - se->exited = 1; + if (se->op.exit) + se->op.exit(se->data, 1); + se->exited = 1; } void fuse_session_reset(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 0); - se->exited = 0; + if (se->op.exit) + se->op.exit(se->data, 0); + se->exited = 0; } int fuse_session_exited(struct fuse_session *se) { - if (se->op.exited) - return se->op.exited(se->data); - else - return se->exited; + if (se->op.exited) + return se->op.exited(se->data); + else + return se->exited; } void *fuse_session_data(struct fuse_session *se) { - return se->data; + return se->data; } - -static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data, - int compat) -{ - struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); - if (ch == NULL) { - fprintf(stderr, "fuse: failed to allocate channel\n"); - return NULL; - } - - 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); - free(ch); -} - -#ifndef __FreeBSD__ -FUSE_SYMVER(".symver fuse_chan_new_compat24,fuse_chan_new@FUSE_2.4"); -#endif diff --git a/libfuse/lib/fuse_signals.c b/libfuse/lib/fuse_signals.c index 353cb24b..edb183fd 100644 --- a/libfuse/lib/fuse_signals.c +++ b/libfuse/lib/fuse_signals.c @@ -16,57 +16,57 @@ static struct fuse_session *fuse_instance; static void exit_handler(int sig) { - (void) sig; - if (fuse_instance) - fuse_session_exit(fuse_instance); + (void) sig; + if (fuse_instance) + fuse_session_exit(fuse_instance); } static int set_one_signal_handler(int sig, void (*handler)(int), int remove) { - struct sigaction sa; - struct sigaction old_sa; + struct sigaction sa; + struct sigaction old_sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = remove ? SIG_DFL : handler; - sigemptyset(&(sa.sa_mask)); - sa.sa_flags = 0; + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = remove ? SIG_DFL : handler; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; - if (sigaction(sig, NULL, &old_sa) == -1) { - perror("fuse: cannot get old signal handler"); - return -1; - } + if (sigaction(sig, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } - if (old_sa.sa_handler == (remove ? handler : SIG_DFL) && - sigaction(sig, &sa, NULL) == -1) { - perror("fuse: cannot set signal handler"); - return -1; - } - return 0; + if (old_sa.sa_handler == (remove ? handler : SIG_DFL) && + sigaction(sig, &sa, NULL) == -1) { + perror("fuse: cannot set signal handler"); + return -1; + } + return 0; } int fuse_set_signal_handlers(struct fuse_session *se) { - if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 || - set_one_signal_handler(SIGINT, exit_handler, 0) == -1 || - set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 || - set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1) - return -1; + if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 || + set_one_signal_handler(SIGINT, exit_handler, 0) == -1 || + set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 || + set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1) + return -1; - fuse_instance = se; - return 0; + fuse_instance = se; + return 0; } void fuse_remove_signal_handlers(struct fuse_session *se) { - if (fuse_instance != se) - fprintf(stderr, - "fuse: fuse_remove_signal_handlers: unknown session\n"); - else - fuse_instance = NULL; + if (fuse_instance != se) + fprintf(stderr, + "fuse: fuse_remove_signal_handlers: unknown session\n"); + else + fuse_instance = NULL; - set_one_signal_handler(SIGHUP, exit_handler, 1); - set_one_signal_handler(SIGINT, exit_handler, 1); - set_one_signal_handler(SIGTERM, exit_handler, 1); - set_one_signal_handler(SIGPIPE, SIG_IGN, 1); + set_one_signal_handler(SIGHUP, exit_handler, 1); + set_one_signal_handler(SIGINT, exit_handler, 1); + set_one_signal_handler(SIGTERM, exit_handler, 1); + set_one_signal_handler(SIGPIPE, SIG_IGN, 1); } diff --git a/libfuse/lib/fuse_versionscript b/libfuse/lib/fuse_versionscript deleted file mode 100644 index 8d91887d..00000000 --- a/libfuse/lib/fuse_versionscript +++ /dev/null @@ -1,207 +0,0 @@ -FUSE_2.2 { - global: - fuse_destroy; - fuse_exit; - fuse_exited; - fuse_invalidate; - fuse_is_lib_option; - fuse_loop; - fuse_loop_mt; - fuse_loop_mt_proc; - fuse_main; - fuse_main_compat1; - fuse_main_compat2; - fuse_mount_compat1; - fuse_new_compat1; - fuse_new_compat2; - fuse_process_cmd; - fuse_read_cmd; - fuse_set_getcontext_func; - fuse_setup_compat2; -}; - -FUSE_2.4 { - global: - fuse_add_dirent; - fuse_chan_bufsize; - fuse_chan_data; - fuse_chan_destroy; - fuse_chan_fd; - fuse_chan_receive; - fuse_chan_send; - fuse_chan_session; - fuse_dirent_size; - fuse_kern_chan_new; - fuse_lowlevel_is_lib_option; - fuse_reply_attr; - fuse_reply_buf; - fuse_reply_entry; - fuse_reply_err; - fuse_reply_none; - fuse_reply_readlink; - fuse_reply_write; - fuse_reply_xattr; - fuse_req_userdata; - fuse_session_add_chan; - fuse_session_destroy; - fuse_session_exit; - fuse_session_exited; - fuse_session_loop; - fuse_session_loop_mt; - fuse_session_new; - fuse_session_next_chan; - fuse_session_process; - fuse_session_reset; -} FUSE_2.2; - -FUSE_2.5 { - global: - fuse_lowlevel_new_compat; - fuse_main_real_compat22; - fuse_mount_compat22; - fuse_new_compat22; - fuse_opt_parse; - fuse_opt_add_opt; - fuse_opt_add_arg; - fuse_opt_free_args; - fuse_opt_match; - fuse_parse_cmdline; - fuse_remove_signal_handlers; - fuse_reply_create; - fuse_reply_open; - fuse_reply_open_compat; - fuse_reply_statfs; - fuse_reply_statfs_compat; - fuse_setup_compat22; - fuse_set_signal_handlers; -} FUSE_2.4; - -FUSE_2.6 { - global: - fuse_add_direntry; - fuse_chan_new; - fuse_chan_new_compat24; - fuse_chan_recv; - fuse_daemonize; - fuse_get_session; - fuse_interrupted; - fuse_lowlevel_new; - fuse_lowlevel_new_compat25; - fuse_main_real; - fuse_main_real_compat25; - fuse_mount; - fuse_mount_compat25; - fuse_new; - fuse_new_compat25; - fuse_opt_insert_arg; - fuse_reply_lock; - fuse_req_interrupt_func; - fuse_req_interrupted; - fuse_session_remove_chan; - fuse_setup; - fuse_setup_compat25; - fuse_teardown; - fuse_teardown_compat22; - fuse_unmount; - fuse_unmount_compat22; -} FUSE_2.5; - -FUSE_2.7 { - global: - fuse_fs_access; - fuse_fs_bmap; - fuse_fs_chmod; - fuse_fs_chown; - fuse_fs_create; - fuse_fs_destroy; - fuse_fs_fgetattr; - fuse_fs_flush; - fuse_fs_fsync; - fuse_fs_fsyncdir; - fuse_fs_ftruncate; - fuse_fs_getattr; - fuse_fs_getxattr; - fuse_fs_init; - fuse_fs_link; - fuse_fs_listxattr; - fuse_fs_lock; - fuse_fs_mkdir; - fuse_fs_mknod; - fuse_fs_new; - fuse_fs_open; - fuse_fs_opendir; - fuse_fs_read; - fuse_fs_readdir; - fuse_fs_readlink; - fuse_fs_release; - fuse_fs_releasedir; - fuse_fs_removexattr; - fuse_fs_rename; - fuse_fs_rmdir; - fuse_fs_setxattr; - fuse_fs_statfs; - fuse_fs_symlink; - fuse_fs_truncate; - fuse_fs_unlink; - fuse_fs_utimens; - fuse_fs_write; - fuse_register_module; - fuse_reply_iov; - fuse_version; -} FUSE_2.6; - -FUSE_2.7.5 { - global: - fuse_reply_bmap; -} FUSE_2.7; - -FUSE_2.8 { - global: - cuse_lowlevel_new; - cuse_lowlevel_main; - cuse_lowlevel_setup; - cuse_lowlevel_teardown; - fuse_fs_ioctl; - fuse_fs_poll; - fuse_get_context; - fuse_getgroups; - fuse_lowlevel_notify_inval_entry; - fuse_lowlevel_notify_inval_inode; - fuse_lowlevel_notify_poll; - fuse_notify_poll; - fuse_opt_add_opt_escaped; - fuse_pollhandle_destroy; - fuse_reply_ioctl; - fuse_reply_ioctl_iov; - fuse_reply_ioctl_retry; - fuse_reply_poll; - fuse_req_ctx; - fuse_req_getgroups; - fuse_session_data; -} FUSE_2.7.5; - -FUSE_2.9 { - global: - fuse_buf_copy; - fuse_buf_size; - fuse_fs_read_buf; - fuse_fs_write_buf; - fuse_lowlevel_notify_retrieve; - fuse_lowlevel_notify_store; - fuse_reply_data; - fuse_session_process_buf; - fuse_session_receive_buf; - fuse_start_cleanup_thread; - fuse_stop_cleanup_thread; - fuse_clean_cache; - fuse_lowlevel_notify_delete; - fuse_fs_flock; -} FUSE_2.8; - -FUSE_2.9.1 { - global: - fuse_fs_fallocate; - - local: - *; -} FUSE_2.9; diff --git a/libfuse/lib/helper.c b/libfuse/lib/helper.c index 75bb291b..9bf1b3ca 100644 --- a/libfuse/lib/helper.c +++ b/libfuse/lib/helper.c @@ -7,11 +7,11 @@ */ #include "config.h" +#include "fuse_chan.h" #include "fuse_i.h" +#include "fuse_lowlevel.h" #include "fuse_misc.h" #include "fuse_opt.h" -#include "fuse_lowlevel.h" -#include "fuse_common_compat.h" #include #include @@ -23,9 +23,9 @@ #include enum { - KEY_HELP, - KEY_HELP_NOHEADER, - KEY_VERSION, + KEY_HELP, + KEY_HELP_NOHEADER, + KEY_VERSION, }; struct helper_opts @@ -42,115 +42,113 @@ static const struct fuse_opt fuse_helper_opts[] = { - FUSE_HELPER_OPT("-d", foreground), - FUSE_HELPER_OPT("debug", foreground), - FUSE_HELPER_OPT("-f", foreground), - FUSE_HELPER_OPT("-s", singlethread), - FUSE_HELPER_OPT("fsname=", nodefault_subtype), - FUSE_HELPER_OPT("subtype=", nodefault_subtype), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END -}; + FUSE_HELPER_OPT("-d", foreground), + FUSE_HELPER_OPT("debug", foreground), + FUSE_HELPER_OPT("-f", foreground), + FUSE_HELPER_OPT("-s", singlethread), + FUSE_HELPER_OPT("fsname=", nodefault_subtype), + FUSE_HELPER_OPT("subtype=", nodefault_subtype), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END + }; static void usage(const char *progname) { - fprintf(stderr, - "usage: %s mountpoint [options]\n\n", progname); - fprintf(stderr, - "general options:\n" - " -o opt,[opt...] mount options\n" - " -h --help print help\n" - " -V --version print version\n" - "\n"); + fprintf(stderr, + "usage: %s mountpoint [options]\n\n", progname); + fprintf(stderr, + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + " -V --version print version\n" + "\n"); } static void helper_help(void) { - fprintf(stderr, - "FUSE options:\n" - " -d -o debug enable debug output (implies -f)\n" - " -f foreground operation\n" - " -s disable multi-threaded operation\n" - "\n" - ); + fprintf(stderr, + "FUSE options:\n" + " -d -o debug enable debug output (implies -f)\n" + " -f foreground operation\n" + "\n" + ); } static void helper_version(void) { - fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); + fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); } static int fuse_helper_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - struct helper_opts *hopts = data; - - switch (key) { - case KEY_HELP: - usage(outargs->argv[0]); - /* fall through */ - - case KEY_HELP_NOHEADER: - helper_help(); - return fuse_opt_add_arg(outargs, "-h"); - - case KEY_VERSION: - helper_version(); - return 1; - - case FUSE_OPT_KEY_NONOPT: - if (!hopts->mountpoint) { - char mountpoint[PATH_MAX]; - if (realpath(arg, mountpoint) == NULL) { - fprintf(stderr, - "fuse: bad mount point `%s': %s\n", - arg, strerror(errno)); - return -1; - } - return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); - } else { - fprintf(stderr, "fuse: invalid argument `%s'\n", arg); - return -1; - } - - default: - return 1; - } + struct helper_opts *hopts = data; + + switch (key) { + case KEY_HELP: + usage(outargs->argv[0]); + /* fall through */ + + case KEY_HELP_NOHEADER: + helper_help(); + return fuse_opt_add_arg(outargs, "-h"); + + case KEY_VERSION: + helper_version(); + return 1; + + case FUSE_OPT_KEY_NONOPT: + if (!hopts->mountpoint) { + char mountpoint[PATH_MAX]; + if (realpath(arg, mountpoint) == NULL) { + fprintf(stderr, + "fuse: bad mount point `%s': %s\n", + arg, strerror(errno)); + return -1; + } + return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); + } else { + fprintf(stderr, "fuse: invalid argument `%s'\n", arg); + return -1; + } + + default: + return 1; + } } static int add_default_subtype(const char *progname, struct fuse_args *args) { - int res; - char *subtype_opt; - const char *basename = strrchr(progname, '/'); - if (basename == NULL) - basename = progname; - else if (basename[1] != '\0') - basename++; - - subtype_opt = (char *) malloc(strlen(basename) + 64); - if (subtype_opt == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - sprintf(subtype_opt, "-osubtype=%s", basename); - res = fuse_opt_add_arg(args, subtype_opt); - free(subtype_opt); - return res; + int res; + char *subtype_opt; + const char *basename = strrchr(progname, '/'); + if (basename == NULL) + basename = progname; + else if (basename[1] != '\0') + basename++; + + subtype_opt = (char *) malloc(strlen(basename) + 64); + if (subtype_opt == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + sprintf(subtype_opt, "-osubtype=%s", basename); + res = fuse_opt_add_arg(args, subtype_opt); + free(subtype_opt); + return res; } int fuse_parse_cmdline(struct fuse_args *args_, char **mountpoint_, - int *multithreaded_, int *foreground_) { int res; @@ -177,8 +175,6 @@ fuse_parse_cmdline(struct fuse_args *args_, else free(hopts.mountpoint); - if(multithreaded_) - *multithreaded_ = !hopts.singlethread; if(foreground_) *foreground_ = hopts.foreground; @@ -191,62 +187,61 @@ fuse_parse_cmdline(struct fuse_args *args_, int fuse_daemonize(int foreground) { - if (!foreground) { - int nullfd; - int waiter[2]; - char completed; - - if (pipe(waiter)) { - perror("fuse_daemonize: pipe"); - return -1; - } - - /* - * demonize current process by forking it and killing the - * parent. This makes current process as a child of 'init'. - */ - switch(fork()) { - case -1: - perror("fuse_daemonize: fork"); - return -1; - case 0: - break; - default: - read(waiter[0], &completed, sizeof(completed)); - _exit(0); - } - - if (setsid() == -1) { - perror("fuse_daemonize: setsid"); - return -1; - } - - (void) chdir("/"); - - nullfd = open("/dev/null", O_RDWR, 0); - if (nullfd != -1) { - (void) dup2(nullfd, 0); - (void) dup2(nullfd, 1); - (void) dup2(nullfd, 2); - if (nullfd > 2) - close(nullfd); - } - - /* Propagate completion of daemon initializatation */ - completed = 1; - write(waiter[1], &completed, sizeof(completed)); - close(waiter[0]); - close(waiter[1]); - } - return 0; + if (!foreground) { + int nullfd; + int waiter[2]; + char completed; + + if (pipe(waiter)) { + perror("fuse_daemonize: pipe"); + return -1; + } + + /* + * demonize current process by forking it and killing the + * parent. This makes current process as a child of 'init'. + */ + switch(fork()) { + case -1: + perror("fuse_daemonize: fork"); + return -1; + case 0: + break; + default: + read(waiter[0], &completed, sizeof(completed)); + _exit(0); + } + + if (setsid() == -1) { + perror("fuse_daemonize: setsid"); + return -1; + } + + (void) chdir("/"); + + nullfd = open("/dev/null", O_RDWR, 0); + if (nullfd != -1) { + (void) dup2(nullfd, 0); + (void) dup2(nullfd, 1); + (void) dup2(nullfd, 2); + if (nullfd > 2) + close(nullfd); + } + + /* Propagate completion of daemon initializatation */ + completed = 1; + write(waiter[1], &completed, sizeof(completed)); + close(waiter[0]); + close(waiter[1]); + } + return 0; } static -struct fuse_chan * +int fuse_mount_common(const char *mountpoint_, struct fuse_args *args_) { - struct fuse_chan *ch; int fd; /* @@ -260,252 +255,143 @@ 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); - if(!ch) - fuse_kern_unmount(mountpoint_, fd); + return -1; - return ch; + return fd; } -struct fuse_chan * +int 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) -{ - if (mountpoint) { - int fd = ch ? fuse_chan_clearfd(ch) : -1; - fuse_kern_unmount(mountpoint, fd); - if (ch) - fuse_chan_destroy(ch); - } -} - -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) -{ - fuse_unmount_common(mountpoint, ch); -} - -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) -{ - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; - struct fuse *fuse; - int foreground; - int res; - - res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); - if (res == -1) - return NULL; - - ch = fuse_mount_common(*mountpoint, &args); - if (!ch) { - fuse_opt_free_args(&args); - goto err_free; - } - - fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); - fuse_opt_free_args(&args); - if (fuse == NULL) - goto err_unmount; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_unmount; - - res = fuse_set_signal_handlers(fuse_get_session(fuse)); - if (res == -1) - goto err_unmount; - - if (fd) - *fd = fuse_chan_fd(ch); - - return fuse; - -err_unmount: - fuse_unmount_common(*mountpoint, ch); - if (fuse) - fuse_destroy(fuse); -err_free: - free(*mountpoint); - return NULL; -} - -struct fuse *fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - char **mountpoint, int *multithreaded, void *user_data) -{ - return fuse_setup_common(argc, argv, op, op_size, mountpoint, - multithreaded, NULL, user_data, 0); -} - -static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) +void +fuse_unmount(const char *mountpoint, + int devfuse_fd) { - struct fuse_session *se = fuse_get_session(fuse); - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - fuse_remove_signal_handlers(se); - fuse_unmount_common(mountpoint, ch); - fuse_destroy(fuse); - free(mountpoint); + if(mountpoint == NULL) + return; + fuse_kern_unmount(mountpoint,devfuse_fd); } -void fuse_teardown(struct fuse *fuse, char *mountpoint) +struct fuse * +fuse_setup_common(int argc, + char *argv[], + const struct fuse_operations *op, + size_t op_size, + char **mountpoint, + void *user_data) { - fuse_teardown_common(fuse, mountpoint); -} + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + int res; + int foreground; + int devfuse_fd; + struct fuse *fuse; -static int fuse_main_common(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - void *user_data, int compat) -{ - struct fuse *fuse; - char *mountpoint; - int multithreaded; - int res; - - fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, - &multithreaded, NULL, user_data, compat); - if (fuse == NULL) - return 1; - - if (multithreaded) - res = fuse_loop_mt(fuse); - else - res = fuse_loop(fuse); - - fuse_teardown_common(fuse, mountpoint); - if (res == -1) - return 1; - - return 0; -} + res = fuse_parse_cmdline(&args, mountpoint, &foreground); + if (res == -1) + return NULL; -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); -} + devfuse_fd = fuse_mount_common(*mountpoint, &args); + if(devfuse_fd == -1) + { + fuse_opt_free_args(&args); + goto err_free; + } -#undef fuse_main -int fuse_main(void); -int fuse_main(void) -{ - fprintf(stderr, "fuse_main(): This function does not exist\n"); - return -1; -} + fuse = fuse_new_common(devfuse_fd, &args, op, op_size, user_data); + fuse_opt_free_args(&args); + if (fuse == NULL) + goto err_unmount; -int fuse_version(void) -{ - return FUSE_VERSION; -} + res = fuse_daemonize(foreground); + if (res == -1) + goto err_unmount; -#include "fuse_compat.h" + res = fuse_set_signal_handlers(fuse_get_session(fuse)); + if (res == -1) + goto err_unmount; -#if !defined(__FreeBSD__) && !defined(__NetBSD__) + return fuse; -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); + err_unmount: + fuse_kern_unmount(*mountpoint,devfuse_fd); + if(fuse) + fuse_destroy(fuse); + err_free: + free(*mountpoint); + return NULL; } -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) +struct fuse *fuse_setup(int argc, char *argv[], + const struct fuse_operations *op, size_t op_size, + char **mountpoint, void *user_data) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - op_size, NULL, 22); + return fuse_setup_common(argc, argv, op, op_size, mountpoint, user_data); } -void fuse_main_compat1(int argc, char *argv[], - const struct fuse_operations_compat1 *op) +static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) { - fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), NULL, 11); + struct fuse_session *se = fuse_get_session(fuse); + fuse_remove_signal_handlers(se); + fuse_kern_unmount(mountpoint,se->devfuse_fd); + fuse_destroy(fuse); + free(mountpoint); } -int fuse_main_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op) +void +fuse_teardown(struct fuse *fuse, + char *mountpoint) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), NULL, - 21); + fuse_teardown_common(fuse,mountpoint); } -int fuse_mount_compat1(const char *mountpoint, const char *args[]) +static +int +fuse_main_common(int argc, char *argv[], + const struct fuse_operations *op, size_t op_size, + void *user_data) { - /* just ignore mount args for now */ - (void) args; - return fuse_mount_compat22(mountpoint, NULL); -} + struct fuse *fuse; + char *mountpoint; + int res; -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"); + fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, + user_data); + if(fuse == NULL) + return 1; -#endif /* __FreeBSD__ || __NetBSD__ */ + res = fuse_loop_mt(fuse); + fuse_teardown_common(fuse,mountpoint); + if (res == -1) + return 1; -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); + return 0; } -int fuse_main_real_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size) +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, (struct fuse_operations *) op, - op_size, NULL, 25); + return fuse_main_common(argc, argv, op, op_size, user_data); } -void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint) +int +fuse_main(int argc, + char *argv[], + const struct fuse_operations *op, + void *user_data) { - (void) fd; - fuse_teardown_common(fuse, mountpoint); + return fuse_main_real(argc, argv, op, sizeof(*(op)), user_data); } -int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args) +int fuse_version(void) { - return fuse_kern_mount(mountpoint, args); + return FUSE_VERSION; } - -FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5"); -FUSE_SYMVER(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2"); -FUSE_SYMVER(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5"); -FUSE_SYMVER(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5"); diff --git a/libfuse/lib/mount_bsd.c b/libfuse/lib/mount_bsd.c index 3aec3e3e..23747bc4 100644 --- a/libfuse/lib/mount_bsd.c +++ b/libfuse/lib/mount_bsd.c @@ -28,364 +28,364 @@ #define FUSE_DEV_TRUNK "/dev/fuse" enum { - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, - KEY_KERN + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, + KEY_KERN }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + char *kernel_opts; }; #define FUSE_DUAL_OPT_KEY(templ, key) \ - FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key) + FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key) static const struct fuse_opt fuse_mount_opts[] = { - { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, - { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - /* standard FreeBSD mount options */ - FUSE_DUAL_OPT_KEY("dev", KEY_KERN), - FUSE_DUAL_OPT_KEY("async", KEY_KERN), - FUSE_DUAL_OPT_KEY("atime", KEY_KERN), - FUSE_DUAL_OPT_KEY("dev", KEY_KERN), - FUSE_DUAL_OPT_KEY("exec", KEY_KERN), - FUSE_DUAL_OPT_KEY("suid", KEY_KERN), - FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN), - FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN), - FUSE_DUAL_OPT_KEY("sync", KEY_KERN), - FUSE_DUAL_OPT_KEY("union", KEY_KERN), - FUSE_DUAL_OPT_KEY("userquota", KEY_KERN), - FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN), - FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN), - FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN), - FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN), - FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN), - FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN), - FUSE_DUAL_OPT_KEY("acls", KEY_KERN), - FUSE_DUAL_OPT_KEY("force", KEY_KERN), - FUSE_DUAL_OPT_KEY("update", KEY_KERN), - FUSE_DUAL_OPT_KEY("ro", KEY_KERN), - FUSE_DUAL_OPT_KEY("rw", KEY_KERN), - FUSE_DUAL_OPT_KEY("auto", KEY_KERN), - /* options supported under both Linux and FBSD */ - FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN), - FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN), - FUSE_OPT_KEY("max_read=", KEY_KERN), - FUSE_OPT_KEY("subtype=", KEY_KERN), - /* FBSD FUSE specific mount options */ - FUSE_DUAL_OPT_KEY("private", KEY_KERN), - FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN), - FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN), - FUSE_OPT_KEY("nosync_unmount", KEY_KERN), - /* stock FBSD mountopt parsing routine lets anything be negated... */ - /* - * Linux specific mount options, but let just the mount util - * handle them - */ - FUSE_OPT_KEY("fsname=", KEY_KERN), - FUSE_OPT_KEY("nonempty", KEY_KERN), - FUSE_OPT_KEY("large_read", KEY_KERN), - FUSE_OPT_END + { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, + { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + /* standard FreeBSD mount options */ + FUSE_DUAL_OPT_KEY("dev", KEY_KERN), + FUSE_DUAL_OPT_KEY("async", KEY_KERN), + FUSE_DUAL_OPT_KEY("atime", KEY_KERN), + FUSE_DUAL_OPT_KEY("dev", KEY_KERN), + FUSE_DUAL_OPT_KEY("exec", KEY_KERN), + FUSE_DUAL_OPT_KEY("suid", KEY_KERN), + FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN), + FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN), + FUSE_DUAL_OPT_KEY("sync", KEY_KERN), + FUSE_DUAL_OPT_KEY("union", KEY_KERN), + FUSE_DUAL_OPT_KEY("userquota", KEY_KERN), + FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN), + FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN), + FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN), + FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN), + FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN), + FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN), + FUSE_DUAL_OPT_KEY("acls", KEY_KERN), + FUSE_DUAL_OPT_KEY("force", KEY_KERN), + FUSE_DUAL_OPT_KEY("update", KEY_KERN), + FUSE_DUAL_OPT_KEY("ro", KEY_KERN), + FUSE_DUAL_OPT_KEY("rw", KEY_KERN), + FUSE_DUAL_OPT_KEY("auto", KEY_KERN), + /* options supported under both Linux and FBSD */ + FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN), + FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN), + FUSE_OPT_KEY("max_read=", KEY_KERN), + FUSE_OPT_KEY("subtype=", KEY_KERN), + /* FBSD FUSE specific mount options */ + FUSE_DUAL_OPT_KEY("private", KEY_KERN), + FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN), + FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN), + FUSE_OPT_KEY("nosync_unmount", KEY_KERN), + /* stock FBSD mountopt parsing routine lets anything be negated... */ + /* + * Linux specific mount options, but let just the mount util + * handle them + */ + FUSE_OPT_KEY("fsname=", KEY_KERN), + FUSE_OPT_KEY("nonempty", KEY_KERN), + FUSE_OPT_KEY("large_read", KEY_KERN), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, - " -o allow_root allow access to root\n" - ); - system(FUSERMOUNT_PROG " --help"); - fputc('\n', stderr); + fprintf(stderr, + " -o allow_root allow access to root\n" + ); + system(FUSERMOUNT_PROG " --help"); + fputc('\n', stderr); } static void mount_version(void) { - system(FUSERMOUNT_PROG " --version"); + system(FUSERMOUNT_PROG " --version"); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - - case KEY_KERN: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + + case KEY_KERN: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } void fuse_unmount_compat22(const char *mountpoint) { - char dev[128]; - char *ssc, *umount_cmd; - FILE *sf; - int rv; - char seekscript[] = - /* error message is annoying in help output */ - "exec 2>/dev/null; " - "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " - "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " - " { if ($3 == %d) print $10; }' | " - "/usr/bin/sort | " - "/usr/bin/uniq | " - "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; - - (void) mountpoint; - - /* - * If we don't know the fd, we have to resort to the scripted - * solution -- iterating over the fd-s is unpractical, as we - * don't know how many of open files we have. (This could be - * looked up in procfs -- however, that's optional on FBSD; or - * read out from the kmem -- however, that's bound to - * privileges (in fact, that's what happens when we call the - * setgid kmem fstat(1) utility). - */ - if (asprintf(&ssc, seekscript, getpid()) == -1) - return; - - errno = 0; - sf = popen(ssc, "r"); - free(ssc); - if (! sf) - return; - - fgets(dev, sizeof(dev), sf); - rv = pclose(sf); - if (rv) - return; - - if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1) - return; - system(umount_cmd); - free(umount_cmd); + char dev[128]; + char *ssc, *umount_cmd; + FILE *sf; + int rv; + char seekscript[] = + /* error message is annoying in help output */ + "exec 2>/dev/null; " + "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " + "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " + " { if ($3 == %d) print $10; }' | " + "/usr/bin/sort | " + "/usr/bin/uniq | " + "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; + + (void) mountpoint; + + /* + * If we don't know the fd, we have to resort to the scripted + * solution -- iterating over the fd-s is unpractical, as we + * don't know how many of open files we have. (This could be + * looked up in procfs -- however, that's optional on FBSD; or + * read out from the kmem -- however, that's bound to + * privileges (in fact, that's what happens when we call the + * setgid kmem fstat(1) utility). + */ + if (asprintf(&ssc, seekscript, getpid()) == -1) + return; + + errno = 0; + sf = popen(ssc, "r"); + free(ssc); + if (! sf) + return; + + fgets(dev, sizeof(dev), sf); + rv = pclose(sf); + if (rv) + return; + + if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1) + return; + system(umount_cmd); + free(umount_cmd); } static void do_unmount(char *dev, int fd) { - char device_path[SPECNAMELEN + 12]; - const char *argv[4]; - const char umount_cmd[] = "/sbin/umount"; - pid_t pid; + char device_path[SPECNAMELEN + 12]; + const char *argv[4]; + const char umount_cmd[] = "/sbin/umount"; + pid_t pid; - snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev); + snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev); - argv[0] = umount_cmd; - argv[1] = "-f"; - argv[2] = device_path; - argv[3] = NULL; + argv[0] = umount_cmd; + argv[1] = "-f"; + argv[2] = device_path; + argv[3] = NULL; - pid = fork(); + pid = fork(); - if (pid == -1) - return; + if (pid == -1) + return; - if (pid == 0) { - close(fd); - execvp(umount_cmd, (char **)argv); - exit(1); - } + if (pid == 0) { + close(fd); + execvp(umount_cmd, (char **)argv); + exit(1); + } - waitpid(pid, NULL, 0); + waitpid(pid, NULL, 0); } void fuse_kern_unmount(const char *mountpoint, int fd) { - char *ep, dev[128]; - struct stat sbuf; + char *ep, dev[128]; + struct stat sbuf; - (void)mountpoint; + (void)mountpoint; - if (fstat(fd, &sbuf) == -1) - goto out; + if (fstat(fd, &sbuf) == -1) + goto out; - devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); + devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); - if (strncmp(dev, "fuse", 4)) - goto out; + if (strncmp(dev, "fuse", 4)) + goto out; - strtol(dev + 4, &ep, 10); - if (*ep != '\0') - goto out; + strtol(dev + 4, &ep, 10); + if (*ep != '\0') + goto out; - do_unmount(dev, fd); + do_unmount(dev, fd); -out: - close(fd); + out: + close(fd); } /* Check if kernel is doing init in background */ static int init_backgrounded(void) { - unsigned ibg, len; + unsigned ibg, len; - len = sizeof(ibg); + len = sizeof(ibg); - if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) - return 0; + if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) + return 0; - return ibg; + return ibg; } static int fuse_mount_core(const char *mountpoint, const char *opts) { - const char *mountprog = FUSERMOUNT_PROG; - int fd; - char *fdnam, *dev; - pid_t pid, cpid; - int status; - - fdnam = getenv("FUSE_DEV_FD"); - - if (fdnam) { - char *ep; - - fd = strtol(fdnam, &ep, 10); - - if (*ep != '\0') { - fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); - return -1; - } - - if (fd < 0) - return -1; - - goto mount; - } - - dev = getenv("FUSE_DEV_NAME"); - - if (! dev) - dev = (char *)FUSE_DEV_TRUNK; - - if ((fd = open(dev, O_RDWR)) < 0) { - perror("fuse: failed to open fuse device"); - return -1; - } - -mount: - if (getenv("FUSE_NO_MOUNT") || ! mountpoint) - goto out; - - pid = fork(); - cpid = pid; - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - return -1; - } - - if (pid == 0) { - if (! init_backgrounded()) { - /* - * If init is not backgrounded, we have to - * call the mount util backgrounded, to avoid - * deadlock. - */ - - pid = fork(); - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - exit(1); - } - } - - if (pid == 0) { - const char *argv[32]; - int a = 0; - - if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) { - perror("fuse: failed to assemble mount arguments"); - exit(1); - } - - argv[a++] = mountprog; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = fdnam; - argv[a++] = mountpoint; - argv[a++] = NULL; - execvp(mountprog, (char **) argv); - perror("fuse: failed to exec mount program"); - exit(1); - } - - exit(0); - } - - if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) { - perror("fuse: failed to mount file system"); - close(fd); - return -1; - } - -out: - return fd; + const char *mountprog = FUSERMOUNT_PROG; + int fd; + char *fdnam, *dev; + pid_t pid, cpid; + int status; + + fdnam = getenv("FUSE_DEV_FD"); + + if (fdnam) { + char *ep; + + fd = strtol(fdnam, &ep, 10); + + if (*ep != '\0') { + fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); + return -1; + } + + if (fd < 0) + return -1; + + goto mount; + } + + dev = getenv("FUSE_DEV_NAME"); + + if (! dev) + dev = (char *)FUSE_DEV_TRUNK; + + if ((fd = open(dev, O_RDWR)) < 0) { + perror("fuse: failed to open fuse device"); + return -1; + } + + mount: + if (getenv("FUSE_NO_MOUNT") || ! mountpoint) + goto out; + + pid = fork(); + cpid = pid; + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + return -1; + } + + if (pid == 0) { + if (! init_backgrounded()) { + /* + * If init is not backgrounded, we have to + * call the mount util backgrounded, to avoid + * deadlock. + */ + + pid = fork(); + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + exit(1); + } + } + + if (pid == 0) { + const char *argv[32]; + int a = 0; + + if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) { + perror("fuse: failed to assemble mount arguments"); + exit(1); + } + + argv[a++] = mountprog; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = fdnam; + argv[a++] = mountpoint; + argv[a++] = NULL; + execvp(mountprog, (char **) argv); + perror("fuse: failed to exec mount program"); + exit(1); + } + + exit(0); + } + + if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) { + perror("fuse: failed to mount file system"); + close(fd); + return -1; + } + + out: + return fd; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - - memset(&mo, 0, sizeof(mo)); - /* mount util should not try to spawn the daemon */ - setenv("MOUNT_FUSEFS_SAFE", "1", 1); - /* to notify the mount util it's called from lib */ - setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - if (mo.ishelp) - return 0; - - res = fuse_mount_core(mountpoint, mo.kernel_opts); -out: - free(mo.kernel_opts); - return res; + struct mount_opts mo; + int res = -1; + + memset(&mo, 0, sizeof(mo)); + /* mount util should not try to spawn the daemon */ + setenv("MOUNT_FUSEFS_SAFE", "1", 1); + /* to notify the mount util it's called from lib */ + setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + if (mo.ishelp) + return 0; + + res = fuse_mount_core(mountpoint, mo.kernel_opts); + out: + free(mo.kernel_opts); + return res; } FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2"); diff --git a/libfuse/lib/mount_generic.c b/libfuse/lib/mount_generic.c index 4a3f1bd5..89756292 100644 --- a/libfuse/lib/mount_generic.c +++ b/libfuse/lib/mount_generic.c @@ -51,200 +51,197 @@ #endif enum { - KEY_KERN_FLAG, - KEY_KERN_OPT, - KEY_FUSERMOUNT_OPT, - KEY_SUBTYPE_OPT, - KEY_MTAB_OPT, - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, + KEY_KERN_FLAG, + KEY_KERN_OPT, + KEY_FUSERMOUNT_OPT, + KEY_SUBTYPE_OPT, + KEY_MTAB_OPT, + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - int flags; - int nonempty; - int auto_unmount; - int blkdev; - char *fsname; - char *subtype; - char *subtype_opt; - char *mtab_opts; - char *fusermount_opts; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + int flags; + int nonempty; + int auto_unmount; + char *fsname; + char *subtype; + char *subtype_opt; + char *mtab_opts; + char *fusermount_opts; + char *kernel_opts; }; #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } static const struct fuse_opt fuse_mount_opts[] = { - FUSE_MOUNT_OPT("allow_other", allow_other), - FUSE_MOUNT_OPT("allow_root", allow_root), - FUSE_MOUNT_OPT("nonempty", nonempty), - FUSE_MOUNT_OPT("blkdev", blkdev), - FUSE_MOUNT_OPT("auto_unmount", auto_unmount), - FUSE_MOUNT_OPT("fsname=%s", fsname), - FUSE_MOUNT_OPT("subtype=%s", subtype), - FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), - FUSE_OPT_KEY("large_read", KEY_KERN_OPT), - FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), - FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), - FUSE_OPT_KEY("context=", KEY_KERN_OPT), - FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT), - FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT), - FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("user=", KEY_MTAB_OPT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("ro", KEY_KERN_FLAG), - FUSE_OPT_KEY("rw", KEY_KERN_FLAG), - FUSE_OPT_KEY("suid", KEY_KERN_FLAG), - FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), - FUSE_OPT_KEY("dev", KEY_KERN_FLAG), - FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), - FUSE_OPT_KEY("exec", KEY_KERN_FLAG), - FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), - FUSE_OPT_KEY("async", KEY_KERN_FLAG), - FUSE_OPT_KEY("sync", KEY_KERN_FLAG), - FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), - FUSE_OPT_KEY("atime", KEY_KERN_FLAG), - FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END + FUSE_MOUNT_OPT("allow_other", allow_other), + FUSE_MOUNT_OPT("allow_root", allow_root), + FUSE_MOUNT_OPT("nonempty", nonempty), + FUSE_MOUNT_OPT("auto_unmount", auto_unmount), + FUSE_MOUNT_OPT("fsname=%s", fsname), + FUSE_MOUNT_OPT("subtype=%s", subtype), + FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), + FUSE_OPT_KEY("large_read", KEY_KERN_OPT), + FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), + FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), + FUSE_OPT_KEY("context=", KEY_KERN_OPT), + FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT), + FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT), + FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("user=", KEY_MTAB_OPT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("ro", KEY_KERN_FLAG), + FUSE_OPT_KEY("rw", KEY_KERN_FLAG), + FUSE_OPT_KEY("suid", KEY_KERN_FLAG), + FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), + FUSE_OPT_KEY("dev", KEY_KERN_FLAG), + FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), + FUSE_OPT_KEY("exec", KEY_KERN_FLAG), + FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), + FUSE_OPT_KEY("async", KEY_KERN_FLAG), + FUSE_OPT_KEY("sync", KEY_KERN_FLAG), + FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), + FUSE_OPT_KEY("atime", KEY_KERN_FLAG), + FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, -" -o allow_other allow access to other users\n" -" -o allow_root allow access to root\n" -" -o auto_unmount auto unmount on process termination\n" -" -o nonempty allow mounts over non-empty file/dir\n" -" -o default_permissions enable permission checking by kernel\n" -" -o fsname=NAME set filesystem name\n" -" -o subtype=NAME set filesystem type\n" -" -o large_read issue large read requests (2.4 only)\n" -" -o max_read=N set maximum size of read requests\n" -"\n"); + fprintf(stderr, + " -o allow_other allow access to other users\n" + " -o allow_root allow access to root\n" + " -o auto_unmount auto unmount on process termination\n" + " -o nonempty allow mounts over non-empty file/dir\n" + " -o default_permissions enable permission checking by kernel\n" + " -o fsname=NAME set filesystem name\n" + " -o subtype=NAME set filesystem type\n" + " -o large_read issue large read requests (2.4 only)\n" + " -o max_read=N set maximum size of read requests\n" + "\n"); } static void exec_fusermount(const char *argv[]) { - execv(FUSERMOUNT_DIR "/mergerfs-" FUSERMOUNT_PROG, (char **) argv); - execvp("mergerfs-" FUSERMOUNT_PROG, (char **) argv); - execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); - execvp(FUSERMOUNT_PROG, (char **) argv); + execv(FUSERMOUNT_DIR "/mergerfs-" FUSERMOUNT_PROG, (char **) argv); + execvp("mergerfs-" FUSERMOUNT_PROG, (char **) argv); + execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); + execvp(FUSERMOUNT_PROG, (char **) argv); } static void mount_version(void) { - int pid = fork(); - if (!pid) { - const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; - exec_fusermount(argv); - _exit(1); - } else if (pid != -1) - waitpid(pid, NULL, 0); + int pid = fork(); + if (!pid) { + const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; + exec_fusermount(argv); + _exit(1); + } else if (pid != -1) + waitpid(pid, NULL, 0); } struct mount_flags { - const char *opt; - unsigned long flag; - int on; + const char *opt; + unsigned long flag; + int on; }; static const struct mount_flags mount_flags[] = { - {"rw", MS_RDONLY, 0}, - {"ro", MS_RDONLY, 1}, - {"suid", MS_NOSUID, 0}, - {"nosuid", MS_NOSUID, 1}, - {"dev", MS_NODEV, 0}, - {"nodev", MS_NODEV, 1}, - {"exec", MS_NOEXEC, 0}, - {"noexec", MS_NOEXEC, 1}, - {"async", MS_SYNCHRONOUS, 0}, - {"sync", MS_SYNCHRONOUS, 1}, - {"atime", MS_NOATIME, 0}, - {"noatime", MS_NOATIME, 1}, + {"rw", MS_RDONLY, 0}, + {"ro", MS_RDONLY, 1}, + {"suid", MS_NOSUID, 0}, + {"nosuid", MS_NOSUID, 1}, + {"dev", MS_NODEV, 0}, + {"nodev", MS_NODEV, 1}, + {"exec", MS_NOEXEC, 0}, + {"noexec", MS_NOEXEC, 1}, + {"async", MS_SYNCHRONOUS, 0}, + {"sync", MS_SYNCHRONOUS, 1}, + {"atime", MS_NOATIME, 0}, + {"noatime", MS_NOATIME, 1}, #ifndef __NetBSD__ - {"dirsync", MS_DIRSYNC, 1}, + {"dirsync", MS_DIRSYNC, 1}, #endif - {NULL, 0, 0} + {NULL, 0, 0} }; static void set_mount_flag(const char *s, int *flags) { - int i; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - const char *opt = mount_flags[i].opt; - if (strcmp(opt, s) == 0) { - if (mount_flags[i].on) - *flags |= mount_flags[i].flag; - else - *flags &= ~mount_flags[i].flag; - return; - } - } - fprintf(stderr, "fuse: internal error, can't find mount flag\n"); - abort(); + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strcmp(opt, s) == 0) { + if (mount_flags[i].on) + *flags |= mount_flags[i].flag; + else + *flags &= ~mount_flags[i].flag; + return; + } + } + fprintf(stderr, "fuse: internal error, can't find mount flag\n"); + abort(); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - case KEY_KERN_FLAG: - set_mount_flag(arg, &mo->flags); - return 0; - - case KEY_KERN_OPT: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_FUSERMOUNT_OPT: - return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg); - - case KEY_SUBTYPE_OPT: - return fuse_opt_add_opt(&mo->subtype_opt, arg); - - case KEY_MTAB_OPT: - return fuse_opt_add_opt(&mo->mtab_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + case KEY_KERN_FLAG: + set_mount_flag(arg, &mo->flags); + return 0; + + case KEY_KERN_OPT: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_FUSERMOUNT_OPT: + return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg); + + case KEY_SUBTYPE_OPT: + return fuse_opt_add_opt(&mo->subtype_opt, arg); + + case KEY_MTAB_OPT: + return fuse_opt_add_opt(&mo->mtab_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } /* return value: @@ -253,393 +250,387 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key, */ static int receive_fd(int fd) { - struct msghdr msg; - struct iovec iov; - char buf[1]; - int rv; - size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; - struct cmsghdr *cmsg; - - iov.iov_base = buf; - iov.iov_len = 1; - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - /* old BSD implementations should use msg_accrights instead of - * msg_control; the interface is different. */ - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof(ccmsg); - - while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); - if (rv == -1) { - perror("recvmsg"); - return -1; - } - if(!rv) { - /* EOF */ - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg->cmsg_type != SCM_RIGHTS) { - fprintf(stderr, "got control message of unknown type %d\n", - cmsg->cmsg_type); - return -1; - } - return *(int*)CMSG_DATA(cmsg); + struct msghdr msg; + struct iovec iov; + char buf[1]; + int rv; + size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; + struct cmsghdr *cmsg; + + iov.iov_base = buf; + iov.iov_len = 1; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + /* old BSD implementations should use msg_accrights instead of + * msg_control; the interface is different. */ + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof(ccmsg); + + while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); + if (rv == -1) { + perror("recvmsg"); + return -1; + } + if(!rv) { + /* EOF */ + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg->cmsg_type != SCM_RIGHTS) { + fprintf(stderr, "got control message of unknown type %d\n", + cmsg->cmsg_type); + return -1; + } + return *(int*)CMSG_DATA(cmsg); } void fuse_kern_unmount(const char *mountpoint, int fd) { - int res; - int pid; + int res; + int pid; - if (!mountpoint) - return; + if (!mountpoint) + return; - if (fd != -1) { - struct pollfd pfd; + if (fd != -1) { + struct pollfd pfd; - pfd.fd = fd; - pfd.events = 0; - res = poll(&pfd, 1, 0); + pfd.fd = fd; + pfd.events = 0; + res = poll(&pfd, 1, 0); - /* Need to close file descriptor, otherwise synchronous umount - would recurse into filesystem, and deadlock. + /* Need to close file descriptor, otherwise synchronous umount + would recurse into filesystem, and deadlock. - Caller expects fuse_kern_unmount to close the fd, so close it - anyway. */ - close(fd); + Caller expects fuse_kern_unmount to close the fd, so close it + anyway. */ + close(fd); - /* If file poll returns POLLERR on the device file descriptor, - then the filesystem is already unmounted */ - if (res == 1 && (pfd.revents & POLLERR)) - return; - } + /* If file poll returns POLLERR on the device file descriptor, + then the filesystem is already unmounted */ + if (res == 1 && (pfd.revents & POLLERR)) + return; + } - if (geteuid() == 0) { - fuse_mnt_umount("fuse", mountpoint, mountpoint, 1); - return; - } + if (geteuid() == 0) { + fuse_mnt_umount("fuse", mountpoint, mountpoint, 1); + return; + } - res = umount2(mountpoint, 2); - if (res == 0) - return; + res = umount2(mountpoint, 2); + if (res == 0) + return; - pid = fork(); - if(pid == -1) - return; + pid = fork(); + if(pid == -1) + return; - if(pid == 0) { - const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", - "--", mountpoint, NULL }; + if(pid == 0) { + const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", + "--", mountpoint, NULL }; - exec_fusermount(argv); - _exit(1); - } - waitpid(pid, NULL, 0); + exec_fusermount(argv); + _exit(1); + } + waitpid(pid, NULL, 0); } void fuse_unmount_compat22(const char *mountpoint) { - fuse_kern_unmount(mountpoint, -1); + fuse_kern_unmount(mountpoint, -1); } static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo, - const char *opts, int quiet) + const char *opts, int quiet) { - int fds[2], pid; - int res; - int rv; - - if (!mountpoint) { - fprintf(stderr, "fuse: missing mountpoint parameter\n"); - return -1; - } - - res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) { - perror("fuse: socketpair() failed"); - return -1; - } - - pid = fork(); - if(pid == -1) { - perror("fuse: fork() failed"); - close(fds[0]); - close(fds[1]); - return -1; - } - - if(pid == 0) { - char env[10]; - const char *argv[32]; - int a = 0; - - if (quiet) { - int fd = open("/dev/null", O_RDONLY); - if (fd != -1) { - dup2(fd, 1); - dup2(fd, 2); - } - } - - argv[a++] = FUSERMOUNT_PROG; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = "--"; - argv[a++] = mountpoint; - argv[a++] = NULL; - - close(fds[1]); - fcntl(fds[0], F_SETFD, 0); - snprintf(env, sizeof(env), "%i", fds[0]); - setenv(FUSE_COMMFD_ENV, env, 1); - exec_fusermount(argv); - perror("fuse: failed to exec fusermount"); - _exit(1); - } - - close(fds[0]); - rv = receive_fd(fds[1]); - - if (!mo->auto_unmount) { - /* with auto_unmount option fusermount will not exit until - this socket is closed */ - close(fds[1]); - waitpid(pid, NULL, 0); /* bury zombie */ - } - - return rv; + int fds[2], pid; + int res; + int rv; + + if (!mountpoint) { + fprintf(stderr, "fuse: missing mountpoint parameter\n"); + return -1; + } + + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if(res == -1) { + perror("fuse: socketpair() failed"); + return -1; + } + + pid = fork(); + if(pid == -1) { + perror("fuse: fork() failed"); + close(fds[0]); + close(fds[1]); + return -1; + } + + if(pid == 0) { + char env[10]; + const char *argv[32]; + int a = 0; + + if (quiet) { + int fd = open("/dev/null", O_RDONLY); + if (fd != -1) { + dup2(fd, 1); + dup2(fd, 2); + } + } + + argv[a++] = FUSERMOUNT_PROG; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = "--"; + argv[a++] = mountpoint; + argv[a++] = NULL; + + close(fds[1]); + fcntl(fds[0], F_SETFD, 0); + snprintf(env, sizeof(env), "%i", fds[0]); + setenv(FUSE_COMMFD_ENV, env, 1); + exec_fusermount(argv); + perror("fuse: failed to exec fusermount"); + _exit(1); + } + + close(fds[0]); + rv = receive_fd(fds[1]); + + if (!mo->auto_unmount) { + /* with auto_unmount option fusermount will not exit until + this socket is closed */ + close(fds[1]); + waitpid(pid, NULL, 0); /* bury zombie */ + } + + return rv; } int fuse_mount_compat22(const char *mountpoint, const char *opts) { - struct mount_opts mo; - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; + struct mount_opts mo; + memset(&mo, 0, sizeof(mo)); + mo.flags = MS_NOSUID | MS_NODEV; - return fuse_mount_fusermount(mountpoint, &mo, opts, 0); + return fuse_mount_fusermount(mountpoint, &mo, opts, 0); } static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, const char *mnt_opts) { - char tmp[128]; - const char *devname = "/dev/fuse"; - char *source = NULL; - char *type = NULL; - struct stat stbuf; - int fd; - int res; - - if (!mnt) { - fprintf(stderr, "fuse: missing mountpoint parameter\n"); - return -1; - } - - res = stat(mnt, &stbuf); - if (res == -1) { - fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", - mnt, strerror(errno)); - return -1; - } - - if (!mo->nonempty) { - res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, - stbuf.st_size); - if (res == -1) - return -1; - } - - if (mo->auto_unmount) { - /* Tell the caller to fallback to fusermount because - auto-unmount does not work otherwise. */ - return -2; - } - - fd = open(devname, O_RDWR); - if (fd == -1) { - if (errno == ENODEV || errno == ENOENT) - fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n"); - else - fprintf(stderr, "fuse: failed to open %s: %s\n", - devname, strerror(errno)); - return -1; - } - - snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u", - fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); - - res = fuse_opt_add_opt(&mo->kernel_opts, tmp); - if (res == -1) - goto out_close; - - source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + - (mo->subtype ? strlen(mo->subtype) : 0) + - strlen(devname) + 32); - - type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); - if (!type || !source) { - fprintf(stderr, "fuse: failed to allocate memory\n"); - goto out_close; - } - - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->subtype) { - strcat(type, "."); - strcat(type, mo->subtype); - } - strcpy(source, - mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); - - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - if (res == -1 && errno == ENODEV && mo->subtype) { - /* Probably missing subtype support */ - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->fsname) { - if (!mo->blkdev) - sprintf(source, "%s#%s", mo->subtype, - mo->fsname); - } else { - strcpy(source, type); - } - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - } - if (res == -1) { - /* - * Maybe kernel doesn't support unprivileged mounts, in this - * case try falling back to fusermount - */ - if (errno == EPERM) { - res = -2; - } else { - int errno_save = errno; - if (mo->blkdev && errno == ENODEV && - !fuse_mnt_check_fuseblk()) - fprintf(stderr, - "fuse: 'fuseblk' support missing\n"); - else - fprintf(stderr, "fuse: mount failed: %s\n", - strerror(errno_save)); - } - - goto out_close; - } + char tmp[128]; + const char *devname = "/dev/fuse"; + char *source = NULL; + char *type = NULL; + struct stat stbuf; + int fd; + int res; + + if (!mnt) { + fprintf(stderr, "fuse: missing mountpoint parameter\n"); + return -1; + } + + res = stat(mnt, &stbuf); + if (res == -1) { + fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", + mnt, strerror(errno)); + return -1; + } + + if (!mo->nonempty) { + res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, + stbuf.st_size); + if (res == -1) + return -1; + } + + if (mo->auto_unmount) { + /* Tell the caller to fallback to fusermount because + auto-unmount does not work otherwise. */ + return -2; + } + + fd = open(devname, O_RDWR); + if (fd == -1) { + if (errno == ENODEV || errno == ENOENT) + fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n"); + else + fprintf(stderr, "fuse: failed to open %s: %s\n", + devname, strerror(errno)); + return -1; + } + + snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u", + fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); + + res = fuse_opt_add_opt(&mo->kernel_opts, tmp); + if (res == -1) + goto out_close; + + source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + + (mo->subtype ? strlen(mo->subtype) : 0) + + strlen(devname) + 32); + + type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); + if (!type || !source) { + fprintf(stderr, "fuse: failed to allocate memory\n"); + goto out_close; + } + + strcpy(type,"fuse"); + if (mo->subtype) { + strcat(type, "."); + strcat(type, mo->subtype); + } + strcpy(source, + mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); + + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + if (res == -1 && errno == ENODEV && mo->subtype) { + /* Probably missing subtype support */ + strcpy(type,"fuse"); + if (mo->fsname) { + sprintf(source, "%s#%s", mo->subtype, mo->fsname); + } else { + strcpy(source, type); + } + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + } + if (res == -1) { + /* + * Maybe kernel doesn't support unprivileged mounts, in this + * case try falling back to fusermount + */ + if (errno == EPERM) { + res = -2; + } else { + int errno_save = errno; + fprintf(stderr, + "fuse: mount failed: %s\n", + strerror(errno_save)); + } + + goto out_close; + } #ifndef __NetBSD__ #ifndef IGNORE_MTAB - if (geteuid() == 0) { - char *newmnt = fuse_mnt_resolve_path("fuse", mnt); - res = -1; - if (!newmnt) - goto out_umount; - - res = fuse_mnt_add_mount("fuse", source, newmnt, type, - mnt_opts); - free(newmnt); - if (res == -1) - goto out_umount; - } + if (geteuid() == 0) { + char *newmnt = fuse_mnt_resolve_path("fuse", mnt); + res = -1; + if (!newmnt) + goto out_umount; + + res = fuse_mnt_add_mount("fuse", source, newmnt, type, + mnt_opts); + free(newmnt); + if (res == -1) + goto out_umount; + } #endif /* IGNORE_MTAB */ #endif /* __NetBSD__ */ - free(type); - free(source); - - return fd; - -out_umount: - umount2(mnt, 2); /* lazy umount */ -out_close: - free(type); - free(source); - close(fd); - return res; + free(type); + free(source); + + return fd; + + out_umount: + umount2(mnt, 2); /* lazy umount */ + out_close: + free(type); + free(source); + close(fd); + return res; } static int get_mnt_flag_opts(char **mnt_optsp, int flags) { - int i; + int i; - if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) - return -1; + if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) + return -1; - for (i = 0; mount_flags[i].opt != NULL; i++) { - if (mount_flags[i].on && (flags & mount_flags[i].flag) && - fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) - return -1; - } - return 0; + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) + return -1; + } + return 0; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - char *mnt_opts = NULL; - - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - res = 0; - if (mo.ishelp) - goto out; - - res = -1; - if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) - goto out; - if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) - goto out; - if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) - goto out; - - res = fuse_mount_sys(mountpoint, &mo, mnt_opts); - if (res == -2) { - if (mo.fusermount_opts && - fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) - goto out; - - if (mo.subtype) { - char *tmp_opts = NULL; - - res = -1; - if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || - fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { - free(tmp_opts); - goto out; - } - - res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1); - free(tmp_opts); - if (res == -1) - res = fuse_mount_fusermount(mountpoint, &mo, - mnt_opts, 0); - } else { - res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0); - } - } -out: - free(mnt_opts); - free(mo.fsname); - free(mo.subtype); - free(mo.fusermount_opts); - free(mo.subtype_opt); - free(mo.kernel_opts); - free(mo.mtab_opts); - return res; + struct mount_opts mo; + int res = -1; + char *mnt_opts = NULL; + + memset(&mo, 0, sizeof(mo)); + mo.flags = MS_NOSUID | MS_NODEV; + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + res = 0; + if (mo.ishelp) + goto out; + + res = -1; + if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) + goto out; + if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) + goto out; + if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) + goto out; + + res = fuse_mount_sys(mountpoint, &mo, mnt_opts); + if (res == -2) { + if (mo.fusermount_opts && + fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) + goto out; + + if (mo.subtype) { + char *tmp_opts = NULL; + + res = -1; + if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || + fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { + free(tmp_opts); + goto out; + } + + res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1); + free(tmp_opts); + if (res == -1) + res = fuse_mount_fusermount(mountpoint, &mo, + mnt_opts, 0); + } else { + res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0); + } + } + out: + free(mnt_opts); + free(mo.fsname); + free(mo.subtype); + free(mo.fusermount_opts); + free(mo.subtype_opt); + free(mo.kernel_opts); + free(mo.mtab_opts); + return res; } FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2"); diff --git a/libfuse/lib/mount_util.c b/libfuse/lib/mount_util.c index defb92f6..1e348c9e 100644 --- a/libfuse/lib/mount_util.c +++ b/libfuse/lib/mount_util.c @@ -31,333 +31,316 @@ #else static int mtab_needs_update(const char *mnt) { - int res; - struct stat stbuf; - - /* If mtab is within new mount, don't touch it */ - if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && - _PATH_MOUNTED[strlen(mnt)] == '/') - return 0; - - /* - * Skip mtab update if /etc/mtab: - * - * - doesn't exist, - * - is a symlink, - * - is on a read-only filesystem. - */ - res = lstat(_PATH_MOUNTED, &stbuf); - if (res == -1) { - if (errno == ENOENT) - return 0; - } else { - uid_t ruid; - int err; - - if (S_ISLNK(stbuf.st_mode)) - return 0; - - ruid = getuid(); - if (ruid != 0) - setreuid(0, -1); - - res = access(_PATH_MOUNTED, W_OK); - err = (res == -1) ? errno : 0; - if (ruid != 0) - setreuid(ruid, -1); - - if (err == EROFS) - return 0; - } - - return 1; + int res; + struct stat stbuf; + + /* If mtab is within new mount, don't touch it */ + if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && + _PATH_MOUNTED[strlen(mnt)] == '/') + return 0; + + /* + * Skip mtab update if /etc/mtab: + * + * - doesn't exist, + * - is a symlink, + * - is on a read-only filesystem. + */ + res = lstat(_PATH_MOUNTED, &stbuf); + if (res == -1) { + if (errno == ENOENT) + return 0; + } else { + uid_t ruid; + int err; + + if (S_ISLNK(stbuf.st_mode)) + return 0; + + ruid = getuid(); + if (ruid != 0) + setreuid(0, -1); + + res = access(_PATH_MOUNTED, W_OK); + err = (res == -1) ? errno : 0; + if (ruid != 0) + setreuid(ruid, -1); + + if (err == EROFS) + return 0; + } + + return 1; } #endif /* __NetBSD__ */ static int add_mount(const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts) + const char *mnt, const char *type, const char *opts) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", - "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); - fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) - res = -1; + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", + "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); + fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) + res = -1; out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); + sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + return res; } int fuse_mnt_add_mount(const char *progname, const char *fsname, const char *mnt, const char *type, const char *opts) { - if (!mtab_needs_update(mnt)) - return 0; + if (!mtab_needs_update(mnt)) + return 0; - return add_mount(progname, fsname, mnt, type, opts); + return add_mount(progname, fsname, mnt, type, opts); } static int exec_umount(const char *progname, const char *rel_mnt, int lazy) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - if (lazy) { - execle("/bin/umount", "/bin/umount", "-i", rel_mnt, - "-l", NULL, &env); - } else { - execle("/bin/umount", "/bin/umount", "-i", rel_mnt, - NULL, &env); - } - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) { - res = -1; - } + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + if (lazy) { + execle("/bin/umount", "/bin/umount", "-i", rel_mnt, + "-l", NULL, &env); + } else { + execle("/bin/umount", "/bin/umount", "-i", rel_mnt, + NULL, &env); + } + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) { + res = -1; + } out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return res; } int fuse_mnt_umount(const char *progname, const char *abs_mnt, const char *rel_mnt, int lazy) { - int res; + int res; - if (!mtab_needs_update(abs_mnt)) { - res = umount2(rel_mnt, lazy ? 2 : 0); - if (res == -1) - fprintf(stderr, "%s: failed to unmount %s: %s\n", - progname, abs_mnt, strerror(errno)); - return res; - } + if (!mtab_needs_update(abs_mnt)) { + res = umount2(rel_mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, abs_mnt, strerror(errno)); + return res; + } - return exec_umount(progname, rel_mnt, lazy); + return exec_umount(progname, rel_mnt, lazy); } static int remove_mount(const char *progname, const char *mnt) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", - "--fake", mnt, NULL, &env); - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) - res = -1; + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", + "--fake", mnt, NULL, &env); + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) + res = -1; out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return res; } int fuse_mnt_remove_mount(const char *progname, const char *mnt) { - if (!mtab_needs_update(mnt)) - return 0; + if (!mtab_needs_update(mnt)) + return 0; - return remove_mount(progname, mnt); + return remove_mount(progname, mnt); } char *fuse_mnt_resolve_path(const char *progname, const char *orig) { - char buf[PATH_MAX]; - char *copy; - char *dst; - char *end; - char *lastcomp; - const char *toresolv; - - if (!orig[0]) { - fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, - orig); - return NULL; - } - - copy = strdup(orig); - if (copy == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return NULL; - } - - toresolv = copy; - lastcomp = NULL; - for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); - if (end[0] != '/') { - char *tmp; - end[1] = '\0'; - tmp = strrchr(copy, '/'); - if (tmp == NULL) { - lastcomp = copy; - toresolv = "."; - } else { - lastcomp = tmp + 1; - if (tmp == copy) - toresolv = "/"; - } - if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { - lastcomp = NULL; - toresolv = copy; - } - else if (tmp) - tmp[0] = '\0'; - } - if (realpath(toresolv, buf) == NULL) { - fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, - strerror(errno)); - free(copy); - return NULL; - } - if (lastcomp == NULL) - dst = strdup(buf); - else { - dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); - if (dst) { - unsigned buflen = strlen(buf); - if (buflen && buf[buflen-1] == '/') - sprintf(dst, "%s%s", buf, lastcomp); - else - sprintf(dst, "%s/%s", buf, lastcomp); - } - } - free(copy); - if (dst == NULL) - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return dst; + char buf[PATH_MAX]; + char *copy; + char *dst; + char *end; + char *lastcomp; + const char *toresolv; + + if (!orig[0]) { + fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, + orig); + return NULL; + } + + copy = strdup(orig); + if (copy == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return NULL; + } + + toresolv = copy; + lastcomp = NULL; + for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); + if (end[0] != '/') { + char *tmp; + end[1] = '\0'; + tmp = strrchr(copy, '/'); + if (tmp == NULL) { + lastcomp = copy; + toresolv = "."; + } else { + lastcomp = tmp + 1; + if (tmp == copy) + toresolv = "/"; + } + if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { + lastcomp = NULL; + toresolv = copy; + } + else if (tmp) + tmp[0] = '\0'; + } + if (realpath(toresolv, buf) == NULL) { + fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, + strerror(errno)); + free(copy); + return NULL; + } + if (lastcomp == NULL) + dst = strdup(buf); + else { + dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); + if (dst) { + unsigned buflen = strlen(buf); + if (buflen && buf[buflen-1] == '/') + sprintf(dst, "%s%s", buf, lastcomp); + else + sprintf(dst, "%s/%s", buf, lastcomp); + } + } + free(copy); + if (dst == NULL) + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return dst; } int fuse_mnt_check_empty(const char *progname, const char *mnt, mode_t rootmode, off_t rootsize) { - int isempty = 1; - - if (S_ISDIR(rootmode)) { - struct dirent *ent; - DIR *dp = opendir(mnt); - if (dp == NULL) { - fprintf(stderr, - "%s: failed to open mountpoint for reading: %s\n", - progname, strerror(errno)); - return -1; - } - while ((ent = readdir(dp)) != NULL) { - if (strcmp(ent->d_name, ".") != 0 && - strcmp(ent->d_name, "..") != 0) { - isempty = 0; - break; - } - } - closedir(dp); - } else if (rootsize) - isempty = 0; - - if (!isempty) { - fprintf(stderr, "%s: mountpoint is not empty\n", progname); - fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); - return -1; - } - return 0; -} - -int fuse_mnt_check_fuseblk(void) -{ - char buf[256]; - FILE *f = fopen("/proc/filesystems", "r"); - if (!f) - return 1; - - while (fgets(buf, sizeof(buf), f)) - if (strstr(buf, "fuseblk\n")) { - fclose(f); - return 1; - } - - fclose(f); - return 0; + int isempty = 1; + + if (S_ISDIR(rootmode)) { + struct dirent *ent; + DIR *dp = opendir(mnt); + if (dp == NULL) { + fprintf(stderr, + "%s: failed to open mountpoint for reading: %s\n", + progname, strerror(errno)); + return -1; + } + while ((ent = readdir(dp)) != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) { + isempty = 0; + break; + } + } + closedir(dp); + } else if (rootsize) + isempty = 0; + + if (!isempty) { + fprintf(stderr, "%s: mountpoint is not empty\n", progname); + fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); + return -1; + } + return 0; } diff --git a/libfuse/lib/mount_util.h b/libfuse/lib/mount_util.h index dc5c916f..ca1fdb8b 100644 --- a/libfuse/lib/mount_util.h +++ b/libfuse/lib/mount_util.h @@ -16,4 +16,3 @@ int fuse_mnt_umount(const char *progname, const char *abs_mnt, char *fuse_mnt_resolve_path(const char *progname, const char *orig); int fuse_mnt_check_empty(const char *progname, const char *mnt, mode_t rootmode, off_t rootsize); -int fuse_mnt_check_fuseblk(void); diff --git a/libfuse/lib/sys.c b/libfuse/lib/sys.c new file mode 100644 index 00000000..9dd35821 --- /dev/null +++ b/libfuse/lib/sys.c @@ -0,0 +1,48 @@ +#define _GNU_SOURCE + +#include +#include + +static +int +sys_get_pagesize_(void) +{ +#ifdef _SC_PAGESIZE + return sysconf(_SC_PAGESIZE); +#else + return getpagesize(); +#endif +} + +int +sys_get_pagesize(void) +{ + static int pagesize = 0; + + if(pagesize == 0) + pagesize = sys_get_pagesize_(); + + return pagesize; +} + +int +sys_alloc_pipe(int pipe_[2], + int bufsize_) +{ +#ifdef F_SETPIPE_SZ + int rv; + + rv = pipe(pipe_); + if(rv == -1) + return -1; + + rv = fcntl(pipe_[0],F_SETPIPE_SZ,bufsize_); + if(rv == -1) + return -1; + + return rv; +#else + errno = ENOSYS; + return -1; +#endif +} diff --git a/libfuse/lib/sys.h b/libfuse/lib/sys.h new file mode 100644 index 00000000..3bbe49f6 --- /dev/null +++ b/libfuse/lib/sys.h @@ -0,0 +1,4 @@ +#pragma once + +int sys_get_pagesize(void); +int sys_alloc_pipe(int p[2], int bufsize); diff --git a/libfuse/lib/ulockmgr.c b/libfuse/lib/ulockmgr.c index b875c507..718d37c6 100644 --- a/libfuse/lib/ulockmgr.c +++ b/libfuse/lib/ulockmgr.c @@ -22,28 +22,28 @@ #include struct message { - unsigned intr : 1; - unsigned nofd : 1; - pthread_t thr; - int cmd; - int fd; - struct flock lock; - int error; + unsigned intr : 1; + unsigned nofd : 1; + pthread_t thr; + int cmd; + int fd; + struct flock lock; + int error; }; struct fd_store { - struct fd_store *next; - int fd; - int inuse; + struct fd_store *next; + int fd; + int inuse; }; struct owner { - struct owner *next; - struct owner *prev; - struct fd_store *fds; - void *id; - size_t id_len; - int cfd; + struct owner *next; + struct owner *prev; + struct fd_store *fds; + void *id; + size_t id_len; + int cfd; }; static pthread_mutex_t ulockmgr_lock; @@ -54,19 +54,19 @@ static struct owner owner_list = { .next = &owner_list, .prev = &owner_list }; static void list_del_owner(struct owner *owner) { - struct owner *prev = owner->prev; - struct owner *next = owner->next; - prev->next = next; - next->prev = prev; + struct owner *prev = owner->prev; + struct owner *next = owner->next; + prev->next = next; + next->prev = prev; } static void list_add_owner(struct owner *owner, struct owner *next) { - struct owner *prev = next->prev; - owner->next = next; - owner->prev = prev; - prev->next = owner; - next->prev = owner; + struct owner *prev = next->prev; + owner->next = next; + owner->prev = prev; + prev->next = owner; + next->prev = owner; } /* @@ -77,368 +77,368 @@ static void list_add_owner(struct owner *owner, struct owner *next) */ static int do_recv(int sock, void *buf, size_t len, int flags) { - int res = recv(sock, buf, len, flags); - if (res == 0) - res = recv(sock, buf, len, flags); + int res = recv(sock, buf, len, flags); + if (res == 0) + res = recv(sock, buf, len, flags); - return res; + return res; } static int ulockmgr_send_message(int sock, void *buf, size_t buflen, int *fdp, int numfds) { - struct msghdr msg; - struct cmsghdr *p_cmsg; - struct iovec vec; - size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; - int res; - - assert(numfds <= MAX_SEND_FDS); - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - p_cmsg = CMSG_FIRSTHDR(&msg); - p_cmsg->cmsg_level = SOL_SOCKET; - p_cmsg->cmsg_type = SCM_RIGHTS; - p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); - memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); - msg.msg_controllen = p_cmsg->cmsg_len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - vec.iov_base = buf; - vec.iov_len = buflen; - res = sendmsg(sock, &msg, MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: sendmsg"); - return -1; - } - if ((size_t) res != buflen) { - fprintf(stderr, "libulockmgr: sendmsg short\n"); - return -1; - } - return 0; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; + int res; + + assert(numfds <= MAX_SEND_FDS); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + p_cmsg = CMSG_FIRSTHDR(&msg); + p_cmsg->cmsg_level = SOL_SOCKET; + p_cmsg->cmsg_type = SCM_RIGHTS; + p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); + memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); + msg.msg_controllen = p_cmsg->cmsg_len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + vec.iov_base = buf; + vec.iov_len = buflen; + res = sendmsg(sock, &msg, MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: sendmsg"); + return -1; + } + if ((size_t) res != buflen) { + fprintf(stderr, "libulockmgr: sendmsg short\n"); + return -1; + } + return 0; } static int ulockmgr_start_daemon(void) { - int sv[2]; - int res; - char tmp[64]; - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - return -1; - } - snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); - res = system(tmp); - close(sv[0]); - if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { - close(sv[1]); - return -1; - } - ulockmgr_cfd = sv[1]; - return 0; + int sv[2]; + int res; + char tmp[64]; + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + return -1; + } + snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); + res = system(tmp); + close(sv[0]); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { + close(sv[1]); + return -1; + } + ulockmgr_cfd = sv[1]; + return 0; } static struct owner *ulockmgr_new_owner(const void *id, size_t id_len) { - int sv[2]; - int res; - char c = 'm'; - struct owner *o; - - if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) - return NULL; - - o = calloc(1, sizeof(struct owner) + id_len); - if (!o) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return NULL; - } - o->id = o + 1; - o->id_len = id_len; - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - goto out_free; - } - res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); - close(sv[0]); - if (res == -1) { - close(ulockmgr_cfd); - ulockmgr_cfd = -1; - goto out_close; - } - - o->cfd = sv[1]; - memcpy(o->id, id, id_len); - list_add_owner(o, &owner_list); - - return o; - -out_close: - close(sv[1]); -out_free: - free(o); - return NULL; + int sv[2]; + int res; + char c = 'm'; + struct owner *o; + + if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) + return NULL; + + o = calloc(1, sizeof(struct owner) + id_len); + if (!o) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return NULL; + } + o->id = o + 1; + o->id_len = id_len; + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + goto out_free; + } + res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); + close(sv[0]); + if (res == -1) { + close(ulockmgr_cfd); + ulockmgr_cfd = -1; + goto out_close; + } + + o->cfd = sv[1]; + memcpy(o->id, id, id_len); + list_add_owner(o, &owner_list); + + return o; + + out_close: + close(sv[1]); + out_free: + free(o); + return NULL; } static int ulockmgr_send_request(struct message *msg, const void *id, size_t id_len) { - int sv[2]; - int cfd; - struct owner *o; - struct fd_store *f = NULL; - struct fd_store *newf = NULL; - struct fd_store **fp; - int fd = msg->fd; - int cmd = msg->cmd; - int res; - int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && - msg->lock.l_start == 0 && msg->lock.l_len == 0); - - for (o = owner_list.next; o != &owner_list; o = o->next) - if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) - break; - - if (o == &owner_list) - o = NULL; - - if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) - o = ulockmgr_new_owner(id, id_len); - - if (!o) { - if (cmd == F_GETLK) { - res = fcntl(msg->fd, F_GETLK, &msg->lock); - return (res == -1) ? -errno : 0; - } else if (msg->lock.l_type == F_UNLCK) - return 0; - else - return -ENOLCK; - } - - if (unlockall) - msg->nofd = 1; - else { - for (fp = &o->fds; *fp; fp = &(*fp)->next) { - f = *fp; - if (f->fd == fd) { - msg->nofd = 1; - break; - } - } - } - - if (!msg->nofd) { - newf = f = calloc(1, sizeof(struct fd_store)); - if (!f) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return -ENOLCK; - } - } - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - free(newf); - return -ENOLCK; - } - - cfd = sv[1]; - sv[1] = msg->fd; - res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, - msg->nofd ? 1 : 2); - close(sv[0]); - if (res == -1) { - free(newf); - close(cfd); - return -EIO; - } - - if (newf) { - newf->fd = msg->fd; - newf->next = o->fds; - o->fds = newf; - } - if (f) - f->inuse++; - - res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); - if (res == -1) { - perror("libulockmgr: recv"); - msg->error = EIO; - } else if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - } else if (cmd == F_SETLKW && msg->error == EAGAIN) { - pthread_mutex_unlock(&ulockmgr_lock); - while (1) { - sigset_t old; - sigset_t unblock; - int errno_save; - - sigemptyset(&unblock); - sigaddset(&unblock, SIGUSR1); - pthread_sigmask(SIG_UNBLOCK, &unblock, &old); - res = do_recv(cfd, msg, sizeof(struct message), - MSG_WAITALL); - errno_save = errno; - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (res == sizeof(struct message)) - break; - else if (res >= 0) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - break; - } else if (errno_save != EINTR) { - errno = errno_save; - perror("libulockmgr: recv"); - msg->error = EIO; - break; - } - msg->intr = 1; - res = send(o->cfd, msg, sizeof(struct message), - MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: send"); - msg->error = EIO; - break; - } - if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: send short\n"); - msg->error = EIO; - break; - } - } - pthread_mutex_lock(&ulockmgr_lock); - - } - if (f) - f->inuse--; - close(cfd); - if (unlockall) { - for (fp = &o->fds; *fp;) { - f = *fp; - if (f->fd == fd && !f->inuse) { - *fp = f->next; - free(f); - } else - fp = &f->next; - } - if (!o->fds) { - list_del_owner(o); - close(o->cfd); - free(o); - } - /* Force OK on unlock-all, since it _will_ succeed once the - owner is deleted */ - msg->error = 0; - } - - return -msg->error; + int sv[2]; + int cfd; + struct owner *o; + struct fd_store *f = NULL; + struct fd_store *newf = NULL; + struct fd_store **fp; + int fd = msg->fd; + int cmd = msg->cmd; + int res; + int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && + msg->lock.l_start == 0 && msg->lock.l_len == 0); + + for (o = owner_list.next; o != &owner_list; o = o->next) + if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) + break; + + if (o == &owner_list) + o = NULL; + + if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) + o = ulockmgr_new_owner(id, id_len); + + if (!o) { + if (cmd == F_GETLK) { + res = fcntl(msg->fd, F_GETLK, &msg->lock); + return (res == -1) ? -errno : 0; + } else if (msg->lock.l_type == F_UNLCK) + return 0; + else + return -ENOLCK; + } + + if (unlockall) + msg->nofd = 1; + else { + for (fp = &o->fds; *fp; fp = &(*fp)->next) { + f = *fp; + if (f->fd == fd) { + msg->nofd = 1; + break; + } + } + } + + if (!msg->nofd) { + newf = f = calloc(1, sizeof(struct fd_store)); + if (!f) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return -ENOLCK; + } + } + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + free(newf); + return -ENOLCK; + } + + cfd = sv[1]; + sv[1] = msg->fd; + res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, + msg->nofd ? 1 : 2); + close(sv[0]); + if (res == -1) { + free(newf); + close(cfd); + return -EIO; + } + + if (newf) { + newf->fd = msg->fd; + newf->next = o->fds; + o->fds = newf; + } + if (f) + f->inuse++; + + res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); + if (res == -1) { + perror("libulockmgr: recv"); + msg->error = EIO; + } else if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + } else if (cmd == F_SETLKW && msg->error == EAGAIN) { + pthread_mutex_unlock(&ulockmgr_lock); + while (1) { + sigset_t old; + sigset_t unblock; + int errno_save; + + sigemptyset(&unblock); + sigaddset(&unblock, SIGUSR1); + pthread_sigmask(SIG_UNBLOCK, &unblock, &old); + res = do_recv(cfd, msg, sizeof(struct message), + MSG_WAITALL); + errno_save = errno; + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (res == sizeof(struct message)) + break; + else if (res >= 0) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + break; + } else if (errno_save != EINTR) { + errno = errno_save; + perror("libulockmgr: recv"); + msg->error = EIO; + break; + } + msg->intr = 1; + res = send(o->cfd, msg, sizeof(struct message), + MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: send"); + msg->error = EIO; + break; + } + if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: send short\n"); + msg->error = EIO; + break; + } + } + pthread_mutex_lock(&ulockmgr_lock); + + } + if (f) + f->inuse--; + close(cfd); + if (unlockall) { + for (fp = &o->fds; *fp;) { + f = *fp; + if (f->fd == fd && !f->inuse) { + *fp = f->next; + free(f); + } else + fp = &f->next; + } + if (!o->fds) { + list_del_owner(o); + close(o->cfd); + free(o); + } + /* Force OK on unlock-all, since it _will_ succeed once the + owner is deleted */ + msg->error = 0; + } + + return -msg->error; } #ifdef DEBUG static uint32_t owner_hash(const unsigned char *id, size_t id_len) { - uint32_t h = 0; - size_t i; - for (i = 0; i < id_len; i++) - h = ((h << 8) | (h >> 24)) ^ id[i]; + uint32_t h = 0; + size_t i; + for (i = 0; i < id_len; i++) + h = ((h << 8) | (h >> 24)) ^ id[i]; - return h; + return h; } #endif static int ulockmgr_canonicalize(int fd, struct flock *lock) { - off_t offset; - if (lock->l_whence == SEEK_CUR) { - offset = lseek(fd, 0, SEEK_CUR); - if (offset == (off_t) -1) - return -errno; - } else if (lock->l_whence == SEEK_END) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) - return -errno; - - offset = stbuf.st_size; - } else - offset = 0; - - lock->l_whence = SEEK_SET; - lock->l_start += offset; - - if (lock->l_start < 0) - return -EINVAL; - - if (lock->l_len < 0) { - lock->l_start += lock->l_len; - if (lock->l_start < 0) - return -EINVAL; - lock->l_len = -lock->l_len; - } - if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) - return -EINVAL; - - return 0; + off_t offset; + if (lock->l_whence == SEEK_CUR) { + offset = lseek(fd, 0, SEEK_CUR); + if (offset == (off_t) -1) + return -errno; + } else if (lock->l_whence == SEEK_END) { + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) + return -errno; + + offset = stbuf.st_size; + } else + offset = 0; + + lock->l_whence = SEEK_SET; + lock->l_start += offset; + + if (lock->l_start < 0) + return -EINVAL; + + if (lock->l_len < 0) { + lock->l_start += lock->l_len; + if (lock->l_start < 0) + return -EINVAL; + lock->l_len = -lock->l_len; + } + if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) + return -EINVAL; + + return 0; } int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, size_t owner_len) { - int err; - struct message msg; - sigset_t old; - sigset_t block; + int err; + struct message msg; + sigset_t old; + sigset_t block; - if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) - return -EINVAL; + if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) + return -EINVAL; - if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK && - lock->l_type != F_UNLCK) - return -EINVAL; + if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK && + lock->l_type != F_UNLCK) + return -EINVAL; - if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && - lock->l_whence != SEEK_END) - return -EINVAL; + if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && + lock->l_whence != SEEK_END) + return -EINVAL; #ifdef DEBUG - fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", - cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, - owner_hash(owner, owner_len)); + fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", + cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, + owner_hash(owner, owner_len)); #endif - /* Unlock should never block anyway */ - if (cmd == F_SETLKW && lock->l_type == F_UNLCK) - cmd = F_SETLK; - - memset(&msg, 0, sizeof(struct message)); - msg.cmd = cmd; - msg.fd = fd; - msg.lock = *lock; - err = ulockmgr_canonicalize(fd, &msg.lock); - if (err) - return err; - - sigemptyset(&block); - sigaddset(&block, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &block, &old); - pthread_mutex_lock(&ulockmgr_lock); - err = ulockmgr_send_request(&msg, owner, owner_len); - pthread_mutex_unlock(&ulockmgr_lock); - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (!err && cmd == F_GETLK) { - if (msg.lock.l_type == F_UNLCK) - lock->l_type = F_UNLCK; - else - *lock = msg.lock; - } - - return err; + /* Unlock should never block anyway */ + if (cmd == F_SETLKW && lock->l_type == F_UNLCK) + cmd = F_SETLK; + + memset(&msg, 0, sizeof(struct message)); + msg.cmd = cmd; + msg.fd = fd; + msg.lock = *lock; + err = ulockmgr_canonicalize(fd, &msg.lock); + if (err) + return err; + + sigemptyset(&block); + sigaddset(&block, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &block, &old); + pthread_mutex_lock(&ulockmgr_lock); + err = ulockmgr_send_request(&msg, owner, owner_len); + pthread_mutex_unlock(&ulockmgr_lock); + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (!err && cmd == F_GETLK) { + if (msg.lock.l_type == F_UNLCK) + lock->l_type = F_UNLCK; + else + *lock = msg.lock; + } + + return err; } diff --git a/libfuse/util/fusermount.c b/libfuse/util/fusermount.c index 5acdba7a..d4e87a48 100644 --- a/libfuse/util/fusermount.c +++ b/libfuse/util/fusermount.c @@ -66,13 +66,13 @@ static int auto_unmount = 0; static const char *get_user_name(void) { - struct passwd *pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_name != NULL) - return pw->pw_name; - else { - fprintf(stderr, "%s: could not determine username\n", progname); - return NULL; - } + struct passwd *pw = getpwuid(getuid()); + if (pw != NULL && pw->pw_name != NULL) + return pw->pw_name; + else { + fprintf(stderr, "%s: could not determine username\n", progname); + return NULL; + } } static uid_t oldfsuid; @@ -80,18 +80,18 @@ static gid_t oldfsgid; static void drop_privs(void) { - if (getuid() != 0) { - oldfsuid = setfsuid(getuid()); - oldfsgid = setfsgid(getgid()); - } + if (getuid() != 0) { + oldfsuid = setfsuid(getuid()); + oldfsgid = setfsgid(getgid()); + } } static void restore_privs(void) { - if (getuid() != 0) { - setfsuid(oldfsuid); - setfsgid(oldfsgid); - } + if (getuid() != 0) { + setfsuid(oldfsuid); + setfsgid(oldfsgid); + } } #ifndef IGNORE_MTAB @@ -100,114 +100,112 @@ static void restore_privs(void) */ static int lock_umount(void) { - const char *mtab_lock = _PATH_MOUNTED ".fuselock"; - int mtablock; - int res; - struct stat mtab_stat; - - /* /etc/mtab could be a symlink to /proc/mounts */ - if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode)) - return -1; - - mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600); - if (mtablock == -1) { - fprintf(stderr, "%s: unable to open fuse lock file: %s\n", - progname, strerror(errno)); - return -1; - } - res = lockf(mtablock, F_LOCK, 0); - if (res < 0) { - fprintf(stderr, "%s: error getting lock: %s\n", progname, - strerror(errno)); - close(mtablock); - return -1; - } - - return mtablock; + const char *mtab_lock = _PATH_MOUNTED ".fuselock"; + int mtablock; + int res; + struct stat mtab_stat; + + /* /etc/mtab could be a symlink to /proc/mounts */ + if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode)) + return -1; + + mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600); + if (mtablock == -1) { + fprintf(stderr, "%s: unable to open fuse lock file: %s\n", + progname, strerror(errno)); + return -1; + } + res = lockf(mtablock, F_LOCK, 0); + if (res < 0) { + fprintf(stderr, "%s: error getting lock: %s\n", progname, + strerror(errno)); + close(mtablock); + return -1; + } + + return mtablock; } static void unlock_umount(int mtablock) { - if (mtablock >= 0) { - int res; - - res = lockf(mtablock, F_ULOCK, 0); - if (res < 0) { - fprintf(stderr, "%s: error releasing lock: %s\n", - progname, strerror(errno)); - } - close(mtablock); - } + if (mtablock >= 0) { + int res; + + res = lockf(mtablock, F_ULOCK, 0); + if (res < 0) { + fprintf(stderr, "%s: error releasing lock: %s\n", + progname, strerror(errno)); + } + close(mtablock); + } } static int add_mount(const char *source, const char *mnt, const char *type, const char *opts) { - return fuse_mnt_add_mount(progname, source, mnt, type, opts); + return fuse_mnt_add_mount(progname, source, mnt, type, opts); } static int may_unmount(const char *mnt, int quiet) { - struct mntent *entp; - FILE *fp; - const char *user = NULL; - char uidstr[32]; - unsigned uidlen = 0; - int found; - const char *mtab = _PATH_MOUNTED; - - user = get_user_name(); - if (user == NULL) - return -1; - - fp = setmntent(mtab, "r"); - if (fp == NULL) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, - strerror(errno)); - return -1; - } - - uidlen = sprintf(uidstr, "%u", getuid()); - - found = 0; - while ((entp = getmntent(fp)) != NULL) { - if (!found && strcmp(entp->mnt_dir, mnt) == 0 && - (strcmp(entp->mnt_type, "fuse") == 0 || - strcmp(entp->mnt_type, "fuseblk") == 0 || - strncmp(entp->mnt_type, "fuse.", 5) == 0 || - strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { - char *p = strstr(entp->mnt_opts, "user="); - if (p && - (p == entp->mnt_opts || *(p-1) == ',') && - strcmp(p + 5, user) == 0) { - found = 1; - break; - } - /* /etc/mtab is a link pointing to - /proc/mounts: */ - else if ((p = - strstr(entp->mnt_opts, "user_id=")) && - (p == entp->mnt_opts || - *(p-1) == ',') && - strncmp(p + 8, uidstr, uidlen) == 0 && - (*(p+8+uidlen) == ',' || - *(p+8+uidlen) == '\0')) { - found = 1; - break; - } - } - } - endmntent(fp); - - if (!found) { - if (!quiet) - fprintf(stderr, - "%s: entry for %s not found in %s\n", - progname, mnt, mtab); - return -1; - } - - return 0; + struct mntent *entp; + FILE *fp; + const char *user = NULL; + char uidstr[32]; + unsigned uidlen = 0; + int found; + const char *mtab = _PATH_MOUNTED; + + user = get_user_name(); + if (user == NULL) + return -1; + + fp = setmntent(mtab, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, + strerror(errno)); + return -1; + } + + uidlen = sprintf(uidstr, "%u", getuid()); + + found = 0; + while ((entp = getmntent(fp)) != NULL) { + if (!found && strcmp(entp->mnt_dir, mnt) == 0 && + (strcmp(entp->mnt_type, "fuse") == 0 || + strncmp(entp->mnt_type, "fuse.", 5) == 0)) { + char *p = strstr(entp->mnt_opts, "user="); + if (p && + (p == entp->mnt_opts || *(p-1) == ',') && + strcmp(p + 5, user) == 0) { + found = 1; + break; + } + /* /etc/mtab is a link pointing to + /proc/mounts: */ + else if ((p = + strstr(entp->mnt_opts, "user_id=")) && + (p == entp->mnt_opts || + *(p-1) == ',') && + strncmp(p + 8, uidstr, uidlen) == 0 && + (*(p+8+uidlen) == ',' || + *(p+8+uidlen) == '\0')) { + found = 1; + break; + } + } + } + endmntent(fp); + + if (!found) { + if (!quiet) + fprintf(stderr, + "%s: entry for %s not found in %s\n", + progname, mnt, mtab); + return -1; + } + + return 0; } /* @@ -235,1104 +233,1091 @@ static int may_unmount(const char *mnt, int quiet) */ static int check_is_mount_child(void *p) { - const char **a = p; - const char *last = a[0]; - const char *mnt = a[1]; - int res; - const char *procmounts = "/proc/mounts"; - int found; - FILE *fp; - struct mntent *entp; - int count; - - res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL); - if (res == -1) { - fprintf(stderr, "%s: failed to mark mounts private: %s\n", - progname, strerror(errno)); - return 1; - } - - fp = setmntent(procmounts, "r"); - if (fp == NULL) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, - procmounts, strerror(errno)); - return 1; - } - - count = 0; - while (getmntent(fp) != NULL) - count++; - endmntent(fp); - - fp = setmntent(procmounts, "r"); - if (fp == NULL) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, - procmounts, strerror(errno)); - return 1; - } - - res = mount(".", "/", "", MS_BIND | MS_REC, NULL); - if (res == -1) { - fprintf(stderr, "%s: failed to bind parent to /: %s\n", - progname, strerror(errno)); - return 1; - } - - found = 0; - while ((entp = getmntent(fp)) != NULL) { - if (count > 0) { - count--; - continue; - } - if (entp->mnt_dir[0] == '/' && - strcmp(entp->mnt_dir + 1, last) == 0) { - found = 1; - break; - } - } - endmntent(fp); - - if (!found) { - fprintf(stderr, "%s: %s not mounted\n", progname, mnt); - return 1; - } - - return 0; + const char **a = p; + const char *last = a[0]; + const char *mnt = a[1]; + int res; + const char *procmounts = "/proc/mounts"; + int found; + FILE *fp; + struct mntent *entp; + int count; + + res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL); + if (res == -1) { + fprintf(stderr, "%s: failed to mark mounts private: %s\n", + progname, strerror(errno)); + return 1; + } + + fp = setmntent(procmounts, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, + procmounts, strerror(errno)); + return 1; + } + + count = 0; + while (getmntent(fp) != NULL) + count++; + endmntent(fp); + + fp = setmntent(procmounts, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, + procmounts, strerror(errno)); + return 1; + } + + res = mount(".", "/", "", MS_BIND | MS_REC, NULL); + if (res == -1) { + fprintf(stderr, "%s: failed to bind parent to /: %s\n", + progname, strerror(errno)); + return 1; + } + + found = 0; + while ((entp = getmntent(fp)) != NULL) { + if (count > 0) { + count--; + continue; + } + if (entp->mnt_dir[0] == '/' && + strcmp(entp->mnt_dir + 1, last) == 0) { + found = 1; + break; + } + } + endmntent(fp); + + if (!found) { + fprintf(stderr, "%s: %s not mounted\n", progname, mnt); + return 1; + } + + return 0; } static pid_t clone_newns(void *a) { - char buf[131072]; - char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15)); + char buf[131072]; + char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15)); #ifdef __ia64__ - extern int __clone2(int (*fn)(void *), - void *child_stack_base, size_t stack_size, - int flags, void *arg, pid_t *ptid, - void *tls, pid_t *ctid); + extern int __clone2(int (*fn)(void *), + void *child_stack_base, size_t stack_size, + int flags, void *arg, pid_t *ptid, + void *tls, pid_t *ctid); - return __clone2(check_is_mount_child, stack, sizeof(buf) / 2, - CLONE_NEWNS, a, NULL, NULL, NULL); + return __clone2(check_is_mount_child, stack, sizeof(buf) / 2, + CLONE_NEWNS, a, NULL, NULL, NULL); #else - return clone(check_is_mount_child, stack, CLONE_NEWNS, a); + return clone(check_is_mount_child, stack, CLONE_NEWNS, a); #endif } static int check_is_mount(const char *last, const char *mnt) { - pid_t pid, p; - int status; - const char *a[2] = { last, mnt }; - - pid = clone_newns((void *) a); - if (pid == (pid_t) -1) { - fprintf(stderr, "%s: failed to clone namespace: %s\n", - progname, strerror(errno)); - return -1; - } - p = waitpid(pid, &status, __WCLONE); - if (p == (pid_t) -1) { - fprintf(stderr, "%s: waitpid failed: %s\n", - progname, strerror(errno)); - return -1; - } - if (!WIFEXITED(status)) { - fprintf(stderr, "%s: child terminated abnormally (status %i)\n", - progname, status); - return -1; - } - if (WEXITSTATUS(status) != 0) - return -1; - - return 0; + pid_t pid, p; + int status; + const char *a[2] = { last, mnt }; + + pid = clone_newns((void *) a); + if (pid == (pid_t) -1) { + fprintf(stderr, "%s: failed to clone namespace: %s\n", + progname, strerror(errno)); + return -1; + } + p = waitpid(pid, &status, __WCLONE); + if (p == (pid_t) -1) { + fprintf(stderr, "%s: waitpid failed: %s\n", + progname, strerror(errno)); + return -1; + } + if (!WIFEXITED(status)) { + fprintf(stderr, "%s: child terminated abnormally (status %i)\n", + progname, status); + return -1; + } + if (WEXITSTATUS(status) != 0) + return -1; + + return 0; } static int chdir_to_parent(char *copy, const char **lastp) { - char *tmp; - const char *parent; - char buf[65536]; - int res; - - tmp = strrchr(copy, '/'); - if (tmp == NULL || tmp[1] == '\0') { - fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n", - progname, copy); - return -1; - } - if (tmp != copy) { - *tmp = '\0'; - parent = copy; - *lastp = tmp + 1; - } else if (tmp[1] != '\0') { - *lastp = tmp + 1; - parent = "/"; - } else { - *lastp = "."; - parent = "/"; - } - - res = chdir(parent); - if (res == -1) { - fprintf(stderr, "%s: failed to chdir to %s: %s\n", - progname, parent, strerror(errno)); - return -1; - } - - if (getcwd(buf, sizeof(buf)) == NULL) { - fprintf(stderr, "%s: failed to obtain current directory: %s\n", - progname, strerror(errno)); - return -1; - } - if (strcmp(buf, parent) != 0) { - fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname, - parent, buf); - return -1; - - } - - return 0; + char *tmp; + const char *parent; + char buf[65536]; + int res; + + tmp = strrchr(copy, '/'); + if (tmp == NULL || tmp[1] == '\0') { + fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n", + progname, copy); + return -1; + } + if (tmp != copy) { + *tmp = '\0'; + parent = copy; + *lastp = tmp + 1; + } else if (tmp[1] != '\0') { + *lastp = tmp + 1; + parent = "/"; + } else { + *lastp = "."; + parent = "/"; + } + + res = chdir(parent); + if (res == -1) { + fprintf(stderr, "%s: failed to chdir to %s: %s\n", + progname, parent, strerror(errno)); + return -1; + } + + if (getcwd(buf, sizeof(buf)) == NULL) { + fprintf(stderr, "%s: failed to obtain current directory: %s\n", + progname, strerror(errno)); + return -1; + } + if (strcmp(buf, parent) != 0) { + fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname, + parent, buf); + return -1; + + } + + return 0; } /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */ static int umount_nofollow_support(void) { - int res = umount2("", UMOUNT_UNUSED); - if (res != -1 || errno != EINVAL) - return 0; + int res = umount2("", UMOUNT_UNUSED); + if (res != -1 || errno != EINVAL) + return 0; - res = umount2("", UMOUNT_NOFOLLOW); - if (res != -1 || errno != ENOENT) - return 0; + res = umount2("", UMOUNT_NOFOLLOW); + if (res != -1 || errno != ENOENT) + return 0; - return 1; + return 1; } static int unmount_fuse_locked(const char *mnt, int quiet, int lazy) { - int res; - char *copy; - const char *last; - int umount_flags = lazy ? UMOUNT_DETACH : 0; - - if (getuid() != 0) { - res = may_unmount(mnt, quiet); - if (res == -1) - return -1; - } - - copy = strdup(mnt); - if (copy == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return -1; - } - - res = chdir_to_parent(copy, &last); - if (res == -1) - goto out; - - if (umount_nofollow_support()) { - umount_flags |= UMOUNT_NOFOLLOW; - } else { - res = check_is_mount(last, mnt); - if (res == -1) - goto out; - } - - res = umount2(last, umount_flags); - if (res == -1 && !quiet) { - fprintf(stderr, "%s: failed to unmount %s: %s\n", - progname, mnt, strerror(errno)); - } - -out: - if (res == -1) - return -1; - - res = chdir("/"); - if (res == -1) { - fprintf(stderr, "%s: failed to chdir to '/'\n", progname); - return -1; - } - - return fuse_mnt_remove_mount(progname, mnt); + int res; + char *copy; + const char *last; + int umount_flags = lazy ? UMOUNT_DETACH : 0; + + if (getuid() != 0) { + res = may_unmount(mnt, quiet); + if (res == -1) + return -1; + } + + copy = strdup(mnt); + if (copy == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + + res = chdir_to_parent(copy, &last); + if (res == -1) + goto out; + + if (umount_nofollow_support()) { + umount_flags |= UMOUNT_NOFOLLOW; + } else { + res = check_is_mount(last, mnt); + if (res == -1) + goto out; + } + + res = umount2(last, umount_flags); + if (res == -1 && !quiet) { + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); + } + + out: + if (res == -1) + return -1; + + res = chdir("/"); + if (res == -1) { + fprintf(stderr, "%s: failed to chdir to '/'\n", progname); + return -1; + } + + return fuse_mnt_remove_mount(progname, mnt); } static int unmount_fuse(const char *mnt, int quiet, int lazy) { - int res; - int mtablock = lock_umount(); + int res; + int mtablock = lock_umount(); - res = unmount_fuse_locked(mnt, quiet, lazy); - unlock_umount(mtablock); + res = unmount_fuse_locked(mnt, quiet, lazy); + unlock_umount(mtablock); - return res; + return res; } static int count_fuse_fs(void) { - struct mntent *entp; - int count = 0; - const char *mtab = _PATH_MOUNTED; - FILE *fp = setmntent(mtab, "r"); - if (fp == NULL) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, - strerror(errno)); - return -1; - } - while ((entp = getmntent(fp)) != NULL) { - if (strcmp(entp->mnt_type, "fuse") == 0 || - strncmp(entp->mnt_type, "fuse.", 5) == 0) - count ++; - } - endmntent(fp); - return count; + struct mntent *entp; + int count = 0; + const char *mtab = _PATH_MOUNTED; + FILE *fp = setmntent(mtab, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, + strerror(errno)); + return -1; + } + while ((entp = getmntent(fp)) != NULL) { + if (strcmp(entp->mnt_type, "fuse") == 0 || + strncmp(entp->mnt_type, "fuse.", 5) == 0) + count ++; + } + endmntent(fp); + return count; } #else /* IGNORE_MTAB */ static int count_fuse_fs() { - return 0; + return 0; } static int add_mount(const char *source, const char *mnt, const char *type, const char *opts) { - (void) source; - (void) mnt; - (void) type; - (void) opts; - return 0; + (void) source; + (void) mnt; + (void) type; + (void) opts; + return 0; } static int unmount_fuse(const char *mnt, int quiet, int lazy) { - return fuse_mnt_umount(progname, mnt, mnt, lazy); + return fuse_mnt_umount(progname, mnt, mnt, lazy); } #endif /* IGNORE_MTAB */ static void strip_line(char *line) { - char *s = strchr(line, '#'); - if (s != NULL) - s[0] = '\0'; - for (s = line + strlen(line) - 1; - s >= line && isspace((unsigned char) *s); s--); - s[1] = '\0'; - for (s = line; isspace((unsigned char) *s); s++); - if (s != line) - memmove(line, s, strlen(s)+1); + char *s = strchr(line, '#'); + if (s != NULL) + s[0] = '\0'; + for (s = line + strlen(line) - 1; + s >= line && isspace((unsigned char) *s); s--); + s[1] = '\0'; + for (s = line; isspace((unsigned char) *s); s++); + if (s != line) + memmove(line, s, strlen(s)+1); } static void parse_line(char *line, int linenum) { - int tmp; - if (strcmp(line, "user_allow_other") == 0) - user_allow_other = 1; - else if (sscanf(line, "mount_max = %i", &tmp) == 1) - mount_max = tmp; - else if(line[0]) - fprintf(stderr, - "%s: unknown parameter in %s at line %i: '%s'\n", - progname, FUSE_CONF, linenum, line); + int tmp; + if (strcmp(line, "user_allow_other") == 0) + user_allow_other = 1; + else if (sscanf(line, "mount_max = %i", &tmp) == 1) + mount_max = tmp; + else if(line[0]) + fprintf(stderr, + "%s: unknown parameter in %s at line %i: '%s'\n", + progname, FUSE_CONF, linenum, line); } static void read_conf(void) { - FILE *fp = fopen(FUSE_CONF, "r"); - if (fp != NULL) { - int linenum = 1; - char line[256]; - int isnewline = 1; - while (fgets(line, sizeof(line), fp) != NULL) { - if (isnewline) { - if (line[strlen(line)-1] == '\n') { - strip_line(line); - parse_line(line, linenum); - } else { - isnewline = 0; - } - } else if(line[strlen(line)-1] == '\n') { - fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum); - - isnewline = 1; - } - if (isnewline) - linenum ++; - } - if (!isnewline) { - fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF); - - } - fclose(fp); - } else if (errno != ENOENT) { - fprintf(stderr, "%s: failed to open %s: %s\n", - progname, FUSE_CONF, strerror(errno)); - } + FILE *fp = fopen(FUSE_CONF, "r"); + if (fp != NULL) { + int linenum = 1; + char line[256]; + int isnewline = 1; + while (fgets(line, sizeof(line), fp) != NULL) { + if (isnewline) { + if (line[strlen(line)-1] == '\n') { + strip_line(line); + parse_line(line, linenum); + } else { + isnewline = 0; + } + } else if(line[strlen(line)-1] == '\n') { + fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum); + + isnewline = 1; + } + if (isnewline) + linenum ++; + } + if (!isnewline) { + fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF); + + } + fclose(fp); + } else if (errno != ENOENT) { + fprintf(stderr, "%s: failed to open %s: %s\n", + progname, FUSE_CONF, strerror(errno)); + } } static int begins_with(const char *s, const char *beg) { - if (strncmp(s, beg, strlen(beg)) == 0) - return 1; - else - return 0; + if (strncmp(s, beg, strlen(beg)) == 0) + return 1; + else + return 0; } struct mount_flags { - const char *opt; - unsigned long flag; - int on; - int safe; + const char *opt; + unsigned long flag; + int on; + int safe; }; static struct mount_flags mount_flags[] = { - {"rw", MS_RDONLY, 0, 1}, - {"ro", MS_RDONLY, 1, 1}, - {"suid", MS_NOSUID, 0, 0}, - {"nosuid", MS_NOSUID, 1, 1}, - {"dev", MS_NODEV, 0, 0}, - {"nodev", MS_NODEV, 1, 1}, - {"exec", MS_NOEXEC, 0, 1}, - {"noexec", MS_NOEXEC, 1, 1}, - {"async", MS_SYNCHRONOUS, 0, 1}, - {"sync", MS_SYNCHRONOUS, 1, 1}, - {"atime", MS_NOATIME, 0, 1}, - {"noatime", MS_NOATIME, 1, 1}, - {"dirsync", MS_DIRSYNC, 1, 1}, - {NULL, 0, 0, 0} + {"rw", MS_RDONLY, 0, 1}, + {"ro", MS_RDONLY, 1, 1}, + {"suid", MS_NOSUID, 0, 0}, + {"nosuid", MS_NOSUID, 1, 1}, + {"dev", MS_NODEV, 0, 0}, + {"nodev", MS_NODEV, 1, 1}, + {"exec", MS_NOEXEC, 0, 1}, + {"noexec", MS_NOEXEC, 1, 1}, + {"async", MS_SYNCHRONOUS, 0, 1}, + {"sync", MS_SYNCHRONOUS, 1, 1}, + {"atime", MS_NOATIME, 0, 1}, + {"noatime", MS_NOATIME, 1, 1}, + {"dirsync", MS_DIRSYNC, 1, 1}, + {NULL, 0, 0, 0} }; static int find_mount_flag(const char *s, unsigned len, int *on, int *flag) { - int i; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - const char *opt = mount_flags[i].opt; - if (strlen(opt) == len && strncmp(opt, s, len) == 0) { - *on = mount_flags[i].on; - *flag = mount_flags[i].flag; - if (!mount_flags[i].safe && getuid() != 0) { - *flag = 0; - fprintf(stderr, - "%s: unsafe option %s ignored\n", - progname, opt); - } - return 1; - } - } - return 0; + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strlen(opt) == len && strncmp(opt, s, len) == 0) { + *on = mount_flags[i].on; + *flag = mount_flags[i].flag; + if (!mount_flags[i].safe && getuid() != 0) { + *flag = 0; + fprintf(stderr, + "%s: unsafe option %s ignored\n", + progname, opt); + } + return 1; + } + } + return 0; } static int add_option(char **optsp, const char *opt, unsigned expand) { - char *newopts; - if (*optsp == NULL) - newopts = strdup(opt); - else { - unsigned oldsize = strlen(*optsp); - unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1; - newopts = (char *) realloc(*optsp, newsize); - if (newopts) - sprintf(newopts + oldsize, ",%s", opt); - } - if (newopts == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return -1; - } - *optsp = newopts; - return 0; + char *newopts; + if (*optsp == NULL) + newopts = strdup(opt); + else { + unsigned oldsize = strlen(*optsp); + unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1; + newopts = (char *) realloc(*optsp, newsize); + if (newopts) + sprintf(newopts + oldsize, ",%s", opt); + } + if (newopts == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + *optsp = newopts; + return 0; } static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) { - int i; - int l; - - if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) - return -1; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - if (mount_flags[i].on && (flags & mount_flags[i].flag) && - add_option(mnt_optsp, mount_flags[i].opt, 0) == -1) - return -1; - } - - if (add_option(mnt_optsp, opts, 0) == -1) - return -1; - /* remove comma from end of opts*/ - l = strlen(*mnt_optsp); - if ((*mnt_optsp)[l-1] == ',') - (*mnt_optsp)[l-1] = '\0'; - if (getuid() != 0) { - const char *user = get_user_name(); - if (user == NULL) - return -1; - - if (add_option(mnt_optsp, "user=", strlen(user)) == -1) - return -1; - strcat(*mnt_optsp, user); - } - return 0; + int i; + int l; + + if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) + return -1; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + add_option(mnt_optsp, mount_flags[i].opt, 0) == -1) + return -1; + } + + if (add_option(mnt_optsp, opts, 0) == -1) + return -1; + /* remove comma from end of opts*/ + l = strlen(*mnt_optsp); + if ((*mnt_optsp)[l-1] == ',') + (*mnt_optsp)[l-1] = '\0'; + if (getuid() != 0) { + const char *user = get_user_name(); + if (user == NULL) + return -1; + + if (add_option(mnt_optsp, "user=", strlen(user)) == -1) + return -1; + strcat(*mnt_optsp, user); + } + return 0; } static int opt_eq(const char *s, unsigned len, const char *opt) { - if(strlen(opt) == len && strncmp(s, opt, len) == 0) - return 1; - else - return 0; + if(strlen(opt) == len && strncmp(s, opt, len) == 0) + return 1; + else + return 0; } static int get_string_opt(const char *s, unsigned len, const char *opt, char **val) { - int i; - unsigned opt_len = strlen(opt); - char *d; - - if (*val) - free(*val); - *val = (char *) malloc(len - opt_len + 1); - if (!*val) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return 0; - } - - d = *val; - s += opt_len; - len -= opt_len; - for (i = 0; i < len; i++) { - if (s[i] == '\\' && i + 1 < len) - i++; - *d++ = s[i]; - } - *d = '\0'; - return 1; + int i; + unsigned opt_len = strlen(opt); + char *d; + + if (*val) + free(*val); + *val = (char *) malloc(len - opt_len + 1); + if (!*val) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return 0; + } + + d = *val; + s += opt_len; + len -= opt_len; + for (i = 0; i < len; i++) { + if (s[i] == '\\' && i + 1 < len) + i++; + *d++ = s[i]; + } + *d = '\0'; + return 1; } static int do_mount(const char *mnt, char **typep, mode_t rootmode, int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp, off_t rootsize) { - int res; - int flags = MS_NOSUID | MS_NODEV; - char *optbuf; - char *mnt_opts = NULL; - const char *s; - char *d; - char *fsname = NULL; - char *subtype = NULL; - char *source = NULL; - char *type = NULL; - int check_empty = 1; - int blkdev = 0; - - optbuf = (char *) malloc(strlen(opts) + 128); - if (!optbuf) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return -1; - } - - for (s = opts, d = optbuf; *s;) { - unsigned len; - const char *fsname_str = "fsname="; - const char *subtype_str = "subtype="; - for (len = 0; s[len]; len++) { - if (s[len] == '\\' && s[len + 1]) - len++; - else if (s[len] == ',') - break; - } - if (begins_with(s, fsname_str)) { - if (!get_string_opt(s, len, fsname_str, &fsname)) - goto err; - } else if (begins_with(s, subtype_str)) { - if (!get_string_opt(s, len, subtype_str, &subtype)) - goto err; - } else if (opt_eq(s, len, "blkdev")) { - if (getuid() != 0) { - fprintf(stderr, - "%s: option blkdev is privileged\n", - progname); - goto err; - } - blkdev = 1; - } else if (opt_eq(s, len, "nonempty")) { - check_empty = 0; - } else if (opt_eq(s, len, "auto_unmount")) { - auto_unmount = 1; - } else if (!begins_with(s, "fd=") && - !begins_with(s, "rootmode=") && - !begins_with(s, "user_id=") && - !begins_with(s, "group_id=")) { - int on; - int flag; - int skip_option = 0; - if (opt_eq(s, len, "large_read")) { - struct utsname utsname; - unsigned kmaj, kmin; - res = uname(&utsname); - if (res == 0 && - sscanf(utsname.release, "%u.%u", - &kmaj, &kmin) == 2 && - (kmaj > 2 || (kmaj == 2 && kmin > 4))) { - fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); - skip_option = 1; - } - } - if (getuid() != 0 && !user_allow_other && - (opt_eq(s, len, "allow_other") || - opt_eq(s, len, "allow_root"))) { - fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); - goto err; - } - if (!skip_option) { - if (find_mount_flag(s, len, &on, &flag)) { - if (on) - flags |= flag; - else - flags &= ~flag; - } else { - memcpy(d, s, len); - d += len; - *d++ = ','; - } - } - } - s += len; - if (*s) - s++; - } - *d = '\0'; - res = get_mnt_opts(flags, optbuf, &mnt_opts); - if (res == -1) - goto err; - - sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u", - fd, rootmode, getuid(), getgid()); - - if (check_empty && - fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) - goto err; - - source = malloc((fsname ? strlen(fsname) : 0) + - (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); - - type = malloc((subtype ? strlen(subtype) : 0) + 32); - if (!type || !source) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - goto err; - } - - if (subtype) - sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); - else - strcpy(type, blkdev ? "fuseblk" : "fuse"); - - if (fsname) - strcpy(source, fsname); - else - strcpy(source, subtype ? subtype : dev); - - res = mount(source, mnt, type, flags, optbuf); - if (res == -1 && errno == ENODEV && subtype) { - /* Probably missing subtype support */ - strcpy(type, blkdev ? "fuseblk" : "fuse"); - if (fsname) { - if (!blkdev) - sprintf(source, "%s#%s", subtype, fsname); - } else { - strcpy(source, type); - } - - res = mount(source, mnt, type, flags, optbuf); - } - if (res == -1 && errno == EINVAL) { - /* It could be an old version not supporting group_id */ - sprintf(d, "fd=%i,rootmode=%o,user_id=%u", - fd, rootmode, getuid()); - res = mount(source, mnt, type, flags, optbuf); - } - if (res == -1) { - int errno_save = errno; - if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) - fprintf(stderr, "%s: 'fuseblk' support missing\n", - progname); - else - fprintf(stderr, "%s: mount failed: %s\n", progname, - strerror(errno_save)); - goto err; - } - *sourcep = source; - *typep = type; - *mnt_optsp = mnt_opts; - free(fsname); - free(optbuf); - - return 0; - -err: - free(fsname); - free(subtype); - free(source); - free(type); - free(mnt_opts); - free(optbuf); - return -1; + int res; + int flags = MS_NOSUID | MS_NODEV; + char *optbuf; + char *mnt_opts = NULL; + const char *s; + char *d; + char *fsname = NULL; + char *subtype = NULL; + char *source = NULL; + char *type = NULL; + int check_empty = 1; + + optbuf = (char *) malloc(strlen(opts) + 128); + if (!optbuf) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + + for (s = opts, d = optbuf; *s;) { + unsigned len; + const char *fsname_str = "fsname="; + const char *subtype_str = "subtype="; + for (len = 0; s[len]; len++) { + if (s[len] == '\\' && s[len + 1]) + len++; + else if (s[len] == ',') + break; + } + if (begins_with(s, fsname_str)) { + if (!get_string_opt(s, len, fsname_str, &fsname)) + goto err; + } else if (begins_with(s, subtype_str)) { + if (!get_string_opt(s, len, subtype_str, &subtype)) + goto err; + } else if (opt_eq(s, len, "nonempty")) { + check_empty = 0; + } else if (opt_eq(s, len, "auto_unmount")) { + auto_unmount = 1; + } else if (!begins_with(s, "fd=") && + !begins_with(s, "rootmode=") && + !begins_with(s, "user_id=") && + !begins_with(s, "group_id=")) { + int on; + int flag; + int skip_option = 0; + if (opt_eq(s, len, "large_read")) { + struct utsname utsname; + unsigned kmaj, kmin; + res = uname(&utsname); + if (res == 0 && + sscanf(utsname.release, "%u.%u", + &kmaj, &kmin) == 2 && + (kmaj > 2 || (kmaj == 2 && kmin > 4))) { + fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); + skip_option = 1; + } + } + if (getuid() != 0 && !user_allow_other && + (opt_eq(s, len, "allow_other") || + opt_eq(s, len, "allow_root"))) { + fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); + goto err; + } + if (!skip_option) { + if (find_mount_flag(s, len, &on, &flag)) { + if (on) + flags |= flag; + else + flags &= ~flag; + } else { + memcpy(d, s, len); + d += len; + *d++ = ','; + } + } + } + s += len; + if (*s) + s++; + } + *d = '\0'; + res = get_mnt_opts(flags, optbuf, &mnt_opts); + if (res == -1) + goto err; + + sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u", + fd, rootmode, getuid(), getgid()); + + if (check_empty && + fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) + goto err; + + source = malloc((fsname ? strlen(fsname) : 0) + + (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); + + type = malloc((subtype ? strlen(subtype) : 0) + 32); + if (!type || !source) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + goto err; + } + + if (subtype) + sprintf(type, "%s.%s", "fuse", subtype); + else + strcpy(type, "fuse"); + + if (fsname) + strcpy(source, fsname); + else + strcpy(source, subtype ? subtype : dev); + + res = mount(source, mnt, type, flags, optbuf); + if (res == -1 && errno == ENODEV && subtype) { + /* Probably missing subtype support */ + strcpy(type, "fuse"); + if (fsname) { + sprintf(source, "%s#%s", subtype, fsname); + } else { + strcpy(source, type); + } + + res = mount(source, mnt, type, flags, optbuf); + } + if (res == -1 && errno == EINVAL) { + /* It could be an old version not supporting group_id */ + sprintf(d, "fd=%i,rootmode=%o,user_id=%u", + fd, rootmode, getuid()); + res = mount(source, mnt, type, flags, optbuf); + } + if (res == -1) { + int errno_save = errno; + fprintf(stderr, + "%s: mount failed: %s\n", progname, + strerror(errno_save)); + goto err; + } + *sourcep = source; + *typep = type; + *mnt_optsp = mnt_opts; + free(fsname); + free(optbuf); + + return 0; + + err: + free(fsname); + free(subtype); + free(source); + free(type); + free(mnt_opts); + free(optbuf); + return -1; } static int check_version(const char *dev) { - int res; - int majorver; - int minorver; - const char *version_file; - FILE *vf; - - if (strcmp(dev, FUSE_DEV_OLD) != 0) - return 0; - - version_file = FUSE_VERSION_FILE_OLD; - vf = fopen(version_file, "r"); - if (vf == NULL) { - fprintf(stderr, "%s: kernel interface too old\n", progname); - return -1; - } - res = fscanf(vf, "%i.%i", &majorver, &minorver); - fclose(vf); - if (res != 2) { - fprintf(stderr, "%s: error reading %s\n", progname, - version_file); - return -1; - } - if (majorver < 3) { - fprintf(stderr, "%s: kernel interface too old\n", progname); - return -1; - } - return 0; + int res; + int majorver; + int minorver; + const char *version_file; + FILE *vf; + + if (strcmp(dev, FUSE_DEV_OLD) != 0) + return 0; + + version_file = FUSE_VERSION_FILE_OLD; + vf = fopen(version_file, "r"); + if (vf == NULL) { + fprintf(stderr, "%s: kernel interface too old\n", progname); + return -1; + } + res = fscanf(vf, "%i.%i", &majorver, &minorver); + fclose(vf); + if (res != 2) { + fprintf(stderr, "%s: error reading %s\n", progname, + version_file); + return -1; + } + if (majorver < 3) { + fprintf(stderr, "%s: kernel interface too old\n", progname); + return -1; + } + return 0; } static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd) { - int res; - const char *mnt = *mntp; - const char *origmnt = mnt; - - res = lstat(mnt, stbuf); - if (res == -1) { - fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", - progname, mnt, strerror(errno)); - return -1; - } - - /* No permission checking is done for root */ - if (getuid() == 0) - return 0; - - if (S_ISDIR(stbuf->st_mode)) { - res = chdir(mnt); - if (res == -1) { - fprintf(stderr, - "%s: failed to chdir to mountpoint: %s\n", - progname, strerror(errno)); - return -1; - } - mnt = *mntp = "."; - res = lstat(mnt, stbuf); - if (res == -1) { - fprintf(stderr, - "%s: failed to access mountpoint %s: %s\n", - progname, origmnt, strerror(errno)); - return -1; - } - - if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { - fprintf(stderr, "%s: mountpoint %s not owned by user\n", - progname, origmnt); - return -1; - } - - res = access(mnt, W_OK); - if (res == -1) { - fprintf(stderr, "%s: user has no write access to mountpoint %s\n", - progname, origmnt); - return -1; - } - } else if (S_ISREG(stbuf->st_mode)) { - static char procfile[256]; - *mountpoint_fd = open(mnt, O_WRONLY); - if (*mountpoint_fd == -1) { - fprintf(stderr, "%s: failed to open %s: %s\n", - progname, mnt, strerror(errno)); - return -1; - } - res = fstat(*mountpoint_fd, stbuf); - if (res == -1) { - fprintf(stderr, - "%s: failed to access mountpoint %s: %s\n", - progname, mnt, strerror(errno)); - return -1; - } - if (!S_ISREG(stbuf->st_mode)) { - fprintf(stderr, - "%s: mountpoint %s is no longer a regular file\n", - progname, mnt); - return -1; - } - - sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); - *mntp = procfile; - } else { - fprintf(stderr, - "%s: mountpoint %s is not a directory or a regular file\n", - progname, mnt); - return -1; - } - - - return 0; + int res; + const char *mnt = *mntp; + const char *origmnt = mnt; + + res = lstat(mnt, stbuf); + if (res == -1) { + fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + + /* No permission checking is done for root */ + if (getuid() == 0) + return 0; + + if (S_ISDIR(stbuf->st_mode)) { + res = chdir(mnt); + if (res == -1) { + fprintf(stderr, + "%s: failed to chdir to mountpoint: %s\n", + progname, strerror(errno)); + return -1; + } + mnt = *mntp = "."; + res = lstat(mnt, stbuf); + if (res == -1) { + fprintf(stderr, + "%s: failed to access mountpoint %s: %s\n", + progname, origmnt, strerror(errno)); + return -1; + } + + if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { + fprintf(stderr, "%s: mountpoint %s not owned by user\n", + progname, origmnt); + return -1; + } + + res = access(mnt, W_OK); + if (res == -1) { + fprintf(stderr, "%s: user has no write access to mountpoint %s\n", + progname, origmnt); + return -1; + } + } else if (S_ISREG(stbuf->st_mode)) { + static char procfile[256]; + *mountpoint_fd = open(mnt, O_WRONLY); + if (*mountpoint_fd == -1) { + fprintf(stderr, "%s: failed to open %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + res = fstat(*mountpoint_fd, stbuf); + if (res == -1) { + fprintf(stderr, + "%s: failed to access mountpoint %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + if (!S_ISREG(stbuf->st_mode)) { + fprintf(stderr, + "%s: mountpoint %s is no longer a regular file\n", + progname, mnt); + return -1; + } + + sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); + *mntp = procfile; + } else { + fprintf(stderr, + "%s: mountpoint %s is not a directory or a regular file\n", + progname, mnt); + return -1; + } + + + return 0; } static int try_open(const char *dev, char **devp, int silent) { - int fd = open(dev, O_RDWR); - if (fd != -1) { - *devp = strdup(dev); - if (*devp == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", - progname); - close(fd); - fd = -1; - } - } else if (errno == ENODEV || - errno == ENOENT)/* check for ENOENT too, for the udev case */ - return -2; - else if (!silent) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, - strerror(errno)); - } - return fd; + int fd = open(dev, O_RDWR); + if (fd != -1) { + *devp = strdup(dev); + if (*devp == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", + progname); + close(fd); + fd = -1; + } + } else if (errno == ENODEV || + errno == ENOENT)/* check for ENOENT too, for the udev case */ + return -2; + else if (!silent) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, + strerror(errno)); + } + return fd; } static int try_open_fuse_device(char **devp) { - int fd; - int err; + int fd; + int err; - drop_privs(); - fd = try_open(FUSE_DEV_NEW, devp, 0); - restore_privs(); - if (fd >= 0) - return fd; + drop_privs(); + fd = try_open(FUSE_DEV_NEW, devp, 0); + restore_privs(); + if (fd >= 0) + return fd; - err = fd; - fd = try_open(FUSE_DEV_OLD, devp, 1); - if (fd >= 0) - return fd; + err = fd; + fd = try_open(FUSE_DEV_OLD, devp, 1); + if (fd >= 0) + return fd; - return err; + return err; } static int open_fuse_device(char **devp) { - int fd = try_open_fuse_device(devp); - if (fd >= -1) - return fd; + int fd = try_open_fuse_device(devp); + if (fd >= -1) + return fd; - fprintf(stderr, - "%s: fuse device not found, try 'modprobe fuse' first\n", - progname); + fprintf(stderr, + "%s: fuse device not found, try 'modprobe fuse' first\n", + progname); - return -1; + return -1; } static int mount_fuse(const char *mnt, const char *opts) { - int res; - int fd; - char *dev; - struct stat stbuf; - char *type = NULL; - char *source = NULL; - char *mnt_opts = NULL; - const char *real_mnt = mnt; - int mountpoint_fd = -1; - - fd = open_fuse_device(&dev); - if (fd == -1) - return -1; - - drop_privs(); - read_conf(); - - if (getuid() != 0 && mount_max != -1) { - int mount_count = count_fuse_fs(); - if (mount_count >= mount_max) { - fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); - goto fail_close_fd; - } - } - - res = check_version(dev); - if (res != -1) { - res = check_perm(&real_mnt, &stbuf, &mountpoint_fd); - restore_privs(); - if (res != -1) - res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, - fd, opts, dev, &source, &mnt_opts, - stbuf.st_size); - } else - restore_privs(); - - if (mountpoint_fd != -1) - close(mountpoint_fd); - - if (res == -1) - goto fail_close_fd; - - res = chdir("/"); - if (res == -1) { - fprintf(stderr, "%s: failed to chdir to '/'\n", progname); - goto fail_close_fd; - } - - if (geteuid() == 0) { - res = add_mount(source, mnt, type, mnt_opts); - if (res == -1) { - /* Can't clean up mount in a non-racy way */ - goto fail_close_fd; - } - } - -out_free: - free(source); - free(type); - free(mnt_opts); - free(dev); - - return fd; - -fail_close_fd: - close(fd); - fd = -1; - goto out_free; + int res; + int fd; + char *dev; + struct stat stbuf; + char *type = NULL; + char *source = NULL; + char *mnt_opts = NULL; + const char *real_mnt = mnt; + int mountpoint_fd = -1; + + fd = open_fuse_device(&dev); + if (fd == -1) + return -1; + + drop_privs(); + read_conf(); + + if (getuid() != 0 && mount_max != -1) { + int mount_count = count_fuse_fs(); + if (mount_count >= mount_max) { + fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); + goto fail_close_fd; + } + } + + res = check_version(dev); + if (res != -1) { + res = check_perm(&real_mnt, &stbuf, &mountpoint_fd); + restore_privs(); + if (res != -1) + res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, + fd, opts, dev, &source, &mnt_opts, + stbuf.st_size); + } else + restore_privs(); + + if (mountpoint_fd != -1) + close(mountpoint_fd); + + if (res == -1) + goto fail_close_fd; + + res = chdir("/"); + if (res == -1) { + fprintf(stderr, "%s: failed to chdir to '/'\n", progname); + goto fail_close_fd; + } + + if (geteuid() == 0) { + res = add_mount(source, mnt, type, mnt_opts); + if (res == -1) { + /* Can't clean up mount in a non-racy way */ + goto fail_close_fd; + } + } + + out_free: + free(source); + free(type); + free(mnt_opts); + free(dev); + + return fd; + + fail_close_fd: + close(fd); + fd = -1; + goto out_free; } static int send_fd(int sock_fd, int fd) { - int retval; - struct msghdr msg; - struct cmsghdr *p_cmsg; - struct iovec vec; - size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; - int *p_fds; - char sendchar = 0; - - 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(fd)); - p_fds = (int *) CMSG_DATA(p_cmsg); - *p_fds = fd; - 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; - /* "To pass file descriptors or credentials you need to send/read at - * least one byte" (man 7 unix) */ - vec.iov_base = &sendchar; - vec.iov_len = sizeof(sendchar); - while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR); - if (retval != 1) { - perror("sending file descriptor"); - return -1; - } - return 0; + int retval; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; + int *p_fds; + char sendchar = 0; + + 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(fd)); + p_fds = (int *) CMSG_DATA(p_cmsg); + *p_fds = fd; + 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; + /* "To pass file descriptors or credentials you need to send/read at + * least one byte" (man 7 unix) */ + vec.iov_base = &sendchar; + vec.iov_len = sizeof(sendchar); + while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR); + if (retval != 1) { + perror("sending file descriptor"); + return -1; + } + return 0; } 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); - exit(1); + 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); + exit(1); } static void show_version(void) { - printf("fusermount version: %s\n", PACKAGE_VERSION); - exit(0); + printf("fusermount version: %s\n", PACKAGE_VERSION); + exit(0); } int main(int argc, char *argv[]) { - sigset_t sigset; - int ch; - int fd; - int res; - char *origmnt; - char *mnt; - static int unmount = 0; - static int lazy = 0; - static int quiet = 0; - char *commfd; - int cfd; - const char *opts = ""; - - static const struct option long_opts[] = { - {"unmount", no_argument, NULL, 'u'}, - {"lazy", no_argument, NULL, 'z'}, - {"quiet", no_argument, NULL, 'q'}, - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'V'}, - {0, 0, 0, 0}}; - - progname = strdup(argv[0]); - if (progname == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", argv[0]); - exit(1); - } - - while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, - NULL)) != -1) { - switch (ch) { - case 'h': - usage(); - break; - - case 'V': - show_version(); - break; - - case 'o': - opts = optarg; - break; - - case 'u': - unmount = 1; - break; - - case 'z': - lazy = 1; - break; - - case 'q': - quiet = 1; - break; - - default: - exit(1); - } - } - - if (lazy && !unmount) { - fprintf(stderr, "%s: -z can only be used with -u\n", progname); - exit(1); - } - - if (optind >= argc) { - fprintf(stderr, "%s: missing mountpoint argument\n", progname); - exit(1); - } else if (argc > optind + 1) { - fprintf(stderr, "%s: extra arguments after the mountpoint\n", - progname); - exit(1); - } - - origmnt = argv[optind]; - - drop_privs(); - mnt = fuse_mnt_resolve_path(progname, origmnt); - if (mnt != NULL) { - res = chdir("/"); - if (res == -1) { - fprintf(stderr, "%s: failed to chdir to '/'\n", progname); - exit(1); - } - } - restore_privs(); - if (mnt == NULL) - exit(1); - - umask(033); - if (unmount) - goto do_unmount; - - commfd = getenv(FUSE_COMMFD_ENV); - if (commfd == NULL) { - fprintf(stderr, "%s: old style mounting not supported\n", - progname); - exit(1); - } - - fd = mount_fuse(mnt, opts); - if (fd == -1) - exit(1); - - cfd = atoi(commfd); - res = send_fd(cfd, fd); - if (res == -1) - exit(1); - close(fd); - - if (!auto_unmount) - return 0; - - /* Become a daemon and wait for the parent to exit or die. - ie For the control socket to get closed. - btw We don't want to use daemon() function here because - it forks and messes with the file descriptors. */ - setsid(); - res = chdir("/"); - if (res == -1) { - fprintf(stderr, "%s: failed to chdir to '/'\n", progname); - exit(1); - } - - sigfillset(&sigset); - sigprocmask(SIG_BLOCK, &sigset, NULL); - - lazy = 1; - quiet = 1; - - while (1) { - unsigned char buf[16]; - int n = recv(cfd, buf, sizeof(buf), 0); - if (!n) - break; - - if (n < 0) { - if (errno == EINTR) - continue; - break; - } - } - -do_unmount: - if (geteuid() == 0) - res = unmount_fuse(mnt, quiet, lazy); - else { - res = umount2(mnt, lazy ? UMOUNT_DETACH : 0); - if (res == -1 && !quiet) - fprintf(stderr, - "%s: failed to unmount %s: %s\n", - progname, mnt, strerror(errno)); - } - if (res == -1) - exit(1); - return 0; + sigset_t sigset; + int ch; + int fd; + int res; + char *origmnt; + char *mnt; + static int unmount = 0; + static int lazy = 0; + static int quiet = 0; + char *commfd; + int cfd; + const char *opts = ""; + + static const struct option long_opts[] = { + {"unmount", no_argument, NULL, 'u'}, + {"lazy", no_argument, NULL, 'z'}, + {"quiet", no_argument, NULL, 'q'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {0, 0, 0, 0}}; + + progname = strdup(argv[0]); + if (progname == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", argv[0]); + exit(1); + } + + while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, + NULL)) != -1) { + switch (ch) { + case 'h': + usage(); + break; + + case 'V': + show_version(); + break; + + case 'o': + opts = optarg; + break; + + case 'u': + unmount = 1; + break; + + case 'z': + lazy = 1; + break; + + case 'q': + quiet = 1; + break; + + default: + exit(1); + } + } + + if (lazy && !unmount) { + fprintf(stderr, "%s: -z can only be used with -u\n", progname); + exit(1); + } + + if (optind >= argc) { + fprintf(stderr, "%s: missing mountpoint argument\n", progname); + exit(1); + } else if (argc > optind + 1) { + fprintf(stderr, "%s: extra arguments after the mountpoint\n", + progname); + exit(1); + } + + origmnt = argv[optind]; + + drop_privs(); + mnt = fuse_mnt_resolve_path(progname, origmnt); + if (mnt != NULL) { + res = chdir("/"); + if (res == -1) { + fprintf(stderr, "%s: failed to chdir to '/'\n", progname); + exit(1); + } + } + restore_privs(); + if (mnt == NULL) + exit(1); + + umask(033); + if (unmount) + goto do_unmount; + + commfd = getenv(FUSE_COMMFD_ENV); + if (commfd == NULL) { + fprintf(stderr, "%s: old style mounting not supported\n", + progname); + exit(1); + } + + fd = mount_fuse(mnt, opts); + if (fd == -1) + exit(1); + + cfd = atoi(commfd); + res = send_fd(cfd, fd); + if (res == -1) + exit(1); + close(fd); + + if (!auto_unmount) + return 0; + + /* Become a daemon and wait for the parent to exit or die. + ie For the control socket to get closed. + btw We don't want to use daemon() function here because + it forks and messes with the file descriptors. */ + setsid(); + res = chdir("/"); + if (res == -1) { + fprintf(stderr, "%s: failed to chdir to '/'\n", progname); + exit(1); + } + + sigfillset(&sigset); + sigprocmask(SIG_BLOCK, &sigset, NULL); + + lazy = 1; + quiet = 1; + + while (1) { + unsigned char buf[16]; + int n = recv(cfd, buf, sizeof(buf), 0); + if (!n) + break; + + if (n < 0) { + if (errno == EINTR) + continue; + break; + } + } + + do_unmount: + if (geteuid() == 0) + res = unmount_fuse(mnt, quiet, lazy); + else { + res = umount2(mnt, lazy ? UMOUNT_DETACH : 0); + if (res == -1 && !quiet) + fprintf(stderr, + "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); + } + if (res == -1) + exit(1); + return 0; } diff --git a/libfuse/util/mount.mergerfs.c b/libfuse/util/mount.mergerfs.c index cf447a96..9ca8c9bb 100644 --- a/libfuse/util/mount.mergerfs.c +++ b/libfuse/util/mount.mergerfs.c @@ -16,216 +16,212 @@ static char *progname; static char *xstrdup(const char *s) { - char *t = strdup(s); - if (!t) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - exit(1); - } - return t; + char *t = strdup(s); + if (!t) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + exit(1); + } + return t; } static void *xrealloc(void *oldptr, size_t size) { - void *ptr = realloc(oldptr, size); - if (!ptr) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - exit(1); - } - return ptr; + void *ptr = realloc(oldptr, size); + if (!ptr) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + exit(1); + } + return ptr; } static void add_arg(char **cmdp, const char *opt) { - size_t optlen = strlen(opt); - size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; - char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); - char *s; - s = cmd + cmdlen; - if (*cmdp) - *s++ = ' '; - - *s++ = '\''; - for (; *opt; opt++) { - if (*opt == '\'') { - *s++ = '\''; - *s++ = '\\'; - *s++ = '\''; - *s++ = '\''; - } else - *s++ = *opt; - } - *s++ = '\''; - *s = '\0'; - *cmdp = cmd; + size_t optlen = strlen(opt); + size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; + char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); + char *s; + s = cmd + cmdlen; + if (*cmdp) + *s++ = ' '; + + *s++ = '\''; + for (; *opt; opt++) { + if (*opt == '\'') { + *s++ = '\''; + *s++ = '\\'; + *s++ = '\''; + *s++ = '\''; + } else + *s++ = *opt; + } + *s++ = '\''; + *s = '\0'; + *cmdp = cmd; } static char *add_option(const char *opt, char *options) { - int oldlen = options ? strlen(options) : 0; - - options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); - if (!oldlen) - strcpy(options, opt); - else { - strcat(options, ","); - strcat(options, opt); - } - return options; + int oldlen = options ? strlen(options) : 0; + + options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); + if (!oldlen) + strcpy(options, opt); + else { + strcat(options, ","); + strcat(options, opt); + } + return options; } int main(int argc, char *argv[]) { - char *type = NULL; - char *source; - const char *mountpoint; - char *basename; - char *options = NULL; - char *command = NULL; - char *setuid = NULL; - int i; - int dev = 1; - int suid = 1; - - progname = argv[0]; - basename = strrchr(argv[0], '/'); - if (basename) - basename++; - else - basename = argv[0]; - - type = "mergerfs"; - if (strncmp(basename, "mount.fuse.", 11) == 0) - type = basename + 11; - if (strncmp(basename, "mount.fuseblk.", 14) == 0) - type = basename + 14; - - if (type && !type[0]) - type = NULL; - - if (argc < 3) { - fprintf(stderr, - "usage: %s %s destination [-t type] [-o opt[,opts...]]\n", - progname, type ? "source" : "type#[source]"); - exit(1); - } - - source = argv[1]; - if (!source[0]) - source = NULL; - - mountpoint = argv[2]; - - for (i = 3; i < argc; i++) { - if (strcmp(argv[i], "-v") == 0) { - continue; - } else if (strcmp(argv[i], "-t") == 0) { - i++; - - if (i == argc) { - fprintf(stderr, - "%s: missing argument to option '-t'\n", - progname); - exit(1); - } - type = argv[i]; - if (strncmp(type, "fuse.", 5) == 0) - type += 5; - else if (strncmp(type, "fuseblk.", 8) == 0) - type += 8; - - if (!type[0]) { - fprintf(stderr, - "%s: empty type given as argument to option '-t'\n", - progname); - exit(1); - } - } else if (strcmp(argv[i], "-o") == 0) { - char *opts; - char *opt; - i++; - if (i == argc) - break; - - opts = xstrdup(argv[i]); - opt = strtok(opts, ","); - while (opt) { - int j; - int ignore = 0; - const char *ignore_opts[] = { "", - "user", - "nouser", - "users", - "auto", - "noauto", - "_netdev", - NULL}; - if (strncmp(opt, "setuid=", 7) == 0) { - setuid = xstrdup(opt + 7); - ignore = 1; - } - for (j = 0; ignore_opts[j]; j++) - if (strcmp(opt, ignore_opts[j]) == 0) - ignore = 1; - - if (!ignore) { - if (strcmp(opt, "nodev") == 0) - dev = 0; - else if (strcmp(opt, "nosuid") == 0) - suid = 0; - - options = add_option(opt, options); - } - opt = strtok(NULL, ","); - } - } - } - - if (dev) - options = add_option("dev", options); - if (suid) - options = add_option("suid", options); - - if (!type) { - if (source) { - type = xstrdup(source); - source = strchr(type, '#'); - if (source) - *source++ = '\0'; - if (!type[0]) { - fprintf(stderr, "%s: empty filesystem type\n", - progname); - exit(1); - } - } else { - fprintf(stderr, "%s: empty source\n", progname); - exit(1); - } - } - - add_arg(&command, type); - if (source) - add_arg(&command, source); - add_arg(&command, mountpoint); - if (options) { - add_arg(&command, "-o"); - add_arg(&command, options); - } - - if (setuid && setuid[0]) { - char *sucommand = command; - command = NULL; - add_arg(&command, "su"); - add_arg(&command, "-"); - add_arg(&command, setuid); - add_arg(&command, "-c"); - add_arg(&command, sucommand); - } else if (!getenv("HOME")) { - /* Hack to make filesystems work in the boot environment */ - setenv("HOME", "/root", 0); - } - - execl("/bin/sh", "/bin/sh", "-c", command, NULL); - fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, - strerror(errno)); - return 1; + char *type = NULL; + char *source; + const char *mountpoint; + char *basename; + char *options = NULL; + char *command = NULL; + char *setuid = NULL; + int i; + int dev = 1; + int suid = 1; + + progname = argv[0]; + basename = strrchr(argv[0], '/'); + if (basename) + basename++; + else + basename = argv[0]; + + type = "mergerfs"; + if (strncmp(basename, "mount.fuse.", 11) == 0) + type = basename + 11; + + if (type && !type[0]) + type = NULL; + + if (argc < 3) { + fprintf(stderr, + "usage: %s %s destination [-t type] [-o opt[,opts...]]\n", + progname, type ? "source" : "type#[source]"); + exit(1); + } + + source = argv[1]; + if (!source[0]) + source = NULL; + + mountpoint = argv[2]; + + for (i = 3; i < argc; i++) { + if (strcmp(argv[i], "-v") == 0) { + continue; + } else if (strcmp(argv[i], "-t") == 0) { + i++; + + if (i == argc) { + fprintf(stderr, + "%s: missing argument to option '-t'\n", + progname); + exit(1); + } + type = argv[i]; + if (strncmp(type, "fuse.", 5) == 0) + type += 5; + + if (!type[0]) { + fprintf(stderr, + "%s: empty type given as argument to option '-t'\n", + progname); + exit(1); + } + } else if (strcmp(argv[i], "-o") == 0) { + char *opts; + char *opt; + i++; + if (i == argc) + break; + + opts = xstrdup(argv[i]); + opt = strtok(opts, ","); + while (opt) { + int j; + int ignore = 0; + const char *ignore_opts[] = { "", + "user", + "nouser", + "users", + "auto", + "noauto", + "_netdev", + NULL}; + if (strncmp(opt, "setuid=", 7) == 0) { + setuid = xstrdup(opt + 7); + ignore = 1; + } + for (j = 0; ignore_opts[j]; j++) + if (strcmp(opt, ignore_opts[j]) == 0) + ignore = 1; + + if (!ignore) { + if (strcmp(opt, "nodev") == 0) + dev = 0; + else if (strcmp(opt, "nosuid") == 0) + suid = 0; + + options = add_option(opt, options); + } + opt = strtok(NULL, ","); + } + } + } + + if (dev) + options = add_option("dev", options); + if (suid) + options = add_option("suid", options); + + if (!type) { + if (source) { + type = xstrdup(source); + source = strchr(type, '#'); + if (source) + *source++ = '\0'; + if (!type[0]) { + fprintf(stderr, "%s: empty filesystem type\n", + progname); + exit(1); + } + } else { + fprintf(stderr, "%s: empty source\n", progname); + exit(1); + } + } + + add_arg(&command, type); + if (source) + add_arg(&command, source); + add_arg(&command, mountpoint); + if (options) { + add_arg(&command, "-o"); + add_arg(&command, options); + } + + if (setuid && setuid[0]) { + char *sucommand = command; + command = NULL; + add_arg(&command, "su"); + add_arg(&command, "-"); + add_arg(&command, setuid); + add_arg(&command, "-c"); + add_arg(&command, sucommand); + } else if (!getenv("HOME")) { + /* Hack to make filesystems work in the boot environment */ + setenv("HOME", "/root", 0); + } + + execl("/bin/sh", "/bin/sh", "-c", command, NULL); + fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, + strerror(errno)); + return 1; } diff --git a/libfuse/util/mount_util.c b/libfuse/util/mount_util.c index defb92f6..1e348c9e 100644 --- a/libfuse/util/mount_util.c +++ b/libfuse/util/mount_util.c @@ -31,333 +31,316 @@ #else static int mtab_needs_update(const char *mnt) { - int res; - struct stat stbuf; - - /* If mtab is within new mount, don't touch it */ - if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && - _PATH_MOUNTED[strlen(mnt)] == '/') - return 0; - - /* - * Skip mtab update if /etc/mtab: - * - * - doesn't exist, - * - is a symlink, - * - is on a read-only filesystem. - */ - res = lstat(_PATH_MOUNTED, &stbuf); - if (res == -1) { - if (errno == ENOENT) - return 0; - } else { - uid_t ruid; - int err; - - if (S_ISLNK(stbuf.st_mode)) - return 0; - - ruid = getuid(); - if (ruid != 0) - setreuid(0, -1); - - res = access(_PATH_MOUNTED, W_OK); - err = (res == -1) ? errno : 0; - if (ruid != 0) - setreuid(ruid, -1); - - if (err == EROFS) - return 0; - } - - return 1; + int res; + struct stat stbuf; + + /* If mtab is within new mount, don't touch it */ + if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && + _PATH_MOUNTED[strlen(mnt)] == '/') + return 0; + + /* + * Skip mtab update if /etc/mtab: + * + * - doesn't exist, + * - is a symlink, + * - is on a read-only filesystem. + */ + res = lstat(_PATH_MOUNTED, &stbuf); + if (res == -1) { + if (errno == ENOENT) + return 0; + } else { + uid_t ruid; + int err; + + if (S_ISLNK(stbuf.st_mode)) + return 0; + + ruid = getuid(); + if (ruid != 0) + setreuid(0, -1); + + res = access(_PATH_MOUNTED, W_OK); + err = (res == -1) ? errno : 0; + if (ruid != 0) + setreuid(ruid, -1); + + if (err == EROFS) + return 0; + } + + return 1; } #endif /* __NetBSD__ */ static int add_mount(const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts) + const char *mnt, const char *type, const char *opts) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", - "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); - fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) - res = -1; + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", + "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); + fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) + res = -1; out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); + sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + return res; } int fuse_mnt_add_mount(const char *progname, const char *fsname, const char *mnt, const char *type, const char *opts) { - if (!mtab_needs_update(mnt)) - return 0; + if (!mtab_needs_update(mnt)) + return 0; - return add_mount(progname, fsname, mnt, type, opts); + return add_mount(progname, fsname, mnt, type, opts); } static int exec_umount(const char *progname, const char *rel_mnt, int lazy) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - if (lazy) { - execle("/bin/umount", "/bin/umount", "-i", rel_mnt, - "-l", NULL, &env); - } else { - execle("/bin/umount", "/bin/umount", "-i", rel_mnt, - NULL, &env); - } - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) { - res = -1; - } + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + if (lazy) { + execle("/bin/umount", "/bin/umount", "-i", rel_mnt, + "-l", NULL, &env); + } else { + execle("/bin/umount", "/bin/umount", "-i", rel_mnt, + NULL, &env); + } + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) { + res = -1; + } out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return res; } int fuse_mnt_umount(const char *progname, const char *abs_mnt, const char *rel_mnt, int lazy) { - int res; + int res; - if (!mtab_needs_update(abs_mnt)) { - res = umount2(rel_mnt, lazy ? 2 : 0); - if (res == -1) - fprintf(stderr, "%s: failed to unmount %s: %s\n", - progname, abs_mnt, strerror(errno)); - return res; - } + if (!mtab_needs_update(abs_mnt)) { + res = umount2(rel_mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, abs_mnt, strerror(errno)); + return res; + } - return exec_umount(progname, rel_mnt, lazy); + return exec_umount(progname, rel_mnt, lazy); } static int remove_mount(const char *progname, const char *mnt) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); - return -1; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - goto out_restore; - } - if (res == 0) { - char *env = NULL; - - sigprocmask(SIG_SETMASK, &oldmask, NULL); - setuid(geteuid()); - execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", - "--fake", mnt, NULL, &env); - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", - progname, strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - - if (status != 0) - res = -1; + int res; + int status; + sigset_t blockmask; + sigset_t oldmask; + + sigemptyset(&blockmask); + sigaddset(&blockmask, SIGCHLD); + res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); + if (res == -1) { + fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); + return -1; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + goto out_restore; + } + if (res == 0) { + char *env = NULL; + + sigprocmask(SIG_SETMASK, &oldmask, NULL); + setuid(geteuid()); + execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", + "--fake", mnt, NULL, &env); + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + + if (status != 0) + res = -1; out_restore: - sigprocmask(SIG_SETMASK, &oldmask, NULL); - return res; + sigprocmask(SIG_SETMASK, &oldmask, NULL); + return res; } int fuse_mnt_remove_mount(const char *progname, const char *mnt) { - if (!mtab_needs_update(mnt)) - return 0; + if (!mtab_needs_update(mnt)) + return 0; - return remove_mount(progname, mnt); + return remove_mount(progname, mnt); } char *fuse_mnt_resolve_path(const char *progname, const char *orig) { - char buf[PATH_MAX]; - char *copy; - char *dst; - char *end; - char *lastcomp; - const char *toresolv; - - if (!orig[0]) { - fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, - orig); - return NULL; - } - - copy = strdup(orig); - if (copy == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return NULL; - } - - toresolv = copy; - lastcomp = NULL; - for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); - if (end[0] != '/') { - char *tmp; - end[1] = '\0'; - tmp = strrchr(copy, '/'); - if (tmp == NULL) { - lastcomp = copy; - toresolv = "."; - } else { - lastcomp = tmp + 1; - if (tmp == copy) - toresolv = "/"; - } - if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { - lastcomp = NULL; - toresolv = copy; - } - else if (tmp) - tmp[0] = '\0'; - } - if (realpath(toresolv, buf) == NULL) { - fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, - strerror(errno)); - free(copy); - return NULL; - } - if (lastcomp == NULL) - dst = strdup(buf); - else { - dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); - if (dst) { - unsigned buflen = strlen(buf); - if (buflen && buf[buflen-1] == '/') - sprintf(dst, "%s%s", buf, lastcomp); - else - sprintf(dst, "%s/%s", buf, lastcomp); - } - } - free(copy); - if (dst == NULL) - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return dst; + char buf[PATH_MAX]; + char *copy; + char *dst; + char *end; + char *lastcomp; + const char *toresolv; + + if (!orig[0]) { + fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, + orig); + return NULL; + } + + copy = strdup(orig); + if (copy == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return NULL; + } + + toresolv = copy; + lastcomp = NULL; + for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); + if (end[0] != '/') { + char *tmp; + end[1] = '\0'; + tmp = strrchr(copy, '/'); + if (tmp == NULL) { + lastcomp = copy; + toresolv = "."; + } else { + lastcomp = tmp + 1; + if (tmp == copy) + toresolv = "/"; + } + if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { + lastcomp = NULL; + toresolv = copy; + } + else if (tmp) + tmp[0] = '\0'; + } + if (realpath(toresolv, buf) == NULL) { + fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, + strerror(errno)); + free(copy); + return NULL; + } + if (lastcomp == NULL) + dst = strdup(buf); + else { + dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); + if (dst) { + unsigned buflen = strlen(buf); + if (buflen && buf[buflen-1] == '/') + sprintf(dst, "%s%s", buf, lastcomp); + else + sprintf(dst, "%s/%s", buf, lastcomp); + } + } + free(copy); + if (dst == NULL) + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return dst; } int fuse_mnt_check_empty(const char *progname, const char *mnt, mode_t rootmode, off_t rootsize) { - int isempty = 1; - - if (S_ISDIR(rootmode)) { - struct dirent *ent; - DIR *dp = opendir(mnt); - if (dp == NULL) { - fprintf(stderr, - "%s: failed to open mountpoint for reading: %s\n", - progname, strerror(errno)); - return -1; - } - while ((ent = readdir(dp)) != NULL) { - if (strcmp(ent->d_name, ".") != 0 && - strcmp(ent->d_name, "..") != 0) { - isempty = 0; - break; - } - } - closedir(dp); - } else if (rootsize) - isempty = 0; - - if (!isempty) { - fprintf(stderr, "%s: mountpoint is not empty\n", progname); - fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); - return -1; - } - return 0; -} - -int fuse_mnt_check_fuseblk(void) -{ - char buf[256]; - FILE *f = fopen("/proc/filesystems", "r"); - if (!f) - return 1; - - while (fgets(buf, sizeof(buf), f)) - if (strstr(buf, "fuseblk\n")) { - fclose(f); - return 1; - } - - fclose(f); - return 0; + int isempty = 1; + + if (S_ISDIR(rootmode)) { + struct dirent *ent; + DIR *dp = opendir(mnt); + if (dp == NULL) { + fprintf(stderr, + "%s: failed to open mountpoint for reading: %s\n", + progname, strerror(errno)); + return -1; + } + while ((ent = readdir(dp)) != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) { + isempty = 0; + break; + } + } + closedir(dp); + } else if (rootsize) + isempty = 0; + + if (!isempty) { + fprintf(stderr, "%s: mountpoint is not empty\n", progname); + fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); + return -1; + } + return 0; } diff --git a/src/config.cpp b/src/config.cpp index b64cde4f..33d60aca 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -55,7 +55,7 @@ Config::Config() writeback_cache(false), readdirplus(false), cache_files(CacheFiles::LIBFUSE), - fuse_msg_size(FUSE_MAX_MAX_PAGES), + fuse_msg_size(FUSE_MSG_MAX_PAGES), POLICYINIT(access), POLICYINIT(chmod), POLICYINIT(chown), diff --git a/src/fuse_init.cpp b/src/fuse_init.cpp index da875a97..d15bb52f 100644 --- a/src/fuse_init.cpp +++ b/src/fuse_init.cpp @@ -73,7 +73,7 @@ namespace l } else { - c_.fuse_msg_size = FUSE_DEFAULT_MAX_PAGES_PER_REQ; + c_.fuse_msg_size = FUSE_MSG_DEFAULT_PAGES; } } } diff --git a/src/option_parser.cpp b/src/option_parser.cpp index a6361124..a335d168 100644 --- a/src/option_parser.cpp +++ b/src/option_parser.cpp @@ -382,7 +382,7 @@ parse_and_process_kv_arg(Config &config, else if(key == "fuse_msg_size") rv = parse_and_process(value,config.fuse_msg_size, 1, - FUSE_MAX_MAX_PAGES); + FUSE_MSG_MAX_PAGES); } if(rv == -1)