From: Ɓukasz Stelmach Date: Tue, 21 Mar 2023 15:35:04 +0000 (+0100) Subject: Imported Upstream version 2.9.9 X-Git-Tag: upstream/2.9.9 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Ftags%2Fupstream%2F2.9.9;p=platform%2Fupstream%2Ffuse.git Imported Upstream version 2.9.9 --- diff --git a/AUTHORS b/AUTHORS index c5ad56c..afc4e6b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,21 +16,18 @@ Contributors CUSE has been written by Tejun Heo . Furthermore, the following people have contributed patches (autogenerated list): +Alexander Anatol Pomozov -Christopher Harrison +Bill Zissimopoulos +Carl Edquist Csaba Henk -cvs2git <> Dalvik Khertel Daniel Thau David McNab Emmanuel Dreyfus -Enke Chen -Eric Wong Fabrice Bauzac -Feng Shuo -Ikey Doherty -Joachim Schiele -Joachim Schiele +Hendrik Brueckner +Jann Horn John Muir Laszlo Papp Madan Valluri @@ -45,9 +42,7 @@ Nikolaus Rath Olivier Blin Ratna_Bolla@dell.com Reuben Hawkins -Richard W.M. Jones -Riku Voipio Roland Bauerschmidt +Rostislav Skudnov Sebastian Pipping therealneworld@gmail.com -Winfried Koehler diff --git a/ChangeLog b/ChangeLog index 18358dc..13a369f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +FUSE 2.9.9 (2019-01-04) +======================= + +* Added OpenAFS to whitelist (so users can now mount FUSE filesystems + on mountpoints within OpenAFS filesystems). +* Added a test of `seekdir` to test_syscalls. +* Fixed `readdir` bug when non-zero offsets are given to filler and the + filesystem client, after reading a whole directory, re-reads it from a + non-zero offset e. g. by calling `seekdir` followed by `readdir`. + +FUSE 2.9.8 (2018-07-24) +======================= + +* SECURITY UPDATE: In previous versions of libfuse it was possible to + for unprivileged users to specify the `allow_other` option even when + this was forbidden in `/etc/fuse.conf`. The vulnerability is + present only on systems where SELinux is active (including in + permissive mode). +* libfuse no longer segfaults when fuse_interrupted() is called outside + the event loop. +* The fusermount binary has been hardened in several ways to reduce + potential attack surface. Most importantly, mountpoints and mount + options must now match a hard-coded whitelist. It is expected that + this whitelist covers all regular use-cases. +* Fixed rename deadlock on FreeBSD. + +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) ======================= diff --git a/Makefile.in b/Makefile.in index f506b60..95cd2c4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -80,11 +90,6 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = . -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/configure $(am__configure_deps) \ - $(srcdir)/fuse.pc.in AUTHORS COPYING COPYING.LIB ChangeLog \ - NEWS compile config.guess config.rpath config.sub depcomp \ - install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -92,6 +97,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d @@ -183,6 +190,9 @@ ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/fuse.pc.in AUTHORS \ + COPYING COPYING.LIB ChangeLog NEWS compile config.guess \ + config.rpath config.sub install-sh ltmain.sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -267,6 +277,7 @@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ @@ -338,6 +349,7 @@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -377,7 +389,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -616,15 +627,15 @@ dist-xz: distdir $(am__post_remove_distdir) dist-tarZ: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) @@ -660,17 +671,17 @@ distcheck: dist esac chmod -R a-w $(distdir) chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_inst + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build \ - && ../configure \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=.. --prefix="$$dc_install_base" \ + --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ @@ -850,6 +861,8 @@ uninstall-am: uninstall-pkgconfigDATA mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkgconfigDATA +.PRECIOUS: Makefile + $(pkgconfig_DATA): config.status diff --git a/README.md b/README.md index 389a272..2243a12 100644 --- a/README.md +++ b/README.md @@ -105,3 +105,4 @@ 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/aclocal.m4 b/aclocal.m4 index fe9ee2b..8f8b465 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.14.1 -*- Autoconf -*- +# generated automatically by aclocal 1.15 -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -20,8 +20,8 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# iconv.m4 serial 18 (gettext-0.18.2) -dnl Copyright (C) 2000-2002, 2007-2014 Free Software Foundation, Inc. +# iconv.m4 serial 19 (gettext-0.18.2) +dnl Copyright (C) 2000-2002, 2007-2014, 2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -94,27 +94,33 @@ AC_DEFUN([AM_ICONV_LINK], if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ + am_cv_func_iconv_works=no + for ac_iconv_const in '' 'const'; do + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[ #include #include -int main () -{ - int result = 0; + +#ifndef ICONV_CONST +# define ICONV_CONST $ac_iconv_const +#endif + ]], + [[int result = 0; /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { - static const char input[] = "\342\202\254"; /* EURO SIGN */ + static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 1; @@ -127,14 +133,14 @@ int main () iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); if (cd_ascii_to_88591 != (iconv_t)(-1)) { - static const char input[] = "\263"; + static ICONV_CONST char input[] = "\263"; char buf[10]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_ascii_to_88591, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 2; @@ -146,14 +152,14 @@ int main () iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { - static const char input[] = "\304"; + static ICONV_CONST char input[] = "\304"; static char buf[2] = { (char)0xDE, (char)0xAD }; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = 1; char *outptr = buf; size_t outbytesleft = 1; size_t res = iconv (cd_88591_to_utf8, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) result |= 4; @@ -166,14 +172,14 @@ int main () iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { - static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) result |= 8; @@ -193,17 +199,14 @@ int main () && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) result |= 16; return result; -}]])], - [am_cv_func_iconv_works=yes], - [am_cv_func_iconv_works=no], - [ -changequote(,)dnl - case "$host_os" in - aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; - *) am_cv_func_iconv_works="guessing yes" ;; - esac -changequote([,])dnl - ]) +]])], + [am_cv_func_iconv_works=yes], , + [case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac]) + test "$am_cv_func_iconv_works" = no || break + done LIBS="$am_save_LIBS" ]) case "$am_cv_func_iconv_works" in @@ -290,7 +293,7 @@ size_t iconv(); ]) # lib-ld.m4 serial 6 -dnl Copyright (C) 1996-2003, 2009-2014 Free Software Foundation, Inc. +dnl Copyright (C) 1996-2003, 2009-2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -410,7 +413,7 @@ AC_LIB_PROG_LD_GNU ]) # lib-link.m4 serial 26 (gettext-0.18.2) -dnl Copyright (C) 2001-2014 Free Software Foundation, Inc. +dnl Copyright (C) 2001-2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -1188,7 +1191,7 @@ AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], ]) # lib-prefix.m4 serial 7 (gettext-0.18) -dnl Copyright (C) 2001-2005, 2008-2014 Free Software Foundation, Inc. +dnl Copyright (C) 2001-2005, 2008-2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -1412,7 +1415,7 @@ sixtyfour bits test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" ]) -# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# Copyright (C) 2002-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1424,10 +1427,10 @@ sixtyfour bits # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.14' +[am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.14.1], [], +m4_if([$1], [1.15], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -1443,14 +1446,14 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.14.1])dnl +[AM_AUTOMAKE_VERSION([1.15])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1502,7 +1505,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1533,7 +1536,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1724,7 +1727,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1800,7 +1803,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1890,8 +1893,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl @@ -1965,6 +1968,9 @@ END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not @@ -1994,7 +2000,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2005,7 +2011,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh}" != xset; then +if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; @@ -2015,7 +2021,7 @@ if test x"${install_sh}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# Copyright (C) 2003-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2036,7 +2042,7 @@ AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2086,7 +2092,7 @@ rm -f confinc confmf # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2125,7 +2131,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2154,7 +2160,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2201,7 +2207,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2220,7 +2226,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2301,7 +2307,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# Copyright (C) 2009-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2361,7 +2367,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2389,7 +2395,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2013 Free Software Foundation, Inc. +# Copyright (C) 2006-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -2408,7 +2414,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2013 Free Software Foundation, Inc. +# Copyright (C) 2004-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/compile b/compile index 531136b..a85b723 100755 --- a/compile +++ b/compile @@ -3,7 +3,7 @@ scriptversion=2012-10-14.11; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify diff --git a/config.guess b/config.guess index 1f5c50c..2e9ad7f 100755 --- a/config.guess +++ b/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2014-03-23' +timestamp='2016-10-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ timestamp='2014-03-23' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. + # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ @@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in os=netbsd ;; esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" + echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` @@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; @@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build - SUN_ARCH="i386" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` @@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} @@ -579,8 +603,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi @@ -617,13 +642,13 @@ EOF sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi @@ -662,11 +687,11 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build @@ -679,12 +704,12 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -789,14 +814,14 @@ EOF echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -878,7 +903,7 @@ EOF exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix @@ -901,7 +926,7 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) @@ -932,6 +957,9 @@ EOF crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -944,6 +972,9 @@ EOF ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -969,6 +1000,9 @@ EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; @@ -1001,6 +1035,9 @@ EOF ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; @@ -1020,7 +1057,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} @@ -1099,7 +1136,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; @@ -1248,6 +1285,9 @@ EOF SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; @@ -1261,9 +1301,9 @@ EOF UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in @@ -1285,7 +1325,7 @@ EOF exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi @@ -1316,7 +1356,7 @@ EOF # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" @@ -1358,7 +1398,7 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos @@ -1369,23 +1409,25 @@ EOF x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; esac cat >&2 < in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp diff --git a/config.rpath b/config.rpath index b625621..98183ff 100755 --- a/config.rpath +++ b/config.rpath @@ -2,7 +2,7 @@ # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # -# Copyright 1996-2014 Free Software Foundation, Inc. +# Copyright 1996-2016 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # diff --git a/config.sub b/config.sub index bba4efb..dd2ca93 100755 --- a/config.sub +++ b/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2014-09-11' +timestamp='2016-11-04' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ timestamp='2014-09-11' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -33,7 +33,7 @@ timestamp='2014-09-11' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -53,8 +53,7 @@ timestamp='2014-09-11' me=`echo "$0" | sed -e 's,.*/,,'` usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. @@ -68,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -255,12 +254,13 @@ case $basic_machine in | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ @@ -301,11 +301,12 @@ case $basic_machine in | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -313,6 +314,7 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -327,6 +329,9 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none @@ -372,12 +377,13 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ + | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ @@ -423,13 +429,15 @@ case $basic_machine in | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ | pyramid-* \ + | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -437,6 +445,7 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -513,6 +522,9 @@ case $basic_machine in basic_machine=i386-pc os=-aros ;; + asmjs) + basic_machine=asmjs-unknown + ;; aux) basic_machine=m68k-apple os=-aux @@ -633,6 +645,14 @@ case $basic_machine in basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -774,6 +794,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -1009,7 +1032,7 @@ case $basic_machine in ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1019,7 +1042,7 @@ case $basic_machine in ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) @@ -1365,18 +1388,18 @@ case $os in | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ @@ -1385,7 +1408,8 @@ case $os in | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1517,6 +1541,8 @@ case $os in ;; -nacl*) ;; + -ios) + ;; -none) ;; *) diff --git a/configure b/configure index 31dbc61..47df8b3 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for fuse 2.9.6. +# Generated by GNU Autoconf 2.69 for fuse 2.9.9. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='fuse' PACKAGE_TARNAME='fuse' -PACKAGE_VERSION='2.9.6' -PACKAGE_STRING='fuse 2.9.6' +PACKAGE_VERSION='2.9.9' +PACKAGE_STRING='fuse 2.9.9' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -649,6 +649,7 @@ LTLIBICONV LIBICONV pkgconfigdir CPP +LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO @@ -745,6 +746,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -772,6 +774,7 @@ enable_shared enable_static with_pic enable_fast_install +with_aix_soname enable_dependency_tracking with_gnu_ld with_sysroot @@ -792,6 +795,7 @@ CFLAGS LDFLAGS LIBS CPPFLAGS +LT_SYS_LIBRARY_PATH CPP' @@ -831,6 +835,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1083,6 +1088,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1220,7 +1234,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1333,7 +1347,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures fuse 2.9.6 to adapt to many kinds of systems. +\`configure' configures fuse 2.9.9 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1373,6 +1387,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1404,7 +1419,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of fuse 2.9.6:";; + short | recursive ) echo "Configuration of fuse 2.9.9:";; esac cat <<\_ACEOF @@ -1434,9 +1449,12 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] + --with-aix-soname=aix|svr4|both + shared library versioning (aka "SONAME") variant to + provide on AIX, [default=aix]. --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-sysroot=DIR Search for dependent libraries within DIR - (or the compiler's sysroot if not specified). + --with-sysroot[=DIR] Search for dependent libraries within DIR (or the + compiler's sysroot if not specified). --with-pkgconfigdir=DIR pkgconfig file in DIR [LIBDIR/pkgconfig] --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib --with-gnu-ld assume the C compiler uses GNU ld [default=no] @@ -1451,6 +1469,8 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory + LT_SYS_LIBRARY_PATH + User-defined run-time library search path. CPP C preprocessor Use these variables to override the choices made by `configure' or to help @@ -1519,7 +1539,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -fuse configure 2.9.6 +fuse configure 2.9.9 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1854,7 +1874,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by fuse $as_me 2.9.6, which was +It was created by fuse $as_me 2.9.9, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2344,7 +2364,7 @@ test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- -am__api_version='1.14' +am__api_version='1.15' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or @@ -2536,7 +2556,7 @@ else $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi -if test x"${install_sh}" != xset; then +if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; @@ -2830,7 +2850,7 @@ fi # Define the identity of the package. PACKAGE='fuse' - VERSION='2.9.6' + VERSION='2.9.9' cat >>confdefs.h <<_ACEOF @@ -2864,8 +2884,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # mkdir_p='$(MKDIR_P)' -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' @@ -2973,8 +2993,8 @@ esac -macro_version='2.4.2' -macro_revision='1.3337' +macro_version='2.4.6' +macro_revision='2.4.6' @@ -2988,7 +3008,7 @@ macro_revision='1.3337' -ltmain="$ac_aux_dir/ltmain.sh" +ltmain=$ac_aux_dir/ltmain.sh # Backslashify metacharacters that are still active within # double-quoted strings. @@ -3037,7 +3057,7 @@ func_echo_all () $ECHO "" } -case "$ECHO" in +case $ECHO in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 @@ -4399,19 +4419,19 @@ test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld -if test "$GCC" = yes; then +if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw + # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; @@ -4425,7 +4445,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; } while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done - test -z "$LD" && LD="$ac_prog" + test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. @@ -4436,7 +4456,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; } with_gnu_ld=unknown ;; esac -elif test "$with_gnu_ld" = yes; then +elif test yes = "$with_gnu_ld"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else @@ -4447,32 +4467,32 @@ if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" + lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } @@ -4515,33 +4535,38 @@ if ${lt_cv_path_NM+:} false; then : else if test -n "$NM"; then # Let the user override the test. - lt_cv_path_NM="$NM" + lt_cv_path_NM=$NM else - lt_nm_to_check="${ac_tool_prefix}nm" + lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. - tmp_nm="$ac_dir/$lt_tmp_nm" - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file - case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in - */dev/null* | *'Invalid file or object type'*) + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" - break + break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" - break + break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but @@ -4552,15 +4577,15 @@ else esac fi done - IFS="$lt_save_ifs" + IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } -if test "$lt_cv_path_NM" != "no"; then - NM="$lt_cv_path_NM" +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : @@ -4666,9 +4691,9 @@ esac fi fi - case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) - DUMPBIN="$DUMPBIN -symbols" + DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: @@ -4676,8 +4701,8 @@ fi esac fi - if test "$DUMPBIN" != ":"; then - NM="$DUMPBIN" + if test : != "$DUMPBIN"; then + NM=$DUMPBIN fi fi test -z "$NM" && NM=nm @@ -4728,7 +4753,7 @@ if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 - teststring="ABCD" + teststring=ABCD case $build_os in msdosdjgpp*) @@ -4768,7 +4793,7 @@ else lt_cv_sys_max_cmd_len=8192; ;; - netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` @@ -4819,22 +4844,22 @@ else *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then + test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8 ; do + for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. - while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && - test $i != 17 # 1/2 MB should be enough + test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring @@ -4852,7 +4877,7 @@ else fi -if test -n $lt_cv_sys_max_cmd_len ; then +if test -n "$lt_cv_sys_max_cmd_len"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else @@ -4870,30 +4895,6 @@ max_cmd_len=$lt_cv_sys_max_cmd_len : ${MV="mv -f"} : ${RM="rm -f"} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 -$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } -# Try some XSI features -xsi_shell=no -( _lt_dummy="a/b/c" - test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ - = c,a/b,b/c, \ - && eval 'test $(( 1 + 1 )) -eq 2 \ - && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ - && xsi_shell=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 -$as_echo "$xsi_shell" >&6; } - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 -$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } -lt_shell_append=no -( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ - >/dev/null 2>&1 \ - && lt_shell_append=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 -$as_echo "$lt_shell_append" >&6; } - - if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else @@ -5016,13 +5017,13 @@ esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) - if test "$GCC" != yes; then + if test yes != "$GCC"; then reload_cmds=false fi ;; darwin*) - if test "$GCC" = yes; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + if test yes = "$GCC"; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi @@ -5150,13 +5151,13 @@ lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. -# `unknown' -- same as none, but documents that we really don't know. +# 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path -# which responds to the $file_magic_cmd with a given extended regex. -# If you have `file' or equivalent on your system and you're not sure -# whether `pass_all' will *always* work, you probably want this one. +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) @@ -5183,8 +5184,7 @@ mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. - # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. - if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else @@ -5280,8 +5280,8 @@ newos6*) lt_cv_deplibs_check_method=pass_all ;; -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' @@ -5334,6 +5334,9 @@ sysv4 | sysv4.3*) tpf*) lt_cv_deplibs_check_method=pass_all ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; esac fi @@ -5491,8 +5494,8 @@ else case $host_os in cygwin* | mingw* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh - # decide which to use based on capabilities of $DLLTOOL + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib @@ -5504,7 +5507,7 @@ cygwin* | mingw* | pw32* | cegcc*) ;; *) # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd="$ECHO" + lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac @@ -5659,7 +5662,7 @@ if ac_fn_c_try_compile "$LINENO"; then : ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } - if test "$ac_status" -eq 0; then + if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 @@ -5667,7 +5670,7 @@ if ac_fn_c_try_compile "$LINENO"; then : ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } - if test "$ac_status" -ne 0; then + if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi @@ -5680,7 +5683,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } -if test "x$lt_cv_ar_at_file" = xno; then +if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file @@ -5897,7 +5900,7 @@ old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in - openbsd*) + bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) @@ -5987,7 +5990,7 @@ cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) - if test "$host_cpu" = ia64; then + if test ia64 = "$host_cpu"; then symcode='[ABCDEGRST]' fi ;; @@ -6020,14 +6023,44 @@ case `$NM -V 2>&1` in symcode='[ABCDGIRSTW]' ;; esac +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= @@ -6045,21 +6078,24 @@ for ac_symprfx in "" "_"; do # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function - # and D for any global variable. + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ -" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ -" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ -" s[1]~/^[@?]/{print s[1], s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" @@ -6107,11 +6143,11 @@ _LT_EOF if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) -/* DATA imports from DLLs on WIN32 con't be const, because runtime +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST -#elif defined(__osf__) +#elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else @@ -6137,7 +6173,7 @@ lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; @@ -6157,13 +6193,13 @@ _LT_EOF mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS - LIBS="conftstm.$ac_objext" + LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext}; then + test $ac_status = 0; } && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS @@ -6184,7 +6220,7 @@ _LT_EOF rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then + if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= @@ -6237,6 +6273,16 @@ fi + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } @@ -6249,9 +6295,9 @@ fi lt_sysroot= -case ${with_sysroot} in #( +case $with_sysroot in #( yes) - if test "$GCC" = yes; then + if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( @@ -6261,8 +6307,8 @@ case ${with_sysroot} in #( no|'') ;; #( *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 -$as_echo "${with_sysroot}" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 +$as_echo "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac @@ -6274,18 +6320,99 @@ $as_echo "${lt_sysroot:-no}" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 +$as_echo_n "checking for a working dd... " >&6; } +if ${ac_cv_path_lt_DD+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +if test -z "$lt_DD"; then + ac_path_lt_DD_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in dd; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_lt_DD" || continue +if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi + $ac_path_lt_DD_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_lt_DD"; then + : + fi +else + ac_cv_path_lt_DD=$lt_DD +fi + +rm -f conftest.i conftest2.i conftest.out +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 +$as_echo "$ac_cv_path_lt_DD" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 +$as_echo_n "checking how to truncate binary pipes... " >&6; } +if ${lt_cv_truncate_bin+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 +$as_echo "$lt_cv_truncate_bin" >&6; } + + + + + + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes +test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) - # Find out which ABI we are using. + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 @@ -6294,24 +6421,25 @@ ia64-*-hpux*) test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) - HPUX_IA64_MODE="32" + HPUX_IA64_MODE=32 ;; *ELF-64*) - HPUX_IA64_MODE="64" + HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) - # Find out which ABI we are using. + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - if test "$lt_cv_prog_gnu_ld" = yes; then + if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" @@ -6340,9 +6468,50 @@ ia64-*-hpux*) rm -rf conftest* ;; +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) - # Find out which ABI we are using. + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 @@ -6365,10 +6534,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) ;; esac ;; - powerpc64le-*) + powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; - powerpc64-*) + powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) @@ -6387,10 +6556,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; - powerpcle-*) + powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; - powerpc-*) + powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) @@ -6408,7 +6577,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS="$CFLAGS" + SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } @@ -6448,13 +6617,14 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } - if test x"$lt_cv_cc_needs_belf" != x"yes"; then + if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS="$SAVE_CFLAGS" + CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) - # Find out which ABI we are using. + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 @@ -6466,7 +6636,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } case $lt_cv_prog_gnu_ld in yes*) case $host in - i?86-*-solaris*) + i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) @@ -6475,7 +6645,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD="${LD-ld}_sol2" + LD=${LD-ld}_sol2 fi ;; *) @@ -6491,7 +6661,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } ;; esac -need_locks="$enable_libtool_lock" +need_locks=$enable_libtool_lock if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. @@ -6602,7 +6772,7 @@ else fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } -if test "x$lt_cv_path_mainfest_tool" != xyes; then +if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi @@ -7105,7 +7275,7 @@ if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no - if test -z "${LT_MULTI_MODULE}"; then + if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the @@ -7123,7 +7293,7 @@ else cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. - elif test -f libconftest.dylib && test $_lt_result -eq 0; then + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 @@ -7162,7 +7332,7 @@ else fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" + LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 @@ -7191,7 +7361,7 @@ _LT_EOF _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 - elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&5 @@ -7204,32 +7374,32 @@ fi $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - 10.[012]*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + 10.[012][,.]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac - if test "$lt_cv_apple_cc_single_mod" = "yes"; then + if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi - if test "$lt_cv_ld_exported_symbols_list" = "yes"; then - _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi - if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= @@ -7237,6 +7407,41 @@ $as_echo "$lt_cv_ld_force_load" >&6; } ;; esac +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -7540,14 +7745,14 @@ if test "${enable_shared+set}" = set; then : *) enable_shared=no # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done - IFS="$lt_save_ifs" + IFS=$lt_save_ifs ;; esac else @@ -7571,14 +7776,14 @@ if test "${enable_static+set}" = set; then : *) enable_static=no # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done - IFS="$lt_save_ifs" + IFS=$lt_save_ifs ;; esac else @@ -7602,14 +7807,14 @@ if test "${with_pic+set}" = set; then : *) pic_mode=default # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done - IFS="$lt_save_ifs" + IFS=$lt_save_ifs ;; esac else @@ -7617,8 +7822,6 @@ else fi -test -z "$pic_mode" && pic_mode=default - @@ -7634,14 +7837,14 @@ if test "${enable_fast_install+set}" = set; then : *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done - IFS="$lt_save_ifs" + IFS=$lt_save_ifs ;; esac else @@ -7655,11 +7858,63 @@ fi + shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[5-9]*,yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 +$as_echo_n "checking which variant of shared library versioning to provide... " >&6; } + +# Check whether --with-aix-soname was given. +if test "${with_aix_soname+set}" = set; then : + withval=$with_aix_soname; case $withval in + aix|svr4|both) + ;; + *) + as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname +else + if ${lt_cv_with_aix_soname+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_with_aix_soname=aix +fi + + with_aix_soname=$lt_cv_with_aix_soname +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 +$as_echo "$with_aix_soname" >&6; } + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + + + + + + + # This can be used to rebuild libtool when needed -LIBTOOL_DEPS="$ltmain" +LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' @@ -7708,7 +7963,7 @@ test -z "$LN_S" && LN_S="ln -s" -if test -n "${ZSH_VERSION+set}" ; then +if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi @@ -7747,7 +8002,7 @@ aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. - if test "X${COLLECT_NAMES+set}" != Xset; then + if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi @@ -7758,14 +8013,14 @@ esac ofile=libtool can_build_shared=yes -# All known linkers require a `.a' archive for static linking (except MSVC, +# All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a -with_gnu_ld="$lt_cv_prog_gnu_ld" +with_gnu_ld=$lt_cv_prog_gnu_ld -old_CC="$CC" -old_CFLAGS="$CFLAGS" +old_CC=$CC +old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc @@ -7774,15 +8029,8 @@ test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +func_cc_basename $compiler +cc_basename=$func_cc_basename_result # Only perform the check for file, if the check method requires it @@ -7797,22 +8045,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then : else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/${ac_tool_prefix}file; then - lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -f "$ac_dir/${ac_tool_prefix}file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : @@ -7835,13 +8083,13 @@ _LT_EOF break fi done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } @@ -7863,22 +8111,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then : else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" + IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/file; then - lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -f "$ac_dir/file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : @@ -7901,13 +8149,13 @@ _LT_EOF break fi done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } @@ -7928,7 +8176,7 @@ esac # Use C for the default configuration in the libtool script -lt_save_CC="$CC" +lt_save_CC=$CC ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -7990,7 +8238,7 @@ if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= -if test "$GCC" = yes; then +if test yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; @@ -8006,7 +8254,7 @@ else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" + lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins @@ -8036,7 +8284,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } -if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then +if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : @@ -8054,17 +8302,18 @@ lt_prog_compiler_pic= lt_prog_compiler_static= - if test "$GCC" = yes; then + if test yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. - if test "$host_cpu" = ia64; then + if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi + lt_prog_compiler_pic='-fPIC' ;; amigaos*) @@ -8075,8 +8324,8 @@ lt_prog_compiler_static= ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac @@ -8092,6 +8341,11 @@ lt_prog_compiler_static= # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac ;; darwin* | rhapsody*) @@ -8162,7 +8416,7 @@ lt_prog_compiler_static= case $host_os in aix*) lt_prog_compiler_wl='-Wl,' - if test "$host_cpu" = ia64; then + if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else @@ -8170,10 +8424,29 @@ lt_prog_compiler_static= fi ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac ;; hpux9* | hpux10* | hpux11*) @@ -8189,7 +8462,7 @@ lt_prog_compiler_static= ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='${wl}-a ${wl}archive' + lt_prog_compiler_static='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) @@ -8200,7 +8473,7 @@ lt_prog_compiler_static= linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in - # old Intel for x86_64 which still supported -KPIC. + # old Intel for x86_64, which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' @@ -8225,6 +8498,12 @@ lt_prog_compiler_static= lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) @@ -8322,7 +8601,7 @@ lt_prog_compiler_static= ;; sysv4*MP*) - if test -d /usr/nec ;then + if test -d /usr/nec; then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi @@ -8351,7 +8630,7 @@ lt_prog_compiler_static= fi case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: + # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; @@ -8383,7 +8662,7 @@ else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins @@ -8413,7 +8692,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } -if test x"$lt_cv_prog_compiler_pic_works" = xyes; then +if test yes = "$lt_cv_prog_compiler_pic_works"; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; @@ -8445,7 +8724,7 @@ if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no - save_LDFLAGS="$LDFLAGS" + save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then @@ -8464,13 +8743,13 @@ else fi fi $RM -r conftest* - LDFLAGS="$save_LDFLAGS" + LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } -if test x"$lt_cv_prog_compiler_static_works" = xyes; then +if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= @@ -8590,8 +8869,8 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; } -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } @@ -8603,9 +8882,9 @@ $as_echo_n "checking if we can lock with hard links... " >&6; } ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } - if test "$hard_links" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + if test no = "$hard_links"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} need_locks=warn fi else @@ -8648,9 +8927,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if @@ -8665,7 +8944,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. - if test "$GCC" != yes; then + if test yes != "$GCC"; then with_gnu_ld=no fi ;; @@ -8673,7 +8952,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; - openbsd*) + openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) @@ -8686,7 +8965,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no - if test "$with_gnu_ld" = yes; then + if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility @@ -8708,24 +8987,24 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie esac fi - if test "$lt_use_gnu_ld_interface" = yes; then + if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' + wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec='${wl}--export-dynamic' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + export_dynamic_flag_spec='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no - case `$LD -v 2>&1` in + case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... @@ -8738,7 +9017,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then + if test ia64 != "$host_cpu"; then ld_shlibs=no cat <<_LT_EOF 1>&2 @@ -8757,7 +9036,7 @@ _LT_EOF case $host_cpu in powerpc) # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) @@ -8773,7 +9052,7 @@ _LT_EOF allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else ld_shlibs=no fi @@ -8783,7 +9062,7 @@ _LT_EOF # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='${wl}--export-all-symbols' + export_dynamic_flag_spec='$wl--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes @@ -8791,61 +9070,89 @@ _LT_EOF exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' link_all_deplibs=yes ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no - if test "$host_os" = linux-dietlibc; then + if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test "$tmp_diet" = no + && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; @@ -8856,42 +9163,47 @@ _LT_EOF lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - if test "x$supports_anon_versioning" = xyes; then + if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in + tcc*) + export_dynamic_flag_spec='-rdynamic' + ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test "x$supports_anon_versioning" = xyes; then + if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac @@ -8905,8 +9217,8 @@ _LT_EOF archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; @@ -8924,8 +9236,8 @@ _LT_EOF _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi @@ -8937,7 +9249,7 @@ _LT_EOF ld_shlibs=no cat <<_LT_EOF 1>&2 -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify @@ -8952,9 +9264,9 @@ _LT_EOF # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi @@ -8971,15 +9283,15 @@ _LT_EOF *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac - if test "$ld_shlibs" = no; then + if test no = "$ld_shlibs"; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= @@ -8995,7 +9307,7 @@ _LT_EOF # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported @@ -9003,34 +9315,57 @@ _LT_EOF ;; aix[4-9]*) - if test "$host_cpu" = ia64; then + if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' - no_entry_flag="" + no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - # Also, AIX nm treats weak defined symbols like other global - # defined symbols, whereas GNU nm marks them as "W". + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else - export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi ;; esac @@ -9049,13 +9384,21 @@ _LT_EOF hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes - file_list_spec='${wl}-f,' + file_list_spec='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct=no + hardcode_direct_absolute=no + ;; + esac - if test "$GCC" = yes; then + if test yes = "$GCC"; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` + collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then @@ -9074,36 +9417,42 @@ _LT_EOF ;; esac shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' fi - link_all_deplibs=no + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' else # not using gcc - if test "$host_cpu" = ia64; then + if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' else - shared_flag='${wl}-bM:SRE' + shared_flag='$wl-bM:SRE' fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' fi fi - export_dynamic_flag_spec='${wl}-bexpall' + export_dynamic_flag_spec='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes - if test "$aix_use_runtimelinking" = yes; then + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then + if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : @@ -9138,7 +9487,7 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_="/usr/lib:/lib" + lt_cv_aix_libpath_=/usr/lib:/lib fi fi @@ -9146,17 +9495,17 @@ fi aix_libpath=$lt_cv_aix_libpath_ fi - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + if test ia64 = "$host_cpu"; then + hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then + if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : @@ -9191,7 +9540,7 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_="/usr/lib:/lib" + lt_cv_aix_libpath_=/usr/lib:/lib fi fi @@ -9199,21 +9548,33 @@ fi aix_libpath=$lt_cv_aix_libpath_ fi - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. - no_undefined_flag=' ${wl}-bernotok' - allow_undefined_flag=' ${wl}-berok' - if test "$with_gnu_ld" = yes; then + no_undefined_flag=' $wl-bernotok' + allow_undefined_flag=' $wl-berok' + if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' fi fi ;; @@ -9222,7 +9583,7 @@ fi case $host_cpu in powerpc) # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) @@ -9252,16 +9613,17 @@ fi # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" + shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; - else - sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes @@ -9270,18 +9632,18 @@ fi # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile="$lt_outputfile.exe" - lt_tool_outputfile="$lt_tool_outputfile.exe" - ;; - esac~ - if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' ;; *) # Assume MSVC wrapper @@ -9290,7 +9652,7 @@ fi # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" + shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. @@ -9309,24 +9671,24 @@ fi hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported - if test "$lt_cv_ld_force_load" = "yes"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes - allow_undefined_flag="$_lt_dar_allow_undefined" + allow_undefined_flag=$_lt_dar_allow_undefined case $cc_basename in - ifort*) _lt_dar_can_shared=yes ;; + ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac - if test "$_lt_dar_can_shared" = "yes"; then + if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" - archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" - module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" else ld_shlibs=no @@ -9368,33 +9730,33 @@ fi ;; hpux9*) - if test "$GCC" = yes; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + if test yes = "$GCC"; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes - export_dynamic_flag_spec='${wl}-E' + export_dynamic_flag_spec='$wl-E' ;; hpux10*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + if test yes,no = "$GCC,$with_gnu_ld"; then + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' + export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes @@ -9402,25 +9764,25 @@ fi ;; hpux11*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then + if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) - archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) @@ -9432,7 +9794,7 @@ if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no - save_LDFLAGS="$LDFLAGS" + save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then @@ -9451,14 +9813,14 @@ else fi fi $RM -r conftest* - LDFLAGS="$save_LDFLAGS" + LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } -if test x"$lt_cv_prog_compiler__b" = xyes; then - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +if test yes = "$lt_cv_prog_compiler__b"; then + archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi @@ -9466,8 +9828,8 @@ fi ;; esac fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: case $host_cpu in @@ -9478,7 +9840,7 @@ fi *) hardcode_direct=yes hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' + export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. @@ -9489,8 +9851,8 @@ fi ;; irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + if test yes = "$GCC"; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. @@ -9500,8 +9862,8 @@ $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " > if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } @@ -9513,24 +9875,35 @@ else fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" + LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } - if test "$lt_cv_irix_exported_symbol" = yes; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi + link_all_deplibs=no else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + ld_shlibs=yes + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out @@ -9545,7 +9918,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; @@ -9553,27 +9926,19 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } *nto* | *qnx*) ;; - openbsd*) + openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' else - case $host_os in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-R$libdir' - ;; - *) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - esac + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no @@ -9584,33 +9949,53 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported - archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes ;; osf3*) - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' else allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' @@ -9621,24 +10006,24 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } solaris*) no_undefined_flag=' -z defs' - if test "$GCC" = yes; then - wlarc='${wl}' - archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + if test yes = "$GCC"; then + wlarc='$wl' + archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' - archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) - wlarc='${wl}' - archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + wlarc='$wl' + archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi @@ -9648,11 +10033,11 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', + # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + if test yes = "$GCC"; then + whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi @@ -9662,10 +10047,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } ;; sunos4*) - if test "x$host_vendor" = xsequent; then + if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. - archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi @@ -9714,43 +10099,43 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='${wl}-z,text' + no_undefined_flag='$wl-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not + # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. - no_undefined_flag='${wl}-z,text' - allow_undefined_flag='${wl}-z,nodefs' + no_undefined_flag='$wl-z,text' + allow_undefined_flag='$wl-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_flag_spec='$wl-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes - export_dynamic_flag_spec='${wl}-Bexport' + export_dynamic_flag_spec='$wl-Bexport' runpath_var='LD_RUN_PATH' - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; @@ -9765,10 +10150,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } ;; esac - if test x$host_vendor = xsni; then + if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='${wl}-Blargedynsym' + export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi @@ -9776,7 +10161,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } -test "$ld_shlibs" = no && can_build_shared=no +test no = "$ld_shlibs" && can_build_shared=no with_gnu_ld=$with_gnu_ld @@ -9802,7 +10187,7 @@ x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes - if test "$enable_shared" = yes && test "$GCC" = yes; then + if test yes,yes = "$GCC,$enable_shared"; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. @@ -10017,14 +10402,14 @@ esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } -if test "$GCC" = yes; then +if test yes = "$GCC"; then case $host_os in - darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; - *) lt_awk_arg="/^libraries:/" ;; + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in - mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; - *) lt_sed_strip_eq="s,=/,/,g" ;; + mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in @@ -10040,28 +10425,35 @@ if test "$GCC" = yes; then ;; esac # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary. + # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= - lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path/$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" - else + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS=" "; FS="/|\n";} { - lt_foo=""; - lt_count=0; +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { - lt_foo="/" $lt_i lt_foo; + lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } @@ -10075,7 +10467,7 @@ BEGIN {RS=" "; FS="/|\n";} { # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's,/\([A-Za-z]:\),\1,g'` ;; + $SED 's|/\([A-Za-z]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else @@ -10084,7 +10476,7 @@ fi library_names_spec= libname_spec='lib$name' soname_spec= -shrext_cmds=".so" +shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= @@ -10101,14 +10493,16 @@ hardcode_into_libs=no # flags to be left without arguments need_version=unknown + + case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' + soname_spec='$libname$release$shared_ext$major' ;; aix[4-9]*) @@ -10116,41 +10510,91 @@ aix[4-9]*) need_lib_prefix=no need_version=no hardcode_into_libs=yes - if test "$host_cpu" = ia64; then + if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' - echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac shlibpath_var=LIBPATH fi ;; @@ -10160,18 +10604,18 @@ amigaos*) powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) - library_names_spec='${libname}${shared_ext}' + library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; @@ -10179,8 +10623,8 @@ beos*) bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" @@ -10192,7 +10636,7 @@ bsdi[45]*) cygwin* | mingw* | pw32* | cegcc*) version_type=windows - shrext_cmds=".dll" + shrext_cmds=.dll need_version=no need_lib_prefix=no @@ -10201,8 +10645,8 @@ cygwin* | mingw* | pw32* | cegcc*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ @@ -10218,17 +10662,17 @@ cygwin* | mingw* | pw32* | cegcc*) case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' @@ -10237,8 +10681,8 @@ cygwin* | mingw* | pw32* | cegcc*) *,cl*) # Native MSVC libname_spec='$name' - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - library_names_spec='${libname}.dll.lib' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' case $build_os in mingw*) @@ -10265,7 +10709,7 @@ cygwin* | mingw* | pw32* | cegcc*) sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) - sys_lib_search_path_spec="$LIB" + sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` @@ -10278,8 +10722,8 @@ cygwin* | mingw* | pw32* | cegcc*) esac # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' @@ -10292,7 +10736,7 @@ cygwin* | mingw* | pw32* | cegcc*) *) # Assume MSVC wrapper - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac @@ -10305,8 +10749,8 @@ darwin* | rhapsody*) version_type=darwin need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' @@ -10319,8 +10763,8 @@ dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; @@ -10338,12 +10782,13 @@ freebsd* | dragonfly*) version_type=freebsd-$objformat case $version_type in freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac @@ -10373,10 +10818,10 @@ haiku*) need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=yes + shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; @@ -10394,14 +10839,15 @@ hpux9* | hpux10* | hpux11*) dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' @@ -10409,8 +10855,8 @@ hpux9* | hpux10* | hpux11*) dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; @@ -10419,8 +10865,8 @@ hpux9* | hpux10* | hpux11*) dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... @@ -10433,8 +10879,8 @@ interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no @@ -10445,7 +10891,7 @@ irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) - if test "$lt_cv_prog_gnu_ld" = yes; then + if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix @@ -10453,8 +10899,8 @@ irix5* | irix6* | nonstopux*) esac need_lib_prefix=no need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= @@ -10473,8 +10919,8 @@ irix5* | irix6* | nonstopux*) esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; @@ -10483,13 +10929,33 @@ linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec='-L$libdir' + ;; + # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no @@ -10533,7 +10999,12 @@ fi # before this can be enabled. hardcode_into_libs=yes - # Append ld.so.conf contents to the search path + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" @@ -10565,12 +11036,12 @@ netbsd*) need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH @@ -10580,7 +11051,7 @@ netbsd*) newsos6) version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; @@ -10589,58 +11060,68 @@ newsos6) version_type=qnx need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; -openbsd*) +openbsd* | bitrig*) version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" + sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no else - shlibpath_overrides_runpath=yes + need_version=yes fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' - shrext_cmds=".dll" + version_type=windows + shrext_cmds=.dll + need_version=no need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) @@ -10651,8 +11132,8 @@ solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes @@ -10662,11 +11143,11 @@ solaris*) sunos4*) version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then + if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes @@ -10674,8 +11155,8 @@ sunos4*) sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) @@ -10696,24 +11177,24 @@ sysv4 | sysv4.3*) ;; sysv4*MP*) - if test -d /usr/nec ;then + if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf + version_type=sco need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then + if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' @@ -10731,7 +11212,7 @@ tpf*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes @@ -10739,8 +11220,8 @@ tpf*) uts4*) version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; @@ -10750,20 +11231,35 @@ uts4*) esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no +test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then +if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi -if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then - sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi -if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then - sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + @@ -10860,15 +11356,15 @@ $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || - test "X$hardcode_automatic" = "Xyes" ; then + test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. - if test "$hardcode_direct" != no && + if test no != "$hardcode_direct" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one - ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && - test "$hardcode_minus_L" != no; then + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && + test no != "$hardcode_minus_L"; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else @@ -10883,12 +11379,12 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } -if test "$hardcode_action" = relink || - test "$inherit_rpath" = yes; then +if test relink = "$hardcode_action" || + test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi @@ -10898,7 +11394,7 @@ fi - if test "x$enable_dlopen" != xyes; then + if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown @@ -10908,23 +11404,23 @@ else case $host_os in beos*) - lt_cv_dlopen="load_add_on" + lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) - lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) - lt_cv_dlopen="dlopen" + lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) - # if libdl is installed we need to link against it + # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : @@ -10962,10 +11458,10 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else - lt_cv_dlopen="dyld" + lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes @@ -10973,10 +11469,18 @@ fi ;; + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : - lt_cv_dlopen="shl_load" + lt_cv_dlopen=shl_load else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } @@ -11015,11 +11519,11 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : - lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" + lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" + lt_cv_dlopen=dlopen else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } @@ -11058,7 +11562,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } @@ -11097,7 +11601,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } @@ -11136,7 +11640,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : - lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" + lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi @@ -11157,21 +11661,21 @@ fi ;; esac - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - else + if test no = "$lt_cv_dlopen"; then enable_dlopen=no + else + enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) - save_CPPFLAGS="$CPPFLAGS" - test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - save_LDFLAGS="$LDFLAGS" + save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - save_LIBS="$LIBS" + save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 @@ -11179,7 +11683,7 @@ $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else - if test "$cross_compiling" = yes; then : + if test yes = "$cross_compiling"; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 @@ -11226,9 +11730,9 @@ else # endif #endif -/* When -fvisbility=hidden is used, assume the code has been annotated +/* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif @@ -11258,7 +11762,7 @@ _LT_EOF (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -11278,14 +11782,14 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } - if test "x$lt_cv_dlopen_self" = xyes; then + if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else - if test "$cross_compiling" = yes; then : + if test yes = "$cross_compiling"; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 @@ -11332,9 +11836,9 @@ else # endif #endif -/* When -fvisbility=hidden is used, assume the code has been annotated +/* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif @@ -11364,7 +11868,7 @@ _LT_EOF (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in @@ -11385,9 +11889,9 @@ fi $as_echo "$lt_cv_dlopen_self_static" >&6; } fi - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS ;; esac @@ -11431,7 +11935,7 @@ else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) - if test -n "$STRIP" ; then + if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 @@ -11459,7 +11963,7 @@ fi - # Report which library types will actually be built + # Report what library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 @@ -11467,13 +11971,13 @@ $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } - test "$can_build_shared" = "no" && enable_shared=no + test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) - test "$enable_shared" = yes && enable_static=no + test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' @@ -11481,8 +11985,12 @@ $as_echo_n "checking whether to build shared libraries... " >&6; } ;; aix[4-9]*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac fi ;; esac @@ -11492,7 +12000,7 @@ $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. - test "$enable_shared" = yes || enable_static=yes + test yes = "$enable_shared" || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } @@ -11506,7 +12014,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -CC="$lt_save_CC" +CC=$lt_save_CC @@ -13287,36 +13795,42 @@ else if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi - if test "$cross_compiling" = yes; then : - - case "$host_os" in - aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; - *) am_cv_func_iconv_works="guessing yes" ;; - esac - + am_cv_func_iconv_works=no + for ac_iconv_const in '' 'const'; do + if test "$cross_compiling" = yes; then : + case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include -int main () + +#ifndef ICONV_CONST +# define ICONV_CONST $ac_iconv_const +#endif + +int +main () { - int result = 0; +int result = 0; /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { - static const char input[] = "\342\202\254"; /* EURO SIGN */ + static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 1; @@ -13329,14 +13843,14 @@ int main () iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); if (cd_ascii_to_88591 != (iconv_t)(-1)) { - static const char input[] = "\263"; + static ICONV_CONST char input[] = "\263"; char buf[10]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_ascii_to_88591, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 2; @@ -13348,14 +13862,14 @@ int main () iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { - static const char input[] = "\304"; + static ICONV_CONST char input[] = "\304"; static char buf[2] = { (char)0xDE, (char)0xAD }; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = 1; char *outptr = buf; size_t outbytesleft = 1; size_t res = iconv (cd_88591_to_utf8, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) result |= 4; @@ -13368,14 +13882,14 @@ int main () iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { - static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; - const char *inptr = input; + ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, - (char **) &inptr, &inbytesleft, + &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) result |= 8; @@ -13395,17 +13909,20 @@ int main () && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) result |= 16; return result; + + ; + return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : am_cv_func_iconv_works=yes -else - am_cv_func_iconv_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi + test "$am_cv_func_iconv_works" = no || break + done LIBS="$am_save_LIBS" fi @@ -14119,7 +14636,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by fuse $as_me 2.9.6, which was +This file was extended by fuse $as_me 2.9.9, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14185,7 +14702,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -fuse config.status 2.9.6 +fuse config.status 2.9.9 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -14320,6 +14837,7 @@ enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' @@ -14369,10 +14887,13 @@ compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' @@ -14437,7 +14958,8 @@ finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' +configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' @@ -14488,9 +15010,12 @@ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_cv_nm_interface \ nm_file_list_spec \ +lt_cv_truncate_bin \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ @@ -14525,7 +15050,7 @@ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -14552,10 +15077,11 @@ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ -sys_lib_dlsearch_path_spec; do +configure_time_dlsearch_path \ +configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -14564,19 +15090,16 @@ sys_lib_dlsearch_path_spec; do done ac_aux_dir='$ac_aux_dir' -xsi_shell='$xsi_shell' -lt_shell_append='$lt_shell_append' -# See if we are running on zsh, and set the options which allow our +# See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}" ; then +if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' - TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' @@ -15291,55 +15814,52 @@ $as_echo X"$file" | ;; "libtool":C) - # See if we are running on zsh, and set the options which allow our + # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then + if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi - cfgfile="${ofile}T" + cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL - -# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. # -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, -# 2006, 2007, 2008, 2009, 2010, 2011 Free Software -# Foundation, Inc. -# Written by Gordon Matzigkeit, 1996 -# -# This file is part of GNU Libtool. -# -# GNU Libtool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. # -# GNU Libtool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with GNU Libtool; see the file COPYING. If not, a copy -# can be downloaded from http://www.gnu.org/licenses/gpl.html, or -# obtained by writing to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# along with this program. If not, see . # The names of the tagged configurations supported by this script. -available_tags="" +available_tags='' + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG @@ -15359,6 +15879,9 @@ pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec=$shared_archive_member_spec + # Shell to use when invoking shell scripts. SHELL=$lt_SHELL @@ -15476,18 +15999,27 @@ global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl +# Transform the output of nm into a list of symbols to manually relocate. +global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import + # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix +# The name lister interface. +nm_interface=$lt_lt_cv_nm_interface + # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec -# The root where to search for dependent libraries,and in which our libraries should be installed. +# The root where to search for dependent libraries,and where our libraries should be installed. lt_sysroot=$lt_sysroot +# Command to truncate a binary pipe. +lt_truncate_bin=$lt_lt_cv_truncate_bin + # The name of the directory that contains temporary libtool files. objdir=$objdir @@ -15578,8 +16110,11 @@ hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec -# Run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # Whether dlopen is supported. dlopen_support=$enable_dlopen @@ -15672,13 +16207,13 @@ hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute @@ -15730,13 +16265,72 @@ hardcode_action=$hardcode_action _LT_EOF + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. -if test "X${COLLECT_NAMES+set}" != Xset; then +if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi @@ -15745,7 +16339,7 @@ _LT_EOF esac -ltmain="$ac_aux_dir/ltmain.sh" +ltmain=$ac_aux_dir/ltmain.sh # We use sed instead of cat because bash on DJGPP gets confused if @@ -15755,165 +16349,6 @@ ltmain="$ac_aux_dir/ltmain.sh" sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) - if test x"$xsi_shell" = xyes; then - sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ -func_dirname ()\ -{\ -\ case ${1} in\ -\ */*) func_dirname_result="${1%/*}${2}" ;;\ -\ * ) func_dirname_result="${3}" ;;\ -\ esac\ -} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_basename ()$/,/^} # func_basename /c\ -func_basename ()\ -{\ -\ func_basename_result="${1##*/}"\ -} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ -func_dirname_and_basename ()\ -{\ -\ case ${1} in\ -\ */*) func_dirname_result="${1%/*}${2}" ;;\ -\ * ) func_dirname_result="${3}" ;;\ -\ esac\ -\ func_basename_result="${1##*/}"\ -} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ -func_stripname ()\ -{\ -\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ -\ # positional parameters, so assign one to ordinary parameter first.\ -\ func_stripname_result=${3}\ -\ func_stripname_result=${func_stripname_result#"${1}"}\ -\ func_stripname_result=${func_stripname_result%"${2}"}\ -} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ -func_split_long_opt ()\ -{\ -\ func_split_long_opt_name=${1%%=*}\ -\ func_split_long_opt_arg=${1#*=}\ -} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ -func_split_short_opt ()\ -{\ -\ func_split_short_opt_arg=${1#??}\ -\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ -} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ -func_lo2o ()\ -{\ -\ case ${1} in\ -\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ -\ *) func_lo2o_result=${1} ;;\ -\ esac\ -} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_xform ()$/,/^} # func_xform /c\ -func_xform ()\ -{\ - func_xform_result=${1%.*}.lo\ -} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_arith ()$/,/^} # func_arith /c\ -func_arith ()\ -{\ - func_arith_result=$(( $* ))\ -} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_len ()$/,/^} # func_len /c\ -func_len ()\ -{\ - func_len_result=${#1}\ -} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - -fi - -if test x"$lt_shell_append" = xyes; then - sed -e '/^func_append ()$/,/^} # func_append /c\ -func_append ()\ -{\ - eval "${1}+=\\${2}"\ -} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ -func_append_quoted ()\ -{\ -\ func_quote_for_eval "${2}"\ -\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ -} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - # Save a `func_append' function call where possible by direct use of '+=' - sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") - test 0 -eq $? || _lt_function_replace_fail=: -else - # Save a `func_append' function call even when '+=' is not available - sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") - test 0 -eq $? || _lt_function_replace_fail=: -fi - -if test x"$_lt_function_replace_fail" = x":"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 -$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} -fi - - mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" diff --git a/configure.ac b/configure.ac index 7bad7f5..9946a0e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(fuse, 2.9.6) +AC_INIT(fuse, 2.9.9) AC_PREREQ(2.59d) AC_CONFIG_MACRO_DIR([m4]) diff --git a/depcomp b/depcomp index 4ebd5b3..fc98710 100755 --- a/depcomp +++ b/depcomp @@ -3,7 +3,7 @@ scriptversion=2013-05-30.07; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/doc/Makefile.in b/doc/Makefile.in index 6433900..e92a308 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,7 +14,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,8 +89,6 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = doc -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(dist_man_MANS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ @@ -88,6 +96,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = @@ -144,6 +153,7 @@ man8dir = $(mandir)/man8 NROFF = nroff MANS = $(dist_man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -187,6 +197,7 @@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ @@ -258,6 +269,7 @@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -288,7 +300,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -555,6 +566,8 @@ uninstall-man: uninstall-man1 uninstall-man8 mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-man uninstall-man1 uninstall-man8 +.PRECIOUS: Makefile + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/doc/html/annotated.html b/doc/html/annotated.html index 1e76c4e..6edc3e6 100644 --- a/doc/html/annotated.html +++ b/doc/html/annotated.html @@ -3,8 +3,9 @@ - -fuse: Data Structures + + +libfuse: Data Structures @@ -16,8 +17,8 @@ - @@ -25,20 +26,15 @@
-
fuse +
+
libfuse
- - - + + + + + diff --git a/doc/html/buffer_8c_source.html b/doc/html/buffer_8c_source.html new file mode 100644 index 0000000..d1949d7 --- /dev/null +++ b/doc/html/buffer_8c_source.html @@ -0,0 +1,78 @@ + + + + + + + +libfuse: lib/buffer.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
buffer.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Functions for dealing with `struct fuse_buf` and `struct
6  fuse_bufvec`.
7 
8  This program can be distributed under the terms of the GNU LGPLv2.
9  See the file COPYING.LIB
10 */
11 
12 #define _GNU_SOURCE
13 
14 #include "config.h"
15 #include "fuse_i.h"
16 #include "fuse_lowlevel.h"
17 #include <string.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <assert.h>
21 
22 size_t fuse_buf_size(const struct fuse_bufvec *bufv)
23 {
24  size_t i;
25  size_t size = 0;
26 
27  for (i = 0; i < bufv->count; i++) {
28  if (bufv->buf[i].size == SIZE_MAX)
29  size = SIZE_MAX;
30  else
31  size += bufv->buf[i].size;
32  }
33 
34  return size;
35 }
36 
37 static size_t min_size(size_t s1, size_t s2)
38 {
39  return s1 < s2 ? s1 : s2;
40 }
41 
42 static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
43  const struct fuse_buf *src, size_t src_off,
44  size_t len)
45 {
46  ssize_t res = 0;
47  size_t copied = 0;
48 
49  while (len) {
50  if (dst->flags & FUSE_BUF_FD_SEEK) {
51  res = pwrite(dst->fd, src->mem + src_off, len,
52  dst->pos + dst_off);
53  } else {
54  res = write(dst->fd, src->mem + src_off, len);
55  }
56  if (res == -1) {
57  if (!copied)
58  return -errno;
59  break;
60  }
61  if (res == 0)
62  break;
63 
64  copied += res;
65  if (!(dst->flags & FUSE_BUF_FD_RETRY))
66  break;
67 
68  src_off += res;
69  dst_off += res;
70  len -= res;
71  }
72 
73  return copied;
74 }
75 
76 static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
77  const struct fuse_buf *src, size_t src_off,
78  size_t len)
79 {
80  ssize_t res = 0;
81  size_t copied = 0;
82 
83  while (len) {
84  if (src->flags & FUSE_BUF_FD_SEEK) {
85  res = pread(src->fd, dst->mem + dst_off, len,
86  src->pos + src_off);
87  } else {
88  res = read(src->fd, dst->mem + dst_off, len);
89  }
90  if (res == -1) {
91  if (!copied)
92  return -errno;
93  break;
94  }
95  if (res == 0)
96  break;
97 
98  copied += res;
99  if (!(src->flags & FUSE_BUF_FD_RETRY))
100  break;
101 
102  dst_off += res;
103  src_off += res;
104  len -= res;
105  }
106 
107  return copied;
108 }
109 
110 static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
111  const struct fuse_buf *src, size_t src_off,
112  size_t len)
113 {
114  char buf[4096];
115  struct fuse_buf tmp = {
116  .size = sizeof(buf),
117  .flags = 0,
118  };
119  ssize_t res;
120  size_t copied = 0;
121 
122  tmp.mem = buf;
123 
124  while (len) {
125  size_t this_len = min_size(tmp.size, len);
126  size_t read_len;
127 
128  res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
129  if (res < 0) {
130  if (!copied)
131  return res;
132  break;
133  }
134  if (res == 0)
135  break;
136 
137  read_len = res;
138  res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
139  if (res < 0) {
140  if (!copied)
141  return res;
142  break;
143  }
144  if (res == 0)
145  break;
146 
147  copied += res;
148 
149  if (res < this_len)
150  break;
151 
152  dst_off += res;
153  src_off += res;
154  len -= res;
155  }
156 
157  return copied;
158 }
159 
160 #ifdef HAVE_SPLICE
161 static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
162  const struct fuse_buf *src, size_t src_off,
163  size_t len, enum fuse_buf_copy_flags flags)
164 {
165  int splice_flags = 0;
166  off_t *srcpos = NULL;
167  off_t *dstpos = NULL;
168  off_t srcpos_val;
169  off_t dstpos_val;
170  ssize_t res;
171  size_t copied = 0;
172 
173  if (flags & FUSE_BUF_SPLICE_MOVE)
174  splice_flags |= SPLICE_F_MOVE;
175  if (flags & FUSE_BUF_SPLICE_NONBLOCK)
176  splice_flags |= SPLICE_F_NONBLOCK;
177 
178  if (src->flags & FUSE_BUF_FD_SEEK) {
179  srcpos_val = src->pos + src_off;
180  srcpos = &srcpos_val;
181  }
182  if (dst->flags & FUSE_BUF_FD_SEEK) {
183  dstpos_val = dst->pos + dst_off;
184  dstpos = &dstpos_val;
185  }
186 
187  while (len) {
188  res = splice(src->fd, srcpos, dst->fd, dstpos, len,
189  splice_flags);
190  if (res == -1) {
191  if (copied)
192  break;
193 
194  if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
195  return -errno;
196 
197  /* Maybe splice is not supported for this combination */
198  return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
199  len);
200  }
201  if (res == 0)
202  break;
203 
204  copied += res;
205  if (!(src->flags & FUSE_BUF_FD_RETRY) &&
206  !(dst->flags & FUSE_BUF_FD_RETRY)) {
207  break;
208  }
209 
210  len -= res;
211  }
212 
213  return copied;
214 }
215 #else
216 static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
217  const struct fuse_buf *src, size_t src_off,
218  size_t len, enum fuse_buf_copy_flags flags)
219 {
220  (void) flags;
221 
222  return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
223 }
224 #endif
225 
226 
227 static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
228  const struct fuse_buf *src, size_t src_off,
229  size_t len, enum fuse_buf_copy_flags flags)
230 {
231  int src_is_fd = src->flags & FUSE_BUF_IS_FD;
232  int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
233 
234  if (!src_is_fd && !dst_is_fd) {
235  void *dstmem = dst->mem + dst_off;
236  void *srcmem = src->mem + src_off;
237 
238  if (dstmem != srcmem) {
239  if (dstmem + len <= srcmem || srcmem + len <= dstmem)
240  memcpy(dstmem, srcmem, len);
241  else
242  memmove(dstmem, srcmem, len);
243  }
244 
245  return len;
246  } else if (!src_is_fd) {
247  return fuse_buf_write(dst, dst_off, src, src_off, len);
248  } else if (!dst_is_fd) {
249  return fuse_buf_read(dst, dst_off, src, src_off, len);
250  } else if (flags & FUSE_BUF_NO_SPLICE) {
251  return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
252  } else {
253  return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
254  }
255 }
256 
257 static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
258 {
259  if (bufv->idx < bufv->count)
260  return &bufv->buf[bufv->idx];
261  else
262  return NULL;
263 }
264 
265 static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
266 {
267  const struct fuse_buf *buf = fuse_bufvec_current(bufv);
268 
269  bufv->off += len;
270  assert(bufv->off <= buf->size);
271  if (bufv->off == buf->size) {
272  assert(bufv->idx < bufv->count);
273  bufv->idx++;
274  if (bufv->idx == bufv->count)
275  return 0;
276  bufv->off = 0;
277  }
278  return 1;
279 }
280 
281 ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
283 {
284  size_t copied = 0;
285 
286  if (dstv == srcv)
287  return fuse_buf_size(dstv);
288 
289  for (;;) {
290  const struct fuse_buf *src = fuse_bufvec_current(srcv);
291  const struct fuse_buf *dst = fuse_bufvec_current(dstv);
292  size_t src_len;
293  size_t dst_len;
294  size_t len;
295  ssize_t res;
296 
297  if (src == NULL || dst == NULL)
298  break;
299 
300  src_len = src->size - srcv->off;
301  dst_len = dst->size - dstv->off;
302  len = min_size(src_len, dst_len);
303 
304  res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
305  if (res < 0) {
306  if (!copied)
307  return res;
308  break;
309  }
310  copied += res;
311 
312  if (!fuse_bufvec_advance(srcv, res) ||
313  !fuse_bufvec_advance(dstv, res))
314  break;
315 
316  if (res < len)
317  break;
318  }
319 
320  return copied;
321 }
size_t off
Definition: fuse_common.h:679
+ + + + +
off_t pos
Definition: fuse_common.h:654
+ +
size_t idx
Definition: fuse_common.h:674
+
size_t count
Definition: fuse_common.h:669
+
enum fuse_buf_flags flags
Definition: fuse_common.h:633
+ +
void * mem
Definition: fuse_common.h:640
+ + +
struct fuse_buf buf[1]
Definition: fuse_common.h:684
+ +
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
+
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:281
+
size_t size
Definition: fuse_common.h:628
+
fuse_buf_copy_flags
Definition: fuse_common.h:579
+ + +
+ + + + diff --git a/doc/html/classes.html b/doc/html/classes.html index 6d3c878..e849cdc 100644 --- a/doc/html/classes.html +++ b/doc/html/classes.html @@ -3,8 +3,9 @@ - -fuse: Data Structure Index + + +libfuse: Data Structure Index @@ -16,8 +17,8 @@ - @@ -25,42 +26,37 @@
-
fuse +
+
libfuse
- - - + + + + +
Data Structure Index
diff --git a/doc/html/config_8h_source.html b/doc/html/config_8h_source.html new file mode 100644 index 0000000..82b17f6 --- /dev/null +++ b/doc/html/config_8h_source.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: build/config.h Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
config.h
+
+
+
1 /*
2  * Autogenerated by the Meson build system.
3  * Do not edit, your changes will be lost.
4  */
5 
6 #pragma once
7 
8 #undef HAVE_COPY_FILE_RANGE
9 
10 #define HAVE_FDATASYNC
11 
12 #define HAVE_FORK
13 
14 #define HAVE_FSTATAT
15 
16 #define HAVE_ICONV
17 
18 #define HAVE_OPENAT
19 
20 #define HAVE_PIPE2
21 
22 #define HAVE_POSIX_FALLOCATE
23 
24 #define HAVE_READLINKAT
25 
26 #define HAVE_SETXATTR
27 
28 #define HAVE_SPLICE
29 
30 #define HAVE_STRUCT_STAT_ST_ATIM
31 
32 #undef HAVE_STRUCT_STAT_ST_ATIMESPEC
33 
34 #define HAVE_UTIMENSAT
35 
36 #define HAVE_VMSPLICE
37 
38 #define PACKAGE_VERSION "3.4.0"
39 
+ + + + diff --git a/doc/html/cuse_8c.html b/doc/html/cuse_8c.html new file mode 100644 index 0000000..c722500 --- /dev/null +++ b/doc/html/cuse_8c.html @@ -0,0 +1,75 @@ + + + + + + + +libfuse: example/cuse.c File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
cuse.c File Reference
+
+
+
#include <cuse_lowlevel.h>
+#include <fuse_opt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "ioctl.h"
+
+

Go to the source code of this file.

+

Detailed Description

+

This example demonstrates how to implement a character device in userspace ("CUSE"). This is only allowed for root. The character device should appear in /dev under the specified name. It can be tested with the cuse_client.c program.

+

Mount the file system with:

cuse -f --name=mydevice
+

You should now have a new /dev/mydevice character device. To "unmount" it, kill the "cuse" process.

+

To compile this example, run

gcc -Wall cuse.c `pkg-config fuse3 --cflags --libs` -o cuse
+

Source code

+
/*
CUSE example: Character device in Userspace
Copyright (C) 2008-2009 SUSE Linux Products GmbH
Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#define FUSE_USE_VERSION 31
#include <cuse_lowlevel.h>
#include <fuse_opt.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "ioctl.h"
static void *cusexmp_buf;
static size_t cusexmp_size;
static const char *usage =
"usage: cusexmp [options]\n"
"\n"
"options:\n"
" --help|-h print this help message\n"
" --maj=MAJ|-M MAJ device major number\n"
" --min=MIN|-m MIN device minor number\n"
" --name=NAME|-n NAME device name (mandatory)\n"
" -d -o debug enable debug output (implies -f)\n"
" -f foreground operation\n"
" -s disable multi-threaded operation\n"
"\n";
static int cusexmp_resize(size_t new_size)
{
void *new_buf;
if (new_size == cusexmp_size)
return 0;
new_buf = realloc(cusexmp_buf, new_size);
if (!new_buf && new_size)
return -ENOMEM;
if (new_size > cusexmp_size)
memset(new_buf + cusexmp_size, 0, new_size - cusexmp_size);
cusexmp_buf = new_buf;
cusexmp_size = new_size;
return 0;
}
static int cusexmp_expand(size_t new_size)
{
if (new_size > cusexmp_size)
return cusexmp_resize(new_size);
return 0;
}
static void cusexmp_open(fuse_req_t req, struct fuse_file_info *fi)
{
fuse_reply_open(req, fi);
}
static void cusexmp_read(fuse_req_t req, size_t size, off_t off,
struct fuse_file_info *fi)
{
(void)fi;
if (off >= cusexmp_size)
off = cusexmp_size;
if (size > cusexmp_size - off)
size = cusexmp_size - off;
fuse_reply_buf(req, cusexmp_buf + off, size);
}
static void cusexmp_write(fuse_req_t req, const char *buf, size_t size,
off_t off, struct fuse_file_info *fi)
{
(void)fi;
if (cusexmp_expand(off + size)) {
fuse_reply_err(req, ENOMEM);
return;
}
memcpy(cusexmp_buf + off, buf, size);
fuse_reply_write(req, size);
}
static void fioc_do_rw(fuse_req_t req, void *addr, const void *in_buf,
size_t in_bufsz, size_t out_bufsz, int is_read)
{
const struct fioc_rw_arg *arg;
struct iovec in_iov[2], out_iov[3], iov[3];
size_t cur_size;
/* read in arg */
in_iov[0].iov_base = addr;
in_iov[0].iov_len = sizeof(*arg);
if (!in_bufsz) {
fuse_reply_ioctl_retry(req, in_iov, 1, NULL, 0);
return;
}
arg = in_buf;
in_buf += sizeof(*arg);
in_bufsz -= sizeof(*arg);
/* prepare size outputs */
out_iov[0].iov_base =
addr + offsetof(struct fioc_rw_arg, prev_size);
out_iov[0].iov_len = sizeof(arg->prev_size);
out_iov[1].iov_base =
addr + offsetof(struct fioc_rw_arg, new_size);
out_iov[1].iov_len = sizeof(arg->new_size);
/* prepare client buf */
if (is_read) {
out_iov[2].iov_base = arg->buf;
out_iov[2].iov_len = arg->size;
if (!out_bufsz) {
fuse_reply_ioctl_retry(req, in_iov, 1, out_iov, 3);
return;
}
} else {
in_iov[1].iov_base = arg->buf;
in_iov[1].iov_len = arg->size;
if (arg->size && !in_bufsz) {
fuse_reply_ioctl_retry(req, in_iov, 2, out_iov, 2);
return;
}
}
/* we're all set */
cur_size = cusexmp_size;
iov[0].iov_base = &cur_size;
iov[0].iov_len = sizeof(cur_size);
iov[1].iov_base = &cusexmp_size;
iov[1].iov_len = sizeof(cusexmp_size);
if (is_read) {
size_t off = arg->offset;
size_t size = arg->size;
if (off >= cusexmp_size)
off = cusexmp_size;
if (size > cusexmp_size - off)
size = cusexmp_size - off;
iov[2].iov_base = cusexmp_buf + off;
iov[2].iov_len = size;
fuse_reply_ioctl_iov(req, size, iov, 3);
} else {
if (cusexmp_expand(arg->offset + in_bufsz)) {
fuse_reply_err(req, ENOMEM);
return;
}
memcpy(cusexmp_buf + arg->offset, in_buf, in_bufsz);
fuse_reply_ioctl_iov(req, in_bufsz, iov, 2);
}
}
static void cusexmp_ioctl(fuse_req_t req, int cmd, void *arg,
struct fuse_file_info *fi, unsigned flags,
const void *in_buf, size_t in_bufsz, size_t out_bufsz)
{
int is_read = 0;
(void)fi;
if (flags & FUSE_IOCTL_COMPAT) {
fuse_reply_err(req, ENOSYS);
return;
}
switch (cmd) {
case FIOC_GET_SIZE:
if (!out_bufsz) {
struct iovec iov = { arg, sizeof(size_t) };
fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
} else
fuse_reply_ioctl(req, 0, &cusexmp_size,
sizeof(cusexmp_size));
break;
case FIOC_SET_SIZE:
if (!in_bufsz) {
struct iovec iov = { arg, sizeof(size_t) };
fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
} else {
cusexmp_resize(*(size_t *)in_buf);
fuse_reply_ioctl(req, 0, NULL, 0);
}
break;
case FIOC_READ:
is_read = 1;
/* fall through */
case FIOC_WRITE:
fioc_do_rw(req, arg, in_buf, in_bufsz, out_bufsz, is_read);
break;
default:
fuse_reply_err(req, EINVAL);
}
}
struct cusexmp_param {
unsigned major;
unsigned minor;
char *dev_name;
int is_help;
};
#define CUSEXMP_OPT(t, p) { t, offsetof(struct cusexmp_param, p), 1 }
static const struct fuse_opt cusexmp_opts[] = {
CUSEXMP_OPT("-M %u", major),
CUSEXMP_OPT("--maj=%u", major),
CUSEXMP_OPT("-m %u", minor),
CUSEXMP_OPT("--min=%u", minor),
CUSEXMP_OPT("-n %s", dev_name),
CUSEXMP_OPT("--name=%s", dev_name),
FUSE_OPT_KEY("-h", 0),
FUSE_OPT_KEY("--help", 0),
};
static int cusexmp_process_arg(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
struct cusexmp_param *param = data;
(void)outargs;
(void)arg;
switch (key) {
case 0:
param->is_help = 1;
fprintf(stderr, "%s", usage);
return fuse_opt_add_arg(outargs, "-ho");
default:
return 1;
}
}
static const struct cuse_lowlevel_ops cusexmp_clop = {
.open = cusexmp_open,
.read = cusexmp_read,
.write = cusexmp_write,
.ioctl = cusexmp_ioctl,
};
int main(int argc, char **argv)
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct cusexmp_param param = { 0, 0, NULL, 0 };
char dev_name[128] = "DEVNAME=";
const char *dev_info_argv[] = { dev_name };
struct cuse_info ci;
if (fuse_opt_parse(&args, &param, cusexmp_opts, cusexmp_process_arg)) {
printf("failed to parse option\n");
return 1;
}
if (!param.is_help) {
if (!param.dev_name) {
fprintf(stderr, "Error: device name missing\n");
return 1;
}
strncat(dev_name, param.dev_name, sizeof(dev_name) - 9);
}
memset(&ci, 0, sizeof(ci));
ci.dev_major = param.major;
ci.dev_minor = param.minor;
ci.dev_info_argc = 1;
ci.dev_info_argv = dev_info_argv;
ci.flags = CUSE_UNRESTRICTED_IOCTL;
return cuse_lowlevel_main(args.argc, args.argv, &ci, &cusexmp_clop,
NULL);
}
+

Definition in file cuse.c.

+
+ + + + diff --git a/doc/html/cuse_8c_source.html b/doc/html/cuse_8c_source.html new file mode 100644 index 0000000..02827fe --- /dev/null +++ b/doc/html/cuse_8c_source.html @@ -0,0 +1,77 @@ + + + + + + + +libfuse: example/cuse.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
cuse.c
+
+
+Go to the documentation of this file.
1 /*
2  CUSE example: Character device in Userspace
3  Copyright (C) 2008-2009 SUSE Linux Products GmbH
4  Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
5 
6  This program can be distributed under the terms of the GNU GPL.
7  See the file COPYING.
8 
9 */
10 
34 #define FUSE_USE_VERSION 31
35 
36 #include <cuse_lowlevel.h>
37 #include <fuse_opt.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <errno.h>
44 
45 #include "ioctl.h"
46 
47 static void *cusexmp_buf;
48 static size_t cusexmp_size;
49 
50 static const char *usage =
51 "usage: cusexmp [options]\n"
52 "\n"
53 "options:\n"
54 " --help|-h print this help message\n"
55 " --maj=MAJ|-M MAJ device major number\n"
56 " --min=MIN|-m MIN device minor number\n"
57 " --name=NAME|-n NAME device name (mandatory)\n"
58 " -d -o debug enable debug output (implies -f)\n"
59 " -f foreground operation\n"
60 " -s disable multi-threaded operation\n"
61 "\n";
62 
63 static int cusexmp_resize(size_t new_size)
64 {
65  void *new_buf;
66 
67  if (new_size == cusexmp_size)
68  return 0;
69 
70  new_buf = realloc(cusexmp_buf, new_size);
71  if (!new_buf && new_size)
72  return -ENOMEM;
73 
74  if (new_size > cusexmp_size)
75  memset(new_buf + cusexmp_size, 0, new_size - cusexmp_size);
76 
77  cusexmp_buf = new_buf;
78  cusexmp_size = new_size;
79 
80  return 0;
81 }
82 
83 static int cusexmp_expand(size_t new_size)
84 {
85  if (new_size > cusexmp_size)
86  return cusexmp_resize(new_size);
87  return 0;
88 }
89 
90 static void cusexmp_open(fuse_req_t req, struct fuse_file_info *fi)
91 {
92  fuse_reply_open(req, fi);
93 }
94 
95 static void cusexmp_read(fuse_req_t req, size_t size, off_t off,
96  struct fuse_file_info *fi)
97 {
98  (void)fi;
99 
100  if (off >= cusexmp_size)
101  off = cusexmp_size;
102  if (size > cusexmp_size - off)
103  size = cusexmp_size - off;
104 
105  fuse_reply_buf(req, cusexmp_buf + off, size);
106 }
107 
108 static void cusexmp_write(fuse_req_t req, const char *buf, size_t size,
109  off_t off, struct fuse_file_info *fi)
110 {
111  (void)fi;
112 
113  if (cusexmp_expand(off + size)) {
114  fuse_reply_err(req, ENOMEM);
115  return;
116  }
117 
118  memcpy(cusexmp_buf + off, buf, size);
119  fuse_reply_write(req, size);
120 }
121 
122 static void fioc_do_rw(fuse_req_t req, void *addr, const void *in_buf,
123  size_t in_bufsz, size_t out_bufsz, int is_read)
124 {
125  const struct fioc_rw_arg *arg;
126  struct iovec in_iov[2], out_iov[3], iov[3];
127  size_t cur_size;
128 
129  /* read in arg */
130  in_iov[0].iov_base = addr;
131  in_iov[0].iov_len = sizeof(*arg);
132  if (!in_bufsz) {
133  fuse_reply_ioctl_retry(req, in_iov, 1, NULL, 0);
134  return;
135  }
136  arg = in_buf;
137  in_buf += sizeof(*arg);
138  in_bufsz -= sizeof(*arg);
139 
140  /* prepare size outputs */
141  out_iov[0].iov_base =
142  addr + offsetof(struct fioc_rw_arg, prev_size);
143  out_iov[0].iov_len = sizeof(arg->prev_size);
144 
145  out_iov[1].iov_base =
146  addr + offsetof(struct fioc_rw_arg, new_size);
147  out_iov[1].iov_len = sizeof(arg->new_size);
148 
149  /* prepare client buf */
150  if (is_read) {
151  out_iov[2].iov_base = arg->buf;
152  out_iov[2].iov_len = arg->size;
153  if (!out_bufsz) {
154  fuse_reply_ioctl_retry(req, in_iov, 1, out_iov, 3);
155  return;
156  }
157  } else {
158  in_iov[1].iov_base = arg->buf;
159  in_iov[1].iov_len = arg->size;
160  if (arg->size && !in_bufsz) {
161  fuse_reply_ioctl_retry(req, in_iov, 2, out_iov, 2);
162  return;
163  }
164  }
165 
166  /* we're all set */
167  cur_size = cusexmp_size;
168  iov[0].iov_base = &cur_size;
169  iov[0].iov_len = sizeof(cur_size);
170 
171  iov[1].iov_base = &cusexmp_size;
172  iov[1].iov_len = sizeof(cusexmp_size);
173 
174  if (is_read) {
175  size_t off = arg->offset;
176  size_t size = arg->size;
177 
178  if (off >= cusexmp_size)
179  off = cusexmp_size;
180  if (size > cusexmp_size - off)
181  size = cusexmp_size - off;
182 
183  iov[2].iov_base = cusexmp_buf + off;
184  iov[2].iov_len = size;
185  fuse_reply_ioctl_iov(req, size, iov, 3);
186  } else {
187  if (cusexmp_expand(arg->offset + in_bufsz)) {
188  fuse_reply_err(req, ENOMEM);
189  return;
190  }
191 
192  memcpy(cusexmp_buf + arg->offset, in_buf, in_bufsz);
193  fuse_reply_ioctl_iov(req, in_bufsz, iov, 2);
194  }
195 }
196 
197 static void cusexmp_ioctl(fuse_req_t req, int cmd, void *arg,
198  struct fuse_file_info *fi, unsigned flags,
199  const void *in_buf, size_t in_bufsz, size_t out_bufsz)
200 {
201  int is_read = 0;
202 
203  (void)fi;
204 
205  if (flags & FUSE_IOCTL_COMPAT) {
206  fuse_reply_err(req, ENOSYS);
207  return;
208  }
209 
210  switch (cmd) {
211  case FIOC_GET_SIZE:
212  if (!out_bufsz) {
213  struct iovec iov = { arg, sizeof(size_t) };
214 
215  fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
216  } else
217  fuse_reply_ioctl(req, 0, &cusexmp_size,
218  sizeof(cusexmp_size));
219  break;
220 
221  case FIOC_SET_SIZE:
222  if (!in_bufsz) {
223  struct iovec iov = { arg, sizeof(size_t) };
224 
225  fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
226  } else {
227  cusexmp_resize(*(size_t *)in_buf);
228  fuse_reply_ioctl(req, 0, NULL, 0);
229  }
230  break;
231 
232  case FIOC_READ:
233  is_read = 1;
234  /* fall through */
235  case FIOC_WRITE:
236  fioc_do_rw(req, arg, in_buf, in_bufsz, out_bufsz, is_read);
237  break;
238 
239  default:
240  fuse_reply_err(req, EINVAL);
241  }
242 }
243 
244 struct cusexmp_param {
245  unsigned major;
246  unsigned minor;
247  char *dev_name;
248  int is_help;
249 };
250 
251 #define CUSEXMP_OPT(t, p) { t, offsetof(struct cusexmp_param, p), 1 }
252 
253 static const struct fuse_opt cusexmp_opts[] = {
254  CUSEXMP_OPT("-M %u", major),
255  CUSEXMP_OPT("--maj=%u", major),
256  CUSEXMP_OPT("-m %u", minor),
257  CUSEXMP_OPT("--min=%u", minor),
258  CUSEXMP_OPT("-n %s", dev_name),
259  CUSEXMP_OPT("--name=%s", dev_name),
260  FUSE_OPT_KEY("-h", 0),
261  FUSE_OPT_KEY("--help", 0),
263 };
264 
265 static int cusexmp_process_arg(void *data, const char *arg, int key,
266  struct fuse_args *outargs)
267 {
268  struct cusexmp_param *param = data;
269 
270  (void)outargs;
271  (void)arg;
272 
273  switch (key) {
274  case 0:
275  param->is_help = 1;
276  fprintf(stderr, "%s", usage);
277  return fuse_opt_add_arg(outargs, "-ho");
278  default:
279  return 1;
280  }
281 }
282 
283 static const struct cuse_lowlevel_ops cusexmp_clop = {
284  .open = cusexmp_open,
285  .read = cusexmp_read,
286  .write = cusexmp_write,
287  .ioctl = cusexmp_ioctl,
288 };
289 
290 int main(int argc, char **argv)
291 {
292  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
293  struct cusexmp_param param = { 0, 0, NULL, 0 };
294  char dev_name[128] = "DEVNAME=";
295  const char *dev_info_argv[] = { dev_name };
296  struct cuse_info ci;
297 
298  if (fuse_opt_parse(&args, &param, cusexmp_opts, cusexmp_process_arg)) {
299  printf("failed to parse option\n");
300  return 1;
301  }
302 
303  if (!param.is_help) {
304  if (!param.dev_name) {
305  fprintf(stderr, "Error: device name missing\n");
306  return 1;
307  }
308  strncat(dev_name, param.dev_name, sizeof(dev_name) - 9);
309  }
310 
311  memset(&ci, 0, sizeof(ci));
312  ci.dev_major = param.major;
313  ci.dev_minor = param.minor;
314  ci.dev_info_argc = 1;
315  ci.dev_info_argv = dev_info_argv;
316  ci.flags = CUSE_UNRESTRICTED_IOCTL;
317 
318  return cuse_lowlevel_main(args.argc, args.argv, &ci, &cusexmp_clop,
319  NULL);
320 }
int fuse_reply_err(fuse_req_t req, int err)
+
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
+
int argc
Definition: fuse_opt.h:111
+
int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
+ +
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
+ +
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
+
#define FUSE_IOCTL_COMPAT
Definition: fuse_common.h:329
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+
char ** argv
Definition: fuse_opt.h:114
+
int fuse_reply_write(fuse_req_t req, size_t count)
+
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
+ + +
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
+ +
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+
+ + + + diff --git a/doc/html/cuse__client_8c.html b/doc/html/cuse__client_8c.html new file mode 100644 index 0000000..5e14520 --- /dev/null +++ b/doc/html/cuse__client_8c.html @@ -0,0 +1,86 @@ + + + + + + + +libfuse: example/cuse_client.c File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
cuse_client.c File Reference
+
+
+
#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include "ioctl.h"
+
+

Go to the source code of this file.

+

Detailed Description

+

This program tests the cuse.c example file system.

+

Example usage (assuming that /dev/foobar is a CUSE device provided by the cuse.c example file system):

$ cuse_client /dev/foobar s
+0
+
+$ echo "hello" | cuse_client /dev/foobar w 6
+Writing 6 bytes
+transferred 6 bytes (0 -> 6)
+
+$ cuse_client /dev/foobar s
+6
+
+$ cuse_client /dev/foobar r 10
+hello
+transferred 6 bytes (6 -> 6)
+

Compiling this example

gcc -Wall cuse_client.c -o cuse_client
+

Source Code

+
/*
FUSE fioclient: FUSE ioctl example client
Copyright (C) 2008 SUSE Linux Products GmbH
Copyright (C) 2008 Tejun Heo <teheo@suse.de>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include "ioctl.h"
const char *usage =
"Usage: cuse_client FIOC_FILE COMMAND\n"
"\n"
"COMMANDS\n"
" s [SIZE] : get size if SIZE is omitted, set size otherwise\n"
" r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n"
" w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n"
"\n";
static int do_rw(int fd, int is_read, size_t size, off_t offset,
size_t *prev_size, size_t *new_size)
{
struct fioc_rw_arg arg = { .offset = offset };
ssize_t ret;
arg.buf = calloc(1, size);
if (!arg.buf) {
fprintf(stderr, "failed to allocated %zu bytes\n", size);
return -1;
}
if (is_read) {
arg.size = size;
ret = ioctl(fd, FIOC_READ, &arg);
if (ret >= 0)
fwrite(arg.buf, 1, ret, stdout);
} else {
arg.size = fread(arg.buf, 1, size, stdin);
fprintf(stderr, "Writing %zu bytes\n", arg.size);
ret = ioctl(fd, FIOC_WRITE, &arg);
}
if (ret >= 0) {
*prev_size = arg.prev_size;
*new_size = arg.new_size;
} else
perror("ioctl");
free(arg.buf);
return ret;
}
int main(int argc, char **argv)
{
size_t param[2] = { };
size_t size, prev_size = 0, new_size = 0;
char cmd;
int fd, i, rc;
if (argc < 3)
goto usage;
fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
cmd = tolower(argv[2][0]);
argc -= 3;
argv += 3;
for (i = 0; i < argc; i++) {
char *endp;
param[i] = strtoul(argv[i], &endp, 0);
if (endp == argv[i] || *endp != '\0')
goto usage;
}
switch (cmd) {
case 's':
if (!argc) {
if (ioctl(fd, FIOC_GET_SIZE, &size)) {
perror("ioctl");
return 1;
}
printf("%zu\n", size);
} else {
size = param[0];
if (ioctl(fd, FIOC_SET_SIZE, &size)) {
perror("ioctl");
return 1;
}
}
return 0;
case 'r':
case 'w':
rc = do_rw(fd, cmd == 'r', param[0], param[1],
&prev_size, &new_size);
if (rc < 0)
return 1;
fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n",
rc, prev_size, new_size);
return 0;
}
usage:
fprintf(stderr, "%s", usage);
return 1;
}
+

Definition in file cuse_client.c.

+
+ + + + diff --git a/doc/html/cuse__client_8c_source.html b/doc/html/cuse__client_8c_source.html new file mode 100644 index 0000000..5df3811 --- /dev/null +++ b/doc/html/cuse__client_8c_source.html @@ -0,0 +1,57 @@ + + + + + + + +libfuse: example/cuse_client.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
cuse_client.c
+
+
+Go to the documentation of this file.
1 /*
2  FUSE fioclient: FUSE ioctl example client
3  Copyright (C) 2008 SUSE Linux Products GmbH
4  Copyright (C) 2008 Tejun Heo <teheo@suse.de>
5 
6  This program can be distributed under the terms of the GNU GPL.
7  See the file COPYING.
8 */
9 
40 #include <sys/types.h>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <sys/ioctl.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include "ioctl.h"
49 
50 const char *usage =
51 "Usage: cuse_client FIOC_FILE COMMAND\n"
52 "\n"
53 "COMMANDS\n"
54 " s [SIZE] : get size if SIZE is omitted, set size otherwise\n"
55 " r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n"
56 " w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n"
57 "\n";
58 
59 static int do_rw(int fd, int is_read, size_t size, off_t offset,
60  size_t *prev_size, size_t *new_size)
61 {
62  struct fioc_rw_arg arg = { .offset = offset };
63  ssize_t ret;
64 
65  arg.buf = calloc(1, size);
66  if (!arg.buf) {
67  fprintf(stderr, "failed to allocated %zu bytes\n", size);
68  return -1;
69  }
70 
71  if (is_read) {
72  arg.size = size;
73  ret = ioctl(fd, FIOC_READ, &arg);
74  if (ret >= 0)
75  fwrite(arg.buf, 1, ret, stdout);
76  } else {
77  arg.size = fread(arg.buf, 1, size, stdin);
78  fprintf(stderr, "Writing %zu bytes\n", arg.size);
79  ret = ioctl(fd, FIOC_WRITE, &arg);
80  }
81 
82  if (ret >= 0) {
83  *prev_size = arg.prev_size;
84  *new_size = arg.new_size;
85  } else
86  perror("ioctl");
87 
88  free(arg.buf);
89  return ret;
90 }
91 
92 int main(int argc, char **argv)
93 {
94  size_t param[2] = { };
95  size_t size, prev_size = 0, new_size = 0;
96  char cmd;
97  int fd, i, rc;
98 
99  if (argc < 3)
100  goto usage;
101 
102  fd = open(argv[1], O_RDWR);
103  if (fd < 0) {
104  perror("open");
105  return 1;
106  }
107 
108  cmd = tolower(argv[2][0]);
109  argc -= 3;
110  argv += 3;
111 
112  for (i = 0; i < argc; i++) {
113  char *endp;
114  param[i] = strtoul(argv[i], &endp, 0);
115  if (endp == argv[i] || *endp != '\0')
116  goto usage;
117  }
118 
119  switch (cmd) {
120  case 's':
121  if (!argc) {
122  if (ioctl(fd, FIOC_GET_SIZE, &size)) {
123  perror("ioctl");
124  return 1;
125  }
126  printf("%zu\n", size);
127  } else {
128  size = param[0];
129  if (ioctl(fd, FIOC_SET_SIZE, &size)) {
130  perror("ioctl");
131  return 1;
132  }
133  }
134  return 0;
135 
136  case 'r':
137  case 'w':
138  rc = do_rw(fd, cmd == 'r', param[0], param[1],
139  &prev_size, &new_size);
140  if (rc < 0)
141  return 1;
142  fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n",
143  rc, prev_size, new_size);
144  return 0;
145  }
146 
147  usage:
148  fprintf(stderr, "%s", usage);
149  return 1;
150 }
+
+ + + + diff --git a/doc/html/cuse__lowlevel_8c_source.html b/doc/html/cuse__lowlevel_8c_source.html new file mode 100644 index 0000000..12c8a1e --- /dev/null +++ b/doc/html/cuse__lowlevel_8c_source.html @@ -0,0 +1,79 @@ + + + + + + + +libfuse: lib/cuse_lowlevel.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
cuse_lowlevel.c
+
+
+
1 /*
2  CUSE: Character device in Userspace
3  Copyright (C) 2008 SUSE Linux Products GmbH
4  Copyright (C) 2008 Tejun Heo <teheo@suse.de>
5 
6  This program can be distributed under the terms of the GNU LGPLv2.
7  See the file COPYING.LIB.
8 */
9 
10 #include "config.h"
11 #include "cuse_lowlevel.h"
12 #include "fuse_kernel.h"
13 #include "fuse_i.h"
14 #include "fuse_opt.h"
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include <errno.h>
21 #include <unistd.h>
22 
23 struct cuse_data {
24  struct cuse_lowlevel_ops clop;
25  unsigned max_read;
26  unsigned dev_major;
27  unsigned dev_minor;
28  unsigned flags;
29  unsigned dev_info_len;
30  char dev_info[];
31 };
32 
33 static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
34 {
35  return &req->se->cuse_data->clop;
36 }
37 
38 static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
39  struct fuse_file_info *fi)
40 {
41  (void)ino;
42  req_clop(req)->open(req, fi);
43 }
44 
45 static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
46  off_t off, struct fuse_file_info *fi)
47 {
48  (void)ino;
49  req_clop(req)->read(req, size, off, fi);
50 }
51 
52 static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
53  size_t size, off_t off, struct fuse_file_info *fi)
54 {
55  (void)ino;
56  req_clop(req)->write(req, buf, size, off, fi);
57 }
58 
59 static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
60  struct fuse_file_info *fi)
61 {
62  (void)ino;
63  req_clop(req)->flush(req, fi);
64 }
65 
66 static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
67  struct fuse_file_info *fi)
68 {
69  (void)ino;
70  req_clop(req)->release(req, fi);
71 }
72 
73 static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
74  struct fuse_file_info *fi)
75 {
76  (void)ino;
77  req_clop(req)->fsync(req, datasync, fi);
78 }
79 
80 static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
81  struct fuse_file_info *fi, unsigned int flags,
82  const void *in_buf, size_t in_bufsz, size_t out_bufsz)
83 {
84  (void)ino;
85  req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
86  out_bufsz);
87 }
88 
89 static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
90  struct fuse_file_info *fi, struct fuse_pollhandle *ph)
91 {
92  (void)ino;
93  req_clop(req)->poll(req, fi, ph);
94 }
95 
96 static size_t cuse_pack_info(int argc, const char **argv, char *buf)
97 {
98  size_t size = 0;
99  int i;
100 
101  for (i = 0; i < argc; i++) {
102  size_t len;
103 
104  len = strlen(argv[i]) + 1;
105  size += len;
106  if (buf) {
107  memcpy(buf, argv[i], len);
108  buf += len;
109  }
110  }
111 
112  return size;
113 }
114 
115 static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
116  const struct cuse_lowlevel_ops *clop)
117 {
118  struct cuse_data *cd;
119  size_t dev_info_len;
120 
121  dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
122  NULL);
123 
124  if (dev_info_len > CUSE_INIT_INFO_MAX) {
125  fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n",
126  dev_info_len, CUSE_INIT_INFO_MAX);
127  return NULL;
128  }
129 
130  cd = calloc(1, sizeof(*cd) + dev_info_len);
131  if (!cd) {
132  fprintf(stderr, "cuse: failed to allocate cuse_data\n");
133  return NULL;
134  }
135 
136  memcpy(&cd->clop, clop, sizeof(cd->clop));
137  cd->max_read = 131072;
138  cd->dev_major = ci->dev_major;
139  cd->dev_minor = ci->dev_minor;
140  cd->dev_info_len = dev_info_len;
141  cd->flags = ci->flags;
142  cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info);
143 
144  return cd;
145 }
146 
147 struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
148  const struct cuse_info *ci,
149  const struct cuse_lowlevel_ops *clop,
150  void *userdata)
151 {
152  struct fuse_lowlevel_ops lop;
153  struct cuse_data *cd;
154  struct fuse_session *se;
155 
156  cd = cuse_prep_data(ci, clop);
157  if (!cd)
158  return NULL;
159 
160  memset(&lop, 0, sizeof(lop));
161  lop.init = clop->init;
162  lop.destroy = clop->destroy;
163  lop.open = clop->open ? cuse_fll_open : NULL;
164  lop.read = clop->read ? cuse_fll_read : NULL;
165  lop.write = clop->write ? cuse_fll_write : NULL;
166  lop.flush = clop->flush ? cuse_fll_flush : NULL;
167  lop.release = clop->release ? cuse_fll_release : NULL;
168  lop.fsync = clop->fsync ? cuse_fll_fsync : NULL;
169  lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL;
170  lop.poll = clop->poll ? cuse_fll_poll : NULL;
171 
172  se = fuse_session_new(args, &lop, sizeof(lop), userdata);
173  if (!se) {
174  free(cd);
175  return NULL;
176  }
177  se->cuse_data = cd;
178 
179  return se;
180 }
181 
182 static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
183  char *dev_info, unsigned dev_info_len)
184 {
185  struct iovec iov[3];
186 
187  iov[1].iov_base = arg;
188  iov[1].iov_len = sizeof(struct cuse_init_out);
189  iov[2].iov_base = dev_info;
190  iov[2].iov_len = dev_info_len;
191 
192  return fuse_send_reply_iov_nofree(req, 0, iov, 3);
193 }
194 
195 void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
196 {
197  struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
198  struct cuse_init_out outarg;
199  struct fuse_session *se = req->se;
200  struct cuse_data *cd = se->cuse_data;
201  size_t bufsize = se->bufsize;
202  struct cuse_lowlevel_ops *clop = req_clop(req);
203 
204  (void) nodeid;
205  if (se->debug) {
206  fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
207  fprintf(stderr, "flags=0x%08x\n", arg->flags);
208  }
209  se->conn.proto_major = arg->major;
210  se->conn.proto_minor = arg->minor;
211  se->conn.capable = 0;
212  se->conn.want = 0;
213 
214  if (arg->major < 7) {
215  fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n",
216  arg->major, arg->minor);
217  fuse_reply_err(req, EPROTO);
218  return;
219  }
220 
221  if (bufsize < FUSE_MIN_READ_BUFFER) {
222  fprintf(stderr, "cuse: warning: buffer size too small: %zu\n",
223  bufsize);
224  bufsize = FUSE_MIN_READ_BUFFER;
225  }
226 
227  bufsize -= 4096;
228  if (bufsize < se->conn.max_write)
229  se->conn.max_write = bufsize;
230 
231  se->got_init = 1;
232  if (se->op.init)
233  se->op.init(se->userdata, &se->conn);
234 
235  memset(&outarg, 0, sizeof(outarg));
236  outarg.major = FUSE_KERNEL_VERSION;
237  outarg.minor = FUSE_KERNEL_MINOR_VERSION;
238  outarg.flags = cd->flags;
239  outarg.max_read = cd->max_read;
240  outarg.max_write = se->conn.max_write;
241  outarg.dev_major = cd->dev_major;
242  outarg.dev_minor = cd->dev_minor;
243 
244  if (se->debug) {
245  fprintf(stderr, " CUSE_INIT: %u.%u\n",
246  outarg.major, outarg.minor);
247  fprintf(stderr, " flags=0x%08x\n", outarg.flags);
248  fprintf(stderr, " max_read=0x%08x\n", outarg.max_read);
249  fprintf(stderr, " max_write=0x%08x\n", outarg.max_write);
250  fprintf(stderr, " dev_major=%u\n", outarg.dev_major);
251  fprintf(stderr, " dev_minor=%u\n", outarg.dev_minor);
252  fprintf(stderr, " dev_info: %.*s\n", cd->dev_info_len,
253  cd->dev_info);
254  }
255 
256  cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
257 
258  if (clop->init_done)
259  clop->init_done(se->userdata);
260 
261  fuse_free_req(req);
262 }
263 
264 struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
265  const struct cuse_info *ci,
266  const struct cuse_lowlevel_ops *clop,
267  int *multithreaded, void *userdata)
268 {
269  const char *devname = "/dev/cuse";
270  static const struct fuse_opt kill_subtype_opts[] = {
271  FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD),
273  };
274  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
275  struct fuse_session *se;
276  struct fuse_cmdline_opts opts;
277  int fd;
278  int res;
279 
280  if (fuse_parse_cmdline(&args, &opts) == -1)
281  return NULL;
282  *multithreaded = !opts.singlethread;
283 
284  /* Remove subtype= option */
285  res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
286  if (res == -1)
287  goto out1;
288 
289  /*
290  * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
291  * would ensue.
292  */
293  do {
294  fd = open("/dev/null", O_RDWR);
295  if (fd > 2)
296  close(fd);
297  } while (fd >= 0 && fd <= 2);
298 
299  se = cuse_lowlevel_new(&args, ci, clop, userdata);
300  if (se == NULL)
301  goto out1;
302 
303  fd = open(devname, O_RDWR);
304  if (fd == -1) {
305  if (errno == ENODEV || errno == ENOENT)
306  fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n");
307  else
308  fprintf(stderr, "cuse: failed to open %s: %s\n",
309  devname, strerror(errno));
310  goto err_se;
311  }
312  se->fd = fd;
313 
314  res = fuse_set_signal_handlers(se);
315  if (res == -1)
316  goto err_se;
317 
318  res = fuse_daemonize(opts.foreground);
319  if (res == -1)
320  goto err_sig;
321 
322  return se;
323 
324 err_sig:
326 err_se:
328 out1:
329  free(opts.mountpoint);
330  fuse_opt_free_args(&args);
331  return NULL;
332 }
333 
334 void cuse_lowlevel_teardown(struct fuse_session *se)
335 {
338 }
339 
340 int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
341  const struct cuse_lowlevel_ops *clop, void *userdata)
342 {
343  struct fuse_session *se;
344  int multithreaded;
345  int res;
346 
347  se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
348  userdata);
349  if (se == NULL)
350  return 1;
351 
352  if (multithreaded) {
353  struct fuse_loop_config config;
354  config.clone_fd = 0;
355  config.max_idle_threads = 10;
356  res = fuse_session_loop_mt_32(se, &config);
357  }
358  else
359  res = fuse_session_loop(se);
360 
361  cuse_lowlevel_teardown(se);
362  if (res == -1)
363  return 1;
364 
365  return 0;
366 }
void fuse_session_destroy(struct fuse_session *se)
+
int fuse_reply_err(fuse_req_t req, int err)
+
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
+
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
+
int fuse_daemonize(int foreground)
Definition: helper.c:225
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
+
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
+
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
+
#define FUSE_OPT_KEY_DISCARD
Definition: fuse_opt.h:153
+ + +
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+ +
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
+ + + +
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
+ +
+ + + + diff --git a/doc/html/cuse__lowlevel_8h_source.html b/doc/html/cuse__lowlevel_8h_source.html new file mode 100644 index 0000000..37d0e18 --- /dev/null +++ b/doc/html/cuse__lowlevel_8h_source.html @@ -0,0 +1,63 @@ + + + + + + + +libfuse: include/cuse_lowlevel.h Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
cuse_lowlevel.h
+
+
+
1 /*
2  CUSE: Character device in Userspace
3  Copyright (C) 2008-2009 SUSE Linux Products GmbH
4  Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
5 
6  This program can be distributed under the terms of the GNU LGPLv2.
7  See the file COPYING.LIB.
8 
9  Read example/cusexmp.c for usages.
10 */
11 
12 #ifndef CUSE_LOWLEVEL_H_
13 #define CUSE_LOWLEVEL_H_
14 
15 #ifndef FUSE_USE_VERSION
16 #define FUSE_USE_VERSION 29
17 #endif
18 
19 #include "fuse_lowlevel.h"
20 
21 #include <fcntl.h>
22 #include <sys/types.h>
23 #include <sys/uio.h>
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */
30 
31 struct fuse_session;
32 
33 struct cuse_info {
34  unsigned dev_major;
35  unsigned dev_minor;
36  unsigned dev_info_argc;
37  const char **dev_info_argv;
38  unsigned flags;
39 };
40 
41 /*
42  * Most ops behave almost identically to the matching fuse_lowlevel
43  * ops except that they don't take @ino.
44  *
45  * init_done : called after initialization is complete
46  * read/write : always direct IO, simultaneous operations allowed
47  * ioctl : might be in unrestricted mode depending on ci->flags
48  */
49 struct cuse_lowlevel_ops {
50  void (*init) (void *userdata, struct fuse_conn_info *conn);
51  void (*init_done) (void *userdata);
52  void (*destroy) (void *userdata);
53  void (*open) (fuse_req_t req, struct fuse_file_info *fi);
54  void (*read) (fuse_req_t req, size_t size, off_t off,
55  struct fuse_file_info *fi);
56  void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off,
57  struct fuse_file_info *fi);
58  void (*flush) (fuse_req_t req, struct fuse_file_info *fi);
59  void (*release) (fuse_req_t req, struct fuse_file_info *fi);
60  void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi);
61  void (*ioctl) (fuse_req_t req, int cmd, void *arg,
62  struct fuse_file_info *fi, unsigned int flags,
63  const void *in_buf, size_t in_bufsz, size_t out_bufsz);
64  void (*poll) (fuse_req_t req, struct fuse_file_info *fi,
65  struct fuse_pollhandle *ph);
66 };
67 
68 struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
69  const struct cuse_info *ci,
70  const struct cuse_lowlevel_ops *clop,
71  void *userdata);
72 
73 struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
74  const struct cuse_info *ci,
75  const struct cuse_lowlevel_ops *clop,
76  int *multithreaded, void *userdata);
77 
78 void cuse_lowlevel_teardown(struct fuse_session *se);
79 
80 int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
81  const struct cuse_lowlevel_ops *clop, void *userdata);
82 
83 #ifdef __cplusplus
84 }
85 #endif
86 
87 #endif /* CUSE_LOWLEVEL_H_ */
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+ + +
unsigned int flush
Definition: fuse_common.h:56
+ + +
+ + + + diff --git a/doc/html/dir_13e138d54eb8818da29c3992edef070a.html b/doc/html/dir_13e138d54eb8818da29c3992edef070a.html new file mode 100644 index 0000000..a7ce485 --- /dev/null +++ b/doc/html/dir_13e138d54eb8818da29c3992edef070a.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: test Directory Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
test Directory Reference
+
+
+
+ + + + diff --git a/doc/html/dir_23ec12649285f9fabf3a6b7380226c28.html b/doc/html/dir_23ec12649285f9fabf3a6b7380226c28.html new file mode 100644 index 0000000..99159c4 --- /dev/null +++ b/doc/html/dir_23ec12649285f9fabf3a6b7380226c28.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: util Directory Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
util Directory Reference
+
+
+
+ + + + diff --git a/doc/html/dir_3ccffc210a036acba650f09ebe71329d.html b/doc/html/dir_4fef79e7177ba769987a8da36c892c5f.html similarity index 52% rename from doc/html/dir_3ccffc210a036acba650f09ebe71329d.html rename to doc/html/dir_4fef79e7177ba769987a8da36c892c5f.html index 19b8c6d..41168ef 100644 --- a/doc/html/dir_3ccffc210a036acba650f09ebe71329d.html +++ b/doc/html/dir_4fef79e7177ba769987a8da36c892c5f.html @@ -3,8 +3,9 @@ - -fuse: include/old Directory Reference + + +libfuse: build Directory Reference @@ -16,8 +17,8 @@ - @@ -25,36 +26,35 @@
-
fuse +
+
libfuse
- - + + + + +
-
old Directory Reference
+
build Directory Reference
- - - +

-Files

file  fuse.h
 

+Directories

diff --git a/doc/html/dir_93598ca166e67dcc8cf3dfff647b911b.html b/doc/html/dir_93598ca166e67dcc8cf3dfff647b911b.html new file mode 100644 index 0000000..28e5554 --- /dev/null +++ b/doc/html/dir_93598ca166e67dcc8cf3dfff647b911b.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: build/meson-private Directory Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
meson-private Directory Reference
+
+
+
+ + + + diff --git a/doc/html/dir_97aefd0d527b934f1d99a682da8fe6a9.html b/doc/html/dir_97aefd0d527b934f1d99a682da8fe6a9.html new file mode 100644 index 0000000..6c3117c --- /dev/null +++ b/doc/html/dir_97aefd0d527b934f1d99a682da8fe6a9.html @@ -0,0 +1,60 @@ + + + + + + + +libfuse: lib Directory Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
lib Directory Reference
+
+
+ + +

+Directories

+
+ + + + diff --git a/doc/html/dir_cfafba98a580ce4b62f8a6fa96d7cbb0.html b/doc/html/dir_cfafba98a580ce4b62f8a6fa96d7cbb0.html new file mode 100644 index 0000000..80c0848 --- /dev/null +++ b/doc/html/dir_cfafba98a580ce4b62f8a6fa96d7cbb0.html @@ -0,0 +1,96 @@ + + + + + + + +libfuse: example Directory Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
example Directory Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Files

file  cuse.c [code]
 
file  cuse_client.c [code]
 
file  hello.c [code]
 
file  hello_ll.c [code]
 
file  invalidate_path.c [code]
 
file  ioctl.c [code]
 
file  ioctl.h [code]
 
file  ioctl_client.c [code]
 
file  notify_inval_entry.c [code]
 
file  notify_inval_inode.c [code]
 
file  notify_store_retrieve.c [code]
 
file  null.c [code]
 
file  passthrough.c [code]
 
file  passthrough_fh.c [code]
 
file  passthrough_ll.c [code]
 
file  poll.c [code]
 
file  poll_client.c [code]
 
file  printcap.c [code]
 
+
+ + + + diff --git a/doc/html/dir_d44c64559bbebec7f509842c48db8b23.html b/doc/html/dir_d44c64559bbebec7f509842c48db8b23.html index 15ab6b0..9e617f4 100644 --- a/doc/html/dir_d44c64559bbebec7f509842c48db8b23.html +++ b/doc/html/dir_d44c64559bbebec7f509842c48db8b23.html @@ -3,8 +3,9 @@ - -fuse: include Directory Reference + + +libfuse: include Directory Reference @@ -16,8 +17,8 @@ - @@ -25,14 +26,15 @@
-
fuse +
+
libfuse
- - + + + + +
- - - -

-Directories

directory  old
 
- - - - - - - - - - - - - - - + - + - + - +

Files

file  config.h
 
file  cuse_lowlevel.h
 
file  fuse.h
 
file  fuse_common.h
 
file  fuse_common_compat.h
 
file  fuse_compat.h
 
file  fuse_kernel.h
 
file  fuse_lowlevel.h
file  fuse.h [code]
 
file  fuse_lowlevel_compat.h
file  fuse_common.h [code]
 
file  fuse_opt.h
file  fuse_lowlevel.h [code]
 
file  ulockmgr.h
file  fuse_opt.h [code]
 
diff --git a/doc/html/dir_e1dbc8ba94a86723d4c32227b7c46099.html b/doc/html/dir_e1dbc8ba94a86723d4c32227b7c46099.html new file mode 100644 index 0000000..7ceb153 --- /dev/null +++ b/doc/html/dir_e1dbc8ba94a86723d4c32227b7c46099.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: lib/modules Directory Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
modules Directory Reference
+
+
+
+ + + + diff --git a/doc/html/ftv2link.png b/doc/html/doc.png similarity index 100% rename from doc/html/ftv2link.png rename to doc/html/doc.png diff --git a/doc/html/doxygen.css b/doc/html/doxygen.css index 02e8b01..4f1ab91 100644 --- a/doc/html/doxygen.css +++ b/doc/html/doxygen.css @@ -1,9 +1,13 @@ -/* The standard CSS for doxygen 1.8.8 */ +/* The standard CSS for doxygen 1.8.13 */ body, table, div, p, dl { font: 400 14px/22px Roboto,sans-serif; } +p.reference, p.definition { + font: 400 14px/22px Roboto,sans-serif; +} + /* @group Heading Levels */ h1.groupheader { @@ -173,7 +177,7 @@ pre.fragment { } div.fragment { - padding: 4px 6px; + padding: 0px; margin: 4px 8px 4px 2px; background-color: #FBFCFD; border: 1px solid #C4CFE5; @@ -206,6 +210,11 @@ div.line { transition-duration: 0.5s; } +div.line:after { + content:"\000A"; + white-space: pre; +} + div.line.glow { background-color: cyan; box-shadow: 0 0 10px cyan; @@ -227,7 +236,16 @@ span.lineno a:hover { background-color: #C8C8C8; } -div.ah { +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { background-color: black; font-weight: bold; color: #ffffff; @@ -242,7 +260,16 @@ div.ah { -webkit-box-shadow: 2px 2px 3px #999; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); - background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; } div.groupHeader { @@ -487,6 +514,29 @@ table.memberdecls { /* Styles for detailed member documentation */ +.memtitle { + padding: 8px; + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: url('nav_f.png'); + background-repeat: repeat-x; + background-color: #E2E8F2; + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + .memtemplate { font-size: 80%; color: #4665A2; @@ -525,7 +575,7 @@ table.memberdecls { } .memname { - font-weight: bold; + font-weight: 400; margin-left: 6px; } @@ -541,24 +591,24 @@ table.memberdecls { color: #253555; font-weight: bold; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); - background-image:url('nav_f.png'); - background-repeat:repeat-x; - background-color: #E2E8F2; + background-color: #DFE5F1; /* opera specific markup */ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); border-top-right-radius: 4px; - border-top-left-radius: 4px; /* firefox specific markup */ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; -moz-border-radius-topright: 4px; - -moz-border-radius-topleft: 4px; /* webkit specific markup */ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); -webkit-border-top-right-radius: 4px; - -webkit-border-top-left-radius: 4px; } +.overload { + font-family: "courier new",courier,monospace; + font-size: 65%; +} + .memdoc, dl.reflist dd { border-bottom: 1px solid #A8B8D9; border-left: 1px solid #A8B8D9; @@ -773,7 +823,7 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('ftv2folderopen.png'); + background-image:url('folderopen.png'); background-position: 0px -4px; background-repeat: repeat-y; vertical-align:top; @@ -784,7 +834,7 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('ftv2folderclosed.png'); + background-image:url('folderclosed.png'); background-position: 0px -4px; background-repeat: repeat-y; vertical-align:top; @@ -795,7 +845,7 @@ div.directory { width: 24px; height: 18px; margin-bottom: 4px; - background-image:url('ftv2doc.png'); + background-image:url('doc.png'); background-position: 0px -4px; background-repeat: repeat-y; vertical-align:top; @@ -823,6 +873,10 @@ address { color: #2A3D61; } +table.doxtable caption { + caption-side: top; +} + table.doxtable { border-collapse:collapse; margin-top: 4px; @@ -896,6 +950,7 @@ table.fieldtable { padding-bottom: 4px; padding-top: 5px; text-align:left; + font-weight: 400; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-left-radius: 4px; @@ -988,6 +1043,18 @@ div.summary a white-space: nowrap; } +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + div.ingroups { font-size: 8pt; @@ -1099,6 +1166,11 @@ dl.section dd { border: 0px none; } +#projectalign +{ + vertical-align: middle; +} + #projectname { font: 300% Tahoma, Arial,sans-serif; @@ -1143,6 +1215,11 @@ dl.section dd { text-align: center; } +.plantumlgraph +{ + text-align: center; +} + .diagraph { text-align: center; @@ -1182,7 +1259,7 @@ div.toc { border-radius: 7px 7px 7px 7px; float: right; height: auto; - margin: 0 20px 10px 10px; + margin: 0 8px 10px 10px; width: 200px; } @@ -1438,3 +1515,82 @@ tr.heading h2 { } } +/* @group Markdown */ + +/* +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTableHead tr { +} + +table.markdownTableBodyLeft td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft { + text-align: left +} + +th.markdownTableHeadRight { + text-align: right +} + +th.markdownTableHeadCenter { + text-align: center +} +*/ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + + +/* @end */ diff --git a/doc/html/dynsections.js b/doc/html/dynsections.js deleted file mode 100644 index 85e1836..0000000 --- a/doc/html/dynsections.js +++ /dev/null @@ -1,97 +0,0 @@ -function toggleVisibility(linkObj) -{ - var base = $(linkObj).attr('id'); - var summary = $('#'+base+'-summary'); - var content = $('#'+base+'-content'); - var trigger = $('#'+base+'-trigger'); - var src=$(trigger).attr('src'); - if (content.is(':visible')===true) { - content.hide(); - summary.show(); - $(linkObj).addClass('closed').removeClass('opened'); - $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); - } else { - content.show(); - summary.hide(); - $(linkObj).removeClass('closed').addClass('opened'); - $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); - } - return false; -} - -function updateStripes() -{ - $('table.directory tr'). - removeClass('even').filter(':visible:even').addClass('even'); -} - -function toggleLevel(level) -{ - $('table.directory tr').each(function() { - var l = this.id.split('_').length-1; - var i = $('#img'+this.id.substring(3)); - var a = $('#arr'+this.id.substring(3)); - if (l - -fuse: File List + + +libfuse: File List @@ -16,8 +17,8 @@ - @@ -25,20 +26,15 @@
-
fuse +
+
libfuse
- - - + + + + +
@@ -46,20 +42,73 @@
Here is a list of all documented files with brief descriptions:
-
[detail level 12]
- - - - - +
[detail level 123]
  include
 fuse.h
 fuse_common.h
 fuse_lowlevel.h
 fuse_opt.h
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  build
  meson-private
 sanitycheckc.c
 config.h
  example
 cuse.c
 cuse_client.c
 hello.c
 hello_ll.c
 invalidate_path.c
 ioctl.c
 ioctl.h
 ioctl_client.c
 notify_inval_entry.c
 notify_inval_inode.c
 notify_store_retrieve.c
 null.c
 passthrough.c
 passthrough_fh.c
 passthrough_ll.c
 poll.c
 poll_client.c
 printcap.c
  include
 cuse_lowlevel.h
 fuse.h
 fuse_common.h
 fuse_kernel.h
 fuse_lowlevel.h
 fuse_opt.h
  lib
  modules
 iconv.c
 subdir.c
 buffer.c
 cuse_lowlevel.c
 fuse.c
 fuse_i.h
 fuse_loop.c
 fuse_loop_mt.c
 fuse_lowlevel.c
 fuse_misc.h
 fuse_opt.c
 fuse_signals.c
 helper.c
 mount.c
 mount_bsd.c
 mount_util.c
 mount_util.h
  test
 stracedecode.c
 test_setattr.c
 test_syscalls.c
 test_write_cache.c
 wrong_command.c
  util
 fusermount.c
 mount.fuse.c
diff --git a/doc/html/ftv2folderclosed.png b/doc/html/folderclosed.png similarity index 100% rename from doc/html/ftv2folderclosed.png rename to doc/html/folderclosed.png diff --git a/doc/html/ftv2folderopen.png b/doc/html/folderopen.png similarity index 100% rename from doc/html/ftv2folderopen.png rename to doc/html/folderopen.png diff --git a/doc/html/ftv2blank.png b/doc/html/ftv2blank.png deleted file mode 100644 index 63c605b..0000000 Binary files a/doc/html/ftv2blank.png and /dev/null differ diff --git a/doc/html/ftv2doc.png b/doc/html/ftv2doc.png deleted file mode 100644 index 17edabf..0000000 Binary files a/doc/html/ftv2doc.png and /dev/null differ diff --git a/doc/html/ftv2lastnode.png b/doc/html/ftv2lastnode.png deleted file mode 100644 index 63c605b..0000000 Binary files a/doc/html/ftv2lastnode.png and /dev/null differ diff --git a/doc/html/ftv2mlastnode.png b/doc/html/ftv2mlastnode.png deleted file mode 100644 index 0b63f6d..0000000 Binary files a/doc/html/ftv2mlastnode.png and /dev/null differ diff --git a/doc/html/ftv2mnode.png b/doc/html/ftv2mnode.png deleted file mode 100644 index 0b63f6d..0000000 Binary files a/doc/html/ftv2mnode.png and /dev/null differ diff --git a/doc/html/ftv2node.png b/doc/html/ftv2node.png deleted file mode 100644 index 63c605b..0000000 Binary files a/doc/html/ftv2node.png and /dev/null differ diff --git a/doc/html/ftv2plastnode.png b/doc/html/ftv2plastnode.png deleted file mode 100644 index c6ee22f..0000000 Binary files a/doc/html/ftv2plastnode.png and /dev/null differ diff --git a/doc/html/ftv2pnode.png b/doc/html/ftv2pnode.png deleted file mode 100644 index c6ee22f..0000000 Binary files a/doc/html/ftv2pnode.png and /dev/null differ diff --git a/doc/html/ftv2vertline.png b/doc/html/ftv2vertline.png deleted file mode 100644 index 63c605b..0000000 Binary files a/doc/html/ftv2vertline.png and /dev/null differ diff --git a/doc/html/functions.html b/doc/html/functions.html index 7f02f26..e5b2cd4 100644 --- a/doc/html/functions.html +++ b/doc/html/functions.html @@ -3,8 +3,9 @@ - -fuse: Data Fields + + +libfuse: Data Fields @@ -16,8 +17,8 @@ - @@ -25,58 +26,26 @@
-
fuse +
+
libfuse
- - - - - + + + + +
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
-

- a -

diff --git a/doc/html/functions_vars.html b/doc/html/functions_vars.html index 990fae5..0e061b5 100644 --- a/doc/html/functions_vars.html +++ b/doc/html/functions_vars.html @@ -3,8 +3,9 @@ - -fuse: Data Fields - Variables + + +libfuse: Data Fields - Variables @@ -16,8 +17,8 @@ - @@ -25,58 +26,26 @@
-
fuse +
+
libfuse
- - - - - + + + + +
  -

- a -

diff --git a/doc/html/fuse_8c_source.html b/doc/html/fuse_8c_source.html new file mode 100644 index 0000000..6393b26 --- /dev/null +++ b/doc/html/fuse_8c_source.html @@ -0,0 +1,180 @@ + + + + + + + +libfuse: lib/fuse.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Implementation of the high-level FUSE API on top of the low-level
6  API.
7 
8  This program can be distributed under the terms of the GNU LGPLv2.
9  See the file COPYING.LIB
10 */
11 
12 
13 /* For pthread_rwlock_t */
14 #define _GNU_SOURCE
15 
16 #include "config.h"
17 #include "fuse_i.h"
18 #include "fuse_lowlevel.h"
19 #include "fuse_opt.h"
20 #include "fuse_misc.h"
21 #include "fuse_kernel.h"
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <stdbool.h>
28 #include <unistd.h>
29 #include <time.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <dlfcn.h>
35 #include <assert.h>
36 #include <poll.h>
37 #include <sys/param.h>
38 #include <sys/uio.h>
39 #include <sys/time.h>
40 #include <sys/mman.h>
41 #include <sys/file.h>
42 
43 #define FUSE_NODE_SLAB 1
44 
45 #ifndef MAP_ANONYMOUS
46 #undef FUSE_NODE_SLAB
47 #endif
48 
49 #ifndef RENAME_EXCHANGE
50 #define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
51 #endif
52 
53 #define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
54 
55 #define FUSE_UNKNOWN_INO 0xffffffff
56 #define OFFSET_MAX 0x7fffffffffffffffLL
57 
58 #define NODE_TABLE_MIN_SIZE 8192
59 
60 struct fuse_fs {
61  struct fuse_operations op;
62  struct fuse_module *m;
63  void *user_data;
64  int debug;
65 };
66 
67 struct fusemod_so {
68  void *handle;
69  int ctr;
70 };
71 
72 struct lock_queue_element {
73  struct lock_queue_element *next;
74  pthread_cond_t cond;
75  fuse_ino_t nodeid1;
76  const char *name1;
77  char **path1;
78  struct node **wnode1;
79  fuse_ino_t nodeid2;
80  const char *name2;
81  char **path2;
82  struct node **wnode2;
83  int err;
84  bool first_locked : 1;
85  bool second_locked : 1;
86  bool done : 1;
87 };
88 
89 struct node_table {
90  struct node **array;
91  size_t use;
92  size_t size;
93  size_t split;
94 };
95 
96 #define container_of(ptr, type, member) ({ \
97  const typeof( ((type *)0)->member ) *__mptr = (ptr); \
98  (type *)( (char *)__mptr - offsetof(type,member) );})
99 
100 #define list_entry(ptr, type, member) \
101  container_of(ptr, type, member)
102 
103 struct list_head {
104  struct list_head *next;
105  struct list_head *prev;
106 };
107 
108 struct node_slab {
109  struct list_head list; /* must be the first member */
110  struct list_head freelist;
111  int used;
112 };
113 
114 struct fuse {
115  struct fuse_session *se;
116  struct node_table name_table;
117  struct node_table id_table;
118  struct list_head lru_table;
119  fuse_ino_t ctr;
120  unsigned int generation;
121  unsigned int hidectr;
122  pthread_mutex_t lock;
123  struct fuse_config conf;
124  int intr_installed;
125  struct fuse_fs *fs;
126  struct lock_queue_element *lockq;
127  int pagesize;
128  struct list_head partial_slabs;
129  struct list_head full_slabs;
130  pthread_t prune_thread;
131 };
132 
133 struct lock {
134  int type;
135  off_t start;
136  off_t end;
137  pid_t pid;
138  uint64_t owner;
139  struct lock *next;
140 };
141 
142 struct node {
143  struct node *name_next;
144  struct node *id_next;
145  fuse_ino_t nodeid;
146  unsigned int generation;
147  int refctr;
148  struct node *parent;
149  char *name;
150  uint64_t nlookup;
151  int open_count;
152  struct timespec stat_updated;
153  struct timespec mtime;
154  off_t size;
155  struct lock *locks;
156  unsigned int is_hidden : 1;
157  unsigned int cache_valid : 1;
158  int treelock;
159  char inline_name[32];
160 };
161 
162 #define TREELOCK_WRITE -1
163 #define TREELOCK_WAIT_OFFSET INT_MIN
164 
165 struct node_lru {
166  struct node node;
167  struct list_head lru;
168  struct timespec forget_time;
169 };
170 
171 struct fuse_direntry {
172  struct stat stat;
173  char *name;
174  struct fuse_direntry *next;
175 };
176 
177 struct fuse_dh {
178  pthread_mutex_t lock;
179  struct fuse *fuse;
180  fuse_req_t req;
181  char *contents;
182  struct fuse_direntry *first;
183  struct fuse_direntry **last;
184  unsigned len;
185  unsigned size;
186  unsigned needlen;
187  int filled;
188  uint64_t fh;
189  int error;
190  fuse_ino_t nodeid;
191 };
192 
193 struct fuse_context_i {
194  struct fuse_context ctx;
195  fuse_req_t req;
196 };
197 
198 /* Defined by FUSE_REGISTER_MODULE() in lib/modules/subdir.c and iconv.c. */
199 extern fuse_module_factory_t fuse_module_subdir_factory;
200 #ifdef HAVE_ICONV
201 extern fuse_module_factory_t fuse_module_iconv_factory;
202 #endif
203 
204 static pthread_key_t fuse_context_key;
205 static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
206 static int fuse_context_ref;
207 static struct fuse_module *fuse_modules = NULL;
208 
209 static int fuse_register_module(const char *name,
210  fuse_module_factory_t factory,
211  struct fusemod_so *so)
212 {
213  struct fuse_module *mod;
214 
215  mod = calloc(1, sizeof(struct fuse_module));
216  if (!mod) {
217  fprintf(stderr, "fuse: failed to allocate module\n");
218  return -1;
219  }
220  mod->name = strdup(name);
221  if (!mod->name) {
222  fprintf(stderr, "fuse: failed to allocate module name\n");
223  free(mod);
224  return -1;
225  }
226  mod->factory = factory;
227  mod->ctr = 0;
228  mod->so = so;
229  if (mod->so)
230  mod->so->ctr++;
231  mod->next = fuse_modules;
232  fuse_modules = mod;
233 
234  return 0;
235 }
236 
237 static void fuse_unregister_module(struct fuse_module *m)
238 {
239  struct fuse_module **mp;
240  for (mp = &fuse_modules; *mp; mp = &(*mp)->next) {
241  if (*mp == m) {
242  *mp = (*mp)->next;
243  break;
244  }
245  }
246  free(m->name);
247  free(m);
248 }
249 
250 static int fuse_load_so_module(const char *module)
251 {
252  int ret = -1;
253  char *tmp;
254  struct fusemod_so *so;
255  fuse_module_factory_t factory;
256 
257  tmp = malloc(strlen(module) + 64);
258  if (!tmp) {
259  fprintf(stderr, "fuse: memory allocation failed\n");
260  return -1;
261  }
262  sprintf(tmp, "libfusemod_%s.so", module);
263  so = calloc(1, sizeof(struct fusemod_so));
264  if (!so) {
265  fprintf(stderr, "fuse: failed to allocate module so\n");
266  goto out;
267  }
268 
269  so->handle = dlopen(tmp, RTLD_NOW);
270  if (so->handle == NULL) {
271  fprintf(stderr, "fuse: dlopen(%s) failed: %s\n",
272  tmp, dlerror());
273  goto out_free_so;
274  }
275 
276  sprintf(tmp, "fuse_module_%s_factory", module);
277  *(void**)(&factory) = dlsym(so->handle, tmp);
278  if (factory == NULL) {
279  fprintf(stderr, "fuse: symbol <%s> not found in module: %s\n",
280  tmp, dlerror());
281  goto out_dlclose;
282  }
283  ret = fuse_register_module(module, factory, so);
284  if (ret)
285  goto out_dlclose;
286 
287 out:
288  free(tmp);
289  return ret;
290 
291 out_dlclose:
292  dlclose(so->handle);
293 out_free_so:
294  free(so);
295  goto out;
296 }
297 
298 static struct fuse_module *fuse_find_module(const char *module)
299 {
300  struct fuse_module *m;
301  for (m = fuse_modules; m; m = m->next) {
302  if (strcmp(module, m->name) == 0) {
303  m->ctr++;
304  break;
305  }
306  }
307  return m;
308 }
309 
310 static struct fuse_module *fuse_get_module(const char *module)
311 {
312  struct fuse_module *m;
313 
314  pthread_mutex_lock(&fuse_context_lock);
315  m = fuse_find_module(module);
316  if (!m) {
317  int err = fuse_load_so_module(module);
318  if (!err)
319  m = fuse_find_module(module);
320  }
321  pthread_mutex_unlock(&fuse_context_lock);
322  return m;
323 }
324 
325 static void fuse_put_module(struct fuse_module *m)
326 {
327  pthread_mutex_lock(&fuse_context_lock);
328  if (m->so)
329  assert(m->ctr > 0);
330  /* Builtin modules may already have m->ctr == 0 */
331  if (m->ctr > 0)
332  m->ctr--;
333  if (!m->ctr && m->so) {
334  struct fusemod_so *so = m->so;
335  assert(so->ctr > 0);
336  so->ctr--;
337  if (!so->ctr) {
338  struct fuse_module **mp;
339  for (mp = &fuse_modules; *mp;) {
340  if ((*mp)->so == so)
341  fuse_unregister_module(*mp);
342  else
343  mp = &(*mp)->next;
344  }
345  dlclose(so->handle);
346  free(so);
347  }
348  } else if (!m->ctr) {
349  fuse_unregister_module(m);
350  }
351  pthread_mutex_unlock(&fuse_context_lock);
352 }
353 
354 static void init_list_head(struct list_head *list)
355 {
356  list->next = list;
357  list->prev = list;
358 }
359 
360 static int list_empty(const struct list_head *head)
361 {
362  return head->next == head;
363 }
364 
365 static void list_add(struct list_head *new, struct list_head *prev,
366  struct list_head *next)
367 {
368  next->prev = new;
369  new->next = next;
370  new->prev = prev;
371  prev->next = new;
372 }
373 
374 static inline void list_add_head(struct list_head *new, struct list_head *head)
375 {
376  list_add(new, head, head->next);
377 }
378 
379 static inline void list_add_tail(struct list_head *new, struct list_head *head)
380 {
381  list_add(new, head->prev, head);
382 }
383 
384 static inline void list_del(struct list_head *entry)
385 {
386  struct list_head *prev = entry->prev;
387  struct list_head *next = entry->next;
388 
389  next->prev = prev;
390  prev->next = next;
391 }
392 
393 static inline int lru_enabled(struct fuse *f)
394 {
395  return f->conf.remember > 0;
396 }
397 
398 static struct node_lru *node_lru(struct node *node)
399 {
400  return (struct node_lru *) node;
401 }
402 
403 static size_t get_node_size(struct fuse *f)
404 {
405  if (lru_enabled(f))
406  return sizeof(struct node_lru);
407  else
408  return sizeof(struct node);
409 }
410 
411 #ifdef FUSE_NODE_SLAB
412 static struct node_slab *list_to_slab(struct list_head *head)
413 {
414  return (struct node_slab *) head;
415 }
416 
417 static struct node_slab *node_to_slab(struct fuse *f, struct node *node)
418 {
419  return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1));
420 }
421 
422 static int alloc_slab(struct fuse *f)
423 {
424  void *mem;
425  struct node_slab *slab;
426  char *start;
427  size_t num;
428  size_t i;
429  size_t node_size = get_node_size(f);
430 
431  mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE,
432  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
433 
434  if (mem == MAP_FAILED)
435  return -1;
436 
437  slab = mem;
438  init_list_head(&slab->freelist);
439  slab->used = 0;
440  num = (f->pagesize - sizeof(struct node_slab)) / node_size;
441 
442  start = (char *) mem + f->pagesize - num * node_size;
443  for (i = 0; i < num; i++) {
444  struct list_head *n;
445 
446  n = (struct list_head *) (start + i * node_size);
447  list_add_tail(n, &slab->freelist);
448  }
449  list_add_tail(&slab->list, &f->partial_slabs);
450 
451  return 0;
452 }
453 
454 static struct node *alloc_node(struct fuse *f)
455 {
456  struct node_slab *slab;
457  struct list_head *node;
458 
459  if (list_empty(&f->partial_slabs)) {
460  int res = alloc_slab(f);
461  if (res != 0)
462  return NULL;
463  }
464  slab = list_to_slab(f->partial_slabs.next);
465  slab->used++;
466  node = slab->freelist.next;
467  list_del(node);
468  if (list_empty(&slab->freelist)) {
469  list_del(&slab->list);
470  list_add_tail(&slab->list, &f->full_slabs);
471  }
472  memset(node, 0, sizeof(struct node));
473 
474  return (struct node *) node;
475 }
476 
477 static void free_slab(struct fuse *f, struct node_slab *slab)
478 {
479  int res;
480 
481  list_del(&slab->list);
482  res = munmap(slab, f->pagesize);
483  if (res == -1)
484  fprintf(stderr, "fuse warning: munmap(%p) failed\n", slab);
485 }
486 
487 static void free_node_mem(struct fuse *f, struct node *node)
488 {
489  struct node_slab *slab = node_to_slab(f, node);
490  struct list_head *n = (struct list_head *) node;
491 
492  slab->used--;
493  if (slab->used) {
494  if (list_empty(&slab->freelist)) {
495  list_del(&slab->list);
496  list_add_tail(&slab->list, &f->partial_slabs);
497  }
498  list_add_head(n, &slab->freelist);
499  } else {
500  free_slab(f, slab);
501  }
502 }
503 #else
504 static struct node *alloc_node(struct fuse *f)
505 {
506  return (struct node *) calloc(1, get_node_size(f));
507 }
508 
509 static void free_node_mem(struct fuse *f, struct node *node)
510 {
511  (void) f;
512  free(node);
513 }
514 #endif
515 
516 static size_t id_hash(struct fuse *f, fuse_ino_t ino)
517 {
518  uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size;
519  uint64_t oldhash = hash % (f->id_table.size / 2);
520 
521  if (oldhash >= f->id_table.split)
522  return oldhash;
523  else
524  return hash;
525 }
526 
527 static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
528 {
529  size_t hash = id_hash(f, nodeid);
530  struct node *node;
531 
532  for (node = f->id_table.array[hash]; node != NULL; node = node->id_next)
533  if (node->nodeid == nodeid)
534  return node;
535 
536  return NULL;
537 }
538 
539 static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
540 {
541  struct node *node = get_node_nocheck(f, nodeid);
542  if (!node) {
543  fprintf(stderr, "fuse internal error: node %llu not found\n",
544  (unsigned long long) nodeid);
545  abort();
546  }
547  return node;
548 }
549 
550 static void curr_time(struct timespec *now);
551 static double diff_timespec(const struct timespec *t1,
552  const struct timespec *t2);
553 
554 static void remove_node_lru(struct node *node)
555 {
556  struct node_lru *lnode = node_lru(node);
557  list_del(&lnode->lru);
558  init_list_head(&lnode->lru);
559 }
560 
561 static void set_forget_time(struct fuse *f, struct node *node)
562 {
563  struct node_lru *lnode = node_lru(node);
564 
565  list_del(&lnode->lru);
566  list_add_tail(&lnode->lru, &f->lru_table);
567  curr_time(&lnode->forget_time);
568 }
569 
570 static void free_node(struct fuse *f, struct node *node)
571 {
572  if (node->name != node->inline_name)
573  free(node->name);
574  free_node_mem(f, node);
575 }
576 
577 static void node_table_reduce(struct node_table *t)
578 {
579  size_t newsize = t->size / 2;
580  void *newarray;
581 
582  if (newsize < NODE_TABLE_MIN_SIZE)
583  return;
584 
585  newarray = realloc(t->array, sizeof(struct node *) * newsize);
586  if (newarray != NULL)
587  t->array = newarray;
588 
589  t->size = newsize;
590  t->split = t->size / 2;
591 }
592 
593 static void remerge_id(struct fuse *f)
594 {
595  struct node_table *t = &f->id_table;
596  int iter;
597 
598  if (t->split == 0)
599  node_table_reduce(t);
600 
601  for (iter = 8; t->split > 0 && iter; iter--) {
602  struct node **upper;
603 
604  t->split--;
605  upper = &t->array[t->split + t->size / 2];
606  if (*upper) {
607  struct node **nodep;
608 
609  for (nodep = &t->array[t->split]; *nodep;
610  nodep = &(*nodep)->id_next);
611 
612  *nodep = *upper;
613  *upper = NULL;
614  break;
615  }
616  }
617 }
618 
619 static void unhash_id(struct fuse *f, struct node *node)
620 {
621  struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)];
622 
623  for (; *nodep != NULL; nodep = &(*nodep)->id_next)
624  if (*nodep == node) {
625  *nodep = node->id_next;
626  f->id_table.use--;
627 
628  if(f->id_table.use < f->id_table.size / 4)
629  remerge_id(f);
630  return;
631  }
632 }
633 
634 static int node_table_resize(struct node_table *t)
635 {
636  size_t newsize = t->size * 2;
637  void *newarray;
638 
639  newarray = realloc(t->array, sizeof(struct node *) * newsize);
640  if (newarray == NULL)
641  return -1;
642 
643  t->array = newarray;
644  memset(t->array + t->size, 0, t->size * sizeof(struct node *));
645  t->size = newsize;
646  t->split = 0;
647 
648  return 0;
649 }
650 
651 static void rehash_id(struct fuse *f)
652 {
653  struct node_table *t = &f->id_table;
654  struct node **nodep;
655  struct node **next;
656  size_t hash;
657 
658  if (t->split == t->size / 2)
659  return;
660 
661  hash = t->split;
662  t->split++;
663  for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) {
664  struct node *node = *nodep;
665  size_t newhash = id_hash(f, node->nodeid);
666 
667  if (newhash != hash) {
668  next = nodep;
669  *nodep = node->id_next;
670  node->id_next = t->array[newhash];
671  t->array[newhash] = node;
672  } else {
673  next = &node->id_next;
674  }
675  }
676  if (t->split == t->size / 2)
677  node_table_resize(t);
678 }
679 
680 static void hash_id(struct fuse *f, struct node *node)
681 {
682  size_t hash = id_hash(f, node->nodeid);
683  node->id_next = f->id_table.array[hash];
684  f->id_table.array[hash] = node;
685  f->id_table.use++;
686 
687  if (f->id_table.use >= f->id_table.size / 2)
688  rehash_id(f);
689 }
690 
691 static size_t name_hash(struct fuse *f, fuse_ino_t parent,
692  const char *name)
693 {
694  uint64_t hash = parent;
695  uint64_t oldhash;
696 
697  for (; *name; name++)
698  hash = hash * 31 + (unsigned char) *name;
699 
700  hash %= f->name_table.size;
701  oldhash = hash % (f->name_table.size / 2);
702  if (oldhash >= f->name_table.split)
703  return oldhash;
704  else
705  return hash;
706 }
707 
708 static void unref_node(struct fuse *f, struct node *node);
709 
710 static void remerge_name(struct fuse *f)
711 {
712  struct node_table *t = &f->name_table;
713  int iter;
714 
715  if (t->split == 0)
716  node_table_reduce(t);
717 
718  for (iter = 8; t->split > 0 && iter; iter--) {
719  struct node **upper;
720 
721  t->split--;
722  upper = &t->array[t->split + t->size / 2];
723  if (*upper) {
724  struct node **nodep;
725 
726  for (nodep = &t->array[t->split]; *nodep;
727  nodep = &(*nodep)->name_next);
728 
729  *nodep = *upper;
730  *upper = NULL;
731  break;
732  }
733  }
734 }
735 
736 static void unhash_name(struct fuse *f, struct node *node)
737 {
738  if (node->name) {
739  size_t hash = name_hash(f, node->parent->nodeid, node->name);
740  struct node **nodep = &f->name_table.array[hash];
741 
742  for (; *nodep != NULL; nodep = &(*nodep)->name_next)
743  if (*nodep == node) {
744  *nodep = node->name_next;
745  node->name_next = NULL;
746  unref_node(f, node->parent);
747  if (node->name != node->inline_name)
748  free(node->name);
749  node->name = NULL;
750  node->parent = NULL;
751  f->name_table.use--;
752 
753  if (f->name_table.use < f->name_table.size / 4)
754  remerge_name(f);
755  return;
756  }
757  fprintf(stderr,
758  "fuse internal error: unable to unhash node: %llu\n",
759  (unsigned long long) node->nodeid);
760  abort();
761  }
762 }
763 
764 static void rehash_name(struct fuse *f)
765 {
766  struct node_table *t = &f->name_table;
767  struct node **nodep;
768  struct node **next;
769  size_t hash;
770 
771  if (t->split == t->size / 2)
772  return;
773 
774  hash = t->split;
775  t->split++;
776  for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) {
777  struct node *node = *nodep;
778  size_t newhash = name_hash(f, node->parent->nodeid, node->name);
779 
780  if (newhash != hash) {
781  next = nodep;
782  *nodep = node->name_next;
783  node->name_next = t->array[newhash];
784  t->array[newhash] = node;
785  } else {
786  next = &node->name_next;
787  }
788  }
789  if (t->split == t->size / 2)
790  node_table_resize(t);
791 }
792 
793 static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
794  const char *name)
795 {
796  size_t hash = name_hash(f, parentid, name);
797  struct node *parent = get_node(f, parentid);
798  if (strlen(name) < sizeof(node->inline_name)) {
799  strcpy(node->inline_name, name);
800  node->name = node->inline_name;
801  } else {
802  node->name = strdup(name);
803  if (node->name == NULL)
804  return -1;
805  }
806 
807  parent->refctr ++;
808  node->parent = parent;
809  node->name_next = f->name_table.array[hash];
810  f->name_table.array[hash] = node;
811  f->name_table.use++;
812 
813  if (f->name_table.use >= f->name_table.size / 2)
814  rehash_name(f);
815 
816  return 0;
817 }
818 
819 static void delete_node(struct fuse *f, struct node *node)
820 {
821  if (f->conf.debug)
822  fprintf(stderr, "DELETE: %llu\n",
823  (unsigned long long) node->nodeid);
824 
825  assert(node->treelock == 0);
826  unhash_name(f, node);
827  if (lru_enabled(f))
828  remove_node_lru(node);
829  unhash_id(f, node);
830  free_node(f, node);
831 }
832 
833 static void unref_node(struct fuse *f, struct node *node)
834 {
835  assert(node->refctr > 0);
836  node->refctr --;
837  if (!node->refctr)
838  delete_node(f, node);
839 }
840 
841 static fuse_ino_t next_id(struct fuse *f)
842 {
843  do {
844  f->ctr = (f->ctr + 1) & 0xffffffff;
845  if (!f->ctr)
846  f->generation ++;
847  } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
848  get_node_nocheck(f, f->ctr) != NULL);
849  return f->ctr;
850 }
851 
852 static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
853  const char *name)
854 {
855  size_t hash = name_hash(f, parent, name);
856  struct node *node;
857 
858  for (node = f->name_table.array[hash]; node != NULL; node = node->name_next)
859  if (node->parent->nodeid == parent &&
860  strcmp(node->name, name) == 0)
861  return node;
862 
863  return NULL;
864 }
865 
866 static void inc_nlookup(struct node *node)
867 {
868  if (!node->nlookup)
869  node->refctr++;
870  node->nlookup++;
871 }
872 
873 static struct node *find_node(struct fuse *f, fuse_ino_t parent,
874  const char *name)
875 {
876  struct node *node;
877 
878  pthread_mutex_lock(&f->lock);
879  if (!name)
880  node = get_node(f, parent);
881  else
882  node = lookup_node(f, parent, name);
883  if (node == NULL) {
884  node = alloc_node(f);
885  if (node == NULL)
886  goto out_err;
887 
888  node->nodeid = next_id(f);
889  node->generation = f->generation;
890  if (f->conf.remember)
891  inc_nlookup(node);
892 
893  if (hash_name(f, node, parent, name) == -1) {
894  free_node(f, node);
895  node = NULL;
896  goto out_err;
897  }
898  hash_id(f, node);
899  if (lru_enabled(f)) {
900  struct node_lru *lnode = node_lru(node);
901  init_list_head(&lnode->lru);
902  }
903  } else if (lru_enabled(f) && node->nlookup == 1) {
904  remove_node_lru(node);
905  }
906  inc_nlookup(node);
907 out_err:
908  pthread_mutex_unlock(&f->lock);
909  return node;
910 }
911 
912 static int lookup_path_in_cache(struct fuse *f,
913  const char *path, fuse_ino_t *inop)
914 {
915  char *tmp = strdup(path);
916  if (!tmp)
917  return -ENOMEM;
918 
919  pthread_mutex_lock(&f->lock);
920  fuse_ino_t ino = FUSE_ROOT_ID;
921 
922  int err = 0;
923  char *save_ptr;
924  char *path_element = strtok_r(tmp, "/", &save_ptr);
925  while (path_element != NULL) {
926  struct node *node = lookup_node(f, ino, path_element);
927  if (node == NULL) {
928  err = -ENOENT;
929  break;
930  }
931  ino = node->nodeid;
932  path_element = strtok_r(NULL, "/", &save_ptr);
933  }
934  pthread_mutex_unlock(&f->lock);
935  free(tmp);
936 
937  if (!err)
938  *inop = ino;
939  return err;
940 }
941 
942 static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
943 {
944  size_t len = strlen(name);
945 
946  if (s - len <= *buf) {
947  unsigned pathlen = *bufsize - (s - *buf);
948  unsigned newbufsize = *bufsize;
949  char *newbuf;
950 
951  while (newbufsize < pathlen + len + 1) {
952  if (newbufsize >= 0x80000000)
953  newbufsize = 0xffffffff;
954  else
955  newbufsize *= 2;
956  }
957 
958  newbuf = realloc(*buf, newbufsize);
959  if (newbuf == NULL)
960  return NULL;
961 
962  *buf = newbuf;
963  s = newbuf + newbufsize - pathlen;
964  memmove(s, newbuf + *bufsize - pathlen, pathlen);
965  *bufsize = newbufsize;
966  }
967  s -= len;
968  strncpy(s, name, len);
969  s--;
970  *s = '/';
971 
972  return s;
973 }
974 
975 static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode,
976  struct node *end)
977 {
978  struct node *node;
979 
980  if (wnode) {
981  assert(wnode->treelock == TREELOCK_WRITE);
982  wnode->treelock = 0;
983  }
984 
985  for (node = get_node(f, nodeid);
986  node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) {
987  assert(node->treelock != 0);
988  assert(node->treelock != TREELOCK_WAIT_OFFSET);
989  assert(node->treelock != TREELOCK_WRITE);
990  node->treelock--;
991  if (node->treelock == TREELOCK_WAIT_OFFSET)
992  node->treelock = 0;
993  }
994 }
995 
996 static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
997  char **path, struct node **wnodep, bool need_lock)
998 {
999  unsigned bufsize = 256;
1000  char *buf;
1001  char *s;
1002  struct node *node;
1003  struct node *wnode = NULL;
1004  int err;
1005 
1006  *path = NULL;
1007 
1008  err = -ENOMEM;
1009  buf = malloc(bufsize);
1010  if (buf == NULL)
1011  goto out_err;
1012 
1013  s = buf + bufsize - 1;
1014  *s = '\0';
1015 
1016  if (name != NULL) {
1017  s = add_name(&buf, &bufsize, s, name);
1018  err = -ENOMEM;
1019  if (s == NULL)
1020  goto out_free;
1021  }
1022 
1023  if (wnodep) {
1024  assert(need_lock);
1025  wnode = lookup_node(f, nodeid, name);
1026  if (wnode) {
1027  if (wnode->treelock != 0) {
1028  if (wnode->treelock > 0)
1029  wnode->treelock += TREELOCK_WAIT_OFFSET;
1030  err = -EAGAIN;
1031  goto out_free;
1032  }
1033  wnode->treelock = TREELOCK_WRITE;
1034  }
1035  }
1036 
1037  for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
1038  node = node->parent) {
1039  err = -ENOENT;
1040  if (node->name == NULL || node->parent == NULL)
1041  goto out_unlock;
1042 
1043  err = -ENOMEM;
1044  s = add_name(&buf, &bufsize, s, node->name);
1045  if (s == NULL)
1046  goto out_unlock;
1047 
1048  if (need_lock) {
1049  err = -EAGAIN;
1050  if (node->treelock < 0)
1051  goto out_unlock;
1052 
1053  node->treelock++;
1054  }
1055  }
1056 
1057  if (s[0])
1058  memmove(buf, s, bufsize - (s - buf));
1059  else
1060  strcpy(buf, "/");
1061 
1062  *path = buf;
1063  if (wnodep)
1064  *wnodep = wnode;
1065 
1066  return 0;
1067 
1068  out_unlock:
1069  if (need_lock)
1070  unlock_path(f, nodeid, wnode, node);
1071  out_free:
1072  free(buf);
1073 
1074  out_err:
1075  return err;
1076 }
1077 
1078 static void queue_element_unlock(struct fuse *f, struct lock_queue_element *qe)
1079 {
1080  struct node *wnode;
1081 
1082  if (qe->first_locked) {
1083  wnode = qe->wnode1 ? *qe->wnode1 : NULL;
1084  unlock_path(f, qe->nodeid1, wnode, NULL);
1085  qe->first_locked = false;
1086  }
1087  if (qe->second_locked) {
1088  wnode = qe->wnode2 ? *qe->wnode2 : NULL;
1089  unlock_path(f, qe->nodeid2, wnode, NULL);
1090  qe->second_locked = false;
1091  }
1092 }
1093 
1094 static void queue_element_wakeup(struct fuse *f, struct lock_queue_element *qe)
1095 {
1096  int err;
1097  bool first = (qe == f->lockq);
1098 
1099  if (!qe->path1) {
1100  /* Just waiting for it to be unlocked */
1101  if (get_node(f, qe->nodeid1)->treelock == 0)
1102  pthread_cond_signal(&qe->cond);
1103 
1104  return;
1105  }
1106 
1107  if (!qe->first_locked) {
1108  err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1,
1109  qe->wnode1, true);
1110  if (!err)
1111  qe->first_locked = true;
1112  else if (err != -EAGAIN)
1113  goto err_unlock;
1114  }
1115  if (!qe->second_locked && qe->path2) {
1116  err = try_get_path(f, qe->nodeid2, qe->name2, qe->path2,
1117  qe->wnode2, true);
1118  if (!err)
1119  qe->second_locked = true;
1120  else if (err != -EAGAIN)
1121  goto err_unlock;
1122  }
1123 
1124  if (qe->first_locked && (qe->second_locked || !qe->path2)) {
1125  err = 0;
1126  goto done;
1127  }
1128 
1129  /*
1130  * Only let the first element be partially locked otherwise there could
1131  * be a deadlock.
1132  *
1133  * But do allow the first element to be partially locked to prevent
1134  * starvation.
1135  */
1136  if (!first)
1137  queue_element_unlock(f, qe);
1138 
1139  /* keep trying */
1140  return;
1141 
1142 err_unlock:
1143  queue_element_unlock(f, qe);
1144 done:
1145  qe->err = err;
1146  qe->done = true;
1147  pthread_cond_signal(&qe->cond);
1148 }
1149 
1150 static void wake_up_queued(struct fuse *f)
1151 {
1152  struct lock_queue_element *qe;
1153 
1154  for (qe = f->lockq; qe != NULL; qe = qe->next)
1155  queue_element_wakeup(f, qe);
1156 }
1157 
1158 static void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid,
1159  const char *name, bool wr)
1160 {
1161  if (f->conf.debug) {
1162  struct node *wnode = NULL;
1163 
1164  if (wr)
1165  wnode = lookup_node(f, nodeid, name);
1166 
1167  if (wnode) {
1168  fprintf(stderr, "%s %llu (w)\n",
1169  msg, (unsigned long long) wnode->nodeid);
1170  } else {
1171  fprintf(stderr, "%s %llu\n",
1172  msg, (unsigned long long) nodeid);
1173  }
1174  }
1175 }
1176 
1177 static void queue_path(struct fuse *f, struct lock_queue_element *qe)
1178 {
1179  struct lock_queue_element **qp;
1180 
1181  qe->done = false;
1182  qe->first_locked = false;
1183  qe->second_locked = false;
1184  pthread_cond_init(&qe->cond, NULL);
1185  qe->next = NULL;
1186  for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next);
1187  *qp = qe;
1188 }
1189 
1190 static void dequeue_path(struct fuse *f, struct lock_queue_element *qe)
1191 {
1192  struct lock_queue_element **qp;
1193 
1194  pthread_cond_destroy(&qe->cond);
1195  for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next);
1196  *qp = qe->next;
1197 }
1198 
1199 static int wait_path(struct fuse *f, struct lock_queue_element *qe)
1200 {
1201  queue_path(f, qe);
1202 
1203  do {
1204  pthread_cond_wait(&qe->cond, &f->lock);
1205  } while (!qe->done);
1206 
1207  dequeue_path(f, qe);
1208 
1209  return qe->err;
1210 }
1211 
1212 static int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name,
1213  char **path, struct node **wnode)
1214 {
1215  int err;
1216 
1217  pthread_mutex_lock(&f->lock);
1218  err = try_get_path(f, nodeid, name, path, wnode, true);
1219  if (err == -EAGAIN) {
1220  struct lock_queue_element qe = {
1221  .nodeid1 = nodeid,
1222  .name1 = name,
1223  .path1 = path,
1224  .wnode1 = wnode,
1225  };
1226  debug_path(f, "QUEUE PATH", nodeid, name, !!wnode);
1227  err = wait_path(f, &qe);
1228  debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode);
1229  }
1230  pthread_mutex_unlock(&f->lock);
1231 
1232  return err;
1233 }
1234 
1235 static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path)
1236 {
1237  return get_path_common(f, nodeid, NULL, path, NULL);
1238 }
1239 
1240 static int get_path_nullok(struct fuse *f, fuse_ino_t nodeid, char **path)
1241 {
1242  int err = 0;
1243 
1244  if (f->conf.nullpath_ok) {
1245  *path = NULL;
1246  } else {
1247  err = get_path_common(f, nodeid, NULL, path, NULL);
1248  if (err == -ENOENT)
1249  err = 0;
1250  }
1251 
1252  return err;
1253 }
1254 
1255 static int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name,
1256  char **path)
1257 {
1258  return get_path_common(f, nodeid, name, path, NULL);
1259 }
1260 
1261 static int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name,
1262  char **path, struct node **wnode)
1263 {
1264  return get_path_common(f, nodeid, name, path, wnode);
1265 }
1266 
1267 #if defined(__FreeBSD__)
1268 #define CHECK_DIR_LOOP
1269 #endif
1270 
1271 #if defined(CHECK_DIR_LOOP)
1272 static int check_dir_loop(struct fuse *f,
1273  fuse_ino_t nodeid1, const char *name1,
1274  fuse_ino_t nodeid2, const char *name2)
1275 {
1276  struct node *node, *node1, *node2;
1277  fuse_ino_t id1, id2;
1278 
1279  node1 = lookup_node(f, nodeid1, name1);
1280  id1 = node1 ? node1->nodeid : nodeid1;
1281 
1282  node2 = lookup_node(f, nodeid2, name2);
1283  id2 = node2 ? node2->nodeid : nodeid2;
1284 
1285  for (node = get_node(f, id2); node->nodeid != FUSE_ROOT_ID;
1286  node = node->parent) {
1287  if (node->name == NULL || node->parent == NULL)
1288  break;
1289 
1290  if (node->nodeid != id2 && node->nodeid == id1)
1291  return -EINVAL;
1292  }
1293 
1294  if (node2)
1295  {
1296  for (node = get_node(f, id1); node->nodeid != FUSE_ROOT_ID;
1297  node = node->parent) {
1298  if (node->name == NULL || node->parent == NULL)
1299  break;
1300 
1301  if (node->nodeid != id1 && node->nodeid == id2)
1302  return -ENOTEMPTY;
1303  }
1304  }
1305 
1306  return 0;
1307 }
1308 #endif
1309 
1310 static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1,
1311  fuse_ino_t nodeid2, const char *name2,
1312  char **path1, char **path2,
1313  struct node **wnode1, struct node **wnode2)
1314 {
1315  int err;
1316 
1317  /* FIXME: locking two paths needs deadlock checking */
1318  err = try_get_path(f, nodeid1, name1, path1, wnode1, true);
1319  if (!err) {
1320  err = try_get_path(f, nodeid2, name2, path2, wnode2, true);
1321  if (err) {
1322  struct node *wn1 = wnode1 ? *wnode1 : NULL;
1323 
1324  unlock_path(f, nodeid1, wn1, NULL);
1325  free(*path1);
1326  }
1327  }
1328  return err;
1329 }
1330 
1331 static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1,
1332  fuse_ino_t nodeid2, const char *name2,
1333  char **path1, char **path2,
1334  struct node **wnode1, struct node **wnode2)
1335 {
1336  int err;
1337 
1338  pthread_mutex_lock(&f->lock);
1339 
1340 #if defined(CHECK_DIR_LOOP)
1341  if (name1)
1342  {
1343  // called during rename; perform dir loop check
1344  err = check_dir_loop(f, nodeid1, name1, nodeid2, name2);
1345  if (err)
1346  goto out_unlock;
1347  }
1348 #endif
1349 
1350  err = try_get_path2(f, nodeid1, name1, nodeid2, name2,
1351  path1, path2, wnode1, wnode2);
1352  if (err == -EAGAIN) {
1353  struct lock_queue_element qe = {
1354  .nodeid1 = nodeid1,
1355  .name1 = name1,
1356  .path1 = path1,
1357  .wnode1 = wnode1,
1358  .nodeid2 = nodeid2,
1359  .name2 = name2,
1360  .path2 = path2,
1361  .wnode2 = wnode2,
1362  };
1363 
1364  debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1);
1365  debug_path(f, " PATH2", nodeid2, name2, !!wnode2);
1366  err = wait_path(f, &qe);
1367  debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1);
1368  debug_path(f, " PATH2", nodeid2, name2, !!wnode2);
1369  }
1370 
1371 #if defined(CHECK_DIR_LOOP)
1372 out_unlock:
1373 #endif
1374  pthread_mutex_unlock(&f->lock);
1375 
1376  return err;
1377 }
1378 
1379 static void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid,
1380  struct node *wnode, char *path)
1381 {
1382  pthread_mutex_lock(&f->lock);
1383  unlock_path(f, nodeid, wnode, NULL);
1384  if (f->lockq)
1385  wake_up_queued(f);
1386  pthread_mutex_unlock(&f->lock);
1387  free(path);
1388 }
1389 
1390 static void free_path(struct fuse *f, fuse_ino_t nodeid, char *path)
1391 {
1392  if (path)
1393  free_path_wrlock(f, nodeid, NULL, path);
1394 }
1395 
1396 static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2,
1397  struct node *wnode1, struct node *wnode2,
1398  char *path1, char *path2)
1399 {
1400  pthread_mutex_lock(&f->lock);
1401  unlock_path(f, nodeid1, wnode1, NULL);
1402  unlock_path(f, nodeid2, wnode2, NULL);
1403  wake_up_queued(f);
1404  pthread_mutex_unlock(&f->lock);
1405  free(path1);
1406  free(path2);
1407 }
1408 
1409 static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
1410 {
1411  struct node *node;
1412  if (nodeid == FUSE_ROOT_ID)
1413  return;
1414  pthread_mutex_lock(&f->lock);
1415  node = get_node(f, nodeid);
1416 
1417  /*
1418  * Node may still be locked due to interrupt idiocy in open,
1419  * create and opendir
1420  */
1421  while (node->nlookup == nlookup && node->treelock) {
1422  struct lock_queue_element qe = {
1423  .nodeid1 = nodeid,
1424  };
1425 
1426  debug_path(f, "QUEUE PATH (forget)", nodeid, NULL, false);
1427  queue_path(f, &qe);
1428 
1429  do {
1430  pthread_cond_wait(&qe.cond, &f->lock);
1431  } while (node->nlookup == nlookup && node->treelock);
1432 
1433  dequeue_path(f, &qe);
1434  debug_path(f, "DEQUEUE_PATH (forget)", nodeid, NULL, false);
1435  }
1436 
1437  assert(node->nlookup >= nlookup);
1438  node->nlookup -= nlookup;
1439  if (!node->nlookup) {
1440  unref_node(f, node);
1441  } else if (lru_enabled(f) && node->nlookup == 1) {
1442  set_forget_time(f, node);
1443  }
1444  pthread_mutex_unlock(&f->lock);
1445 }
1446 
1447 static void unlink_node(struct fuse *f, struct node *node)
1448 {
1449  if (f->conf.remember) {
1450  assert(node->nlookup > 1);
1451  node->nlookup--;
1452  }
1453  unhash_name(f, node);
1454 }
1455 
1456 static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
1457 {
1458  struct node *node;
1459 
1460  pthread_mutex_lock(&f->lock);
1461  node = lookup_node(f, dir, name);
1462  if (node != NULL)
1463  unlink_node(f, node);
1464  pthread_mutex_unlock(&f->lock);
1465 }
1466 
1467 static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
1468  fuse_ino_t newdir, const char *newname, int hide)
1469 {
1470  struct node *node;
1471  struct node *newnode;
1472  int err = 0;
1473 
1474  pthread_mutex_lock(&f->lock);
1475  node = lookup_node(f, olddir, oldname);
1476  newnode = lookup_node(f, newdir, newname);
1477  if (node == NULL)
1478  goto out;
1479 
1480  if (newnode != NULL) {
1481  if (hide) {
1482  fprintf(stderr, "fuse: hidden file got created during hiding\n");
1483  err = -EBUSY;
1484  goto out;
1485  }
1486  unlink_node(f, newnode);
1487  }
1488 
1489  unhash_name(f, node);
1490  if (hash_name(f, node, newdir, newname) == -1) {
1491  err = -ENOMEM;
1492  goto out;
1493  }
1494 
1495  if (hide)
1496  node->is_hidden = 1;
1497 
1498 out:
1499  pthread_mutex_unlock(&f->lock);
1500  return err;
1501 }
1502 
1503 static int exchange_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
1504  fuse_ino_t newdir, const char *newname)
1505 {
1506  struct node *oldnode;
1507  struct node *newnode;
1508  int err;
1509 
1510  pthread_mutex_lock(&f->lock);
1511  oldnode = lookup_node(f, olddir, oldname);
1512  newnode = lookup_node(f, newdir, newname);
1513 
1514  if (oldnode)
1515  unhash_name(f, oldnode);
1516  if (newnode)
1517  unhash_name(f, newnode);
1518 
1519  err = -ENOMEM;
1520  if (oldnode) {
1521  if (hash_name(f, oldnode, newdir, newname) == -1)
1522  goto out;
1523  }
1524  if (newnode) {
1525  if (hash_name(f, newnode, olddir, oldname) == -1)
1526  goto out;
1527  }
1528  err = 0;
1529 out:
1530  pthread_mutex_unlock(&f->lock);
1531  return err;
1532 }
1533 
1534 static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
1535 {
1536  if (!f->conf.use_ino)
1537  stbuf->st_ino = nodeid;
1538  if (f->conf.set_mode)
1539  stbuf->st_mode = (stbuf->st_mode & S_IFMT) |
1540  (0777 & ~f->conf.umask);
1541  if (f->conf.set_uid)
1542  stbuf->st_uid = f->conf.uid;
1543  if (f->conf.set_gid)
1544  stbuf->st_gid = f->conf.gid;
1545 }
1546 
1547 static struct fuse *req_fuse(fuse_req_t req)
1548 {
1549  return (struct fuse *) fuse_req_userdata(req);
1550 }
1551 
1552 static void fuse_intr_sighandler(int sig)
1553 {
1554  (void) sig;
1555  /* Nothing to do */
1556 }
1557 
1558 struct fuse_intr_data {
1559  pthread_t id;
1560  pthread_cond_t cond;
1561  int finished;
1562 };
1563 
1564 static void fuse_interrupt(fuse_req_t req, void *d_)
1565 {
1566  struct fuse_intr_data *d = d_;
1567  struct fuse *f = req_fuse(req);
1568 
1569  if (d->id == pthread_self())
1570  return;
1571 
1572  pthread_mutex_lock(&f->lock);
1573  while (!d->finished) {
1574  struct timeval now;
1575  struct timespec timeout;
1576 
1577  pthread_kill(d->id, f->conf.intr_signal);
1578  gettimeofday(&now, NULL);
1579  timeout.tv_sec = now.tv_sec + 1;
1580  timeout.tv_nsec = now.tv_usec * 1000;
1581  pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
1582  }
1583  pthread_mutex_unlock(&f->lock);
1584 }
1585 
1586 static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
1587  struct fuse_intr_data *d)
1588 {
1589  pthread_mutex_lock(&f->lock);
1590  d->finished = 1;
1591  pthread_cond_broadcast(&d->cond);
1592  pthread_mutex_unlock(&f->lock);
1593  fuse_req_interrupt_func(req, NULL, NULL);
1594  pthread_cond_destroy(&d->cond);
1595 }
1596 
1597 static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
1598 {
1599  d->id = pthread_self();
1600  pthread_cond_init(&d->cond, NULL);
1601  d->finished = 0;
1602  fuse_req_interrupt_func(req, fuse_interrupt, d);
1603 }
1604 
1605 static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
1606  struct fuse_intr_data *d)
1607 {
1608  if (f->conf.intr)
1609  fuse_do_finish_interrupt(f, req, d);
1610 }
1611 
1612 static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
1613  struct fuse_intr_data *d)
1614 {
1615  if (f->conf.intr)
1616  fuse_do_prepare_interrupt(req, d);
1617 }
1618 
1619 static const char* file_info_string(struct fuse_file_info *fi,
1620  char* buf, size_t len)
1621 {
1622  if(fi == NULL)
1623  return "NULL";
1624  snprintf(buf, len, "%llu", (unsigned long long) fi->fh);
1625  return buf;
1626 }
1627 
1628 int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf,
1629  struct fuse_file_info *fi)
1630 {
1631  fuse_get_context()->private_data = fs->user_data;
1632  if (fs->op.getattr) {
1633  if (fs->debug) {
1634  char buf[10];
1635  fprintf(stderr, "getattr[%s] %s\n",
1636  file_info_string(fi, buf, sizeof(buf)),
1637  path);
1638  }
1639  return fs->op.getattr(path, buf, fi);
1640  } else {
1641  return -ENOSYS;
1642  }
1643 }
1644 
1645 int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
1646  const char *newpath, unsigned int flags)
1647 {
1648  fuse_get_context()->private_data = fs->user_data;
1649  if (fs->op.rename) {
1650  if (fs->debug)
1651  fprintf(stderr, "rename %s %s 0x%x\n", oldpath, newpath,
1652  flags);
1653 
1654  return fs->op.rename(oldpath, newpath, flags);
1655  } else {
1656  return -ENOSYS;
1657  }
1658 }
1659 
1660 int fuse_fs_unlink(struct fuse_fs *fs, const char *path)
1661 {
1662  fuse_get_context()->private_data = fs->user_data;
1663  if (fs->op.unlink) {
1664  if (fs->debug)
1665  fprintf(stderr, "unlink %s\n", path);
1666 
1667  return fs->op.unlink(path);
1668  } else {
1669  return -ENOSYS;
1670  }
1671 }
1672 
1673 int fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
1674 {
1675  fuse_get_context()->private_data = fs->user_data;
1676  if (fs->op.rmdir) {
1677  if (fs->debug)
1678  fprintf(stderr, "rmdir %s\n", path);
1679 
1680  return fs->op.rmdir(path);
1681  } else {
1682  return -ENOSYS;
1683  }
1684 }
1685 
1686 int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
1687 {
1688  fuse_get_context()->private_data = fs->user_data;
1689  if (fs->op.symlink) {
1690  if (fs->debug)
1691  fprintf(stderr, "symlink %s %s\n", linkname, path);
1692 
1693  return fs->op.symlink(linkname, path);
1694  } else {
1695  return -ENOSYS;
1696  }
1697 }
1698 
1699 int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
1700 {
1701  fuse_get_context()->private_data = fs->user_data;
1702  if (fs->op.link) {
1703  if (fs->debug)
1704  fprintf(stderr, "link %s %s\n", oldpath, newpath);
1705 
1706  return fs->op.link(oldpath, newpath);
1707  } else {
1708  return -ENOSYS;
1709  }
1710 }
1711 
1712 int fuse_fs_release(struct fuse_fs *fs, const char *path,
1713  struct fuse_file_info *fi)
1714 {
1715  fuse_get_context()->private_data = fs->user_data;
1716  if (fs->op.release) {
1717  if (fs->debug)
1718  fprintf(stderr, "release%s[%llu] flags: 0x%x\n",
1719  fi->flush ? "+flush" : "",
1720  (unsigned long long) fi->fh, fi->flags);
1721 
1722  return fs->op.release(path, fi);
1723  } else {
1724  return 0;
1725  }
1726 }
1727 
1728 int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
1729  struct fuse_file_info *fi)
1730 {
1731  fuse_get_context()->private_data = fs->user_data;
1732  if (fs->op.opendir) {
1733  int err;
1734 
1735  if (fs->debug)
1736  fprintf(stderr, "opendir flags: 0x%x %s\n", fi->flags,
1737  path);
1738 
1739  err = fs->op.opendir(path, fi);
1740 
1741  if (fs->debug && !err)
1742  fprintf(stderr, " opendir[%llu] flags: 0x%x %s\n",
1743  (unsigned long long) fi->fh, fi->flags, path);
1744 
1745  return err;
1746  } else {
1747  return 0;
1748  }
1749 }
1750 
1751 int fuse_fs_open(struct fuse_fs *fs, const char *path,
1752  struct fuse_file_info *fi)
1753 {
1754  fuse_get_context()->private_data = fs->user_data;
1755  if (fs->op.open) {
1756  int err;
1757 
1758  if (fs->debug)
1759  fprintf(stderr, "open flags: 0x%x %s\n", fi->flags,
1760  path);
1761 
1762  err = fs->op.open(path, fi);
1763 
1764  if (fs->debug && !err)
1765  fprintf(stderr, " open[%llu] flags: 0x%x %s\n",
1766  (unsigned long long) fi->fh, fi->flags, path);
1767 
1768  return err;
1769  } else {
1770  return 0;
1771  }
1772 }
1773 
1774 static void fuse_free_buf(struct fuse_bufvec *buf)
1775 {
1776  if (buf != NULL) {
1777  size_t i;
1778 
1779  for (i = 0; i < buf->count; i++)
1780  if (!(buf->buf[0].flags & FUSE_BUF_IS_FD))
1781  free(buf->buf[i].mem);
1782  free(buf);
1783  }
1784 }
1785 
1786 int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
1787  struct fuse_bufvec **bufp, size_t size, off_t off,
1788  struct fuse_file_info *fi)
1789 {
1790  fuse_get_context()->private_data = fs->user_data;
1791  if (fs->op.read || fs->op.read_buf) {
1792  int res;
1793 
1794  if (fs->debug)
1795  fprintf(stderr,
1796  "read[%llu] %zu bytes from %llu flags: 0x%x\n",
1797  (unsigned long long) fi->fh,
1798  size, (unsigned long long) off, fi->flags);
1799 
1800  if (fs->op.read_buf) {
1801  res = fs->op.read_buf(path, bufp, size, off, fi);
1802  } else {
1803  struct fuse_bufvec *buf;
1804  void *mem;
1805 
1806  buf = malloc(sizeof(struct fuse_bufvec));
1807  if (buf == NULL)
1808  return -ENOMEM;
1809 
1810  mem = malloc(size);
1811  if (mem == NULL) {
1812  free(buf);
1813  return -ENOMEM;
1814  }
1815  *buf = FUSE_BUFVEC_INIT(size);
1816  buf->buf[0].mem = mem;
1817  *bufp = buf;
1818 
1819  res = fs->op.read(path, mem, size, off, fi);
1820  if (res >= 0)
1821  buf->buf[0].size = res;
1822  }
1823 
1824  if (fs->debug && res >= 0)
1825  fprintf(stderr, " read[%llu] %zu bytes from %llu\n",
1826  (unsigned long long) fi->fh,
1827  fuse_buf_size(*bufp),
1828  (unsigned long long) off);
1829  if (res >= 0 && fuse_buf_size(*bufp) > size)
1830  fprintf(stderr, "fuse: read too many bytes\n");
1831 
1832  if (res < 0)
1833  return res;
1834 
1835  return 0;
1836  } else {
1837  return -ENOSYS;
1838  }
1839 }
1840 
1841 int fuse_fs_read(struct fuse_fs *fs, const char *path, char *mem, size_t size,
1842  off_t off, struct fuse_file_info *fi)
1843 {
1844  fuse_get_context()->private_data = fs->user_data;
1845  if (fs->op.read || fs->op.read_buf) {
1846  int res;
1847 
1848  if (fs->debug)
1849  fprintf(stderr,
1850  "read[%llu] %zu bytes from %llu flags: 0x%x\n",
1851  (unsigned long long) fi->fh,
1852  size, (unsigned long long) off, fi->flags);
1853 
1854  if (fs->op.read_buf) {
1855  struct fuse_bufvec *buf = NULL;
1856 
1857  res = fs->op.read_buf(path, &buf, size, off, fi);
1858  if (res == 0) {
1859  struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size);
1860 
1861  dst.buf[0].mem = mem;
1862  res = fuse_buf_copy(&dst, buf, 0);
1863  }
1864  fuse_free_buf(buf);
1865  } else {
1866  res = fs->op.read(path, mem, size, off, fi);
1867  }
1868 
1869  if (fs->debug && res >= 0)
1870  fprintf(stderr, " read[%llu] %u bytes from %llu\n",
1871  (unsigned long long) fi->fh,
1872  res,
1873  (unsigned long long) off);
1874  if (res >= 0 && res > (int) size)
1875  fprintf(stderr, "fuse: read too many bytes\n");
1876 
1877  return res;
1878  } else {
1879  return -ENOSYS;
1880  }
1881 }
1882 
1883 int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
1884  struct fuse_bufvec *buf, off_t off,
1885  struct fuse_file_info *fi)
1886 {
1887  fuse_get_context()->private_data = fs->user_data;
1888  if (fs->op.write_buf || fs->op.write) {
1889  int res;
1890  size_t size = fuse_buf_size(buf);
1891 
1892  assert(buf->idx == 0 && buf->off == 0);
1893  if (fs->debug)
1894  fprintf(stderr,
1895  "write%s[%llu] %zu bytes to %llu flags: 0x%x\n",
1896  fi->writepage ? "page" : "",
1897  (unsigned long long) fi->fh,
1898  size,
1899  (unsigned long long) off,
1900  fi->flags);
1901 
1902  if (fs->op.write_buf) {
1903  res = fs->op.write_buf(path, buf, off, fi);
1904  } else {
1905  void *mem = NULL;
1906  struct fuse_buf *flatbuf;
1907  struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size);
1908 
1909  if (buf->count == 1 &&
1910  !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
1911  flatbuf = &buf->buf[0];
1912  } else {
1913  res = -ENOMEM;
1914  mem = malloc(size);
1915  if (mem == NULL)
1916  goto out;
1917 
1918  tmp.buf[0].mem = mem;
1919  res = fuse_buf_copy(&tmp, buf, 0);
1920  if (res <= 0)
1921  goto out_free;
1922 
1923  tmp.buf[0].size = res;
1924  flatbuf = &tmp.buf[0];
1925  }
1926 
1927  res = fs->op.write(path, flatbuf->mem, flatbuf->size,
1928  off, fi);
1929 out_free:
1930  free(mem);
1931  }
1932 out:
1933  if (fs->debug && res >= 0)
1934  fprintf(stderr, " write%s[%llu] %u bytes to %llu\n",
1935  fi->writepage ? "page" : "",
1936  (unsigned long long) fi->fh, res,
1937  (unsigned long long) off);
1938  if (res > (int) size)
1939  fprintf(stderr, "fuse: wrote too many bytes\n");
1940 
1941  return res;
1942  } else {
1943  return -ENOSYS;
1944  }
1945 }
1946 
1947 int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *mem,
1948  size_t size, off_t off, struct fuse_file_info *fi)
1949 {
1950  struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size);
1951 
1952  bufv.buf[0].mem = (void *) mem;
1953 
1954  return fuse_fs_write_buf(fs, path, &bufv, off, fi);
1955 }
1956 
1957 int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
1958  struct fuse_file_info *fi)
1959 {
1960  fuse_get_context()->private_data = fs->user_data;
1961  if (fs->op.fsync) {
1962  if (fs->debug)
1963  fprintf(stderr, "fsync[%llu] datasync: %i\n",
1964  (unsigned long long) fi->fh, datasync);
1965 
1966  return fs->op.fsync(path, datasync, fi);
1967  } else {
1968  return -ENOSYS;
1969  }
1970 }
1971 
1972 int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
1973  struct fuse_file_info *fi)
1974 {
1975  fuse_get_context()->private_data = fs->user_data;
1976  if (fs->op.fsyncdir) {
1977  if (fs->debug)
1978  fprintf(stderr, "fsyncdir[%llu] datasync: %i\n",
1979  (unsigned long long) fi->fh, datasync);
1980 
1981  return fs->op.fsyncdir(path, datasync, fi);
1982  } else {
1983  return -ENOSYS;
1984  }
1985 }
1986 
1987 int fuse_fs_flush(struct fuse_fs *fs, const char *path,
1988  struct fuse_file_info *fi)
1989 {
1990  fuse_get_context()->private_data = fs->user_data;
1991  if (fs->op.flush) {
1992  if (fs->debug)
1993  fprintf(stderr, "flush[%llu]\n",
1994  (unsigned long long) fi->fh);
1995 
1996  return fs->op.flush(path, fi);
1997  } else {
1998  return -ENOSYS;
1999  }
2000 }
2001 
2002 int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
2003 {
2004  fuse_get_context()->private_data = fs->user_data;
2005  if (fs->op.statfs) {
2006  if (fs->debug)
2007  fprintf(stderr, "statfs %s\n", path);
2008 
2009  return fs->op.statfs(path, buf);
2010  } else {
2011  buf->f_namemax = 255;
2012  buf->f_bsize = 512;
2013  return 0;
2014  }
2015 }
2016 
2017 int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
2018  struct fuse_file_info *fi)
2019 {
2020  fuse_get_context()->private_data = fs->user_data;
2021  if (fs->op.releasedir) {
2022  if (fs->debug)
2023  fprintf(stderr, "releasedir[%llu] flags: 0x%x\n",
2024  (unsigned long long) fi->fh, fi->flags);
2025 
2026  return fs->op.releasedir(path, fi);
2027  } else {
2028  return 0;
2029  }
2030 }
2031 
2032 int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
2033  fuse_fill_dir_t filler, off_t off,
2034  struct fuse_file_info *fi,
2035  enum fuse_readdir_flags flags)
2036 {
2037  fuse_get_context()->private_data = fs->user_data;
2038  if (fs->op.readdir) {
2039  if (fs->debug) {
2040  fprintf(stderr, "readdir%s[%llu] from %llu\n",
2041  (flags & FUSE_READDIR_PLUS) ? "plus" : "",
2042  (unsigned long long) fi->fh,
2043  (unsigned long long) off);
2044  }
2045 
2046  return fs->op.readdir(path, buf, filler, off, fi, flags);
2047  } else {
2048  return -ENOSYS;
2049  }
2050 }
2051 
2052 int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
2053  struct fuse_file_info *fi)
2054 {
2055  fuse_get_context()->private_data = fs->user_data;
2056  if (fs->op.create) {
2057  int err;
2058 
2059  if (fs->debug)
2060  fprintf(stderr,
2061  "create flags: 0x%x %s 0%o umask=0%03o\n",
2062  fi->flags, path, mode,
2063  fuse_get_context()->umask);
2064 
2065  err = fs->op.create(path, mode, fi);
2066 
2067  if (fs->debug && !err)
2068  fprintf(stderr, " create[%llu] flags: 0x%x %s\n",
2069  (unsigned long long) fi->fh, fi->flags, path);
2070 
2071  return err;
2072  } else {
2073  return -ENOSYS;
2074  }
2075 }
2076 
2077 int fuse_fs_lock(struct fuse_fs *fs, const char *path,
2078  struct fuse_file_info *fi, int cmd, struct flock *lock)
2079 {
2080  fuse_get_context()->private_data = fs->user_data;
2081  if (fs->op.lock) {
2082  if (fs->debug)
2083  fprintf(stderr, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n",
2084  (unsigned long long) fi->fh,
2085  (cmd == F_GETLK ? "F_GETLK" :
2086  (cmd == F_SETLK ? "F_SETLK" :
2087  (cmd == F_SETLKW ? "F_SETLKW" : "???"))),
2088  (lock->l_type == F_RDLCK ? "F_RDLCK" :
2089  (lock->l_type == F_WRLCK ? "F_WRLCK" :
2090  (lock->l_type == F_UNLCK ? "F_UNLCK" :
2091  "???"))),
2092  (unsigned long long) lock->l_start,
2093  (unsigned long long) lock->l_len,
2094  (unsigned long long) lock->l_pid);
2095 
2096  return fs->op.lock(path, fi, cmd, lock);
2097  } else {
2098  return -ENOSYS;
2099  }
2100 }
2101 
2102 int fuse_fs_flock(struct fuse_fs *fs, const char *path,
2103  struct fuse_file_info *fi, int op)
2104 {
2105  fuse_get_context()->private_data = fs->user_data;
2106  if (fs->op.flock) {
2107  if (fs->debug) {
2108  int xop = op & ~LOCK_NB;
2109 
2110  fprintf(stderr, "lock[%llu] %s%s\n",
2111  (unsigned long long) fi->fh,
2112  xop == LOCK_SH ? "LOCK_SH" :
2113  (xop == LOCK_EX ? "LOCK_EX" :
2114  (xop == LOCK_UN ? "LOCK_UN" : "???")),
2115  (op & LOCK_NB) ? "|LOCK_NB" : "");
2116  }
2117  return fs->op.flock(path, fi, op);
2118  } else {
2119  return -ENOSYS;
2120  }
2121 }
2122 
2123 int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid,
2124  gid_t gid, struct fuse_file_info *fi)
2125 {
2126  fuse_get_context()->private_data = fs->user_data;
2127  if (fs->op.chown) {
2128  if (fs->debug) {
2129  char buf[10];
2130  fprintf(stderr, "chown[%s] %s %lu %lu\n",
2131  file_info_string(fi, buf, sizeof(buf)),
2132  path, (unsigned long) uid, (unsigned long) gid);
2133  }
2134  return fs->op.chown(path, uid, gid, fi);
2135  } else {
2136  return -ENOSYS;
2137  }
2138 }
2139 
2140 int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size,
2141  struct fuse_file_info *fi)
2142 {
2143  fuse_get_context()->private_data = fs->user_data;
2144  if (fs->op.truncate) {
2145  if (fs->debug) {
2146  char buf[10];
2147  fprintf(stderr, "truncate[%s] %llu\n",
2148  file_info_string(fi, buf, sizeof(buf)),
2149  (unsigned long long) size);
2150  }
2151  return fs->op.truncate(path, size, fi);
2152  } else {
2153  return -ENOSYS;
2154  }
2155 }
2156 
2157 int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
2158  const struct timespec tv[2], struct fuse_file_info *fi)
2159 {
2160  fuse_get_context()->private_data = fs->user_data;
2161  if (fs->op.utimens) {
2162  if (fs->debug) {
2163  char buf[10];
2164  fprintf(stderr, "utimens[%s] %s %li.%09lu %li.%09lu\n",
2165  file_info_string(fi, buf, sizeof(buf)),
2166  path, tv[0].tv_sec, tv[0].tv_nsec,
2167  tv[1].tv_sec, tv[1].tv_nsec);
2168  }
2169  return fs->op.utimens(path, tv, fi);
2170  } else {
2171  return -ENOSYS;
2172  }
2173 }
2174 
2175 int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
2176 {
2177  fuse_get_context()->private_data = fs->user_data;
2178  if (fs->op.access) {
2179  if (fs->debug)
2180  fprintf(stderr, "access %s 0%o\n", path, mask);
2181 
2182  return fs->op.access(path, mask);
2183  } else {
2184  return -ENOSYS;
2185  }
2186 }
2187 
2188 int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
2189  size_t len)
2190 {
2191  fuse_get_context()->private_data = fs->user_data;
2192  if (fs->op.readlink) {
2193  if (fs->debug)
2194  fprintf(stderr, "readlink %s %lu\n", path,
2195  (unsigned long) len);
2196 
2197  return fs->op.readlink(path, buf, len);
2198  } else {
2199  return -ENOSYS;
2200  }
2201 }
2202 
2203 int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
2204  dev_t rdev)
2205 {
2206  fuse_get_context()->private_data = fs->user_data;
2207  if (fs->op.mknod) {
2208  if (fs->debug)
2209  fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n",
2210  path, mode, (unsigned long long) rdev,
2211  fuse_get_context()->umask);
2212 
2213  return fs->op.mknod(path, mode, rdev);
2214  } else {
2215  return -ENOSYS;
2216  }
2217 }
2218 
2219 int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
2220 {
2221  fuse_get_context()->private_data = fs->user_data;
2222  if (fs->op.mkdir) {
2223  if (fs->debug)
2224  fprintf(stderr, "mkdir %s 0%o umask=0%03o\n",
2225  path, mode, fuse_get_context()->umask);
2226 
2227  return fs->op.mkdir(path, mode);
2228  } else {
2229  return -ENOSYS;
2230  }
2231 }
2232 
2233 int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
2234  const char *value, size_t size, int flags)
2235 {
2236  fuse_get_context()->private_data = fs->user_data;
2237  if (fs->op.setxattr) {
2238  if (fs->debug)
2239  fprintf(stderr, "setxattr %s %s %lu 0x%x\n",
2240  path, name, (unsigned long) size, flags);
2241 
2242  return fs->op.setxattr(path, name, value, size, flags);
2243  } else {
2244  return -ENOSYS;
2245  }
2246 }
2247 
2248 int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
2249  char *value, size_t size)
2250 {
2251  fuse_get_context()->private_data = fs->user_data;
2252  if (fs->op.getxattr) {
2253  if (fs->debug)
2254  fprintf(stderr, "getxattr %s %s %lu\n",
2255  path, name, (unsigned long) size);
2256 
2257  return fs->op.getxattr(path, name, value, size);
2258  } else {
2259  return -ENOSYS;
2260  }
2261 }
2262 
2263 int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
2264  size_t size)
2265 {
2266  fuse_get_context()->private_data = fs->user_data;
2267  if (fs->op.listxattr) {
2268  if (fs->debug)
2269  fprintf(stderr, "listxattr %s %lu\n",
2270  path, (unsigned long) size);
2271 
2272  return fs->op.listxattr(path, list, size);
2273  } else {
2274  return -ENOSYS;
2275  }
2276 }
2277 
2278 int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
2279  uint64_t *idx)
2280 {
2281  fuse_get_context()->private_data = fs->user_data;
2282  if (fs->op.bmap) {
2283  if (fs->debug)
2284  fprintf(stderr, "bmap %s blocksize: %lu index: %llu\n",
2285  path, (unsigned long) blocksize,
2286  (unsigned long long) *idx);
2287 
2288  return fs->op.bmap(path, blocksize, idx);
2289  } else {
2290  return -ENOSYS;
2291  }
2292 }
2293 
2294 int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
2295 {
2296  fuse_get_context()->private_data = fs->user_data;
2297  if (fs->op.removexattr) {
2298  if (fs->debug)
2299  fprintf(stderr, "removexattr %s %s\n", path, name);
2300 
2301  return fs->op.removexattr(path, name);
2302  } else {
2303  return -ENOSYS;
2304  }
2305 }
2306 
2307 int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
2308  struct fuse_file_info *fi, unsigned int flags, void *data)
2309 {
2310  fuse_get_context()->private_data = fs->user_data;
2311  if (fs->op.ioctl) {
2312  if (fs->debug)
2313  fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
2314  (unsigned long long) fi->fh, cmd, flags);
2315 
2316  return fs->op.ioctl(path, cmd, arg, fi, flags, data);
2317  } else
2318  return -ENOSYS;
2319 }
2320 
2321 int fuse_fs_poll(struct fuse_fs *fs, const char *path,
2322  struct fuse_file_info *fi, struct fuse_pollhandle *ph,
2323  unsigned *reventsp)
2324 {
2325  fuse_get_context()->private_data = fs->user_data;
2326  if (fs->op.poll) {
2327  int res;
2328 
2329  if (fs->debug)
2330  fprintf(stderr, "poll[%llu] ph: %p, events 0x%x\n",
2331  (unsigned long long) fi->fh, ph,
2332  fi->poll_events);
2333 
2334  res = fs->op.poll(path, fi, ph, reventsp);
2335 
2336  if (fs->debug && !res)
2337  fprintf(stderr, " poll[%llu] revents: 0x%x\n",
2338  (unsigned long long) fi->fh, *reventsp);
2339 
2340  return res;
2341  } else
2342  return -ENOSYS;
2343 }
2344 
2345 int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
2346  off_t offset, off_t length, struct fuse_file_info *fi)
2347 {
2348  fuse_get_context()->private_data = fs->user_data;
2349  if (fs->op.fallocate) {
2350  if (fs->debug)
2351  fprintf(stderr, "fallocate %s mode %x, offset: %llu, length: %llu\n",
2352  path,
2353  mode,
2354  (unsigned long long) offset,
2355  (unsigned long long) length);
2356 
2357  return fs->op.fallocate(path, mode, offset, length, fi);
2358  } else
2359  return -ENOSYS;
2360 }
2361 
2362 ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
2363  struct fuse_file_info *fi_in, off_t off_in,
2364  const char *path_out,
2365  struct fuse_file_info *fi_out, off_t off_out,
2366  size_t len, int flags)
2367 {
2368  fuse_get_context()->private_data = fs->user_data;
2369  if (fs->op.copy_file_range) {
2370  if (fs->debug)
2371  fprintf(stderr, "copy_file_range from %s:%llu to "
2372  "%s:%llu, length: %llu\n",
2373  path_in,
2374  (unsigned long long) off_in,
2375  path_out,
2376  (unsigned long long) off_out,
2377  (unsigned long long) len);
2378 
2379  return fs->op.copy_file_range(path_in, fi_in, off_in, path_out,
2380  fi_out, off_out, len, flags);
2381  } else
2382  return -ENOSYS;
2383 }
2384 
2385 static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
2386 {
2387  struct node *node;
2388  int isopen = 0;
2389  pthread_mutex_lock(&f->lock);
2390  node = lookup_node(f, dir, name);
2391  if (node && node->open_count > 0)
2392  isopen = 1;
2393  pthread_mutex_unlock(&f->lock);
2394  return isopen;
2395 }
2396 
2397 static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
2398  char *newname, size_t bufsize)
2399 {
2400  struct stat buf;
2401  struct node *node;
2402  struct node *newnode;
2403  char *newpath;
2404  int res;
2405  int failctr = 10;
2406 
2407  do {
2408  pthread_mutex_lock(&f->lock);
2409  node = lookup_node(f, dir, oldname);
2410  if (node == NULL) {
2411  pthread_mutex_unlock(&f->lock);
2412  return NULL;
2413  }
2414  do {
2415  f->hidectr ++;
2416  snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
2417  (unsigned int) node->nodeid, f->hidectr);
2418  newnode = lookup_node(f, dir, newname);
2419  } while(newnode);
2420 
2421  res = try_get_path(f, dir, newname, &newpath, NULL, false);
2422  pthread_mutex_unlock(&f->lock);
2423  if (res)
2424  break;
2425 
2426  memset(&buf, 0, sizeof(buf));
2427  res = fuse_fs_getattr(f->fs, newpath, &buf, NULL);
2428  if (res == -ENOENT)
2429  break;
2430  free(newpath);
2431  newpath = NULL;
2432  } while(res == 0 && --failctr);
2433 
2434  return newpath;
2435 }
2436 
2437 static int hide_node(struct fuse *f, const char *oldpath,
2438  fuse_ino_t dir, const char *oldname)
2439 {
2440  char newname[64];
2441  char *newpath;
2442  int err = -EBUSY;
2443 
2444  newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
2445  if (newpath) {
2446  err = fuse_fs_rename(f->fs, oldpath, newpath, 0);
2447  if (!err)
2448  err = rename_node(f, dir, oldname, dir, newname, 1);
2449  free(newpath);
2450  }
2451  return err;
2452 }
2453 
2454 static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
2455 {
2456  return stbuf->st_mtime == ts->tv_sec &&
2457  ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
2458 }
2459 
2460 #ifndef CLOCK_MONOTONIC
2461 #define CLOCK_MONOTONIC CLOCK_REALTIME
2462 #endif
2463 
2464 static void curr_time(struct timespec *now)
2465 {
2466  static clockid_t clockid = CLOCK_MONOTONIC;
2467  int res = clock_gettime(clockid, now);
2468  if (res == -1 && errno == EINVAL) {
2469  clockid = CLOCK_REALTIME;
2470  res = clock_gettime(clockid, now);
2471  }
2472  if (res == -1) {
2473  perror("fuse: clock_gettime");
2474  abort();
2475  }
2476 }
2477 
2478 static void update_stat(struct node *node, const struct stat *stbuf)
2479 {
2480  if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
2481  stbuf->st_size != node->size))
2482  node->cache_valid = 0;
2483  node->mtime.tv_sec = stbuf->st_mtime;
2484  node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
2485  node->size = stbuf->st_size;
2486  curr_time(&node->stat_updated);
2487 }
2488 
2489 static int do_lookup(struct fuse *f, fuse_ino_t nodeid, const char *name,
2490  struct fuse_entry_param *e)
2491 {
2492  struct node *node;
2493 
2494  node = find_node(f, nodeid, name);
2495  if (node == NULL)
2496  return -ENOMEM;
2497 
2498  e->ino = node->nodeid;
2499  e->generation = node->generation;
2500  e->entry_timeout = f->conf.entry_timeout;
2501  e->attr_timeout = f->conf.attr_timeout;
2502  if (f->conf.auto_cache) {
2503  pthread_mutex_lock(&f->lock);
2504  update_stat(node, &e->attr);
2505  pthread_mutex_unlock(&f->lock);
2506  }
2507  set_stat(f, e->ino, &e->attr);
2508  return 0;
2509 }
2510 
2511 static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
2512  const char *name, const char *path,
2513  struct fuse_entry_param *e, struct fuse_file_info *fi)
2514 {
2515  int res;
2516 
2517  memset(e, 0, sizeof(struct fuse_entry_param));
2518  res = fuse_fs_getattr(f->fs, path, &e->attr, fi);
2519  if (res == 0) {
2520  res = do_lookup(f, nodeid, name, e);
2521  if (res == 0 && f->conf.debug) {
2522  fprintf(stderr, " NODEID: %llu\n",
2523  (unsigned long long) e->ino);
2524  }
2525  }
2526  return res;
2527 }
2528 
2529 static struct fuse_context_i *fuse_get_context_internal(void)
2530 {
2531  return (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
2532 }
2533 
2534 static struct fuse_context_i *fuse_create_context(struct fuse *f)
2535 {
2536  struct fuse_context_i *c = fuse_get_context_internal();
2537  if (c == NULL) {
2538  c = (struct fuse_context_i *)
2539  calloc(1, sizeof(struct fuse_context_i));
2540  if (c == NULL) {
2541  /* This is hard to deal with properly, so just
2542  abort. If memory is so low that the
2543  context cannot be allocated, there's not
2544  much hope for the filesystem anyway */
2545  fprintf(stderr, "fuse: failed to allocate thread specific data\n");
2546  abort();
2547  }
2548  pthread_setspecific(fuse_context_key, c);
2549  } else {
2550  memset(c, 0, sizeof(*c));
2551  }
2552  c->ctx.fuse = f;
2553 
2554  return c;
2555 }
2556 
2557 static void fuse_freecontext(void *data)
2558 {
2559  free(data);
2560 }
2561 
2562 static int fuse_create_context_key(void)
2563 {
2564  int err = 0;
2565  pthread_mutex_lock(&fuse_context_lock);
2566  if (!fuse_context_ref) {
2567  err = pthread_key_create(&fuse_context_key, fuse_freecontext);
2568  if (err) {
2569  fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
2570  strerror(err));
2571  pthread_mutex_unlock(&fuse_context_lock);
2572  return -1;
2573  }
2574  }
2575  fuse_context_ref++;
2576  pthread_mutex_unlock(&fuse_context_lock);
2577  return 0;
2578 }
2579 
2580 static void fuse_delete_context_key(void)
2581 {
2582  pthread_mutex_lock(&fuse_context_lock);
2583  fuse_context_ref--;
2584  if (!fuse_context_ref) {
2585  free(pthread_getspecific(fuse_context_key));
2586  pthread_key_delete(fuse_context_key);
2587  }
2588  pthread_mutex_unlock(&fuse_context_lock);
2589 }
2590 
2591 static struct fuse *req_fuse_prepare(fuse_req_t req)
2592 {
2593  struct fuse_context_i *c = fuse_create_context(req_fuse(req));
2594  const struct fuse_ctx *ctx = fuse_req_ctx(req);
2595  c->req = req;
2596  c->ctx.uid = ctx->uid;
2597  c->ctx.gid = ctx->gid;
2598  c->ctx.pid = ctx->pid;
2599  c->ctx.umask = ctx->umask;
2600  return c->ctx.fuse;
2601 }
2602 
2603 static inline void reply_err(fuse_req_t req, int err)
2604 {
2605  /* fuse_reply_err() uses non-negated errno values */
2606  fuse_reply_err(req, -err);
2607 }
2608 
2609 static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
2610  int err)
2611 {
2612  if (!err) {
2613  struct fuse *f = req_fuse(req);
2614  if (fuse_reply_entry(req, e) == -ENOENT) {
2615  /* Skip forget for negative result */
2616  if (e->ino != 0)
2617  forget_node(f, e->ino, 1);
2618  }
2619  } else
2620  reply_err(req, err);
2621 }
2622 
2623 void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
2624  struct fuse_config *cfg)
2625 {
2626  fuse_get_context()->private_data = fs->user_data;
2627  if (!fs->op.write_buf)
2628  conn->want &= ~FUSE_CAP_SPLICE_READ;
2629  if (!fs->op.lock)
2630  conn->want &= ~FUSE_CAP_POSIX_LOCKS;
2631  if (!fs->op.flock)
2632  conn->want &= ~FUSE_CAP_FLOCK_LOCKS;
2633  if (fs->op.init)
2634  fs->user_data = fs->op.init(conn, cfg);
2635 }
2636 
2637 static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
2638 {
2639  struct fuse *f = (struct fuse *) data;
2640 
2641  fuse_create_context(f);
2642  if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
2643  conn->want |= FUSE_CAP_EXPORT_SUPPORT;
2644  fuse_fs_init(f->fs, conn, &f->conf);
2645 }
2646 
2647 void fuse_fs_destroy(struct fuse_fs *fs)
2648 {
2649  fuse_get_context()->private_data = fs->user_data;
2650  if (fs->op.destroy)
2651  fs->op.destroy(fs->user_data);
2652  if (fs->m)
2653  fuse_put_module(fs->m);
2654  free(fs);
2655 }
2656 
2657 static void fuse_lib_destroy(void *data)
2658 {
2659  struct fuse *f = (struct fuse *) data;
2660 
2661  fuse_create_context(f);
2662  fuse_fs_destroy(f->fs);
2663  f->fs = NULL;
2664 }
2665 
2666 static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
2667  const char *name)
2668 {
2669  struct fuse *f = req_fuse_prepare(req);
2670  struct fuse_entry_param e;
2671  char *path;
2672  int err;
2673  struct node *dot = NULL;
2674 
2675  if (name[0] == '.') {
2676  int len = strlen(name);
2677 
2678  if (len == 1 || (name[1] == '.' && len == 2)) {
2679  pthread_mutex_lock(&f->lock);
2680  if (len == 1) {
2681  if (f->conf.debug)
2682  fprintf(stderr, "LOOKUP-DOT\n");
2683  dot = get_node_nocheck(f, parent);
2684  if (dot == NULL) {
2685  pthread_mutex_unlock(&f->lock);
2686  reply_entry(req, &e, -ESTALE);
2687  return;
2688  }
2689  dot->refctr++;
2690  } else {
2691  if (f->conf.debug)
2692  fprintf(stderr, "LOOKUP-DOTDOT\n");
2693  parent = get_node(f, parent)->parent->nodeid;
2694  }
2695  pthread_mutex_unlock(&f->lock);
2696  name = NULL;
2697  }
2698  }
2699 
2700  err = get_path_name(f, parent, name, &path);
2701  if (!err) {
2702  struct fuse_intr_data d;
2703  if (f->conf.debug)
2704  fprintf(stderr, "LOOKUP %s\n", path);
2705  fuse_prepare_interrupt(f, req, &d);
2706  err = lookup_path(f, parent, name, path, &e, NULL);
2707  if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
2708  e.ino = 0;
2709  e.entry_timeout = f->conf.negative_timeout;
2710  err = 0;
2711  }
2712  fuse_finish_interrupt(f, req, &d);
2713  free_path(f, parent, path);
2714  }
2715  if (dot) {
2716  pthread_mutex_lock(&f->lock);
2717  unref_node(f, dot);
2718  pthread_mutex_unlock(&f->lock);
2719  }
2720  reply_entry(req, &e, err);
2721 }
2722 
2723 static void do_forget(struct fuse *f, fuse_ino_t ino, uint64_t nlookup)
2724 {
2725  if (f->conf.debug)
2726  fprintf(stderr, "FORGET %llu/%llu\n", (unsigned long long)ino,
2727  (unsigned long long) nlookup);
2728  forget_node(f, ino, nlookup);
2729 }
2730 
2731 static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
2732 {
2733  do_forget(req_fuse(req), ino, nlookup);
2734  fuse_reply_none(req);
2735 }
2736 
2737 static void fuse_lib_forget_multi(fuse_req_t req, size_t count,
2738  struct fuse_forget_data *forgets)
2739 {
2740  struct fuse *f = req_fuse(req);
2741  size_t i;
2742 
2743  for (i = 0; i < count; i++)
2744  do_forget(f, forgets[i].ino, forgets[i].nlookup);
2745 
2746  fuse_reply_none(req);
2747 }
2748 
2749 
2750 static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
2751  struct fuse_file_info *fi)
2752 {
2753  struct fuse *f = req_fuse_prepare(req);
2754  struct stat buf;
2755  char *path;
2756  int err;
2757 
2758  memset(&buf, 0, sizeof(buf));
2759 
2760  if (fi != NULL)
2761  err = get_path_nullok(f, ino, &path);
2762  else
2763  err = get_path(f, ino, &path);
2764  if (!err) {
2765  struct fuse_intr_data d;
2766  fuse_prepare_interrupt(f, req, &d);
2767  err = fuse_fs_getattr(f->fs, path, &buf, fi);
2768  fuse_finish_interrupt(f, req, &d);
2769  free_path(f, ino, path);
2770  }
2771  if (!err) {
2772  struct node *node;
2773 
2774  pthread_mutex_lock(&f->lock);
2775  node = get_node(f, ino);
2776  if (node->is_hidden && buf.st_nlink > 0)
2777  buf.st_nlink--;
2778  if (f->conf.auto_cache)
2779  update_stat(node, &buf);
2780  pthread_mutex_unlock(&f->lock);
2781  set_stat(f, ino, &buf);
2782  fuse_reply_attr(req, &buf, f->conf.attr_timeout);
2783  } else
2784  reply_err(req, err);
2785 }
2786 
2787 int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode,
2788  struct fuse_file_info *fi)
2789 {
2790  fuse_get_context()->private_data = fs->user_data;
2791  if (fs->op.chmod) {
2792  if (fs->debug) {
2793  char buf[10];
2794  fprintf(stderr, "chmod[%s] %s %llo\n",
2795  file_info_string(fi, buf, sizeof(buf)),
2796  path, (unsigned long long) mode);
2797  }
2798  return fs->op.chmod(path, mode, fi);
2799  }
2800  else
2801  return -ENOSYS;
2802 }
2803 
2804 static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
2805  int valid, struct fuse_file_info *fi)
2806 {
2807  struct fuse *f = req_fuse_prepare(req);
2808  struct stat buf;
2809  char *path;
2810  int err;
2811 
2812  memset(&buf, 0, sizeof(buf));
2813  if (fi != NULL)
2814  err = get_path_nullok(f, ino, &path);
2815  else
2816  err = get_path(f, ino, &path);
2817  if (!err) {
2818  struct fuse_intr_data d;
2819  fuse_prepare_interrupt(f, req, &d);
2820  err = 0;
2821  if (!err && (valid & FUSE_SET_ATTR_MODE))
2822  err = fuse_fs_chmod(f->fs, path, attr->st_mode, fi);
2823  if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
2824  uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
2825  attr->st_uid : (uid_t) -1;
2826  gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
2827  attr->st_gid : (gid_t) -1;
2828  err = fuse_fs_chown(f->fs, path, uid, gid, fi);
2829  }
2830  if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
2831  err = fuse_fs_truncate(f->fs, path,
2832  attr->st_size, fi);
2833  }
2834 #ifdef HAVE_UTIMENSAT
2835  if (!err &&
2836  (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) {
2837  struct timespec tv[2];
2838 
2839  tv[0].tv_sec = 0;
2840  tv[1].tv_sec = 0;
2841  tv[0].tv_nsec = UTIME_OMIT;
2842  tv[1].tv_nsec = UTIME_OMIT;
2843 
2844  if (valid & FUSE_SET_ATTR_ATIME_NOW)
2845  tv[0].tv_nsec = UTIME_NOW;
2846  else if (valid & FUSE_SET_ATTR_ATIME)
2847  tv[0] = attr->st_atim;
2848 
2849  if (valid & FUSE_SET_ATTR_MTIME_NOW)
2850  tv[1].tv_nsec = UTIME_NOW;
2851  else if (valid & FUSE_SET_ATTR_MTIME)
2852  tv[1] = attr->st_mtim;
2853 
2854  err = fuse_fs_utimens(f->fs, path, tv, fi);
2855  } else
2856 #endif
2857  if (!err &&
2858  (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
2859  (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
2860  struct timespec tv[2];
2861  tv[0].tv_sec = attr->st_atime;
2862  tv[0].tv_nsec = ST_ATIM_NSEC(attr);
2863  tv[1].tv_sec = attr->st_mtime;
2864  tv[1].tv_nsec = ST_MTIM_NSEC(attr);
2865  err = fuse_fs_utimens(f->fs, path, tv, fi);
2866  }
2867  if (!err) {
2868  err = fuse_fs_getattr(f->fs, path, &buf, fi);
2869  }
2870  fuse_finish_interrupt(f, req, &d);
2871  free_path(f, ino, path);
2872  }
2873  if (!err) {
2874  if (f->conf.auto_cache) {
2875  pthread_mutex_lock(&f->lock);
2876  update_stat(get_node(f, ino), &buf);
2877  pthread_mutex_unlock(&f->lock);
2878  }
2879  set_stat(f, ino, &buf);
2880  fuse_reply_attr(req, &buf, f->conf.attr_timeout);
2881  } else
2882  reply_err(req, err);
2883 }
2884 
2885 static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
2886 {
2887  struct fuse *f = req_fuse_prepare(req);
2888  char *path;
2889  int err;
2890 
2891  err = get_path(f, ino, &path);
2892  if (!err) {
2893  struct fuse_intr_data d;
2894 
2895  fuse_prepare_interrupt(f, req, &d);
2896  err = fuse_fs_access(f->fs, path, mask);
2897  fuse_finish_interrupt(f, req, &d);
2898  free_path(f, ino, path);
2899  }
2900  reply_err(req, err);
2901 }
2902 
2903 static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
2904 {
2905  struct fuse *f = req_fuse_prepare(req);
2906  char linkname[PATH_MAX + 1];
2907  char *path;
2908  int err;
2909 
2910  err = get_path(f, ino, &path);
2911  if (!err) {
2912  struct fuse_intr_data d;
2913  fuse_prepare_interrupt(f, req, &d);
2914  err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
2915  fuse_finish_interrupt(f, req, &d);
2916  free_path(f, ino, path);
2917  }
2918  if (!err) {
2919  linkname[PATH_MAX] = '\0';
2920  fuse_reply_readlink(req, linkname);
2921  } else
2922  reply_err(req, err);
2923 }
2924 
2925 static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
2926  mode_t mode, dev_t rdev)
2927 {
2928  struct fuse *f = req_fuse_prepare(req);
2929  struct fuse_entry_param e;
2930  char *path;
2931  int err;
2932 
2933  err = get_path_name(f, parent, name, &path);
2934  if (!err) {
2935  struct fuse_intr_data d;
2936 
2937  fuse_prepare_interrupt(f, req, &d);
2938  err = -ENOSYS;
2939  if (S_ISREG(mode)) {
2940  struct fuse_file_info fi;
2941 
2942  memset(&fi, 0, sizeof(fi));
2943  fi.flags = O_CREAT | O_EXCL | O_WRONLY;
2944  err = fuse_fs_create(f->fs, path, mode, &fi);
2945  if (!err) {
2946  err = lookup_path(f, parent, name, path, &e,
2947  &fi);
2948  fuse_fs_release(f->fs, path, &fi);
2949  }
2950  }
2951  if (err == -ENOSYS) {
2952  err = fuse_fs_mknod(f->fs, path, mode, rdev);
2953  if (!err)
2954  err = lookup_path(f, parent, name, path, &e,
2955  NULL);
2956  }
2957  fuse_finish_interrupt(f, req, &d);
2958  free_path(f, parent, path);
2959  }
2960  reply_entry(req, &e, err);
2961 }
2962 
2963 static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
2964  mode_t mode)
2965 {
2966  struct fuse *f = req_fuse_prepare(req);
2967  struct fuse_entry_param e;
2968  char *path;
2969  int err;
2970 
2971  err = get_path_name(f, parent, name, &path);
2972  if (!err) {
2973  struct fuse_intr_data d;
2974 
2975  fuse_prepare_interrupt(f, req, &d);
2976  err = fuse_fs_mkdir(f->fs, path, mode);
2977  if (!err)
2978  err = lookup_path(f, parent, name, path, &e, NULL);
2979  fuse_finish_interrupt(f, req, &d);
2980  free_path(f, parent, path);
2981  }
2982  reply_entry(req, &e, err);
2983 }
2984 
2985 static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
2986  const char *name)
2987 {
2988  struct fuse *f = req_fuse_prepare(req);
2989  struct node *wnode;
2990  char *path;
2991  int err;
2992 
2993  err = get_path_wrlock(f, parent, name, &path, &wnode);
2994  if (!err) {
2995  struct fuse_intr_data d;
2996 
2997  fuse_prepare_interrupt(f, req, &d);
2998  if (!f->conf.hard_remove && is_open(f, parent, name)) {
2999  err = hide_node(f, path, parent, name);
3000  } else {
3001  err = fuse_fs_unlink(f->fs, path);
3002  if (!err)
3003  remove_node(f, parent, name);
3004  }
3005  fuse_finish_interrupt(f, req, &d);
3006  free_path_wrlock(f, parent, wnode, path);
3007  }
3008  reply_err(req, err);
3009 }
3010 
3011 static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
3012 {
3013  struct fuse *f = req_fuse_prepare(req);
3014  struct node *wnode;
3015  char *path;
3016  int err;
3017 
3018  err = get_path_wrlock(f, parent, name, &path, &wnode);
3019  if (!err) {
3020  struct fuse_intr_data d;
3021 
3022  fuse_prepare_interrupt(f, req, &d);
3023  err = fuse_fs_rmdir(f->fs, path);
3024  fuse_finish_interrupt(f, req, &d);
3025  if (!err)
3026  remove_node(f, parent, name);
3027  free_path_wrlock(f, parent, wnode, path);
3028  }
3029  reply_err(req, err);
3030 }
3031 
3032 static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
3033  fuse_ino_t parent, const char *name)
3034 {
3035  struct fuse *f = req_fuse_prepare(req);
3036  struct fuse_entry_param e;
3037  char *path;
3038  int err;
3039 
3040  err = get_path_name(f, parent, name, &path);
3041  if (!err) {
3042  struct fuse_intr_data d;
3043 
3044  fuse_prepare_interrupt(f, req, &d);
3045  err = fuse_fs_symlink(f->fs, linkname, path);
3046  if (!err)
3047  err = lookup_path(f, parent, name, path, &e, NULL);
3048  fuse_finish_interrupt(f, req, &d);
3049  free_path(f, parent, path);
3050  }
3051  reply_entry(req, &e, err);
3052 }
3053 
3054 static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
3055  const char *oldname, fuse_ino_t newdir,
3056  const char *newname, unsigned int flags)
3057 {
3058  struct fuse *f = req_fuse_prepare(req);
3059  char *oldpath;
3060  char *newpath;
3061  struct node *wnode1;
3062  struct node *wnode2;
3063  int err;
3064 
3065  err = get_path2(f, olddir, oldname, newdir, newname,
3066  &oldpath, &newpath, &wnode1, &wnode2);
3067  if (!err) {
3068  struct fuse_intr_data d;
3069  err = 0;
3070  fuse_prepare_interrupt(f, req, &d);
3071  if (!f->conf.hard_remove && !(flags & RENAME_EXCHANGE) &&
3072  is_open(f, newdir, newname))
3073  err = hide_node(f, newpath, newdir, newname);
3074  if (!err) {
3075  err = fuse_fs_rename(f->fs, oldpath, newpath, flags);
3076  if (!err) {
3077  if (flags & RENAME_EXCHANGE) {
3078  err = exchange_node(f, olddir, oldname,
3079  newdir, newname);
3080  } else {
3081  err = rename_node(f, olddir, oldname,
3082  newdir, newname, 0);
3083  }
3084  }
3085  }
3086  fuse_finish_interrupt(f, req, &d);
3087  free_path2(f, olddir, newdir, wnode1, wnode2, oldpath, newpath);
3088  }
3089  reply_err(req, err);
3090 }
3091 
3092 static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
3093  const char *newname)
3094 {
3095  struct fuse *f = req_fuse_prepare(req);
3096  struct fuse_entry_param e;
3097  char *oldpath;
3098  char *newpath;
3099  int err;
3100 
3101  err = get_path2(f, ino, NULL, newparent, newname,
3102  &oldpath, &newpath, NULL, NULL);
3103  if (!err) {
3104  struct fuse_intr_data d;
3105 
3106  fuse_prepare_interrupt(f, req, &d);
3107  err = fuse_fs_link(f->fs, oldpath, newpath);
3108  if (!err)
3109  err = lookup_path(f, newparent, newname, newpath,
3110  &e, NULL);
3111  fuse_finish_interrupt(f, req, &d);
3112  free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath);
3113  }
3114  reply_entry(req, &e, err);
3115 }
3116 
3117 static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
3118  struct fuse_file_info *fi)
3119 {
3120  struct node *node;
3121  int unlink_hidden = 0;
3122 
3123  fuse_fs_release(f->fs, path, fi);
3124 
3125  pthread_mutex_lock(&f->lock);
3126  node = get_node(f, ino);
3127  assert(node->open_count > 0);
3128  --node->open_count;
3129  if (node->is_hidden && !node->open_count) {
3130  unlink_hidden = 1;
3131  node->is_hidden = 0;
3132  }
3133  pthread_mutex_unlock(&f->lock);
3134 
3135  if(unlink_hidden) {
3136  if (path) {
3137  fuse_fs_unlink(f->fs, path);
3138  } else if (f->conf.nullpath_ok) {
3139  char *unlinkpath;
3140 
3141  if (get_path(f, ino, &unlinkpath) == 0)
3142  fuse_fs_unlink(f->fs, unlinkpath);
3143 
3144  free_path(f, ino, unlinkpath);
3145  }
3146  }
3147 }
3148 
3149 static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
3150  const char *name, mode_t mode,
3151  struct fuse_file_info *fi)
3152 {
3153  struct fuse *f = req_fuse_prepare(req);
3154  struct fuse_intr_data d;
3155  struct fuse_entry_param e;
3156  char *path;
3157  int err;
3158 
3159  err = get_path_name(f, parent, name, &path);
3160  if (!err) {
3161  fuse_prepare_interrupt(f, req, &d);
3162  err = fuse_fs_create(f->fs, path, mode, fi);
3163  if (!err) {
3164  err = lookup_path(f, parent, name, path, &e, fi);
3165  if (err)
3166  fuse_fs_release(f->fs, path, fi);
3167  else if (!S_ISREG(e.attr.st_mode)) {
3168  err = -EIO;
3169  fuse_fs_release(f->fs, path, fi);
3170  forget_node(f, e.ino, 1);
3171  } else {
3172  if (f->conf.direct_io)
3173  fi->direct_io = 1;
3174  if (f->conf.kernel_cache)
3175  fi->keep_cache = 1;
3176 
3177  }
3178  }
3179  fuse_finish_interrupt(f, req, &d);
3180  }
3181  if (!err) {
3182  pthread_mutex_lock(&f->lock);
3183  get_node(f, e.ino)->open_count++;
3184  pthread_mutex_unlock(&f->lock);
3185  if (fuse_reply_create(req, &e, fi) == -ENOENT) {
3186  /* The open syscall was interrupted, so it
3187  must be cancelled */
3188  fuse_do_release(f, e.ino, path, fi);
3189  forget_node(f, e.ino, 1);
3190  }
3191  } else {
3192  reply_err(req, err);
3193  }
3194 
3195  free_path(f, parent, path);
3196 }
3197 
3198 static double diff_timespec(const struct timespec *t1,
3199  const struct timespec *t2)
3200 {
3201  return (t1->tv_sec - t2->tv_sec) +
3202  ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
3203 }
3204 
3205 static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
3206  struct fuse_file_info *fi)
3207 {
3208  struct node *node;
3209 
3210  pthread_mutex_lock(&f->lock);
3211  node = get_node(f, ino);
3212  if (node->cache_valid) {
3213  struct timespec now;
3214 
3215  curr_time(&now);
3216  if (diff_timespec(&now, &node->stat_updated) >
3217  f->conf.ac_attr_timeout) {
3218  struct stat stbuf;
3219  int err;
3220  pthread_mutex_unlock(&f->lock);
3221  err = fuse_fs_getattr(f->fs, path, &stbuf, fi);
3222  pthread_mutex_lock(&f->lock);
3223  if (!err)
3224  update_stat(node, &stbuf);
3225  else
3226  node->cache_valid = 0;
3227  }
3228  }
3229  if (node->cache_valid)
3230  fi->keep_cache = 1;
3231 
3232  node->cache_valid = 1;
3233  pthread_mutex_unlock(&f->lock);
3234 }
3235 
3236 static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
3237  struct fuse_file_info *fi)
3238 {
3239  struct fuse *f = req_fuse_prepare(req);
3240  struct fuse_intr_data d;
3241  char *path;
3242  int err;
3243 
3244  err = get_path(f, ino, &path);
3245  if (!err) {
3246  fuse_prepare_interrupt(f, req, &d);
3247  err = fuse_fs_open(f->fs, path, fi);
3248  if (!err) {
3249  if (f->conf.direct_io)
3250  fi->direct_io = 1;
3251  if (f->conf.kernel_cache)
3252  fi->keep_cache = 1;
3253 
3254  if (f->conf.auto_cache)
3255  open_auto_cache(f, ino, path, fi);
3256  }
3257  fuse_finish_interrupt(f, req, &d);
3258  }
3259  if (!err) {
3260  pthread_mutex_lock(&f->lock);
3261  get_node(f, ino)->open_count++;
3262  pthread_mutex_unlock(&f->lock);
3263  if (fuse_reply_open(req, fi) == -ENOENT) {
3264  /* The open syscall was interrupted, so it
3265  must be cancelled */
3266  fuse_do_release(f, ino, path, fi);
3267  }
3268  } else
3269  reply_err(req, err);
3270 
3271  free_path(f, ino, path);
3272 }
3273 
3274 static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
3275  off_t off, struct fuse_file_info *fi)
3276 {
3277  struct fuse *f = req_fuse_prepare(req);
3278  struct fuse_bufvec *buf = NULL;
3279  char *path;
3280  int res;
3281 
3282  res = get_path_nullok(f, ino, &path);
3283  if (res == 0) {
3284  struct fuse_intr_data d;
3285 
3286  fuse_prepare_interrupt(f, req, &d);
3287  res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi);
3288  fuse_finish_interrupt(f, req, &d);
3289  free_path(f, ino, path);
3290  }
3291 
3292  if (res == 0)
3294  else
3295  reply_err(req, res);
3296 
3297  fuse_free_buf(buf);
3298 }
3299 
3300 static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino,
3301  struct fuse_bufvec *buf, off_t off,
3302  struct fuse_file_info *fi)
3303 {
3304  struct fuse *f = req_fuse_prepare(req);
3305  char *path;
3306  int res;
3307 
3308  res = get_path_nullok(f, ino, &path);
3309  if (res == 0) {
3310  struct fuse_intr_data d;
3311 
3312  fuse_prepare_interrupt(f, req, &d);
3313  res = fuse_fs_write_buf(f->fs, path, buf, off, fi);
3314  fuse_finish_interrupt(f, req, &d);
3315  free_path(f, ino, path);
3316  }
3317 
3318  if (res >= 0)
3319  fuse_reply_write(req, res);
3320  else
3321  reply_err(req, res);
3322 }
3323 
3324 static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
3325  struct fuse_file_info *fi)
3326 {
3327  struct fuse *f = req_fuse_prepare(req);
3328  char *path;
3329  int err;
3330 
3331  err = get_path_nullok(f, ino, &path);
3332  if (!err) {
3333  struct fuse_intr_data d;
3334 
3335  fuse_prepare_interrupt(f, req, &d);
3336  err = fuse_fs_fsync(f->fs, path, datasync, fi);
3337  fuse_finish_interrupt(f, req, &d);
3338  free_path(f, ino, path);
3339  }
3340  reply_err(req, err);
3341 }
3342 
3343 static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
3344  struct fuse_file_info *fi)
3345 {
3346  struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
3347  memset(fi, 0, sizeof(struct fuse_file_info));
3348  fi->fh = dh->fh;
3349  return dh;
3350 }
3351 
3352 static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
3353  struct fuse_file_info *llfi)
3354 {
3355  struct fuse *f = req_fuse_prepare(req);
3356  struct fuse_intr_data d;
3357  struct fuse_dh *dh;
3358  struct fuse_file_info fi;
3359  char *path;
3360  int err;
3361 
3362  dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
3363  if (dh == NULL) {
3364  reply_err(req, -ENOMEM);
3365  return;
3366  }
3367  memset(dh, 0, sizeof(struct fuse_dh));
3368  dh->fuse = f;
3369  dh->contents = NULL;
3370  dh->first = NULL;
3371  dh->len = 0;
3372  dh->filled = 0;
3373  dh->nodeid = ino;
3374  fuse_mutex_init(&dh->lock);
3375 
3376  llfi->fh = (uintptr_t) dh;
3377 
3378  memset(&fi, 0, sizeof(fi));
3379  fi.flags = llfi->flags;
3380 
3381  err = get_path(f, ino, &path);
3382  if (!err) {
3383  fuse_prepare_interrupt(f, req, &d);
3384  err = fuse_fs_opendir(f->fs, path, &fi);
3385  fuse_finish_interrupt(f, req, &d);
3386  dh->fh = fi.fh;
3387  }
3388  if (!err) {
3389  if (fuse_reply_open(req, llfi) == -ENOENT) {
3390  /* The opendir syscall was interrupted, so it
3391  must be cancelled */
3392  fuse_fs_releasedir(f->fs, path, &fi);
3393  pthread_mutex_destroy(&dh->lock);
3394  free(dh);
3395  }
3396  } else {
3397  reply_err(req, err);
3398  pthread_mutex_destroy(&dh->lock);
3399  free(dh);
3400  }
3401  free_path(f, ino, path);
3402 }
3403 
3404 static int extend_contents(struct fuse_dh *dh, unsigned minsize)
3405 {
3406  if (minsize > dh->size) {
3407  char *newptr;
3408  unsigned newsize = dh->size;
3409  if (!newsize)
3410  newsize = 1024;
3411  while (newsize < minsize) {
3412  if (newsize >= 0x80000000)
3413  newsize = 0xffffffff;
3414  else
3415  newsize *= 2;
3416  }
3417 
3418  newptr = (char *) realloc(dh->contents, newsize);
3419  if (!newptr) {
3420  dh->error = -ENOMEM;
3421  return -1;
3422  }
3423  dh->contents = newptr;
3424  dh->size = newsize;
3425  }
3426  return 0;
3427 }
3428 
3429 static int fuse_add_direntry_to_dh(struct fuse_dh *dh, const char *name,
3430  struct stat *st)
3431 {
3432  struct fuse_direntry *de;
3433 
3434  de = malloc(sizeof(struct fuse_direntry));
3435  if (!de) {
3436  dh->error = -ENOMEM;
3437  return -1;
3438  }
3439  de->name = strdup(name);
3440  if (!de->name) {
3441  dh->error = -ENOMEM;
3442  free(de);
3443  return -1;
3444  }
3445  de->stat = *st;
3446  de->next = NULL;
3447 
3448  *dh->last = de;
3449  dh->last = &de->next;
3450 
3451  return 0;
3452 }
3453 
3454 static fuse_ino_t lookup_nodeid(struct fuse *f, fuse_ino_t parent,
3455  const char *name)
3456 {
3457  struct node *node;
3458  fuse_ino_t res = FUSE_UNKNOWN_INO;
3459 
3460  pthread_mutex_lock(&f->lock);
3461  node = lookup_node(f, parent, name);
3462  if (node)
3463  res = node->nodeid;
3464  pthread_mutex_unlock(&f->lock);
3465 
3466  return res;
3467 }
3468 
3469 static int fill_dir(void *dh_, const char *name, const struct stat *statp,
3470  off_t off, enum fuse_fill_dir_flags flags)
3471 {
3472  struct fuse_dh *dh = (struct fuse_dh *) dh_;
3473  struct stat stbuf;
3474 
3475  if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) {
3476  dh->error = -EIO;
3477  return 1;
3478  }
3479 
3480  if (statp)
3481  stbuf = *statp;
3482  else {
3483  memset(&stbuf, 0, sizeof(stbuf));
3484  stbuf.st_ino = FUSE_UNKNOWN_INO;
3485  }
3486 
3487  if (!dh->fuse->conf.use_ino) {
3488  stbuf.st_ino = FUSE_UNKNOWN_INO;
3489  if (dh->fuse->conf.readdir_ino) {
3490  stbuf.st_ino = (ino_t)
3491  lookup_nodeid(dh->fuse, dh->nodeid, name);
3492  }
3493  }
3494 
3495  if (off) {
3496  size_t newlen;
3497 
3498  if (dh->filled) {
3499  dh->error = -EIO;
3500  return 1;
3501  }
3502 
3503  if (dh->first) {
3504  dh->error = -EIO;
3505  return 1;
3506  }
3507 
3508  if (extend_contents(dh, dh->needlen) == -1)
3509  return 1;
3510 
3511  newlen = dh->len +
3512  fuse_add_direntry(dh->req, dh->contents + dh->len,
3513  dh->needlen - dh->len, name,
3514  &stbuf, off);
3515  if (newlen > dh->needlen)
3516  return 1;
3517 
3518  dh->len = newlen;
3519  } else {
3520  dh->filled = 1;
3521 
3522  if (fuse_add_direntry_to_dh(dh, name, &stbuf) == -1)
3523  return 1;
3524  }
3525  return 0;
3526 }
3527 
3528 static int is_dot_or_dotdot(const char *name)
3529 {
3530  return name[0] == '.' && (name[1] == '\0' ||
3531  (name[1] == '.' && name[2] == '\0'));
3532 }
3533 
3534 static int fill_dir_plus(void *dh_, const char *name, const struct stat *statp,
3535  off_t off, enum fuse_fill_dir_flags flags)
3536 {
3537  struct fuse_dh *dh = (struct fuse_dh *) dh_;
3538  struct fuse_entry_param e = {
3539  /* ino=0 tells the kernel to ignore readdirplus stat info */
3540  .ino = 0,
3541  };
3542  struct fuse *f = dh->fuse;
3543  int res;
3544 
3545  if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) {
3546  dh->error = -EIO;
3547  return 1;
3548  }
3549 
3550  if (off && statp && (flags & FUSE_FILL_DIR_PLUS)) {
3551  e.attr = *statp;
3552 
3553  if (!is_dot_or_dotdot(name)) {
3554  res = do_lookup(f, dh->nodeid, name, &e);
3555  if (res) {
3556  dh->error = res;
3557  return 1;
3558  }
3559  }
3560  } else {
3561  e.attr.st_ino = FUSE_UNKNOWN_INO;
3562  if (!f->conf.use_ino && f->conf.readdir_ino) {
3563  e.attr.st_ino = (ino_t)
3564  lookup_nodeid(f, dh->nodeid, name);
3565  }
3566  }
3567 
3568  if (off) {
3569  size_t newlen;
3570 
3571  if (dh->filled) {
3572  dh->error = -EIO;
3573  return 1;
3574  }
3575 
3576  if (dh->first) {
3577  dh->error = -EIO;
3578  return 1;
3579  }
3580  if (extend_contents(dh, dh->needlen) == -1)
3581  return 1;
3582 
3583  newlen = dh->len +
3584  fuse_add_direntry_plus(dh->req, dh->contents + dh->len,
3585  dh->needlen - dh->len, name,
3586  &e, off);
3587  if (newlen > dh->needlen)
3588  return 1;
3589  dh->len = newlen;
3590  } else {
3591  dh->filled = 1;
3592 
3593  if (fuse_add_direntry_to_dh(dh, name, &e.attr) == -1)
3594  return 1;
3595  }
3596 
3597  return 0;
3598 }
3599 
3600 static void free_direntries(struct fuse_direntry *de)
3601 {
3602  while (de) {
3603  struct fuse_direntry *next = de->next;
3604  free(de->name);
3605  free(de);
3606  de = next;
3607  }
3608 }
3609 
3610 static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
3611  size_t size, off_t off, struct fuse_dh *dh,
3612  struct fuse_file_info *fi,
3613  enum fuse_readdir_flags flags)
3614 {
3615  char *path;
3616  int err;
3617 
3618  if (f->fs->op.readdir)
3619  err = get_path_nullok(f, ino, &path);
3620  else
3621  err = get_path(f, ino, &path);
3622  if (!err) {
3623  struct fuse_intr_data d;
3624  fuse_fill_dir_t filler = fill_dir;
3625 
3626  if (flags & FUSE_READDIR_PLUS)
3627  filler = fill_dir_plus;
3628 
3629  free_direntries(dh->first);
3630  dh->first = NULL;
3631  dh->last = &dh->first;
3632  dh->len = 0;
3633  dh->error = 0;
3634  dh->needlen = size;
3635  dh->filled = 0;
3636  dh->req = req;
3637  fuse_prepare_interrupt(f, req, &d);
3638  err = fuse_fs_readdir(f->fs, path, dh, filler, off, fi, flags);
3639  fuse_finish_interrupt(f, req, &d);
3640  dh->req = NULL;
3641  if (!err)
3642  err = dh->error;
3643  if (err)
3644  dh->filled = 0;
3645  free_path(f, ino, path);
3646  }
3647  return err;
3648 }
3649 
3650 static int readdir_fill_from_list(fuse_req_t req, struct fuse_dh *dh,
3651  off_t off, enum fuse_readdir_flags flags)
3652 {
3653  off_t pos;
3654  struct fuse_direntry *de = dh->first;
3655 
3656  dh->len = 0;
3657 
3658  if (extend_contents(dh, dh->needlen) == -1)
3659  return dh->error;
3660 
3661  for (pos = 0; pos < off; pos++) {
3662  if (!de)
3663  break;
3664 
3665  de = de->next;
3666  }
3667  while (de) {
3668  char *p = dh->contents + dh->len;
3669  unsigned rem = dh->needlen - dh->len;
3670  unsigned thislen;
3671  unsigned newlen;
3672  pos++;
3673 
3674  if (flags & FUSE_READDIR_PLUS) {
3675  struct fuse_entry_param e = {
3676  .ino = 0,
3677  .attr = de->stat,
3678  };
3679  thislen = fuse_add_direntry_plus(req, p, rem,
3680  de->name, &e, pos);
3681  } else {
3682  thislen = fuse_add_direntry(req, p, rem,
3683  de->name, &de->stat, pos);
3684  }
3685  newlen = dh->len + thislen;
3686  if (newlen > dh->needlen)
3687  break;
3688  dh->len = newlen;
3689  de = de->next;
3690  }
3691  return 0;
3692 }
3693 
3694 static void fuse_readdir_common(fuse_req_t req, fuse_ino_t ino, size_t size,
3695  off_t off, struct fuse_file_info *llfi,
3696  enum fuse_readdir_flags flags)
3697 {
3698  struct fuse *f = req_fuse_prepare(req);
3699  struct fuse_file_info fi;
3700  struct fuse_dh *dh = get_dirhandle(llfi, &fi);
3701  int err;
3702 
3703  pthread_mutex_lock(&dh->lock);
3704  /* According to SUS, directory contents need to be refreshed on
3705  rewinddir() */
3706  if (!off)
3707  dh->filled = 0;
3708 
3709  if (!dh->filled) {
3710  err = readdir_fill(f, req, ino, size, off, dh, &fi, flags);
3711  if (err) {
3712  reply_err(req, err);
3713  goto out;
3714  }
3715  }
3716  if (dh->filled) {
3717  dh->needlen = size;
3718  err = readdir_fill_from_list(req, dh, off, flags);
3719  if (err) {
3720  reply_err(req, err);
3721  goto out;
3722  }
3723  }
3724  fuse_reply_buf(req, dh->contents, dh->len);
3725 out:
3726  pthread_mutex_unlock(&dh->lock);
3727 }
3728 
3729 static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
3730  off_t off, struct fuse_file_info *llfi)
3731 {
3732  fuse_readdir_common(req, ino, size, off, llfi, 0);
3733 }
3734 
3735 static void fuse_lib_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
3736  off_t off, struct fuse_file_info *llfi)
3737 {
3738  fuse_readdir_common(req, ino, size, off, llfi, FUSE_READDIR_PLUS);
3739 }
3740 
3741 static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
3742  struct fuse_file_info *llfi)
3743 {
3744  struct fuse *f = req_fuse_prepare(req);
3745  struct fuse_intr_data d;
3746  struct fuse_file_info fi;
3747  struct fuse_dh *dh = get_dirhandle(llfi, &fi);
3748  char *path;
3749 
3750  get_path_nullok(f, ino, &path);
3751 
3752  fuse_prepare_interrupt(f, req, &d);
3753  fuse_fs_releasedir(f->fs, path, &fi);
3754  fuse_finish_interrupt(f, req, &d);
3755  free_path(f, ino, path);
3756 
3757  pthread_mutex_lock(&dh->lock);
3758  pthread_mutex_unlock(&dh->lock);
3759  pthread_mutex_destroy(&dh->lock);
3760  free_direntries(dh->first);
3761  free(dh->contents);
3762  free(dh);
3763  reply_err(req, 0);
3764 }
3765 
3766 static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
3767  struct fuse_file_info *llfi)
3768 {
3769  struct fuse *f = req_fuse_prepare(req);
3770  struct fuse_file_info fi;
3771  char *path;
3772  int err;
3773 
3774  get_dirhandle(llfi, &fi);
3775 
3776  err = get_path_nullok(f, ino, &path);
3777  if (!err) {
3778  struct fuse_intr_data d;
3779  fuse_prepare_interrupt(f, req, &d);
3780  err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
3781  fuse_finish_interrupt(f, req, &d);
3782  free_path(f, ino, path);
3783  }
3784  reply_err(req, err);
3785 }
3786 
3787 static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
3788 {
3789  struct fuse *f = req_fuse_prepare(req);
3790  struct statvfs buf;
3791  char *path = NULL;
3792  int err = 0;
3793 
3794  memset(&buf, 0, sizeof(buf));
3795  if (ino)
3796  err = get_path(f, ino, &path);
3797 
3798  if (!err) {
3799  struct fuse_intr_data d;
3800  fuse_prepare_interrupt(f, req, &d);
3801  err = fuse_fs_statfs(f->fs, path ? path : "/", &buf);
3802  fuse_finish_interrupt(f, req, &d);
3803  free_path(f, ino, path);
3804  }
3805 
3806  if (!err)
3807  fuse_reply_statfs(req, &buf);
3808  else
3809  reply_err(req, err);
3810 }
3811 
3812 static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
3813  const char *value, size_t size, int flags)
3814 {
3815  struct fuse *f = req_fuse_prepare(req);
3816  char *path;
3817  int err;
3818 
3819  err = get_path(f, ino, &path);
3820  if (!err) {
3821  struct fuse_intr_data d;
3822  fuse_prepare_interrupt(f, req, &d);
3823  err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
3824  fuse_finish_interrupt(f, req, &d);
3825  free_path(f, ino, path);
3826  }
3827  reply_err(req, err);
3828 }
3829 
3830 static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
3831  const char *name, char *value, size_t size)
3832 {
3833  int err;
3834  char *path;
3835 
3836  err = get_path(f, ino, &path);
3837  if (!err) {
3838  struct fuse_intr_data d;
3839  fuse_prepare_interrupt(f, req, &d);
3840  err = fuse_fs_getxattr(f->fs, path, name, value, size);
3841  fuse_finish_interrupt(f, req, &d);
3842  free_path(f, ino, path);
3843  }
3844  return err;
3845 }
3846 
3847 static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
3848  size_t size)
3849 {
3850  struct fuse *f = req_fuse_prepare(req);
3851  int res;
3852 
3853  if (size) {
3854  char *value = (char *) malloc(size);
3855  if (value == NULL) {
3856  reply_err(req, -ENOMEM);
3857  return;
3858  }
3859  res = common_getxattr(f, req, ino, name, value, size);
3860  if (res > 0)
3861  fuse_reply_buf(req, value, res);
3862  else
3863  reply_err(req, res);
3864  free(value);
3865  } else {
3866  res = common_getxattr(f, req, ino, name, NULL, 0);
3867  if (res >= 0)
3868  fuse_reply_xattr(req, res);
3869  else
3870  reply_err(req, res);
3871  }
3872 }
3873 
3874 static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
3875  char *list, size_t size)
3876 {
3877  char *path;
3878  int err;
3879 
3880  err = get_path(f, ino, &path);
3881  if (!err) {
3882  struct fuse_intr_data d;
3883  fuse_prepare_interrupt(f, req, &d);
3884  err = fuse_fs_listxattr(f->fs, path, list, size);
3885  fuse_finish_interrupt(f, req, &d);
3886  free_path(f, ino, path);
3887  }
3888  return err;
3889 }
3890 
3891 static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
3892 {
3893  struct fuse *f = req_fuse_prepare(req);
3894  int res;
3895 
3896  if (size) {
3897  char *list = (char *) malloc(size);
3898  if (list == NULL) {
3899  reply_err(req, -ENOMEM);
3900  return;
3901  }
3902  res = common_listxattr(f, req, ino, list, size);
3903  if (res > 0)
3904  fuse_reply_buf(req, list, res);
3905  else
3906  reply_err(req, res);
3907  free(list);
3908  } else {
3909  res = common_listxattr(f, req, ino, NULL, 0);
3910  if (res >= 0)
3911  fuse_reply_xattr(req, res);
3912  else
3913  reply_err(req, res);
3914  }
3915 }
3916 
3917 static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
3918  const char *name)
3919 {
3920  struct fuse *f = req_fuse_prepare(req);
3921  char *path;
3922  int err;
3923 
3924  err = get_path(f, ino, &path);
3925  if (!err) {
3926  struct fuse_intr_data d;
3927  fuse_prepare_interrupt(f, req, &d);
3928  err = fuse_fs_removexattr(f->fs, path, name);
3929  fuse_finish_interrupt(f, req, &d);
3930  free_path(f, ino, path);
3931  }
3932  reply_err(req, err);
3933 }
3934 
3935 static struct lock *locks_conflict(struct node *node, const struct lock *lock)
3936 {
3937  struct lock *l;
3938 
3939  for (l = node->locks; l; l = l->next)
3940  if (l->owner != lock->owner &&
3941  lock->start <= l->end && l->start <= lock->end &&
3942  (l->type == F_WRLCK || lock->type == F_WRLCK))
3943  break;
3944 
3945  return l;
3946 }
3947 
3948 static void delete_lock(struct lock **lockp)
3949 {
3950  struct lock *l = *lockp;
3951  *lockp = l->next;
3952  free(l);
3953 }
3954 
3955 static void insert_lock(struct lock **pos, struct lock *lock)
3956 {
3957  lock->next = *pos;
3958  *pos = lock;
3959 }
3960 
3961 static int locks_insert(struct node *node, struct lock *lock)
3962 {
3963  struct lock **lp;
3964  struct lock *newl1 = NULL;
3965  struct lock *newl2 = NULL;
3966 
3967  if (lock->type != F_UNLCK || lock->start != 0 ||
3968  lock->end != OFFSET_MAX) {
3969  newl1 = malloc(sizeof(struct lock));
3970  newl2 = malloc(sizeof(struct lock));
3971 
3972  if (!newl1 || !newl2) {
3973  free(newl1);
3974  free(newl2);
3975  return -ENOLCK;
3976  }
3977  }
3978 
3979  for (lp = &node->locks; *lp;) {
3980  struct lock *l = *lp;
3981  if (l->owner != lock->owner)
3982  goto skip;
3983 
3984  if (lock->type == l->type) {
3985  if (l->end < lock->start - 1)
3986  goto skip;
3987  if (lock->end < l->start - 1)
3988  break;
3989  if (l->start <= lock->start && lock->end <= l->end)
3990  goto out;
3991  if (l->start < lock->start)
3992  lock->start = l->start;
3993  if (lock->end < l->end)
3994  lock->end = l->end;
3995  goto delete;
3996  } else {
3997  if (l->end < lock->start)
3998  goto skip;
3999  if (lock->end < l->start)
4000  break;
4001  if (lock->start <= l->start && l->end <= lock->end)
4002  goto delete;
4003  if (l->end <= lock->end) {
4004  l->end = lock->start - 1;
4005  goto skip;
4006  }
4007  if (lock->start <= l->start) {
4008  l->start = lock->end + 1;
4009  break;
4010  }
4011  *newl2 = *l;
4012  newl2->start = lock->end + 1;
4013  l->end = lock->start - 1;
4014  insert_lock(&l->next, newl2);
4015  newl2 = NULL;
4016  }
4017  skip:
4018  lp = &l->next;
4019  continue;
4020 
4021  delete:
4022  delete_lock(lp);
4023  }
4024  if (lock->type != F_UNLCK) {
4025  *newl1 = *lock;
4026  insert_lock(lp, newl1);
4027  newl1 = NULL;
4028  }
4029 out:
4030  free(newl1);
4031  free(newl2);
4032  return 0;
4033 }
4034 
4035 static void flock_to_lock(struct flock *flock, struct lock *lock)
4036 {
4037  memset(lock, 0, sizeof(struct lock));
4038  lock->type = flock->l_type;
4039  lock->start = flock->l_start;
4040  lock->end =
4041  flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
4042  lock->pid = flock->l_pid;
4043 }
4044 
4045 static void lock_to_flock(struct lock *lock, struct flock *flock)
4046 {
4047  flock->l_type = lock->type;
4048  flock->l_start = lock->start;
4049  flock->l_len =
4050  (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
4051  flock->l_pid = lock->pid;
4052 }
4053 
4054 static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
4055  const char *path, struct fuse_file_info *fi)
4056 {
4057  struct fuse_intr_data d;
4058  struct flock lock;
4059  struct lock l;
4060  int err;
4061  int errlock;
4062 
4063  fuse_prepare_interrupt(f, req, &d);
4064  memset(&lock, 0, sizeof(lock));
4065  lock.l_type = F_UNLCK;
4066  lock.l_whence = SEEK_SET;
4067  err = fuse_fs_flush(f->fs, path, fi);
4068  errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
4069  fuse_finish_interrupt(f, req, &d);
4070 
4071  if (errlock != -ENOSYS) {
4072  flock_to_lock(&lock, &l);
4073  l.owner = fi->lock_owner;
4074  pthread_mutex_lock(&f->lock);
4075  locks_insert(get_node(f, ino), &l);
4076  pthread_mutex_unlock(&f->lock);
4077 
4078  /* if op.lock() is defined FLUSH is needed regardless
4079  of op.flush() */
4080  if (err == -ENOSYS)
4081  err = 0;
4082  }
4083  return err;
4084 }
4085 
4086 static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
4087  struct fuse_file_info *fi)
4088 {
4089  struct fuse *f = req_fuse_prepare(req);
4090  struct fuse_intr_data d;
4091  char *path;
4092  int err = 0;
4093 
4094  get_path_nullok(f, ino, &path);
4095  if (fi->flush) {
4096  err = fuse_flush_common(f, req, ino, path, fi);
4097  if (err == -ENOSYS)
4098  err = 0;
4099  }
4100 
4101  fuse_prepare_interrupt(f, req, &d);
4102  fuse_do_release(f, ino, path, fi);
4103  fuse_finish_interrupt(f, req, &d);
4104  free_path(f, ino, path);
4105 
4106  reply_err(req, err);
4107 }
4108 
4109 static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
4110  struct fuse_file_info *fi)
4111 {
4112  struct fuse *f = req_fuse_prepare(req);
4113  char *path;
4114  int err;
4115 
4116  get_path_nullok(f, ino, &path);
4117  err = fuse_flush_common(f, req, ino, path, fi);
4118  free_path(f, ino, path);
4119 
4120  reply_err(req, err);
4121 }
4122 
4123 static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
4124  struct fuse_file_info *fi, struct flock *lock,
4125  int cmd)
4126 {
4127  struct fuse *f = req_fuse_prepare(req);
4128  char *path;
4129  int err;
4130 
4131  err = get_path_nullok(f, ino, &path);
4132  if (!err) {
4133  struct fuse_intr_data d;
4134  fuse_prepare_interrupt(f, req, &d);
4135  err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
4136  fuse_finish_interrupt(f, req, &d);
4137  free_path(f, ino, path);
4138  }
4139  return err;
4140 }
4141 
4142 static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
4143  struct fuse_file_info *fi, struct flock *lock)
4144 {
4145  int err;
4146  struct lock l;
4147  struct lock *conflict;
4148  struct fuse *f = req_fuse(req);
4149 
4150  flock_to_lock(lock, &l);
4151  l.owner = fi->lock_owner;
4152  pthread_mutex_lock(&f->lock);
4153  conflict = locks_conflict(get_node(f, ino), &l);
4154  if (conflict)
4155  lock_to_flock(conflict, lock);
4156  pthread_mutex_unlock(&f->lock);
4157  if (!conflict)
4158  err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
4159  else
4160  err = 0;
4161 
4162  if (!err)
4163  fuse_reply_lock(req, lock);
4164  else
4165  reply_err(req, err);
4166 }
4167 
4168 static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
4169  struct fuse_file_info *fi, struct flock *lock,
4170  int sleep)
4171 {
4172  int err = fuse_lock_common(req, ino, fi, lock,
4173  sleep ? F_SETLKW : F_SETLK);
4174  if (!err) {
4175  struct fuse *f = req_fuse(req);
4176  struct lock l;
4177  flock_to_lock(lock, &l);
4178  l.owner = fi->lock_owner;
4179  pthread_mutex_lock(&f->lock);
4180  locks_insert(get_node(f, ino), &l);
4181  pthread_mutex_unlock(&f->lock);
4182  }
4183  reply_err(req, err);
4184 }
4185 
4186 static void fuse_lib_flock(fuse_req_t req, fuse_ino_t ino,
4187  struct fuse_file_info *fi, int op)
4188 {
4189  struct fuse *f = req_fuse_prepare(req);
4190  char *path;
4191  int err;
4192 
4193  err = get_path_nullok(f, ino, &path);
4194  if (err == 0) {
4195  struct fuse_intr_data d;
4196  fuse_prepare_interrupt(f, req, &d);
4197  err = fuse_fs_flock(f->fs, path, fi, op);
4198  fuse_finish_interrupt(f, req, &d);
4199  free_path(f, ino, path);
4200  }
4201  reply_err(req, err);
4202 }
4203 
4204 static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
4205  uint64_t idx)
4206 {
4207  struct fuse *f = req_fuse_prepare(req);
4208  struct fuse_intr_data d;
4209  char *path;
4210  int err;
4211 
4212  err = get_path(f, ino, &path);
4213  if (!err) {
4214  fuse_prepare_interrupt(f, req, &d);
4215  err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
4216  fuse_finish_interrupt(f, req, &d);
4217  free_path(f, ino, path);
4218  }
4219  if (!err)
4220  fuse_reply_bmap(req, idx);
4221  else
4222  reply_err(req, err);
4223 }
4224 
4225 static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
4226  struct fuse_file_info *llfi, unsigned int flags,
4227  const void *in_buf, size_t in_bufsz,
4228  size_t out_bufsz)
4229 {
4230  struct fuse *f = req_fuse_prepare(req);
4231  struct fuse_intr_data d;
4232  struct fuse_file_info fi;
4233  char *path, *out_buf = NULL;
4234  int err;
4235 
4236  err = -EPERM;
4237  if (flags & FUSE_IOCTL_UNRESTRICTED)
4238  goto err;
4239 
4240  if (flags & FUSE_IOCTL_DIR)
4241  get_dirhandle(llfi, &fi);
4242  else
4243  fi = *llfi;
4244 
4245  if (out_bufsz) {
4246  err = -ENOMEM;
4247  out_buf = malloc(out_bufsz);
4248  if (!out_buf)
4249  goto err;
4250  }
4251 
4252  assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
4253  if (out_buf && in_bufsz)
4254  memcpy(out_buf, in_buf, in_bufsz);
4255 
4256  err = get_path_nullok(f, ino, &path);
4257  if (err)
4258  goto err;
4259 
4260  fuse_prepare_interrupt(f, req, &d);
4261 
4262  err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags,
4263  out_buf ?: (void *)in_buf);
4264 
4265  fuse_finish_interrupt(f, req, &d);
4266  free_path(f, ino, path);
4267 
4268  fuse_reply_ioctl(req, err, out_buf, out_bufsz);
4269  goto out;
4270 err:
4271  reply_err(req, err);
4272 out:
4273  free(out_buf);
4274 }
4275 
4276 static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino,
4277  struct fuse_file_info *fi, struct fuse_pollhandle *ph)
4278 {
4279  struct fuse *f = req_fuse_prepare(req);
4280  struct fuse_intr_data d;
4281  char *path;
4282  int err;
4283  unsigned revents = 0;
4284 
4285  err = get_path_nullok(f, ino, &path);
4286  if (!err) {
4287  fuse_prepare_interrupt(f, req, &d);
4288  err = fuse_fs_poll(f->fs, path, fi, ph, &revents);
4289  fuse_finish_interrupt(f, req, &d);
4290  free_path(f, ino, path);
4291  }
4292  if (!err)
4293  fuse_reply_poll(req, revents);
4294  else
4295  reply_err(req, err);
4296 }
4297 
4298 static void fuse_lib_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
4299  off_t offset, off_t length, struct fuse_file_info *fi)
4300 {
4301  struct fuse *f = req_fuse_prepare(req);
4302  struct fuse_intr_data d;
4303  char *path;
4304  int err;
4305 
4306  err = get_path_nullok(f, ino, &path);
4307  if (!err) {
4308  fuse_prepare_interrupt(f, req, &d);
4309  err = fuse_fs_fallocate(f->fs, path, mode, offset, length, fi);
4310  fuse_finish_interrupt(f, req, &d);
4311  free_path(f, ino, path);
4312  }
4313  reply_err(req, err);
4314 }
4315 
4316 static void fuse_lib_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
4317  off_t off_in, struct fuse_file_info *fi_in,
4318  fuse_ino_t nodeid_out, off_t off_out,
4319  struct fuse_file_info *fi_out, size_t len,
4320  int flags)
4321 {
4322  struct fuse *f = req_fuse_prepare(req);
4323  struct fuse_intr_data d;
4324  char *path_in, *path_out;
4325  int err;
4326  ssize_t res;
4327 
4328  err = get_path_nullok(f, nodeid_in, &path_in);
4329  if (err) {
4330  reply_err(req, err);
4331  return;
4332  }
4333 
4334  err = get_path_nullok(f, nodeid_out, &path_out);
4335  if (err) {
4336  free_path(f, nodeid_in, path_in);
4337  reply_err(req, err);
4338  return;
4339  }
4340 
4341  fuse_prepare_interrupt(f, req, &d);
4342  res = fuse_fs_copy_file_range(f->fs, path_in, fi_in, off_in, path_out,
4343  fi_out, off_out, len, flags);
4344  fuse_finish_interrupt(f, req, &d);
4345 
4346  if (res >= 0)
4347  fuse_reply_write(req, res);
4348  else
4349  reply_err(req, res);
4350 
4351  free_path(f, nodeid_in, path_in);
4352  free_path(f, nodeid_out, path_out);
4353 }
4354 
4355 static int clean_delay(struct fuse *f)
4356 {
4357  /*
4358  * This is calculating the delay between clean runs. To
4359  * reduce the number of cleans we are doing them 10 times
4360  * within the remember window.
4361  */
4362  int min_sleep = 60;
4363  int max_sleep = 3600;
4364  int sleep_time = f->conf.remember / 10;
4365 
4366  if (sleep_time > max_sleep)
4367  return max_sleep;
4368  if (sleep_time < min_sleep)
4369  return min_sleep;
4370  return sleep_time;
4371 }
4372 
4373 int fuse_clean_cache(struct fuse *f)
4374 {
4375  struct node_lru *lnode;
4376  struct list_head *curr, *next;
4377  struct node *node;
4378  struct timespec now;
4379 
4380  pthread_mutex_lock(&f->lock);
4381 
4382  curr_time(&now);
4383 
4384  for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) {
4385  double age;
4386 
4387  next = curr->next;
4388  lnode = list_entry(curr, struct node_lru, lru);
4389  node = &lnode->node;
4390 
4391  age = diff_timespec(&now, &lnode->forget_time);
4392  if (age <= f->conf.remember)
4393  break;
4394 
4395  assert(node->nlookup == 1);
4396 
4397  /* Don't forget active directories */
4398  if (node->refctr > 1)
4399  continue;
4400 
4401  node->nlookup = 0;
4402  unhash_name(f, node);
4403  unref_node(f, node);
4404  }
4405  pthread_mutex_unlock(&f->lock);
4406 
4407  return clean_delay(f);
4408 }
4409 
4410 static struct fuse_lowlevel_ops fuse_path_ops = {
4411  .init = fuse_lib_init,
4412  .destroy = fuse_lib_destroy,
4413  .lookup = fuse_lib_lookup,
4414  .forget = fuse_lib_forget,
4415  .forget_multi = fuse_lib_forget_multi,
4416  .getattr = fuse_lib_getattr,
4417  .setattr = fuse_lib_setattr,
4418  .access = fuse_lib_access,
4419  .readlink = fuse_lib_readlink,
4420  .mknod = fuse_lib_mknod,
4421  .mkdir = fuse_lib_mkdir,
4422  .unlink = fuse_lib_unlink,
4423  .rmdir = fuse_lib_rmdir,
4424  .symlink = fuse_lib_symlink,
4425  .rename = fuse_lib_rename,
4426  .link = fuse_lib_link,
4427  .create = fuse_lib_create,
4428  .open = fuse_lib_open,
4429  .read = fuse_lib_read,
4430  .write_buf = fuse_lib_write_buf,
4431  .flush = fuse_lib_flush,
4432  .release = fuse_lib_release,
4433  .fsync = fuse_lib_fsync,
4434  .opendir = fuse_lib_opendir,
4435  .readdir = fuse_lib_readdir,
4436  .readdirplus = fuse_lib_readdirplus,
4437  .releasedir = fuse_lib_releasedir,
4438  .fsyncdir = fuse_lib_fsyncdir,
4439  .statfs = fuse_lib_statfs,
4440  .setxattr = fuse_lib_setxattr,
4441  .getxattr = fuse_lib_getxattr,
4442  .listxattr = fuse_lib_listxattr,
4443  .removexattr = fuse_lib_removexattr,
4444  .getlk = fuse_lib_getlk,
4445  .setlk = fuse_lib_setlk,
4446  .flock = fuse_lib_flock,
4447  .bmap = fuse_lib_bmap,
4448  .ioctl = fuse_lib_ioctl,
4449  .poll = fuse_lib_poll,
4450  .fallocate = fuse_lib_fallocate,
4451  .copy_file_range = fuse_lib_copy_file_range,
4452 };
4453 
4454 int fuse_notify_poll(struct fuse_pollhandle *ph)
4455 {
4456  return fuse_lowlevel_notify_poll(ph);
4457 }
4458 
4459 struct fuse_session *fuse_get_session(struct fuse *f)
4460 {
4461  return f->se;
4462 }
4463 
4464 static int fuse_session_loop_remember(struct fuse *f)
4465 {
4466  struct fuse_session *se = f->se;
4467  int res = 0;
4468  struct timespec now;
4469  time_t next_clean;
4470  struct pollfd fds = {
4471  .fd = se->fd,
4472  .events = POLLIN
4473  };
4474  struct fuse_buf fbuf = {
4475  .mem = NULL,
4476  };
4477 
4478  curr_time(&now);
4479  next_clean = now.tv_sec;
4480  while (!fuse_session_exited(se)) {
4481  unsigned timeout;
4482 
4483  curr_time(&now);
4484  if (now.tv_sec < next_clean)
4485  timeout = next_clean - now.tv_sec;
4486  else
4487  timeout = 0;
4488 
4489  res = poll(&fds, 1, timeout * 1000);
4490  if (res == -1) {
4491  if (errno == -EINTR)
4492  continue;
4493  else
4494  break;
4495  } else if (res > 0) {
4496  res = fuse_session_receive_buf_int(se, &fbuf, NULL);
4497 
4498  if (res == -EINTR)
4499  continue;
4500  if (res <= 0)
4501  break;
4502 
4503  fuse_session_process_buf_int(se, &fbuf, NULL);
4504  } else {
4505  timeout = fuse_clean_cache(f);
4506  curr_time(&now);
4507  next_clean = now.tv_sec + timeout;
4508  }
4509  }
4510 
4511  free(fbuf.mem);
4512  fuse_session_reset(se);
4513  return res < 0 ? -1 : 0;
4514 }
4515 
4516 int fuse_loop(struct fuse *f)
4517 {
4518  if (!f)
4519  return -1;
4520 
4521  if (lru_enabled(f))
4522  return fuse_session_loop_remember(f);
4523 
4524  return fuse_session_loop(f->se);
4525 }
4526 
4527 FUSE_SYMVER(".symver fuse_loop_mt_32,fuse_loop_mt@@FUSE_3.2");
4528 int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config)
4529 {
4530  if (f == NULL)
4531  return -1;
4532 
4533  int res = fuse_start_cleanup_thread(f);
4534  if (res)
4535  return -1;
4536 
4537  res = fuse_session_loop_mt_32(fuse_get_session(f), config);
4539  return res;
4540 }
4541 
4542 int fuse_loop_mt_31(struct fuse *f, int clone_fd);
4543 FUSE_SYMVER(".symver fuse_loop_mt_31,fuse_loop_mt@FUSE_3.0");
4544 int fuse_loop_mt_31(struct fuse *f, int clone_fd)
4545 {
4546  struct fuse_loop_config config;
4547  config.clone_fd = clone_fd;
4548  config.max_idle_threads = 10;
4549  return fuse_loop_mt_32(f, &config);
4550 }
4551 
4552 void fuse_exit(struct fuse *f)
4553 {
4554  fuse_session_exit(f->se);
4555 }
4556 
4558 {
4559  struct fuse_context_i *c = fuse_get_context_internal();
4560 
4561  if (c)
4562  return &c->ctx;
4563  else
4564  return NULL;
4565 }
4566 
4567 int fuse_getgroups(int size, gid_t list[])
4568 {
4569  struct fuse_context_i *c = fuse_get_context_internal();
4570  if (!c)
4571  return -EINVAL;
4572 
4573  return fuse_req_getgroups(c->req, size, list);
4574 }
4575 
4577 {
4578  struct fuse_context_i *c = fuse_get_context_internal();
4579 
4580  if (c)
4581  return fuse_req_interrupted(c->req);
4582  else
4583  return 0;
4584 }
4585 
4586 int fuse_invalidate_path(struct fuse *f, const char *path) {
4587  fuse_ino_t ino;
4588  int err = lookup_path_in_cache(f, path, &ino);
4589  if (err) {
4590  return err;
4591  }
4592 
4593  return fuse_lowlevel_notify_inval_inode(f->se, ino, 0, 0);
4594 }
4595 
4596 #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
4597 
4598 static const struct fuse_opt fuse_lib_opts[] = {
4599  FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
4601  FUSE_LIB_OPT("debug", debug, 1),
4602  FUSE_LIB_OPT("-d", debug, 1),
4603  FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
4604  FUSE_LIB_OPT("auto_cache", auto_cache, 1),
4605  FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
4606  FUSE_LIB_OPT("umask=", set_mode, 1),
4607  FUSE_LIB_OPT("umask=%o", umask, 0),
4608  FUSE_LIB_OPT("uid=", set_uid, 1),
4609  FUSE_LIB_OPT("uid=%d", uid, 0),
4610  FUSE_LIB_OPT("gid=", set_gid, 1),
4611  FUSE_LIB_OPT("gid=%d", gid, 0),
4612  FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
4613  FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
4614  FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
4615  FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
4616  FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
4617  FUSE_LIB_OPT("noforget", remember, -1),
4618  FUSE_LIB_OPT("remember=%u", remember, 0),
4619  FUSE_LIB_OPT("modules=%s", modules, 0),
4620  FUSE_OPT_END
4621 };
4622 
4623 static int fuse_lib_opt_proc(void *data, const char *arg, int key,
4624  struct fuse_args *outargs)
4625 {
4626  (void) arg; (void) outargs; (void) data; (void) key;
4627 
4628  /* Pass through unknown options */
4629  return 1;
4630 }
4631 
4632 
4633 static const struct fuse_opt fuse_help_opts[] = {
4634  FUSE_LIB_OPT("modules=%s", modules, 1),
4635  FUSE_OPT_KEY("modules=%s", FUSE_OPT_KEY_KEEP),
4636  FUSE_OPT_END
4637 };
4638 
4639 static void print_module_help(const char *name,
4640  fuse_module_factory_t *fac)
4641 {
4642  struct fuse_args a = FUSE_ARGS_INIT(0, NULL);
4643  if (fuse_opt_add_arg(&a, "") == -1 ||
4644  fuse_opt_add_arg(&a, "-h") == -1)
4645  return;
4646  printf("\nOptions for %s module:\n", name);
4647  (*fac)(&a, NULL);
4648 }
4649 
4650 void fuse_lib_help(struct fuse_args *args)
4651 {
4652  /* These are not all options, but only the ones that
4653  may be of interest to an end-user */
4654  printf(
4655 " -o kernel_cache cache files in kernel\n"
4656 " -o [no]auto_cache enable caching based on modification times (off)\n"
4657 " -o umask=M set file permissions (octal)\n"
4658 " -o uid=N set file owner\n"
4659 " -o gid=N set file group\n"
4660 " -o entry_timeout=T cache timeout for names (1.0s)\n"
4661 " -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
4662 " -o attr_timeout=T cache timeout for attributes (1.0s)\n"
4663 " -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
4664 " -o noforget never forget cached inodes\n"
4665 " -o remember=T remember cached inodes for T seconds (0s)\n"
4666 " -o modules=M1[:M2...] names of modules to push onto filesystem stack\n");
4667 
4668 
4669  /* Print low-level help */
4671 
4672  /* Print help for builtin modules */
4673  print_module_help("subdir", &fuse_module_subdir_factory);
4674 #ifdef HAVE_ICONV
4675  print_module_help("iconv", &fuse_module_iconv_factory);
4676 #endif
4677 
4678  /* Parse command line options in case we need to
4679  activate more modules */
4680  struct fuse_config conf = { .modules = NULL };
4681  if (fuse_opt_parse(args, &conf, fuse_help_opts,
4682  fuse_lib_opt_proc) == -1
4683  || !conf.modules)
4684  return;
4685 
4686  char *module;
4687  char *next;
4688  struct fuse_module *m;
4689 
4690  // Iterate over all modules
4691  for (module = conf.modules; module; module = next) {
4692  char *p;
4693  for (p = module; *p && *p != ':'; p++);
4694  next = *p ? p + 1 : NULL;
4695  *p = '\0';
4696 
4697  m = fuse_get_module(module);
4698  if (m)
4699  print_module_help(module, &m->factory);
4700  }
4701 }
4702 
4703 
4704 
4705 static int fuse_init_intr_signal(int signum, int *installed)
4706 {
4707  struct sigaction old_sa;
4708 
4709  if (sigaction(signum, NULL, &old_sa) == -1) {
4710  perror("fuse: cannot get old signal handler");
4711  return -1;
4712  }
4713 
4714  if (old_sa.sa_handler == SIG_DFL) {
4715  struct sigaction sa;
4716 
4717  memset(&sa, 0, sizeof(struct sigaction));
4718  sa.sa_handler = fuse_intr_sighandler;
4719  sigemptyset(&sa.sa_mask);
4720 
4721  if (sigaction(signum, &sa, NULL) == -1) {
4722  perror("fuse: cannot set interrupt signal handler");
4723  return -1;
4724  }
4725  *installed = 1;
4726  }
4727  return 0;
4728 }
4729 
4730 static void fuse_restore_intr_signal(int signum)
4731 {
4732  struct sigaction sa;
4733 
4734  memset(&sa, 0, sizeof(struct sigaction));
4735  sa.sa_handler = SIG_DFL;
4736  sigaction(signum, &sa, NULL);
4737 }
4738 
4739 
4740 static int fuse_push_module(struct fuse *f, const char *module,
4741  struct fuse_args *args)
4742 {
4743  struct fuse_fs *fs[2] = { f->fs, NULL };
4744  struct fuse_fs *newfs;
4745  struct fuse_module *m = fuse_get_module(module);
4746 
4747  if (!m)
4748  return -1;
4749 
4750  newfs = m->factory(args, fs);
4751  if (!newfs) {
4752  fuse_put_module(m);
4753  return -1;
4754  }
4755  newfs->m = m;
4756  f->fs = newfs;
4757  return 0;
4758 }
4759 
4760 struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
4761  void *user_data)
4762 {
4763  struct fuse_fs *fs;
4764 
4765  if (sizeof(struct fuse_operations) < op_size) {
4766  fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
4767  op_size = sizeof(struct fuse_operations);
4768  }
4769 
4770  fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
4771  if (!fs) {
4772  fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
4773  return NULL;
4774  }
4775 
4776  fs->user_data = user_data;
4777  if (op)
4778  memcpy(&fs->op, op, op_size);
4779  return fs;
4780 }
4781 
4782 static int node_table_init(struct node_table *t)
4783 {
4784  t->size = NODE_TABLE_MIN_SIZE;
4785  t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size);
4786  if (t->array == NULL) {
4787  fprintf(stderr, "fuse: memory allocation failed\n");
4788  return -1;
4789  }
4790  t->use = 0;
4791  t->split = 0;
4792 
4793  return 0;
4794 }
4795 
4796 static void *fuse_prune_nodes(void *fuse)
4797 {
4798  struct fuse *f = fuse;
4799  int sleep_time;
4800 
4801  while(1) {
4802  sleep_time = fuse_clean_cache(f);
4803  sleep(sleep_time);
4804  }
4805  return NULL;
4806 }
4807 
4808 int fuse_start_cleanup_thread(struct fuse *f)
4809 {
4810  if (lru_enabled(f))
4811  return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f);
4812 
4813  return 0;
4814 }
4815 
4816 void fuse_stop_cleanup_thread(struct fuse *f)
4817 {
4818  if (lru_enabled(f)) {
4819  pthread_mutex_lock(&f->lock);
4820  pthread_cancel(f->prune_thread);
4821  pthread_mutex_unlock(&f->lock);
4822  pthread_join(f->prune_thread, NULL);
4823  }
4824 }
4825 
4826 
4827 FUSE_SYMVER(".symver fuse_new_31,fuse_new@@FUSE_3.1");
4828 struct fuse *fuse_new_31(struct fuse_args *args,
4829  const struct fuse_operations *op,
4830  size_t op_size, void *user_data)
4831 {
4832  struct fuse *f;
4833  struct node *root;
4834  struct fuse_fs *fs;
4835  struct fuse_lowlevel_ops llop = fuse_path_ops;
4836 
4837  f = (struct fuse *) calloc(1, sizeof(struct fuse));
4838  if (f == NULL) {
4839  fprintf(stderr, "fuse: failed to allocate fuse object\n");
4840  goto out;
4841  }
4842 
4843  f->conf.entry_timeout = 1.0;
4844  f->conf.attr_timeout = 1.0;
4845  f->conf.negative_timeout = 0.0;
4846  f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
4847 
4848  /* Parse options */
4849  if (fuse_opt_parse(args, &f->conf, fuse_lib_opts,
4850  fuse_lib_opt_proc) == -1)
4851  goto out_free;
4852 
4853  pthread_mutex_lock(&fuse_context_lock);
4854  static int builtin_modules_registered = 0;
4855  /* Have the builtin modules already been registered? */
4856  if (builtin_modules_registered == 0) {
4857  /* If not, register them. */
4858  fuse_register_module("subdir", fuse_module_subdir_factory, NULL);
4859 #ifdef HAVE_ICONV
4860  fuse_register_module("iconv", fuse_module_iconv_factory, NULL);
4861 #endif
4862  builtin_modules_registered= 1;
4863  }
4864  pthread_mutex_unlock(&fuse_context_lock);
4865 
4866  if (fuse_create_context_key() == -1)
4867  goto out_free;
4868 
4869  fs = fuse_fs_new(op, op_size, user_data);
4870  if (!fs)
4871  goto out_delete_context_key;
4872 
4873  f->fs = fs;
4874 
4875  /* Oh f**k, this is ugly! */
4876  if (!fs->op.lock) {
4877  llop.getlk = NULL;
4878  llop.setlk = NULL;
4879  }
4880 
4881  f->pagesize = getpagesize();
4882  init_list_head(&f->partial_slabs);
4883  init_list_head(&f->full_slabs);
4884  init_list_head(&f->lru_table);
4885 
4886  if (f->conf.modules) {
4887  char *module;
4888  char *next;
4889 
4890  for (module = f->conf.modules; module; module = next) {
4891  char *p;
4892  for (p = module; *p && *p != ':'; p++);
4893  next = *p ? p + 1 : NULL;
4894  *p = '\0';
4895  if (module[0] &&
4896  fuse_push_module(f, module, args) == -1)
4897  goto out_free_fs;
4898  }
4899  }
4900 
4901  if (!f->conf.ac_attr_timeout_set)
4902  f->conf.ac_attr_timeout = f->conf.attr_timeout;
4903 
4904 #if defined(__FreeBSD__) || defined(__NetBSD__)
4905  /*
4906  * In FreeBSD, we always use these settings as inode numbers
4907  * are needed to make getcwd(3) work.
4908  */
4909  f->conf.readdir_ino = 1;
4910 #endif
4911 
4912  f->se = fuse_session_new(args, &llop, sizeof(llop), f);
4913  if (f->se == NULL)
4914  goto out_free_fs;
4915 
4916  if (f->conf.debug) {
4917  fprintf(stderr, "nullpath_ok: %i\n", f->conf.nullpath_ok);
4918  }
4919 
4920  /* Trace topmost layer by default */
4921  f->fs->debug = f->conf.debug;
4922  f->ctr = 0;
4923  f->generation = 0;
4924  if (node_table_init(&f->name_table) == -1)
4925  goto out_free_session;
4926 
4927  if (node_table_init(&f->id_table) == -1)
4928  goto out_free_name_table;
4929 
4930  fuse_mutex_init(&f->lock);
4931 
4932  root = alloc_node(f);
4933  if (root == NULL) {
4934  fprintf(stderr, "fuse: memory allocation failed\n");
4935  goto out_free_id_table;
4936  }
4937  if (lru_enabled(f)) {
4938  struct node_lru *lnode = node_lru(root);
4939  init_list_head(&lnode->lru);
4940  }
4941 
4942  strcpy(root->inline_name, "/");
4943  root->name = root->inline_name;
4944 
4945  if (f->conf.intr &&
4946  fuse_init_intr_signal(f->conf.intr_signal,
4947  &f->intr_installed) == -1)
4948  goto out_free_root;
4949 
4950  root->parent = NULL;
4951  root->nodeid = FUSE_ROOT_ID;
4952  inc_nlookup(root);
4953  hash_id(f, root);
4954 
4955  return f;
4956 
4957 out_free_root:
4958  free(root);
4959 out_free_id_table:
4960  free(f->id_table.array);
4961 out_free_name_table:
4962  free(f->name_table.array);
4963 out_free_session:
4964  fuse_session_destroy(f->se);
4965 out_free_fs:
4966  if (f->fs->m)
4967  fuse_put_module(f->fs->m);
4968  free(f->fs);
4969  free(f->conf.modules);
4970 out_delete_context_key:
4971  fuse_delete_context_key();
4972 out_free:
4973  free(f);
4974 out:
4975  return NULL;
4976 }
4977 
4978 /* Emulates 3.0-style fuse_new(), which processes --help */
4979 struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op,
4980  size_t op_size, void *private_data);
4981 FUSE_SYMVER(".symver fuse_new_30,fuse_new@FUSE_3.0");
4982 struct fuse *fuse_new_30(struct fuse_args *args,
4983  const struct fuse_operations *op,
4984  size_t op_size, void *user_data)
4985 {
4986  struct fuse_config conf;
4987 
4988  memset(&conf, 0, sizeof(conf));
4989 
4990  const struct fuse_opt opts[] = {
4991  FUSE_LIB_OPT("-h", show_help, 1),
4992  FUSE_LIB_OPT("--help", show_help, 1),
4993  FUSE_OPT_END
4994  };
4995 
4996  if (fuse_opt_parse(args, &conf, opts,
4997  fuse_lib_opt_proc) == -1)
4998  return NULL;
4999 
5000  if (conf.show_help) {
5001  fuse_lib_help(args);
5002  return NULL;
5003  } else
5004  return fuse_new_31(args, op, op_size, user_data);
5005 }
5006 
5007 void fuse_destroy(struct fuse *f)
5008 {
5009  size_t i;
5010 
5011  if (f->conf.intr && f->intr_installed)
5012  fuse_restore_intr_signal(f->conf.intr_signal);
5013 
5014  if (f->fs) {
5015  fuse_create_context(f);
5016 
5017  for (i = 0; i < f->id_table.size; i++) {
5018  struct node *node;
5019 
5020  for (node = f->id_table.array[i]; node != NULL;
5021  node = node->id_next) {
5022  if (node->is_hidden) {
5023  char *path;
5024  if (try_get_path(f, node->nodeid, NULL, &path, NULL, false) == 0) {
5025  fuse_fs_unlink(f->fs, path);
5026  free(path);
5027  }
5028  }
5029  }
5030  }
5031  }
5032  for (i = 0; i < f->id_table.size; i++) {
5033  struct node *node;
5034  struct node *next;
5035 
5036  for (node = f->id_table.array[i]; node != NULL; node = next) {
5037  next = node->id_next;
5038  free_node(f, node);
5039  f->id_table.use--;
5040  }
5041  }
5042  assert(list_empty(&f->partial_slabs));
5043  assert(list_empty(&f->full_slabs));
5044 
5045  while (fuse_modules) {
5046  fuse_put_module(fuse_modules);
5047  }
5048  free(f->id_table.array);
5049  free(f->name_table.array);
5050  pthread_mutex_destroy(&f->lock);
5051  fuse_session_destroy(f->se);
5052  free(f->conf.modules);
5053  free(f);
5054  fuse_delete_context_key();
5055 }
5056 
5057 int fuse_mount(struct fuse *f, const char *mountpoint) {
5058  return fuse_session_mount(fuse_get_session(f), mountpoint);
5059 }
5060 
5061 
5062 void fuse_unmount(struct fuse *f) {
5064 }
5065 
5066 int fuse_version(void)
5067 {
5068  return FUSE_VERSION;
5069 }
5070 
5071 const char *fuse_pkgversion(void)
5072 {
5073  return PACKAGE_VERSION;
5074 }
void fuse_session_destroy(struct fuse_session *se)
+
int fuse_reply_err(fuse_req_t req, int err)
+
size_t off
Definition: fuse_common.h:679
+
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
+
void fuse_session_exit(struct fuse_session *se)
+
unsigned capable
Definition: fuse_common.h:381
+
uint64_t fh
Definition: fuse_common.h:72
+
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
+ + +
unsigned int writepage
Definition: fuse_common.h:43
+
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
+
void fuse_lowlevel_help(void)
+
unsigned int direct_io
Definition: fuse_common.h:46
+ +
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
+
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
+
uint32_t poll_events
Definition: fuse_common.h:79
+
const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
+
void fuse_stop_cleanup_thread(struct fuse *fuse)
Definition: fuse.c:4816
+
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
+
unsigned int max_idle_threads
Definition: fuse_common.h:103
+
mode_t umask
+
int fuse_loop(struct fuse *f)
Definition: fuse.c:4516
+
fuse_fill_dir_flags
Definition: fuse.h:54
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+
struct stat attr
Definition: fuse_lowlevel.h:91
+
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
+
void * fuse_req_userdata(fuse_req_t req)
+ +
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
+ +
int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
+
unsigned int keep_cache
Definition: fuse_common.h:51
+
Definition: fuse_lowlevel.h:59
+
fuse_readdir_flags
Definition: fuse.h:42
+
#define FUSE_CAP_EXPORT_SUPPORT
Definition: fuse_common.h:144
+
fuse_ino_t ino
Definition: fuse_lowlevel.h:67
+
uint64_t lock_owner
Definition: fuse_common.h:75
+
int fuse_reply_xattr(fuse_req_t req, size_t count)
+
int fuse_session_exited(struct fuse_session *se)
+
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+
void(* getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
+
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
+ +
int fuse_clean_cache(struct fuse *fuse)
Definition: fuse.c:4373
+ +
int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
+
void fuse_destroy(struct fuse *f)
Definition: fuse.c:5007
+
int fuse_version(void)
Definition: fuse.c:5066
+
int fuse_req_interrupted(fuse_req_t req)
+
void fuse_session_reset(struct fuse_session *se)
+
void fuse_reply_none(fuse_req_t req)
+
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+ + + + +
size_t idx
Definition: fuse_common.h:674
+ +
size_t count
Definition: fuse_common.h:669
+ +
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
+
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
+
#define FUSE_CAP_SPLICE_READ
Definition: fuse_common.h:177
+
void fuse_session_unmount(struct fuse_session *se)
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+
enum fuse_buf_flags flags
Definition: fuse_common.h:633
+
struct fuse_fs *(* fuse_module_factory_t)(struct fuse_args *args, struct fuse_fs *fs[])
Definition: fuse.h:1226
+
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
+
struct fuse_session * fuse_get_session(struct fuse *f)
Definition: fuse.c:4459
+
unsigned int flush
Definition: fuse_common.h:56
+
#define FUSE_OPT_KEY_KEEP
Definition: fuse_opt.h:145
+
void * private_data
Definition: fuse.h:791
+
int fuse_invalidate_path(struct fuse *f, const char *path)
Definition: fuse.c:4586
+ +
struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
Definition: fuse.c:4760
+
#define FUSE_ROOT_ID
Definition: fuse_lowlevel.h:43
+
int fuse_start_cleanup_thread(struct fuse *fuse)
Definition: fuse.c:4808
+ +
#define FUSE_CAP_FLOCK_LOCKS
Definition: fuse_common.h:190
+
void fuse_lib_help(struct fuse_args *args)
Definition: fuse.c:4650
+
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
+
int fuse_interrupted(void)
Definition: fuse.c:4576
+
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:82
+
int show_help
Definition: fuse.h:271
+
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
+
uint64_t generation
Definition: fuse_lowlevel.h:82
+
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
+
int fuse_reply_write(fuse_req_t req, size_t count)
+
void * mem
Definition: fuse_common.h:640
+
int fuse_getgroups(int size, gid_t list[])
Definition: fuse.c:4567
+ +
int fuse_mount(struct fuse *f, const char *mountpoint)
Definition: fuse.c:5057
+
#define FUSE_CAP_POSIX_LOCKS
Definition: fuse_common.h:128
+
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
+
void(* setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
+ + +
struct fuse_buf buf[1]
Definition: fuse_common.h:684
+ + + +
unsigned want
Definition: fuse_common.h:389
+
void fuse_unmount(struct fuse *f)
Definition: fuse.c:5062
+ +
int fuse_loop_mt_31(struct fuse *f, int clone_fd)
Definition: fuse.c:4544
+
const char * fuse_pkgversion(void)
Definition: fuse.c:5071
+
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
+
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
+
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:281
+
size_t size
Definition: fuse_common.h:628
+
struct fuse_context * fuse_get_context(void)
Definition: fuse.c:4557
+
double entry_timeout
+
double attr_timeout
Definition: fuse_lowlevel.h:97
+ + +
int fuse_reply_readlink(fuse_req_t req, const char *link)
+
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+
void(* init)(void *userdata, struct fuse_conn_info *conn)
+
int fuse_reply_poll(fuse_req_t req, unsigned revents)
+
void fuse_exit(struct fuse *f)
Definition: fuse.c:4552
+
+ + + + diff --git a/doc/html/fuse_8h.html b/doc/html/fuse_8h.html index af83459..27e3dc3 100644 --- a/doc/html/fuse_8h.html +++ b/doc/html/fuse_8h.html @@ -3,8 +3,9 @@ - -fuse: include/fuse.h File Reference + + +libfuse: include/fuse.h File Reference @@ -16,8 +17,8 @@ - @@ -25,20 +26,15 @@
-
fuse +
+
libfuse
- - - + + + + +
fuse.h File Reference
-
#include "fuse_common.h"
+
#include "fuse_common.h"
#include <fcntl.h>
#include <time.h>
-#include <utime.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/uio.h>
-#include "fuse_compat.h"
-
+ +

Go to the source code of this file.

+
+ + - -

Data Structures

struct  fuse_config
 
struct  fuse_operations
 
struct  fuse_context
 
struct  fuse_module
 
- - - + + + - -

Macros

#define fuse_main(argc, argv, op, user_data)   fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
 
#define FUSE_REGISTER_MODULE(name_, factory_)
#define fuse_main(argc, argv, op, private_data)   fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)
 
#define FUSE_REGISTER_MODULE(name_, factory_)   fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
 
#define fuse_main   fuse_main_compat2
 
- - - - + + + + +

Typedefs

typedef int(* fuse_fill_dir_t )(void *buf, const char *name, const struct stat *stbuf, off_t off)
 
typedef void(* fuse_processor_t )(struct fuse *, struct fuse_cmd *, void *)
 
typedef int(* fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
 
typedef struct fuse_fs *(* fuse_module_factory_t) (struct fuse_args *args, struct fuse_fs *fs[])
 
+ + + + +

+Enumerations

enum  fuse_readdir_flags { FUSE_READDIR_PLUS = (1 << 0) + }
 
enum  fuse_fill_dir_flags { FUSE_FILL_DIR_PLUS = (1 << 1) + }
 
- - + + + + + + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - - - - + + + +

Functions

struct fuse * fuse_new (struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data)
 
void fuse_lib_help (struct fuse_args *args)
 
struct fuse * fuse_new (struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data)
 
int fuse_mount (struct fuse *f, const char *mountpoint)
 
void fuse_unmount (struct fuse *f)
 
void fuse_destroy (struct fuse *f)
 
int fuse_loop (struct fuse *f)
 
void fuse_exit (struct fuse *f)
 
int fuse_loop_mt (struct fuse *f)
 
int fuse_loop_mt_31 (struct fuse *f, int clone_fd)
 
struct fuse_contextfuse_get_context (void)
 
int fuse_getgroups (int size, gid_t list[])
 
int fuse_interrupted (void)
 
int fuse_invalidate (struct fuse *f, const char *path)
 
int fuse_main_real (int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data)
 
int fuse_invalidate_path (struct fuse *f, const char *path)
 
int fuse_main_real (int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *private_data)
 
int fuse_start_cleanup_thread (struct fuse *fuse)
 
void fuse_stop_cleanup_thread (struct fuse *fuse)
 
int fuse_clean_cache (struct fuse *fuse)
 
struct fuse_fs * fuse_fs_new (const struct fuse_operations *op, size_t op_size, void *user_data)
 
void fuse_register_module (struct fuse_module *mod)
 
struct fuse * fuse_setup (int argc, char *argv[], const struct fuse_operations *op, size_t op_size, char **mountpoint, int *multithreaded, void *user_data)
 
void fuse_teardown (struct fuse *fuse, char *mountpoint)
 
struct fuse_cmd * fuse_read_cmd (struct fuse *f)
 
void fuse_process_cmd (struct fuse *f, struct fuse_cmd *cmd)
 
int fuse_loop_mt_proc (struct fuse *f, fuse_processor_t proc, void *data)
 
int fuse_exited (struct fuse *f)
 
void fuse_set_getcontext_func (struct fuse_context *(*func)(void))
 
struct fuse_fs * fuse_fs_new (const struct fuse_operations *op, size_t op_size, void *private_data)
 
struct fuse_session * fuse_get_session (struct fuse *f)
 
int fuse_open_channel (const char *mountpoint, const char *options)
 

Detailed Description

This file defines the library interface of FUSE

-

IMPORTANT: you should define FUSE_USE_VERSION before including this header. To use the newest API define it to 26 (recommended for any new application), to use the old API define it to 21 (default) 22 or 25, to use the even older 1.X API define it to 11.

+

IMPORTANT: you should define FUSE_USE_VERSION before including this header.

+ +

Definition in file fuse.h.

Macro Definition Documentation

- + +

◆ fuse_main

+
@@ -168,75 +168,49 @@ Functions - + - +
 user_data private_data 
)   fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)   fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)

Main function of FUSE.

This is for the lazy. This is all that has to be called from the main() function.

This function does the following:

    -
  • parses command line options (-d -s and -h)
  • -
  • passes relevant mount options to the fuse_mount()
  • +
  • parses command line options, and handles –help and –version
  • installs signal handlers for INT, HUP, TERM and PIPE
  • registers an exit handler to unmount the filesystem on program exit
  • creates a fuse handle
  • registers the operations
  • calls either the single-threaded or the multi-threaded event loop
+

Most file systems will have to parse some file-system specific arguments before calling this function. It is recommended to do this with fuse_opt_parse() and a processing function that passes through any unknown options (this can also be achieved by just passing NULL as the processing function). That way, the remaining options can be passed directly to fuse_main().

+

fuse_main() accepts all options that can be passed to fuse_parse_cmdline(), fuse_new(), or fuse_session_new().

+

Option parsing skips argv[0], which is assumed to contain the program name. This element must always be present and is used to construct a basic usage: message for the –help output. argv[0] may also be set to the empty string. In this case the usage message is suppressed. This can be used by file systems to print their own usage line first. See hello.c for an example of how to do this.

Note: this is currently implemented as a macro.

+

The following error codes may be returned from fuse_main(): 1: Invalid option arguments 2: No mount point specified 3: FUSE setup failed 4: Mounting failed 5: Failed to daemonize (detach from session) 6: Failed to set up signal handlers 7: An error occured during the life of the file system

Parameters
- +
argcthe argument counter passed to the main() function
argvthe argument vector passed to the main() function
opthe file system operation
user_datauser data supplied in the context during the init() method
private_dataInitial value for the private_data field of struct fuse_context. May be overridden by the struct fuse_operations.init handler.
-
Returns
0 on success, nonzero on failure
+
Returns
0 on success, nonzero on failure
+

Example usage, see hello.c

-
-
- -
-
- - - - -
#define fuse_main   fuse_main_compat2
-
-

Main function of FUSE.

-

This is for the lazy. This is all that has to be called from the main() function.

-

This function does the following:

    -
  • parses command line options (-d -s and -h)
  • -
  • passes relevant mount options to the fuse_mount()
  • -
  • installs signal handlers for INT, HUP, TERM and PIPE
  • -
  • registers an exit handler to unmount the filesystem on program exit
  • -
  • creates a fuse handle
  • -
  • registers the operations
  • -
  • calls either the single-threaded or the multi-threaded event loop
  • -
-

Note: this is currently implemented as a macro.

-
Parameters
- - - - - -
argcthe argument counter passed to the main() function
argvthe argument vector passed to the main() function
opthe file system operation
user_datauser data supplied in the context during the init() method
-
-
-
Returns
0 on success, nonzero on failure
+

Definition at line 855 of file fuse.h.

- + +

◆ FUSE_REGISTER_MODULE

+
@@ -255,60 +229,130 @@ Functions - +
)   fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
-Value:
static __attribute__((constructor)) void name_ ## _register(void) \
-
{ \
-
static struct fuse_module mod = \
-
{ #name_, factory_, NULL, NULL, 0 }; \
-
fuse_register_module(&mod); \
-
}
-

Register filesystem module

-

For the parameters, see description of the fields in 'struct fuse_module'

+

Register filesystem module

+

If the "-omodules=*name*_:..." option is present, filesystem objects are created and pushed onto the stack with the factory_ function.

+
Parameters
+ + + +
name_the name of this filesystem module
factory_the factory function for this filesystem module
+
+
+ +

Definition at line 1238 of file fuse.h.

Typedef Documentation

- + +

◆ fuse_fill_dir_t

+
- +
typedef int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off)typedef int(* fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)

Function to add an entry in a readdir() operation

+

The off parameter can be any non-zero value that enableds the filesystem to identify the current point in the directory stream. It does not need to be the actual physical position. A value of zero is reserved to indicate that seeking in directories is not supported.

Parameters
+
bufthe buffer passed to the readdir() operation
namethe file name of the directory entry
statfile attributes, can be NULL
offoffset of the next entry or zero
flagsfill flags
Returns
1 if buffer is full, zero otherwise
+

Definition at line 82 of file fuse.h.

+ +
+
+ +

◆ fuse_module_factory_t

+ +
+
+ + + + +
typedef struct fuse_fs*(* fuse_module_factory_t) (struct fuse_args *args, struct fuse_fs *fs[])
+
+

Factory for creating filesystem objects

+

The function may use and remove options from 'args' that belong to this module.

+

For now the 'fs' vector always contains exactly one filesystem. This is the filesystem which will be below the newly created filesystem in the stack.

+
Parameters
+ + + +
argsthe command line arguments
fsNULL terminated filesystem object vector
+
+
+
Returns
the new filesystem object
+ +

Definition at line 1226 of file fuse.h.

+
- +

Enumeration Type Documentation

+ +

◆ fuse_fill_dir_flags

+
- +
typedef void(* fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *)enum fuse_fill_dir_flags
-

Function type used to process commands

+ + +
Enumerator
FUSE_FILL_DIR_PLUS 

"Plus" mode: all file attributes are valid

+

The attributes are used by the kernel to prefill the inode cache during a readdir.

+

It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set and vice versa.

+
+ +

Definition at line 54 of file fuse.h.

+ +
+
+ +

◆ fuse_readdir_flags

+ +
+
+ + + + +
enum fuse_readdir_flags
+
+

Readdir flags, passed to ->readdir()

+ + +
Enumerator
FUSE_READDIR_PLUS 

"Plus" mode.

+

The kernel wants to prefill the inode cache during readdir. The filesystem may honour this by filling in the attributes and setting FUSE_FILL_DIR_FLAGS for the filler function. The filesystem may also just ignore this flag completely.

+
+ +

Definition at line 42 of file fuse.h.

Function Documentation

- + +

◆ fuse_clean_cache()

+
@@ -331,9 +375,13 @@ Functions
Returns
the number of seconds until the next cleanup
+

Definition at line 4373 of file fuse.c.

+ - + +

◆ fuse_destroy()

+
@@ -347,8 +395,7 @@ Functions

Destroy the FUSE handle.

-

The communication channel attached to the handle is also destroyed.

-

NOTE: This function does not unmount the filesystem. If this is needed, call fuse_unmount() before calling this function.

+

NOTE: This function does not unmount the filesystem. If this is needed, call fuse_unmount() before calling this function.

Parameters
@@ -356,9 +403,13 @@ Functions +

Definition at line 5007 of file fuse.c.

+ - + +

◆ fuse_exit()

+
fthe FUSE handle
@@ -371,7 +422,8 @@ Functions
-

Exit from event loop

+

Flag session as terminated

+

This function will cause any running event loops to exit on the next opportunity.

Parameters
@@ -379,26 +431,13 @@ Functions - - - -
-
-
fthe FUSE handle
- - - - - - - -
int fuse_exited (struct fuse * f)
-
-

Return the exited flag, which indicates if fuse_exit() has been called

+

Definition at line 4552 of file fuse.c.

- + +

◆ fuse_fs_new()

+
@@ -418,7 +457,7 @@ Functions - + @@ -433,15 +472,19 @@ Functions
void * user_data private_data 
- +
opthe filesystem operations
op_sizethe size of the fuse_operations structure
user_datauser data supplied in the context during the init() method
private_dataInitial value for the private_data field of struct fuse_context. May be overridden by the struct fuse_operations.init handler.
Returns
a new filesystem object
+

Definition at line 4760 of file fuse.c.

+
- + +

◆ fuse_get_context()

+
@@ -458,9 +501,13 @@ Functions

The context is only valid for the duration of a filesystem operation, and thus must not be stored and used later.

Returns
the context
+

Definition at line 4557 of file fuse.c.

+ - + +

◆ fuse_get_session()

+
@@ -475,9 +522,13 @@ Functions

Get session from fuse object

+

Definition at line 4459 of file fuse.c.

+
- + +

◆ fuse_getgroups()

+
@@ -513,9 +564,13 @@ Functions
Returns
the total number of supplementary group IDs or -errno on failure
+

Definition at line 4567 of file fuse.c.

+ - + +

◆ fuse_interrupted()

+
@@ -531,14 +586,18 @@ Functions

Check if the current request has already been interrupted

Returns
1 if the request has been interrupted, 0 otherwise
+

Definition at line 4576 of file fuse.c.

+ - + +

◆ fuse_invalidate_path()

+
- + @@ -556,42 +615,50 @@ Functions
int fuse_invalidate int fuse_invalidate_path ( struct fuse *  f,
-

Obsolete, doesn't do anything

-
Returns
-EINVAL
+

Invalidates cache for the given path.

+

This calls fuse_lowlevel_notify_inval_inode internally.

+
Returns
0 on successful invalidation, negative error value otherwise. This routine may return -ENOENT to indicate that there was no entry to be invalidated, e.g., because the path has not been seen before or has been forgotten; this should not be considered to be an error.
+ +

Definition at line 4586 of file fuse.c.

- + +

◆ fuse_lib_help()

+
- + - - + +
int fuse_loop void fuse_lib_help (struct fuse * f)struct fuse_argsargs)
-

FUSE event loop.

-

Requests from the kernel are processed, and the appropriate operations are called.

+

Print available options (high- and low-level) to stdout. This is not an exhaustive list, but includes only those options that may be of interest to an end-user of a file system.

+

The function looks at the argument vector only to determine if there are additional modules to be loaded (module=foo option), and attempts to call their help functions as well.

Parameters
- +
fthe FUSE handle
argsthe argument vector.
-
Returns
0 if no error occurred, -1 otherwise
+ +

Definition at line 4650 of file fuse.c.

- + +

◆ fuse_loop()

+
- + @@ -599,25 +666,30 @@ Functions
int fuse_loop_mt int fuse_loop ( struct fuse *  f)
-

FUSE event loop with multiple threads

-

Requests from the kernel are processed, and the appropriate operations are called. Request are processed in parallel by distributing them between multiple threads.

-

Calling this function requires the pthreads library to be linked to the application.

+

FUSE event loop.

+

Requests from the kernel are processed, and the appropriate operations are called.

+

For a description of the return value and the conditions when the event loop exits, refer to the documentation of fuse_session_loop().

Parameters
fthe FUSE handle
-
Returns
0 if no error occurred, -1 otherwise
+
Returns
see fuse_session_loop()
+

See also: fuse_loop_mt()

+ +

Definition at line 4516 of file fuse.c.

- + +

◆ fuse_loop_mt_31()

+
- + @@ -625,14 +697,8 @@ Functions - - - - - - - - + + @@ -641,11 +707,29 @@ Functions
int fuse_loop_mt_proc int fuse_loop_mt_31 ( struct fuse *  f,
fuse_processor_t proc,
void * data int clone_fd 
-

Multi threaded event loop, which calls the custom command processor function

+

FUSE event loop with multiple threads

+

Requests from the kernel are processed, and the appropriate operations are called. Request are processed in parallel by distributing them between multiple threads.

+

For a description of the return value and the conditions when the event loop exits, refer to the documentation of fuse_session_loop().

+

Note: using fuse_loop() instead of fuse_loop_mt() means you are running in single-threaded mode, and that you will not have to worry about reentrancy, though you will have to worry about recursive lookups. In single-threaded mode, FUSE will wait for one callback to return before calling another.

+

Enabling multiple threads, by using fuse_loop_mt(), will cause FUSE to make multiple simultaneous calls into the various callback functions given by your fuse_operations record.

+

If you are using multiple threads, you can enjoy all the parallel execution and interactive response benefits of threads, and you get to enjoy all the benefits of race conditions and locking bugs, too. Ensure that any code used in the callback function of fuse_operations is also thread-safe.

+
Parameters
+ + + +
fthe FUSE handle
configloop configuration
+
+
+
Returns
see fuse_session_loop()
+

See also: fuse_loop()

+ +

Definition at line 4544 of file fuse.c.

- + +

◆ fuse_main_real()

+
@@ -677,7 +761,7 @@ Functions - + @@ -687,43 +771,29 @@ Functions
void * user_data private_data 

The real main function

-

Do not call this directly, use fuse_main()

+

Do not call this directly, use fuse_main()

+ +

Definition at line 279 of file helper.c.

- + +

◆ fuse_mount()

+
- + - - - - - - - - - - - - - - - - - - - - + + - - + + @@ -732,145 +802,92 @@ Functions
struct fuse* fuse_new int fuse_mount (struct fuse_chan * ch,
struct fuse_argsargs,
const struct fuse_operationsop,
size_t op_size, struct fuse * f,
void * user_data const char * mountpoint 
-

Create a new FUSE filesystem.

+

Mount a FUSE file system.

Parameters
- - - - - + +
chthe communication channel
argsargument vector
opthe filesystem operations
op_sizethe size of the fuse_operations structure
user_datauser data supplied in the context during the init() method
mountpointthe mount point path
fthe FUSE handle
-
Returns
the created FUSE handle
+
Returns
0 on success, -1 on failure.
+ +

Definition at line 5057 of file fuse.c.

- + +

◆ fuse_new()

+
- + - - + + - - + + + - - + + -
void fuse_process_cmd struct fuse* fuse_new (struct fuse * f, struct fuse_argsargs,
struct fuse_cmd * cmd const struct fuse_operationsop,
)size_t op_size,
-
-

Process a single command

- -
-
- -
-
- - - - - + + + -
struct fuse_cmd* fuse_read_cmd (struct fuse * f) void * private_data 
-
-

Read a single command. If none are read, return NULL

- -
-
- -
-
- - - - - + +
void fuse_register_module (struct fuse_modulemod) )
-

Register a filesystem module

-

This function is used by FUSE_REGISTER_MODULE and there's usually no need to call it directly

+

Create a new FUSE filesystem.

+

This function accepts most file-system independent mount options (like context, nodev, ro - see mount(8)), as well as the FUSE-specific mount options from mount.fuse(8).

+

If the –help option is specified, the function writes a help text to stdout and returns NULL.

+

Option parsing skips argv[0], which is assumed to contain the program name. This element must always be present and is used to construct a basic usage: message for the –help output. If argv[0] is set to the empty string, no usage message is included in the –help output.

+

If an unknown option is passed in, an error message is written to stderr and the function returns NULL.

+
Parameters
+ + + + + +
argsargument vector
opthe filesystem operations
op_sizethe size of the fuse_operations structure
private_dataInitial value for the private_data field of struct fuse_context. May be overridden by the struct fuse_operations.init handler.
+
+
+
Returns
the created FUSE handle
- -
-
- - - - - - - - -
void fuse_set_getcontext_func (struct fuse_context *(*)(void) func)
-
-

This function is obsolete and implemented as a no-op

+ +

◆ fuse_open_channel()

-
-
-
- + - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + + @@ -879,11 +896,23 @@ Functions
struct fuse* fuse_setup int fuse_open_channel (int argc,
char * argv[],
const struct fuse_operationsop,
size_t op_size,
char ** const char *  mountpoint,
int * multithreaded,
void * user_data const char * options 
-

This is the part of fuse_main() before the event loop

+

Open a FUSE file descriptor and set up the mount for the given mountpoint and flags.

+
Parameters
+ + + +
mountpointreference to the mount in the file system
optionsmount options
+
+
+
Returns
the FUSE file descriptor or -1 upon error
+ +

Definition at line 424 of file helper.c.

- + +

◆ fuse_start_cleanup_thread()

+
@@ -897,7 +926,7 @@ Functions

Start the cleanup thread when using option "remember".

-

This is done automatically by fuse_loop_mt()

Parameters
+

This is done automatically by fuse_loop_mt()

Parameters
fusestruct fuse pointer for fuse instance
@@ -905,9 +934,13 @@ Functions
Returns
0 on success and -1 on error
+

Definition at line 4808 of file fuse.c.

+
- + +

◆ fuse_stop_cleanup_thread()

+
@@ -921,48 +954,51 @@ Functions

Stop the cleanup thread when using option "remember".

-

This is done automatically by fuse_loop_mt()

Parameters
+

This is done automatically by fuse_loop_mt()

Parameters
fusestruct fuse pointer for fuse instance
+

Definition at line 4816 of file fuse.c.

+
- + +

◆ fuse_unmount()

+
- + - - - - - - - - - + - -
void fuse_teardown void fuse_unmount ( struct fuse * fuse,
char * mountpoint 
f) )
-

This is the part of fuse_main() after the event loop

+

Unmount a FUSE file system.

+

See fuse_session_unmount() for additional information.

+
Parameters
+ + +
fthe FUSE handle
+
+
+ +

Definition at line 5062 of file fuse.c.

diff --git a/doc/html/fuse_8h_source.html b/doc/html/fuse_8h_source.html new file mode 100644 index 0000000..ede7cdb --- /dev/null +++ b/doc/html/fuse_8h_source.html @@ -0,0 +1,116 @@ + + + + + + + +libfuse: include/fuse.h Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse.h
+
+
+Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU LGPLv2.
6  See the file COPYING.LIB.
7 */
8 
9 #ifndef FUSE_H_
10 #define FUSE_H_
11 
19 #include "fuse_common.h"
20 
21 #include <fcntl.h>
22 #include <time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/statvfs.h>
26 #include <sys/uio.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 /* ----------------------------------------------------------- *
33  * Basic FUSE API *
34  * ----------------------------------------------------------- */
35 
37 struct fuse;
38 
51  FUSE_READDIR_PLUS = (1 << 0),
52 };
53 
64  FUSE_FILL_DIR_PLUS = (1 << 1),
65 };
66 
82 typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
83  const struct stat *stbuf, off_t off,
84  enum fuse_fill_dir_flags flags);
93 struct fuse_config {
98  int set_gid;
99  unsigned int gid;
100 
105  int set_uid;
106  unsigned int uid;
107 
112  int set_mode;
113  unsigned int umask;
114 
120 
130 
135  double attr_timeout;
136 
140  int intr;
141 
148 
159  int remember;
160 
178 
190  int use_ino;
191 
200 
219 
238 
246 
253  double ac_attr_timeout;
254 
266 
272  char *modules;
273  int debug;
274 };
275 
276 
311  int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi);
312 
321  int (*readlink) (const char *, char *, size_t);
322 
329  int (*mknod) (const char *, mode_t, dev_t);
330 
337  int (*mkdir) (const char *, mode_t);
338 
340  int (*unlink) (const char *);
341 
343  int (*rmdir) (const char *);
344 
346  int (*symlink) (const char *, const char *);
347 
357  int (*rename) (const char *, const char *, unsigned int flags);
358 
360  int (*link) (const char *, const char *);
361 
367  int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
368 
377  int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi);
378 
387  int (*truncate) (const char *, off_t, struct fuse_file_info *fi);
388 
437  int (*open) (const char *, struct fuse_file_info *);
438 
448  int (*read) (const char *, char *, size_t, off_t,
449  struct fuse_file_info *);
450 
460  int (*write) (const char *, const char *, size_t, off_t,
461  struct fuse_file_info *);
462 
467  int (*statfs) (const char *, struct statvfs *);
468 
490  int (*flush) (const char *, struct fuse_file_info *);
491 
504  int (*release) (const char *, struct fuse_file_info *);
505 
511  int (*fsync) (const char *, int, struct fuse_file_info *);
512 
514  int (*setxattr) (const char *, const char *, const char *, size_t, int);
515 
517  int (*getxattr) (const char *, const char *, char *, size_t);
518 
520  int (*listxattr) (const char *, char *, size_t);
521 
523  int (*removexattr) (const char *, const char *);
524 
533  int (*opendir) (const char *, struct fuse_file_info *);
534 
550  int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
551  struct fuse_file_info *, enum fuse_readdir_flags);
552 
555  int (*releasedir) (const char *, struct fuse_file_info *);
556 
562  int (*fsyncdir) (const char *, int, struct fuse_file_info *);
563 
572  void *(*init) (struct fuse_conn_info *conn,
573  struct fuse_config *cfg);
574 
580  void (*destroy) (void *private_data);
581 
591  int (*access) (const char *, int);
592 
603  int (*create) (const char *, mode_t, struct fuse_file_info *);
604 
635  int (*lock) (const char *, struct fuse_file_info *, int cmd,
636  struct flock *);
637 
650  int (*utimens) (const char *, const struct timespec tv[2],
651  struct fuse_file_info *fi);
652 
659  int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
660 
674  int (*ioctl) (const char *, int cmd, void *arg,
675  struct fuse_file_info *, unsigned int flags, void *data);
676 
692  int (*poll) (const char *, struct fuse_file_info *,
693  struct fuse_pollhandle *ph, unsigned *reventsp);
694 
704  int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
705  struct fuse_file_info *);
706 
721  int (*read_buf) (const char *, struct fuse_bufvec **bufp,
722  size_t size, off_t off, struct fuse_file_info *);
741  int (*flock) (const char *, struct fuse_file_info *, int op);
742 
751  int (*fallocate) (const char *, int, off_t, off_t,
752  struct fuse_file_info *);
753 
765  ssize_t (*copy_file_range) (const char *path_in,
766  struct fuse_file_info *fi_in,
767  off_t offset_in, const char *path_out,
768  struct fuse_file_info *fi_out,
769  off_t offset_out, size_t size, int flags);
770 };
771 
777 struct fuse_context {
779  struct fuse *fuse;
780 
782  uid_t uid;
783 
785  gid_t gid;
786 
788  pid_t pid;
789 
792 
794  mode_t umask;
795 };
796 
851 /*
852  int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
853  void *private_data);
854 */
855 #define fuse_main(argc, argv, op, private_data) \
856  fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)
857 
858 /* ----------------------------------------------------------- *
859  * More detailed API *
860  * ----------------------------------------------------------- */
861 
873 void fuse_lib_help(struct fuse_args *args);
874 
902 #if FUSE_USE_VERSION == 30
903 struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op,
904  size_t op_size, void *private_data);
905 #define fuse_new(args, op, size, data) fuse_new_30(args, op, size, data)
906 #else
907 struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op,
908  size_t op_size, void *private_data);
909 #endif
910 
919 int fuse_mount(struct fuse *f, const char *mountpoint);
920 
928 void fuse_unmount(struct fuse *f);
929 
938 void fuse_destroy(struct fuse *f);
939 
955 int fuse_loop(struct fuse *f);
956 
965 void fuse_exit(struct fuse *f);
966 
998 #if FUSE_USE_VERSION < 32
999 int fuse_loop_mt_31(struct fuse *f, int clone_fd);
1000 #define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd)
1001 #else
1002 int fuse_loop_mt(struct fuse *f, struct fuse_loop_config *config);
1003 #endif
1004 
1013 struct fuse_context *fuse_get_context(void);
1014 
1033 int fuse_getgroups(int size, gid_t list[]);
1034 
1040 int fuse_interrupted(void);
1041 
1053 int fuse_invalidate_path(struct fuse *f, const char *path);
1054 
1060 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
1061  size_t op_size, void *private_data);
1062 
1070 int fuse_start_cleanup_thread(struct fuse *fuse);
1071 
1078 void fuse_stop_cleanup_thread(struct fuse *fuse);
1079 
1089 int fuse_clean_cache(struct fuse *fuse);
1090 
1091 /*
1092  * Stacking API
1093  */
1094 
1100 struct fuse_fs;
1101 
1102 /*
1103  * These functions call the relevant filesystem operation, and return
1104  * the result.
1105  *
1106  * If the operation is not defined, they return -ENOSYS, with the
1107  * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir,
1108  * fuse_fs_releasedir and fuse_fs_statfs, which return 0.
1109  */
1110 
1111 int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf,
1112  struct fuse_file_info *fi);
1113 int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
1114  const char *newpath, unsigned int flags);
1115 int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
1116 int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
1117 int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
1118  const char *path);
1119 int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
1120 int fuse_fs_release(struct fuse_fs *fs, const char *path,
1121  struct fuse_file_info *fi);
1122 int fuse_fs_open(struct fuse_fs *fs, const char *path,
1123  struct fuse_file_info *fi);
1124 int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
1125  off_t off, struct fuse_file_info *fi);
1126 int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
1127  struct fuse_bufvec **bufp, size_t size, off_t off,
1128  struct fuse_file_info *fi);
1129 int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
1130  size_t size, off_t off, struct fuse_file_info *fi);
1131 int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
1132  struct fuse_bufvec *buf, off_t off,
1133  struct fuse_file_info *fi);
1134 int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
1135  struct fuse_file_info *fi);
1136 int fuse_fs_flush(struct fuse_fs *fs, const char *path,
1137  struct fuse_file_info *fi);
1138 int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
1139 int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
1140  struct fuse_file_info *fi);
1141 int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
1142  fuse_fill_dir_t filler, off_t off,
1143  struct fuse_file_info *fi, enum fuse_readdir_flags flags);
1144 int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
1145  struct fuse_file_info *fi);
1146 int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
1147  struct fuse_file_info *fi);
1148 int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
1149  struct fuse_file_info *fi);
1150 int fuse_fs_lock(struct fuse_fs *fs, const char *path,
1151  struct fuse_file_info *fi, int cmd, struct flock *lock);
1152 int fuse_fs_flock(struct fuse_fs *fs, const char *path,
1153  struct fuse_file_info *fi, int op);
1154 int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode,
1155  struct fuse_file_info *fi);
1156 int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid,
1157  struct fuse_file_info *fi);
1158 int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size,
1159  struct fuse_file_info *fi);
1160 int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
1161  const struct timespec tv[2], struct fuse_file_info *fi);
1162 int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
1163 int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
1164  size_t len);
1165 int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
1166  dev_t rdev);
1167 int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
1168 int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
1169  const char *value, size_t size, int flags);
1170 int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
1171  char *value, size_t size);
1172 int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
1173  size_t size);
1174 int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
1175  const char *name);
1176 int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
1177  uint64_t *idx);
1178 int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
1179  struct fuse_file_info *fi, unsigned int flags, void *data);
1180 int fuse_fs_poll(struct fuse_fs *fs, const char *path,
1181  struct fuse_file_info *fi, struct fuse_pollhandle *ph,
1182  unsigned *reventsp);
1183 int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
1184  off_t offset, off_t length, struct fuse_file_info *fi);
1185 ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
1186  struct fuse_file_info *fi_in, off_t off_in,
1187  const char *path_out,
1188  struct fuse_file_info *fi_out, off_t off_out,
1189  size_t len, int flags);
1190 void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
1191  struct fuse_config *cfg);
1192 void fuse_fs_destroy(struct fuse_fs *fs);
1193 
1194 int fuse_notify_poll(struct fuse_pollhandle *ph);
1195 
1209 struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
1210  void *private_data);
1211 
1226 typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args,
1227  struct fuse_fs *fs[]);
1238 #define FUSE_REGISTER_MODULE(name_, factory_) \
1239  fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
1240 
1242 struct fuse_session *fuse_get_session(struct fuse *f);
1243 
1252 int fuse_open_channel(const char *mountpoint, const char *options);
1253 
1254 #ifdef __cplusplus
1255 }
1256 #endif
1257 
1258 #endif /* FUSE_H_ */
size_t off
Definition: fuse_common.h:679
+ + +
int auto_cache
Definition: fuse.h:245
+
void fuse_stop_cleanup_thread(struct fuse *fuse)
Definition: fuse.c:4816
+
int set_gid
Definition: fuse.h:98
+
int fuse_loop(struct fuse *f)
Definition: fuse.c:4516
+
struct fuse * fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data)
+
fuse_fill_dir_flags
Definition: fuse.h:54
+
int readdir_ino
Definition: fuse.h:199
+
int intr
Definition: fuse.h:140
+
int set_mode
Definition: fuse.h:112
+
fuse_readdir_flags
Definition: fuse.h:42
+ +
int nullpath_ok
Definition: fuse.h:265
+
double negative_timeout
Definition: fuse.h:129
+
pid_t pid
Definition: fuse.h:788
+ +
int fuse_clean_cache(struct fuse *fuse)
Definition: fuse.c:4373
+
void fuse_destroy(struct fuse *f)
Definition: fuse.c:5007
+
int set_uid
Definition: fuse.h:105
+
int remember
Definition: fuse.h:159
+
int use_ino
Definition: fuse.h:190
+ + + + +
int fuse_open_channel(const char *mountpoint, const char *options)
Definition: helper.c:424
+
gid_t gid
Definition: fuse.h:785
+
struct fuse_session * fuse_get_session(struct fuse *f)
Definition: fuse.c:4459
+
mode_t umask
Definition: fuse.h:794
+
void * private_data
Definition: fuse.h:791
+
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *private_data)
Definition: helper.c:279
+
int fuse_invalidate_path(struct fuse *f, const char *path)
Definition: fuse.c:4586
+ +
double attr_timeout
Definition: fuse.h:135
+
struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
Definition: fuse.c:4760
+
int direct_io
Definition: fuse.h:218
+
int fuse_start_cleanup_thread(struct fuse *fuse)
Definition: fuse.c:4808
+
void fuse_lib_help(struct fuse_args *args)
Definition: fuse.c:4650
+
int fuse_interrupted(void)
Definition: fuse.c:4576
+
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:82
+
int show_help
Definition: fuse.h:271
+
int fuse_getgroups(int size, gid_t list[])
Definition: fuse.c:4567
+ +
int fuse_mount(struct fuse *f, const char *mountpoint)
Definition: fuse.c:5057
+
uid_t uid
Definition: fuse.h:782
+
struct fuse * fuse
Definition: fuse.h:779
+
struct fuse_buf buf[1]
Definition: fuse_common.h:684
+ +
int ac_attr_timeout_set
Definition: fuse.h:252
+
void fuse_unmount(struct fuse *f)
Definition: fuse.c:5062
+ +
int fuse_loop_mt_31(struct fuse *f, int clone_fd)
Definition: fuse.c:4544
+
struct fuse_context * fuse_get_context(void)
Definition: fuse.c:4557
+
double entry_timeout
Definition: fuse.h:119
+
int kernel_cache
Definition: fuse.h:237
+
int intr_signal
Definition: fuse.h:147
+
int hard_remove
Definition: fuse.h:177
+
void fuse_exit(struct fuse *f)
Definition: fuse.c:4552
+
+ + + + diff --git a/doc/html/fuse__common_8h.html b/doc/html/fuse__common_8h.html index b9c8231..94f1f4c 100644 --- a/doc/html/fuse__common_8h.html +++ b/doc/html/fuse__common_8h.html @@ -3,8 +3,9 @@ - -fuse: include/fuse_common.h File Reference + + +libfuse: include/fuse_common.h File Reference @@ -16,8 +17,8 @@ - @@ -25,20 +26,15 @@
-
fuse +
+
libfuse
- - - + + + + +
-
#include "fuse_opt.h"
+
#include "fuse_opt.h"
#include <stdint.h>
#include <sys/types.h>
-#include "fuse_common_compat.h"
-
+ +

Go to the source code of this file.

+
+ + @@ -72,12 +71,48 @@ Data Structures

Data Structures

struct  fuse_file_info
 
struct  fuse_loop_config
 
struct  fuse_conn_info
 
struct  fuse_buf
- + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Macros

#define FUSE_MAJOR_VERSION   2
#define FUSE_MAJOR_VERSION   3
 
#define FUSE_MINOR_VERSION   9
#define FUSE_MINOR_VERSION   2
 
#define FUSE_CAP_ASYNC_READ   (1 << 0)
 
#define FUSE_CAP_POSIX_LOCKS   (1 << 1)
 
#define FUSE_CAP_ATOMIC_O_TRUNC   (1 << 3)
 
#define FUSE_CAP_EXPORT_SUPPORT   (1 << 4)
 
#define FUSE_CAP_DONT_MASK   (1 << 6)
 
#define FUSE_CAP_SPLICE_WRITE   (1 << 7)
 
#define FUSE_CAP_SPLICE_MOVE   (1 << 8)
 
#define FUSE_CAP_SPLICE_READ   (1 << 9)
 
#define FUSE_CAP_FLOCK_LOCKS   (1 << 10)
 
#define FUSE_CAP_IOCTL_DIR   (1 << 11)
 
#define FUSE_CAP_AUTO_INVAL_DATA   (1 << 12)
 
#define FUSE_CAP_READDIRPLUS   (1 << 13)
 
#define FUSE_CAP_READDIRPLUS_AUTO   (1 << 14)
 
#define FUSE_CAP_ASYNC_DIO   (1 << 15)
 
#define FUSE_CAP_WRITEBACK_CACHE   (1 << 16)
 
#define FUSE_CAP_NO_OPEN_SUPPORT   (1 << 17)
 
#define FUSE_CAP_PARALLEL_DIROPS   (1 << 18)
 
#define FUSE_CAP_POSIX_ACL   (1 << 19)
 
#define FUSE_CAP_HANDLE_KILLPRIV   (1 << 20)
 
#define FUSE_IOCTL_COMPAT   (1 << 0)
 
@@ -97,16 +132,16 @@ Enumerations
- - - - - - + + + + + + @@ -119,7 +154,28 @@ Functions

Functions

struct fuse_chan * fuse_mount (const char *mountpoint, struct fuse_args *args)
 
void fuse_unmount (const char *mountpoint, struct fuse_chan *ch)
 
int fuse_parse_cmdline (struct fuse_args *args, char **mountpoint, int *multithreaded, int *foreground)
 
struct fuse_conn_info_opts * fuse_parse_conn_info_opts (struct fuse_args *args)
 
void fuse_apply_conn_info_opts (struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn)
 
int fuse_daemonize (int foreground)
 
int fuse_version (void)
 
const char * fuse_pkgversion (void)
 
void fuse_pollhandle_destroy (struct fuse_pollhandle *ph)
 
size_t fuse_buf_size (const struct fuse_bufvec *bufv)
 

Macro Definition Documentation

- + +

◆ FUSE_CAP_ASYNC_DIO

+ +
+
+ + + + +
#define FUSE_CAP_ASYNC_DIO   (1 << 15)
+
+

Indicates that the filesystem supports asynchronous direct I/O submission.

+

If this capability is not requested/available, the kernel will ensure that there is at most one pending read and one pending write request per direct I/O file-handle at any time.

+

This feature is enabled by default when supported by the kernel.

+ +

Definition at line 257 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_ASYNC_READ

+
@@ -128,12 +184,331 @@ Functions
-

Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'

-

FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice() FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device FUSE_CAP_IOCTL_DIR: ioctl support on directories

+

Indicates that the filesystem supports asynchronous read requests.

+

If this capability is not requested/available, the kernel will ensure that there is at most one pending read request per file-handle at any time, and will attempt to order read requests by increasing offset.

+

This feature is enabled by default when supported by the kernel.

+ +

Definition at line 120 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_ATOMIC_O_TRUNC

+ +
+
+ + + + +
#define FUSE_CAP_ATOMIC_O_TRUNC   (1 << 3)
+
+

Indicates that the filesystem supports the O_TRUNC open flag. If disabled, and an application specifies O_TRUNC, fuse first calls truncate() and then open() with O_TRUNC filtered out.

+

This feature is enabled by default when supported by the kernel.

+ +

Definition at line 137 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_AUTO_INVAL_DATA

+ +
+
+ + + + +
#define FUSE_CAP_AUTO_INVAL_DATA   (1 << 12)
+
+

Traditionally, while a file is open the FUSE kernel module only asks the filesystem for an update of the file's attributes when a client attempts to read beyond EOF. This is unsuitable for e.g. network filesystems, where the file contents may change without the kernel knowing about it.

+

If this flag is set, FUSE will check the validity of the attributes on every read. If the attributes are no longer valid (i.e., if the attr_timeout passed to fuse_reply_attr() or set in struct fuse_entry_param has passed), it will first issue a getattr request. If the new mtime differs from the previous value, any cached file contents will be invalidated as well.

+

This flag should always be set when available. If all file changes go through the kernel, attr_timeout should be set to a very large number to avoid unnecessary getattr() calls.

+

This feature is enabled by default when supported by the kernel.

+ +

Definition at line 219 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_DONT_MASK

+ +
+
+ + + + +
#define FUSE_CAP_DONT_MASK   (1 << 6)
+
+

Indicates that the kernel should not apply the umask to the file mode on create operations.

+

This feature is disabled by default.

+ +

Definition at line 152 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_EXPORT_SUPPORT

+ +
+
+ + + + +
#define FUSE_CAP_EXPORT_SUPPORT   (1 << 4)
+
+

Indicates that the filesystem supports lookups of "." and "..".

+

This feature is disabled by default.

+ +

Definition at line 144 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_FLOCK_LOCKS

+ +
+
+ + + + +
#define FUSE_CAP_FLOCK_LOCKS   (1 << 10)
+
+

If set, the calls to flock(2) will be emulated using POSIX locks and must then be handled by the filesystem's setlock() handler.

+

If not set, flock(2) calls will be handled by the FUSE kernel module internally (so any access that does not go through the kernel cannot be taken into account).

+

This feature is enabled by default when supported by the kernel and if the filesystem implements a flock() handler.

+ +

Definition at line 190 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_HANDLE_KILLPRIV

+ +
+
+ + + + +
#define FUSE_CAP_HANDLE_KILLPRIV   (1 << 20)
+
+

Indicates that the filesystem is responsible for unsetting setuid and setgid bits when a file is written, truncated, or its owner is changed.

+

This feature is enabled by default when supported by the kernel.

+ +

Definition at line 317 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_IOCTL_DIR

+ +
+
+ + + + +
#define FUSE_CAP_IOCTL_DIR   (1 << 11)
+
+

Indicates that the filesystem supports ioctl's on directories.

+

This feature is enabled by default when supported by the kernel.

+ +

Definition at line 197 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_NO_OPEN_SUPPORT

+ +
+
+ + + + +
#define FUSE_CAP_NO_OPEN_SUPPORT   (1 << 17)
+
+

Indicates support for zero-message opens. If this flag is set in the capable field of the fuse_conn_info structure, then the filesystem may return ENOSYS from the open() handler to indicate success. Further attempts to open files will be handled in the kernel. (If this flag is not set, returning ENOSYS will be treated as an error and signaled to the caller).

+

Setting (or unsetting) this flag in the want field has no effect.

+ +

Definition at line 279 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_PARALLEL_DIROPS

+ +
+
+ + + + +
#define FUSE_CAP_PARALLEL_DIROPS   (1 << 18)
+
+

Indicates support for parallel directory operations. If this flag is unset, the FUSE kernel module will ensure that lookup() and readdir() requests are never issued concurrently for the same directory.

+

This feature is enabled by default when supported by the kernel.

+ +

Definition at line 289 of file fuse_common.h.

- + +

◆ FUSE_CAP_POSIX_ACL

+ +
+
+ + + + +
#define FUSE_CAP_POSIX_ACL   (1 << 19)
+
+

Indicates support for POSIX ACLs.

+

If this feature is enabled, the kernel will cache and have responsibility for enforcing ACLs. ACL will be stored as xattrs and passed to userspace, which is responsible for updating the ACLs in the filesystem, keeping the file mode in sync with the ACL, and ensuring inheritance of default ACLs when new filesystem nodes are created. Note that this requires that the file system is able to parse and interpret the xattr representation of ACLs.

+

Enabling this feature implicitly turns on the default_permissions mount option (even if it was not passed to mount(2)).

+

This feature is disabled by default.

+ +

Definition at line 308 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_POSIX_LOCKS

+ +
+
+ + + + +
#define FUSE_CAP_POSIX_LOCKS   (1 << 1)
+
+

Indicates that the filesystem supports "remote" locking.

+

This feature is enabled by default when supported by the kernel, and if getlk() and setlk() handlers are implemented.

+ +

Definition at line 128 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_READDIRPLUS

+ +
+
+ + + + +
#define FUSE_CAP_READDIRPLUS   (1 << 13)
+
+

Indicates that the filesystem supports readdirplus.

+

This feature is enabled by default when supported by the kernel and if the filesystem implements a readdirplus() handler.

+ +

Definition at line 227 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_READDIRPLUS_AUTO

+ +
+
+ + + + +
#define FUSE_CAP_READDIRPLUS_AUTO   (1 << 14)
+
+

Indicates that the filesystem supports adaptive readdirplus.

+

If FUSE_CAP_READDIRPLUS is not set, this flag has no effect.

+

If FUSE_CAP_READDIRPLUS is set and this flag is not set, the kernel will always issue readdirplus() requests to retrieve directory contents.

+

If FUSE_CAP_READDIRPLUS is set and this flag is set, the kernel will issue both readdir() and readdirplus() requests, depending on how much information is expected to be required.

+

This feature is enabled by default when supported by the kernel and if the filesystem implements both a readdirplus() and a readdir() handler.

+ +

Definition at line 246 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_SPLICE_MOVE

+ +
+
+ + + + +
#define FUSE_CAP_SPLICE_MOVE   (1 << 8)
+
+

Indicates that libfuse should try to move pages instead of copying when writing to / reading from the fuse device. This may improve performance.

+

This feature is disabled by default.

+ +

Definition at line 168 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_SPLICE_READ

+ +
+
+ + + + +
#define FUSE_CAP_SPLICE_READ   (1 << 9)
+
+

Indicates that libfuse should try to use splice() when reading from the fuse device. This may improve performance.

+

This feature is enabled by default when supported by the kernel and if the filesystem implements a write_buf() handler.

+ +

Definition at line 177 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_SPLICE_WRITE

+ +
+
+ + + + +
#define FUSE_CAP_SPLICE_WRITE   (1 << 7)
+
+

Indicates that libfuse should try to use splice() when writing to the fuse device. This may improve performance.

+

This feature is disabled by default.

+ +

Definition at line 160 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_CAP_WRITEBACK_CACHE

+ +
+
+ + + + +
#define FUSE_CAP_WRITEBACK_CACHE   (1 << 16)
+
+

Indicates that writeback caching should be enabled. This means that individual write request may be buffered and merged in the kernel before they are send to the filesystem.

+

This feature is disabled by default.

+ +

Definition at line 266 of file fuse_common.h.

+ +
+
+ +

◆ FUSE_IOCTL_COMPAT

+
@@ -146,36 +521,48 @@ Functions

FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed FUSE_IOCTL_RETRY: retry with new iovecs FUSE_IOCTL_DIR: is a directory

FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs

+

Definition at line 329 of file fuse_common.h.

+ - + +

◆ FUSE_MAJOR_VERSION

+
- +
#define FUSE_MAJOR_VERSION   2#define FUSE_MAJOR_VERSION   3

Major version of FUSE library interface

+

Definition at line 22 of file fuse_common.h.

+
- + +

◆ FUSE_MINOR_VERSION

+
- +
#define FUSE_MINOR_VERSION   9#define FUSE_MINOR_VERSION   2

Minor version of FUSE library interface

+

Definition at line 25 of file fuse_common.h.

+

Enumeration Type Documentation

- + +

◆ fuse_buf_copy_flags

+
@@ -186,28 +573,28 @@ Functions

Buffer copy flags

- - - -
Enumerator
FUSE_BUF_NO_SPLICE  -

Don't use splice(2)

+
Enumerator
FUSE_BUF_NO_SPLICE 

Don't use splice(2)

Always fall back to using read and write instead of splice(2) to copy data from one file descriptor to another.

If this flag is not set, then only fall back if splice is unavailable.

FUSE_BUF_FORCE_SPLICE  -

Force splice

+
FUSE_BUF_FORCE_SPLICE 

Force splice

Always use splice(2) to copy data from one file descriptor to another. If splice is not available, return -EINVAL.

FUSE_BUF_SPLICE_MOVE  -

Try to move data with splice.

+
FUSE_BUF_SPLICE_MOVE 

Try to move data with splice.

If splice is used, try to move pages from the source to the destination instead of copying. See documentation of SPLICE_F_MOVE in splice(2) man page.

FUSE_BUF_SPLICE_NONBLOCK  -

Don't block on the pipe when copying data with splice

+
FUSE_BUF_SPLICE_NONBLOCK 

Don't block on the pipe when copying data with splice

Makes the operations on the pipe non-blocking (if the pipe is full or empty). See SPLICE_F_NONBLOCK in the splice(2) man page.

+

Definition at line 579 of file fuse_common.h.

+
- + +

◆ fuse_buf_flags

+
@@ -218,24 +605,56 @@ Functions

Buffer flags

- - -
Enumerator
FUSE_BUF_IS_FD  -

Buffer contains a file descriptor

+
Enumerator
FUSE_BUF_IS_FD 

Buffer contains a file descriptor

If this flag is set, the .fd field is valid, otherwise the .mem fields is valid.

FUSE_BUF_FD_SEEK  -

Seek on the file descriptor

+
FUSE_BUF_FD_SEEK 

Seek on the file descriptor

If this flag is set then the .pos field is valid and is used to seek to the given offset before performing operation on file descriptor.

FUSE_BUF_FD_RETRY  -

Retry operation on file descriptor

+
FUSE_BUF_FD_RETRY 

Retry operation on file descriptor

If this flag is set then retry operation on file descriptor until .size bytes have been copied or an error or EOF is detected.

+

Definition at line 548 of file fuse_common.h.

+

Function Documentation

- + +

◆ fuse_apply_conn_info_opts()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void fuse_apply_conn_info_opts (struct fuse_conn_info_opts * opts,
struct fuse_conn_infoconn 
)
+
+

This function applies the (parsed) parameters in opts to the conn pointer. It may modify the following fields: wants, max_write, max_readahead, congestion_threshold, max_background, time_gran. A field is only set (or unset) if the corresponding option has been explicitly set.

+ +

Definition at line 361 of file helper.c.

+ +
+
+ +

◆ fuse_buf_copy()

+
@@ -275,9 +694,13 @@ Functions
Returns
actual number of bytes copied or -errno on error
+

Definition at line 281 of file buffer.c.

+ - + +

◆ fuse_buf_size()

+
@@ -299,9 +722,13 @@ Functions
Returns
size of data
+

Definition at line 22 of file buffer.c.

+ - + +

◆ fuse_daemonize()

+
@@ -323,97 +750,67 @@ Functions
Returns
0 on success, -1 on failure
+

Definition at line 225 of file helper.c.

+ - + +

◆ fuse_parse_conn_info_opts()

+
- + - - - - - - - - - + - -
struct fuse_chan* fuse_mount struct fuse_conn_info_opts* fuse_parse_conn_info_opts (const char * mountpoint,
struct fuse_argsargs 
args) )
-

Create a FUSE mountpoint

-

Returns a control file descriptor suitable for passing to fuse_new()

+

This function parses several command-line options that can be used to override elements of struct fuse_conn_info. The pointer returned by this function should be passed to the fuse_apply_conn_info_opts() method by the file system's init() handler.

+

Before using this function, think twice if you really want these parameters to be adjustable from the command line. In most cases, they should be determined by the file system internally.

+

The following options are recognized:

+

-o max_write=N sets conn->max_write -o max_readahead=N sets conn->max_readahead -o max_background=N sets conn->max_background -o congestion_threshold=N sets conn->congestion_threshold -o async_read sets FUSE_CAP_ASYNC_READ in conn->want -o sync_read unsets FUSE_CAP_ASYNC_READ in conn->want -o atomic_o_trunc sets FUSE_CAP_ATOMIC_O_TRUNC in conn->want -o no_remote_lock Equivalent to -o no_remote_flock,no_remote_posix_lock -o no_remote_flock Unsets FUSE_CAP_FLOCK_LOCKS in conn->want -o no_remote_posix_lock Unsets FUSE_CAP_POSIX_LOCKS in conn->want -o [no_]splice_write (un-)sets FUSE_CAP_SPLICE_WRITE in conn->want -o [no_]splice_move (un-)sets FUSE_CAP_SPLICE_MOVE in conn->want -o [no_]splice_read (un-)sets FUSE_CAP_SPLICE_READ in conn->want -o [no_]auto_inval_data (un-)sets FUSE_CAP_AUTO_INVAL_DATA in conn->want -o readdirplus=no unsets FUSE_CAP_READDIRPLUS in conn->want -o readdirplus=yes sets FUSE_CAP_READDIRPLUS and unsets FUSE_CAP_READDIRPLUS_AUTO in conn->want -o readdirplus=auto sets FUSE_CAP_READDIRPLUS and FUSE_CAP_READDIRPLUS_AUTO in conn->want -o [no_]async_dio (un-)sets FUSE_CAP_ASYNC_DIO in conn->want -o [no_]writeback_cache (un-)sets FUSE_CAP_WRITEBACK_CACHE in conn->want -o time_gran=N sets conn->time_gran

+

Known options will be removed from args, unknown options will be passed through unchanged.

Parameters
- - +
mountpointthe mount point path
argsargument vector
argsargument vector (input+output)
-
Returns
the communication channel on success, NULL on failure
+
Returns
parsed options
+ +

Definition at line 408 of file helper.c.

- + +

◆ fuse_pkgversion()

+
- + - - - - - - - - - - - - - - - - - + + - - - - - - -
int fuse_parse_cmdline const char* fuse_pkgversion (struct fuse_argsargs,
char ** mountpoint,
int * multithreaded,
void ) int * foreground 
)
-

Parse common options

-

The following options are parsed:

-

'-f' foreground '-d' '-odebug' foreground, but keep the debug option '-s' single threaded '-h' '–help' help '-ho' help without header '-ofsname=..' file system name, if not present, then set to the program name

-

All parameters may be NULL

-
Parameters
- - - - - -
argsargument vector
mountpointthe returned mountpoint, should be freed after use
multithreadedset to 1 unless the '-s' option is present
foregroundset to 1 if one of the relevant options is present
-
-
-
Returns
0 on success, -1 on failure
+

Get the full package version string of the library

+
Returns
the package version
+ +

Definition at line 5071 of file fuse.c.

- + +

◆ fuse_pollhandle_destroy()

+
@@ -434,9 +831,13 @@ Functions +

Definition at line 1766 of file fuse_lowlevel.c.

+ - + +

◆ fuse_remove_signal_handlers()

+
@@ -453,14 +854,19 @@ Functions

Resets global session. After this fuse_set_signal_handlers() may be called again.

Parameters
- +
sethe same session as given in fuse_set_signal_handlers()
sethe same session as given in fuse_set_signal_handlers()
+

See also: fuse_set_signal_handlers()

+ +

Definition at line 79 of file fuse_signals.c.

- + +

◆ fuse_set_signal_handlers()

+
@@ -475,51 +881,23 @@ Functions

Exit session on HUP, TERM and INT signals and ignore PIPE signal

Stores session in a global variable. May only be called once per process until fuse_remove_signal_handlers() is called.

+

Once either of the POSIX signals arrives, the signal handler calls fuse_session_exit().

Parameters
sethe session to exit
-
Returns
0 on success, -1 on failure
+
Returns
0 on success, -1 on failure
+

See also: fuse_remove_signal_handlers()

-
-
- -
-
- - - - - - - - - - - - - - - - - - -
void fuse_unmount (const char * mountpoint,
struct fuse_chan * ch 
)
-
-

Umount a FUSE mountpoint

-
Parameters
- - - -
mountpointthe mount point path
chthe communication channel
-
-
+

Definition at line 62 of file fuse_signals.c.

- + +

◆ fuse_version()

+
@@ -535,14 +913,16 @@ Functions

Get the version of the library

Returns
the version
+

Definition at line 5066 of file fuse.c.

+ diff --git a/doc/html/fuse__common_8h_source.html b/doc/html/fuse__common_8h_source.html new file mode 100644 index 0000000..031f563 --- /dev/null +++ b/doc/html/fuse__common_8h_source.html @@ -0,0 +1,111 @@ + + + + + + + +libfuse: include/fuse_common.h Source File + + + + + + +
+
+
+ + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_common.h
+
+
+Go to the documentation of this file.
1 /* FUSE: Filesystem in Userspace
2  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
3 
4  This program can be distributed under the terms of the GNU LGPLv2.
5  See the file COPYING.LIB.
6 */
7 
10 #if !defined(FUSE_H_) && !defined(FUSE_LOWLEVEL_H_)
11 #error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
12 #endif
13 
14 #ifndef FUSE_COMMON_H_
15 #define FUSE_COMMON_H_
16 
17 #include "fuse_opt.h"
18 #include <stdint.h>
19 #include <sys/types.h>
20 
22 #define FUSE_MAJOR_VERSION 3
23 
25 #define FUSE_MINOR_VERSION 2
26 
27 #define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
28 #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
39  int flags;
40 
43  unsigned int writepage : 1;
44 
46  unsigned int direct_io : 1;
47 
51  unsigned int keep_cache : 1;
52 
56  unsigned int flush : 1;
57 
60  unsigned int nonseekable : 1;
61 
62  /* Indicates that flock locks for this file should be
63  released. If set, lock_owner shall contain a valid value.
64  May only be set in ->release(). */
65  unsigned int flock_release : 1;
66 
68  unsigned int padding : 27;
69 
72  uint64_t fh;
73 
75  uint64_t lock_owner;
76 
79  uint32_t poll_events;
80 };
81 
91  int clone_fd;
92 
103  unsigned int max_idle_threads;
104 };
105 
106 /**************************************************************************
107  * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' *
108  **************************************************************************/
109 
120 #define FUSE_CAP_ASYNC_READ (1 << 0)
121 
128 #define FUSE_CAP_POSIX_LOCKS (1 << 1)
129 
137 #define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
138 
144 #define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
145 
152 #define FUSE_CAP_DONT_MASK (1 << 6)
153 
160 #define FUSE_CAP_SPLICE_WRITE (1 << 7)
161 
168 #define FUSE_CAP_SPLICE_MOVE (1 << 8)
169 
177 #define FUSE_CAP_SPLICE_READ (1 << 9)
178 
190 #define FUSE_CAP_FLOCK_LOCKS (1 << 10)
191 
197 #define FUSE_CAP_IOCTL_DIR (1 << 11)
198 
219 #define FUSE_CAP_AUTO_INVAL_DATA (1 << 12)
220 
227 #define FUSE_CAP_READDIRPLUS (1 << 13)
228 
246 #define FUSE_CAP_READDIRPLUS_AUTO (1 << 14)
247 
257 #define FUSE_CAP_ASYNC_DIO (1 << 15)
258 
266 #define FUSE_CAP_WRITEBACK_CACHE (1 << 16)
267 
279 #define FUSE_CAP_NO_OPEN_SUPPORT (1 << 17)
280 
289 #define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
290 
308 #define FUSE_CAP_POSIX_ACL (1 << 19)
309 
317 #define FUSE_CAP_HANDLE_KILLPRIV (1 << 20)
318 
329 #define FUSE_IOCTL_COMPAT (1 << 0)
330 #define FUSE_IOCTL_UNRESTRICTED (1 << 1)
331 #define FUSE_IOCTL_RETRY (1 << 2)
332 #define FUSE_IOCTL_DIR (1 << 4)
333 
334 #define FUSE_IOCTL_MAX_IOV 256
335 
347  unsigned proto_major;
348 
352  unsigned proto_minor;
353 
357  unsigned max_write;
358 
371  unsigned max_read;
372 
376  unsigned max_readahead;
377 
381  unsigned capable;
382 
389  unsigned want;
390 
419  unsigned max_background;
420 
430 
446  unsigned time_gran;
447 
451  unsigned reserved[22];
452 };
453 
454 struct fuse_session;
455 struct fuse_pollhandle;
456 struct fuse_conn_info_opts;
457 
500 struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args);
501 
509 void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
510  struct fuse_conn_info *conn);
511 
518 int fuse_daemonize(int foreground);
519 
525 int fuse_version(void);
526 
532 const char *fuse_pkgversion(void);
533 
539 void fuse_pollhandle_destroy(struct fuse_pollhandle *ph);
540 
541 /* ----------------------------------------------------------- *
542  * Data buffer *
543  * ----------------------------------------------------------- */
544 
555  FUSE_BUF_IS_FD = (1 << 1),
556 
564  FUSE_BUF_FD_SEEK = (1 << 2),
565 
573  FUSE_BUF_FD_RETRY = (1 << 3),
574 };
575 
589  FUSE_BUF_NO_SPLICE = (1 << 1),
590 
598 
607 
616 };
617 
624 struct fuse_buf {
628  size_t size;
629 
634 
640  void *mem;
641 
647  int fd;
648 
654  off_t pos;
655 };
656 
665 struct fuse_bufvec {
669  size_t count;
670 
674  size_t idx;
675 
679  size_t off;
680 
684  struct fuse_buf buf[1];
685 };
686 
687 /* Initialize bufvec with a single buffer of given size */
688 #define FUSE_BUFVEC_INIT(size__) \
689  ((struct fuse_bufvec) { \
690  /* .count= */ 1, \
691  /* .idx = */ 0, \
692  /* .off = */ 0, \
693  /* .buf = */ { /* [0] = */ { \
694  /* .size = */ (size__), \
695  /* .flags = */ (enum fuse_buf_flags) 0, \
696  /* .mem = */ NULL, \
697  /* .fd = */ -1, \
698  /* .pos = */ 0, \
699  } } \
700  } )
701 
708 size_t fuse_buf_size(const struct fuse_bufvec *bufv);
709 
718 ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
720 
721 /* ----------------------------------------------------------- *
722  * Signal handling *
723  * ----------------------------------------------------------- */
724 
740 int fuse_set_signal_handlers(struct fuse_session *se);
741 
753 void fuse_remove_signal_handlers(struct fuse_session *se);
754 
755 /* ----------------------------------------------------------- *
756  * Compatibility stuff *
757  * ----------------------------------------------------------- */
758 
759 #if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30
760 # error only API version 30 or greater is supported
761 #endif
762 
763 #ifdef __cplusplus
764 }
765 #endif
766 
767 
768 /*
769  * This interface uses 64 bit off_t.
770  *
771  * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags!
772  */
773 
774 #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
775 _Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit");
776 #else
777 struct _fuse_off_t_must_be_64bit_dummy_struct \
778  { unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); };
779 #endif
780 
781 #endif /* FUSE_COMMON_H_ */
size_t off
Definition: fuse_common.h:679
+
fuse_buf_flags
Definition: fuse_common.h:548
+
unsigned capable
Definition: fuse_common.h:381
+
uint64_t fh
Definition: fuse_common.h:72
+ +
unsigned int writepage
Definition: fuse_common.h:43
+
unsigned int direct_io
Definition: fuse_common.h:46
+ +
uint32_t poll_events
Definition: fuse_common.h:79
+
int fuse_daemonize(int foreground)
Definition: helper.c:225
+
unsigned max_write
Definition: fuse_common.h:357
+ +
unsigned proto_minor
Definition: fuse_common.h:352
+
unsigned int max_idle_threads
Definition: fuse_common.h:103
+
unsigned max_background
Definition: fuse_common.h:419
+ +
unsigned int keep_cache
Definition: fuse_common.h:51
+
uint64_t lock_owner
Definition: fuse_common.h:75
+ +
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
+
off_t pos
Definition: fuse_common.h:654
+
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
+ +
int fuse_version(void)
Definition: fuse.c:5066
+
struct fuse_conn_info_opts * fuse_parse_conn_info_opts(struct fuse_args *args)
Definition: helper.c:408
+ +
void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn)
Definition: helper.c:361
+ + +
size_t idx
Definition: fuse_common.h:674
+
size_t count
Definition: fuse_common.h:669
+ +
unsigned int nonseekable
Definition: fuse_common.h:60
+
unsigned congestion_threshold
Definition: fuse_common.h:429
+
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
+
unsigned int flush
Definition: fuse_common.h:56
+
unsigned max_read
Definition: fuse_common.h:371
+ +
unsigned max_readahead
Definition: fuse_common.h:376
+
unsigned proto_major
Definition: fuse_common.h:347
+
void * mem
Definition: fuse_common.h:640
+ +
unsigned want
Definition: fuse_common.h:389
+ +
const char * fuse_pkgversion(void)
Definition: fuse.c:5071
+ +
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
+
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:281
+
size_t size
Definition: fuse_common.h:628
+
fuse_buf_copy_flags
Definition: fuse_common.h:579
+ + +
unsigned int padding
Definition: fuse_common.h:68
+
unsigned time_gran
Definition: fuse_common.h:446
+ +
+ + + + diff --git a/doc/html/fuse__i_8h_source.html b/doc/html/fuse__i_8h_source.html new file mode 100644 index 0000000..7771c32 --- /dev/null +++ b/doc/html/fuse__i_8h_source.html @@ -0,0 +1,70 @@ + + + + + + + +libfuse: lib/fuse_i.h Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_i.h
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU LGPLv2.
6  See the file COPYING.LIB
7 */
8 
9 #include "fuse.h"
10 #include "fuse_lowlevel.h"
11 
12 struct mount_opts;
13 
14 struct fuse_req {
15  struct fuse_session *se;
16  uint64_t unique;
17  int ctr;
18  pthread_mutex_t lock;
19  struct fuse_ctx ctx;
20  struct fuse_chan *ch;
21  int interrupted;
22  unsigned int ioctl_64bit : 1;
23  union {
24  struct {
25  uint64_t unique;
26  } i;
27  struct {
29  void *data;
30  } ni;
31  } u;
32  struct fuse_req *next;
33  struct fuse_req *prev;
34 };
35 
36 struct fuse_notify_req {
37  uint64_t unique;
38  void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
39  const void *, const struct fuse_buf *);
40  struct fuse_notify_req *next;
41  struct fuse_notify_req *prev;
42 };
43 
44 struct fuse_session {
45  char *mountpoint;
46  volatile int exited;
47  int fd;
48  struct mount_opts *mo;
49  int debug;
50  int deny_others;
51  struct fuse_lowlevel_ops op;
52  int got_init;
53  struct cuse_data *cuse_data;
54  void *userdata;
55  uid_t owner;
56  struct fuse_conn_info conn;
57  struct fuse_req list;
58  struct fuse_req interrupts;
59  pthread_mutex_t lock;
60  int got_destroy;
61  pthread_key_t pipe_key;
62  int broken_splice_nonblock;
63  uint64_t notify_ctr;
64  struct fuse_notify_req notify_list;
65  size_t bufsize;
66  int error;
67 };
68 
69 struct fuse_chan {
70  pthread_mutex_t lock;
71  int ctr;
72  int fd;
73 };
74 
82 struct fuse_module {
83  char *name;
84  fuse_module_factory_t factory;
85  struct fuse_module *next;
86  struct fusemod_so *so;
87  int ctr;
88 };
89 
90 /* ----------------------------------------------------------- *
91  * Channel interface (when using -o clone_fd) *
92  * ----------------------------------------------------------- */
93 
100 struct fuse_chan *fuse_chan_get(struct fuse_chan *ch);
101 
107 void fuse_chan_put(struct fuse_chan *ch);
108 
109 struct mount_opts *parse_mount_opts(struct fuse_args *args);
110 void destroy_mount_opts(struct mount_opts *mo);
111 void fuse_mount_version(void);
112 unsigned get_max_read(struct mount_opts *o);
113 void fuse_kern_unmount(const char *mountpoint, int fd);
114 int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo);
115 
116 int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
117  int count);
118 void fuse_free_req(fuse_req_t req);
119 
120 void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
121 
122 int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
123 
124 int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
125  struct fuse_chan *ch);
126 void fuse_session_process_buf_int(struct fuse_session *se,
127  const struct fuse_buf *buf, struct fuse_chan *ch);
128 
129 struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op,
130  size_t op_size, void *private_data);
131 int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config);
132 int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config);
133 
+
void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+ + + +
struct fuse_fs *(* fuse_module_factory_t)(struct fuse_args *args, struct fuse_fs *fs[])
Definition: fuse.h:1226
+ + +
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
+ + + + +
+ + + + diff --git a/doc/html/fuse__kernel_8h_source.html b/doc/html/fuse__kernel_8h_source.html new file mode 100644 index 0000000..628b188 --- /dev/null +++ b/doc/html/fuse__kernel_8h_source.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: include/fuse_kernel.h Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_kernel.h
+
+
+
1 /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
2 /*
3  This file defines the kernel interface of FUSE
4  Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
5 
6  This program can be distributed under the terms of the GNU GPL.
7  See the file COPYING.
8 
9  This -- and only this -- header file may also be distributed under
10  the terms of the BSD Licence as follows:
11 
12  Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
13 
14  Redistribution and use in source and binary forms, with or without
15  modification, are permitted provided that the following conditions
16  are met:
17  1. Redistributions of source code must retain the above copyright
18  notice, this list of conditions and the following disclaimer.
19  2. Redistributions in binary form must reproduce the above copyright
20  notice, this list of conditions and the following disclaimer in the
21  documentation and/or other materials provided with the distribution.
22 
23  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  SUCH DAMAGE.
34 */
35 
36 /*
37  * This file defines the kernel interface of FUSE
38  *
39  * Protocol changelog:
40  *
41  * 7.9:
42  * - new fuse_getattr_in input argument of GETATTR
43  * - add lk_flags in fuse_lk_in
44  * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
45  * - add blksize field to fuse_attr
46  * - add file flags field to fuse_read_in and fuse_write_in
47  *
48  * 7.10
49  * - add nonseekable open flag
50  *
51  * 7.11
52  * - add IOCTL message
53  * - add unsolicited notification support
54  * - add POLL message and NOTIFY_POLL notification
55  *
56  * 7.12
57  * - add umask flag to input argument of open, mknod and mkdir
58  * - add notification messages for invalidation of inodes and
59  * directory entries
60  *
61  * 7.13
62  * - make max number of background requests and congestion threshold
63  * tunables
64  *
65  * 7.14
66  * - add splice support to fuse device
67  *
68  * 7.15
69  * - add store notify
70  * - add retrieve notify
71  *
72  * 7.16
73  * - add BATCH_FORGET request
74  * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
75  * fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
76  * - add FUSE_IOCTL_32BIT flag
77  *
78  * 7.17
79  * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
80  *
81  * 7.18
82  * - add FUSE_IOCTL_DIR flag
83  * - add FUSE_NOTIFY_DELETE
84  *
85  * 7.19
86  * - add FUSE_FALLOCATE
87  *
88  * 7.20
89  * - add FUSE_AUTO_INVAL_DATA
90  *
91  * 7.21
92  * - add FUSE_READDIRPLUS
93  * - send the requested events in POLL request
94  *
95  * 7.22
96  * - add FUSE_ASYNC_DIO
97  *
98  * 7.23
99  * - add FUSE_WRITEBACK_CACHE
100  * - add time_gran to fuse_init_out
101  * - add reserved space to fuse_init_out
102  * - add FATTR_CTIME
103  * - add ctime and ctimensec to fuse_setattr_in
104  * - add FUSE_RENAME2 request
105  * - add FUSE_NO_OPEN_SUPPORT flag
106  *
107  * 7.24
108  * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
109  *
110  * 7.25
111  * - add FUSE_PARALLEL_DIROPS
112  *
113  * 7.26
114  * - add FUSE_HANDLE_KILLPRIV
115  * - add FUSE_POSIX_ACL
116  *
117  * 7.27
118  * - add FUSE_ABORT_ERROR
119  *
120  * 7.28
121  * - add FUSE_COPY_FILE_RANGE
122  */
123 
124 #ifndef _LINUX_FUSE_H
125 #define _LINUX_FUSE_H
126 
127 #ifdef __KERNEL__
128 #include <linux/types.h>
129 #else
130 #include <stdint.h>
131 #endif
132 
133 /*
134  * Version negotiation:
135  *
136  * Both the kernel and userspace send the version they support in the
137  * INIT request and reply respectively.
138  *
139  * If the major versions match then both shall use the smallest
140  * of the two minor versions for communication.
141  *
142  * If the kernel supports a larger major version, then userspace shall
143  * reply with the major version it supports, ignore the rest of the
144  * INIT message and expect a new INIT message from the kernel with a
145  * matching major version.
146  *
147  * If the library supports a larger major version, then it shall fall
148  * back to the major protocol version sent by the kernel for
149  * communication and reply with that major version (and an arbitrary
150  * supported minor version).
151  */
152 
154 #define FUSE_KERNEL_VERSION 7
155 
157 #define FUSE_KERNEL_MINOR_VERSION 27
158 
160 #define FUSE_ROOT_ID 1
161 
162 /* Make sure all structures are padded to 64bit boundary, so 32bit
163  userspace works under 64bit kernels */
164 
165 struct fuse_attr {
166  uint64_t ino;
167  uint64_t size;
168  uint64_t blocks;
169  uint64_t atime;
170  uint64_t mtime;
171  uint64_t ctime;
172  uint32_t atimensec;
173  uint32_t mtimensec;
174  uint32_t ctimensec;
175  uint32_t mode;
176  uint32_t nlink;
177  uint32_t uid;
178  uint32_t gid;
179  uint32_t rdev;
180  uint32_t blksize;
181  uint32_t padding;
182 };
183 
184 struct fuse_kstatfs {
185  uint64_t blocks;
186  uint64_t bfree;
187  uint64_t bavail;
188  uint64_t files;
189  uint64_t ffree;
190  uint32_t bsize;
191  uint32_t namelen;
192  uint32_t frsize;
193  uint32_t padding;
194  uint32_t spare[6];
195 };
196 
197 struct fuse_file_lock {
198  uint64_t start;
199  uint64_t end;
200  uint32_t type;
201  uint32_t pid; /* tgid */
202 };
203 
207 #define FATTR_MODE (1 << 0)
208 #define FATTR_UID (1 << 1)
209 #define FATTR_GID (1 << 2)
210 #define FATTR_SIZE (1 << 3)
211 #define FATTR_ATIME (1 << 4)
212 #define FATTR_MTIME (1 << 5)
213 #define FATTR_FH (1 << 6)
214 #define FATTR_ATIME_NOW (1 << 7)
215 #define FATTR_MTIME_NOW (1 << 8)
216 #define FATTR_LOCKOWNER (1 << 9)
217 #define FATTR_CTIME (1 << 10)
218 
226 #define FOPEN_DIRECT_IO (1 << 0)
227 #define FOPEN_KEEP_CACHE (1 << 1)
228 #define FOPEN_NONSEEKABLE (1 << 2)
229 
256 #define FUSE_ASYNC_READ (1 << 0)
257 #define FUSE_POSIX_LOCKS (1 << 1)
258 #define FUSE_FILE_OPS (1 << 2)
259 #define FUSE_ATOMIC_O_TRUNC (1 << 3)
260 #define FUSE_EXPORT_SUPPORT (1 << 4)
261 #define FUSE_BIG_WRITES (1 << 5)
262 #define FUSE_DONT_MASK (1 << 6)
263 #define FUSE_SPLICE_WRITE (1 << 7)
264 #define FUSE_SPLICE_MOVE (1 << 8)
265 #define FUSE_SPLICE_READ (1 << 9)
266 #define FUSE_FLOCK_LOCKS (1 << 10)
267 #define FUSE_HAS_IOCTL_DIR (1 << 11)
268 #define FUSE_AUTO_INVAL_DATA (1 << 12)
269 #define FUSE_DO_READDIRPLUS (1 << 13)
270 #define FUSE_READDIRPLUS_AUTO (1 << 14)
271 #define FUSE_ASYNC_DIO (1 << 15)
272 #define FUSE_WRITEBACK_CACHE (1 << 16)
273 #define FUSE_NO_OPEN_SUPPORT (1 << 17)
274 #define FUSE_PARALLEL_DIROPS (1 << 18)
275 #define FUSE_HANDLE_KILLPRIV (1 << 19)
276 #define FUSE_POSIX_ACL (1 << 20)
277 #define FUSE_ABORT_ERROR (1 << 21)
278 
284 #define CUSE_UNRESTRICTED_IOCTL (1 << 0)
285 
289 #define FUSE_RELEASE_FLUSH (1 << 0)
290 #define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1)
291 
295 #define FUSE_GETATTR_FH (1 << 0)
296 
300 #define FUSE_LK_FLOCK (1 << 0)
301 
308 #define FUSE_WRITE_CACHE (1 << 0)
309 #define FUSE_WRITE_LOCKOWNER (1 << 1)
310 
314 #define FUSE_READ_LOCKOWNER (1 << 1)
315 
327 #define FUSE_IOCTL_COMPAT (1 << 0)
328 #define FUSE_IOCTL_UNRESTRICTED (1 << 1)
329 #define FUSE_IOCTL_RETRY (1 << 2)
330 #define FUSE_IOCTL_32BIT (1 << 3)
331 #define FUSE_IOCTL_DIR (1 << 4)
332 
333 #define FUSE_IOCTL_MAX_IOV 256
334 
340 #define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
341 
342 enum fuse_opcode {
343  FUSE_LOOKUP = 1,
344  FUSE_FORGET = 2, /* no reply */
345  FUSE_GETATTR = 3,
346  FUSE_SETATTR = 4,
347  FUSE_READLINK = 5,
348  FUSE_SYMLINK = 6,
349  FUSE_MKNOD = 8,
350  FUSE_MKDIR = 9,
351  FUSE_UNLINK = 10,
352  FUSE_RMDIR = 11,
353  FUSE_RENAME = 12,
354  FUSE_LINK = 13,
355  FUSE_OPEN = 14,
356  FUSE_READ = 15,
357  FUSE_WRITE = 16,
358  FUSE_STATFS = 17,
359  FUSE_RELEASE = 18,
360  FUSE_FSYNC = 20,
361  FUSE_SETXATTR = 21,
362  FUSE_GETXATTR = 22,
363  FUSE_LISTXATTR = 23,
364  FUSE_REMOVEXATTR = 24,
365  FUSE_FLUSH = 25,
366  FUSE_INIT = 26,
367  FUSE_OPENDIR = 27,
368  FUSE_READDIR = 28,
369  FUSE_RELEASEDIR = 29,
370  FUSE_FSYNCDIR = 30,
371  FUSE_GETLK = 31,
372  FUSE_SETLK = 32,
373  FUSE_SETLKW = 33,
374  FUSE_ACCESS = 34,
375  FUSE_CREATE = 35,
376  FUSE_INTERRUPT = 36,
377  FUSE_BMAP = 37,
378  FUSE_DESTROY = 38,
379  FUSE_IOCTL = 39,
380  FUSE_POLL = 40,
381  FUSE_NOTIFY_REPLY = 41,
382  FUSE_BATCH_FORGET = 42,
383  FUSE_FALLOCATE = 43,
384  FUSE_READDIRPLUS = 44,
385  FUSE_RENAME2 = 45,
386  FUSE_LSEEK = 46,
387  FUSE_COPY_FILE_RANGE = 47,
388 
389  /* CUSE specific operations */
390  CUSE_INIT = 4096,
391 };
392 
393 enum fuse_notify_code {
394  FUSE_NOTIFY_POLL = 1,
395  FUSE_NOTIFY_INVAL_INODE = 2,
396  FUSE_NOTIFY_INVAL_ENTRY = 3,
397  FUSE_NOTIFY_STORE = 4,
398  FUSE_NOTIFY_RETRIEVE = 5,
399  FUSE_NOTIFY_DELETE = 6,
400  FUSE_NOTIFY_CODE_MAX,
401 };
402 
403 /* The read buffer is required to be at least 8k, but may be much larger */
404 #define FUSE_MIN_READ_BUFFER 8192
405 
406 #define FUSE_COMPAT_ENTRY_OUT_SIZE 120
407 
408 struct fuse_entry_out {
409  uint64_t nodeid; /* Inode ID */
410  uint64_t generation; /* Inode generation: nodeid:gen must
411  be unique for the fs's lifetime */
412  uint64_t entry_valid; /* Cache timeout for the name */
413  uint64_t attr_valid; /* Cache timeout for the attributes */
414  uint32_t entry_valid_nsec;
415  uint32_t attr_valid_nsec;
416  struct fuse_attr attr;
417 };
418 
419 struct fuse_forget_in {
420  uint64_t nlookup;
421 };
422 
423 struct fuse_forget_one {
424  uint64_t nodeid;
425  uint64_t nlookup;
426 };
427 
428 struct fuse_batch_forget_in {
429  uint32_t count;
430  uint32_t dummy;
431 };
432 
433 struct fuse_getattr_in {
434  uint32_t getattr_flags;
435  uint32_t dummy;
436  uint64_t fh;
437 };
438 
439 #define FUSE_COMPAT_ATTR_OUT_SIZE 96
440 
441 struct fuse_attr_out {
442  uint64_t attr_valid; /* Cache timeout for the attributes */
443  uint32_t attr_valid_nsec;
444  uint32_t dummy;
445  struct fuse_attr attr;
446 };
447 
448 #define FUSE_COMPAT_MKNOD_IN_SIZE 8
449 
450 struct fuse_mknod_in {
451  uint32_t mode;
452  uint32_t rdev;
453  uint32_t umask;
454  uint32_t padding;
455 };
456 
457 struct fuse_mkdir_in {
458  uint32_t mode;
459  uint32_t umask;
460 };
461 
462 struct fuse_rename_in {
463  uint64_t newdir;
464 };
465 
466 struct fuse_rename2_in {
467  uint64_t newdir;
468  uint32_t flags;
469  uint32_t padding;
470 };
471 
472 struct fuse_link_in {
473  uint64_t oldnodeid;
474 };
475 
476 struct fuse_setattr_in {
477  uint32_t valid;
478  uint32_t padding;
479  uint64_t fh;
480  uint64_t size;
481  uint64_t lock_owner;
482  uint64_t atime;
483  uint64_t mtime;
484  uint64_t ctime;
485  uint32_t atimensec;
486  uint32_t mtimensec;
487  uint32_t ctimensec;
488  uint32_t mode;
489  uint32_t unused4;
490  uint32_t uid;
491  uint32_t gid;
492  uint32_t unused5;
493 };
494 
495 struct fuse_open_in {
496  uint32_t flags;
497  uint32_t unused;
498 };
499 
500 struct fuse_create_in {
501  uint32_t flags;
502  uint32_t mode;
503  uint32_t umask;
504  uint32_t padding;
505 };
506 
507 struct fuse_open_out {
508  uint64_t fh;
509  uint32_t open_flags;
510  uint32_t padding;
511 };
512 
513 struct fuse_release_in {
514  uint64_t fh;
515  uint32_t flags;
516  uint32_t release_flags;
517  uint64_t lock_owner;
518 };
519 
520 struct fuse_flush_in {
521  uint64_t fh;
522  uint32_t unused;
523  uint32_t padding;
524  uint64_t lock_owner;
525 };
526 
527 struct fuse_read_in {
528  uint64_t fh;
529  uint64_t offset;
530  uint32_t size;
531  uint32_t read_flags;
532  uint64_t lock_owner;
533  uint32_t flags;
534  uint32_t padding;
535 };
536 
537 #define FUSE_COMPAT_WRITE_IN_SIZE 24
538 
539 struct fuse_write_in {
540  uint64_t fh;
541  uint64_t offset;
542  uint32_t size;
543  uint32_t write_flags;
544  uint64_t lock_owner;
545  uint32_t flags;
546  uint32_t padding;
547 };
548 
549 struct fuse_write_out {
550  uint32_t size;
551  uint32_t padding;
552 };
553 
554 #define FUSE_COMPAT_STATFS_SIZE 48
555 
556 struct fuse_statfs_out {
557  struct fuse_kstatfs st;
558 };
559 
560 struct fuse_fsync_in {
561  uint64_t fh;
562  uint32_t fsync_flags;
563  uint32_t padding;
564 };
565 
566 struct fuse_setxattr_in {
567  uint32_t size;
568  uint32_t flags;
569 };
570 
571 struct fuse_getxattr_in {
572  uint32_t size;
573  uint32_t padding;
574 };
575 
576 struct fuse_getxattr_out {
577  uint32_t size;
578  uint32_t padding;
579 };
580 
581 struct fuse_lk_in {
582  uint64_t fh;
583  uint64_t owner;
584  struct fuse_file_lock lk;
585  uint32_t lk_flags;
586  uint32_t padding;
587 };
588 
589 struct fuse_lk_out {
590  struct fuse_file_lock lk;
591 };
592 
593 struct fuse_access_in {
594  uint32_t mask;
595  uint32_t padding;
596 };
597 
598 struct fuse_init_in {
599  uint32_t major;
600  uint32_t minor;
601  uint32_t max_readahead;
602  uint32_t flags;
603 };
604 
605 #define FUSE_COMPAT_INIT_OUT_SIZE 8
606 #define FUSE_COMPAT_22_INIT_OUT_SIZE 24
607 
608 struct fuse_init_out {
609  uint32_t major;
610  uint32_t minor;
611  uint32_t max_readahead;
612  uint32_t flags;
613  uint16_t max_background;
614  uint16_t congestion_threshold;
615  uint32_t max_write;
616  uint32_t time_gran;
617  uint32_t unused[9];
618 };
619 
620 #define CUSE_INIT_INFO_MAX 4096
621 
622 struct cuse_init_in {
623  uint32_t major;
624  uint32_t minor;
625  uint32_t unused;
626  uint32_t flags;
627 };
628 
629 struct cuse_init_out {
630  uint32_t major;
631  uint32_t minor;
632  uint32_t unused;
633  uint32_t flags;
634  uint32_t max_read;
635  uint32_t max_write;
636  uint32_t dev_major; /* chardev major */
637  uint32_t dev_minor; /* chardev minor */
638  uint32_t spare[10];
639 };
640 
641 struct fuse_interrupt_in {
642  uint64_t unique;
643 };
644 
645 struct fuse_bmap_in {
646  uint64_t block;
647  uint32_t blocksize;
648  uint32_t padding;
649 };
650 
651 struct fuse_bmap_out {
652  uint64_t block;
653 };
654 
655 struct fuse_ioctl_in {
656  uint64_t fh;
657  uint32_t flags;
658  uint32_t cmd;
659  uint64_t arg;
660  uint32_t in_size;
661  uint32_t out_size;
662 };
663 
664 struct fuse_ioctl_iovec {
665  uint64_t base;
666  uint64_t len;
667 };
668 
669 struct fuse_ioctl_out {
670  int32_t result;
671  uint32_t flags;
672  uint32_t in_iovs;
673  uint32_t out_iovs;
674 };
675 
676 struct fuse_poll_in {
677  uint64_t fh;
678  uint64_t kh;
679  uint32_t flags;
680  uint32_t events;
681 };
682 
683 struct fuse_poll_out {
684  uint32_t revents;
685  uint32_t padding;
686 };
687 
688 struct fuse_notify_poll_wakeup_out {
689  uint64_t kh;
690 };
691 
692 struct fuse_fallocate_in {
693  uint64_t fh;
694  uint64_t offset;
695  uint64_t length;
696  uint32_t mode;
697  uint32_t padding;
698 };
699 
700 struct fuse_in_header {
701  uint32_t len;
702  uint32_t opcode;
703  uint64_t unique;
704  uint64_t nodeid;
705  uint32_t uid;
706  uint32_t gid;
707  uint32_t pid;
708  uint32_t padding;
709 };
710 
711 struct fuse_out_header {
712  uint32_t len;
713  int32_t error;
714  uint64_t unique;
715 };
716 
717 struct fuse_dirent {
718  uint64_t ino;
719  uint64_t off;
720  uint32_t namelen;
721  uint32_t type;
722  char name[];
723 };
724 
725 #define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
726 #define FUSE_DIRENT_ALIGN(x) \
727  (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
728 #define FUSE_DIRENT_SIZE(d) \
729  FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
730 
731 struct fuse_direntplus {
732  struct fuse_entry_out entry_out;
733  struct fuse_dirent dirent;
734 };
735 
736 #define FUSE_NAME_OFFSET_DIRENTPLUS \
737  offsetof(struct fuse_direntplus, dirent.name)
738 #define FUSE_DIRENTPLUS_SIZE(d) \
739  FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen)
740 
741 struct fuse_notify_inval_inode_out {
742  uint64_t ino;
743  int64_t off;
744  int64_t len;
745 };
746 
747 struct fuse_notify_inval_entry_out {
748  uint64_t parent;
749  uint32_t namelen;
750  uint32_t padding;
751 };
752 
753 struct fuse_notify_delete_out {
754  uint64_t parent;
755  uint64_t child;
756  uint32_t namelen;
757  uint32_t padding;
758 };
759 
760 struct fuse_notify_store_out {
761  uint64_t nodeid;
762  uint64_t offset;
763  uint32_t size;
764  uint32_t padding;
765 };
766 
767 struct fuse_notify_retrieve_out {
768  uint64_t notify_unique;
769  uint64_t nodeid;
770  uint64_t offset;
771  uint32_t size;
772  uint32_t padding;
773 };
774 
775 /* Matches the size of fuse_write_in */
776 struct fuse_notify_retrieve_in {
777  uint64_t dummy1;
778  uint64_t offset;
779  uint32_t size;
780  uint32_t dummy2;
781  uint64_t dummy3;
782  uint64_t dummy4;
783 };
784 
785 /* Device ioctls: */
786 #define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t)
787 
788 struct fuse_lseek_in {
789  uint64_t fh;
790  uint64_t offset;
791  uint32_t whence;
792  uint32_t padding;
793 };
794 
795 struct fuse_lseek_out {
796  uint64_t offset;
797 };
798 
799 struct fuse_copy_file_range_in {
800  uint64_t fh_in;
801  uint64_t off_in;
802  uint64_t nodeid_out;
803  uint64_t fh_out;
804  uint64_t off_out;
805  uint64_t len;
806  uint64_t flags;
807 };
808 
809 #endif /* _LINUX_FUSE_H */
+ + + + diff --git a/doc/html/fuse__loop_8c_source.html b/doc/html/fuse__loop_8c_source.html new file mode 100644 index 0000000..095769f --- /dev/null +++ b/doc/html/fuse__loop_8c_source.html @@ -0,0 +1,62 @@ + + + + + + + +libfuse: lib/fuse_loop.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_loop.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Implementation of the single-threaded FUSE session loop.
6 
7  This program can be distributed under the terms of the GNU LGPLv2.
8  See the file COPYING.LIB
9 */
10 
11 #include "config.h"
12 #include "fuse_lowlevel.h"
13 #include "fuse_i.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 
19 int fuse_session_loop(struct fuse_session *se)
20 {
21  int res = 0;
22  struct fuse_buf fbuf = {
23  .mem = NULL,
24  };
25 
26  while (!fuse_session_exited(se)) {
27  res = fuse_session_receive_buf_int(se, &fbuf, NULL);
28 
29  if (res == -EINTR)
30  continue;
31  if (res <= 0)
32  break;
33 
34  fuse_session_process_buf_int(se, &fbuf, NULL);
35  }
36 
37  free(fbuf.mem);
38  if(res > 0)
39  /* No error, just the length of the most recently read
40  request */
41  res = 0;
42  if(se->error != 0)
43  res = se->error;
45  return res;
46 }
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
+
int fuse_session_exited(struct fuse_session *se)
+
void fuse_session_reset(struct fuse_session *se)
+
void * mem
Definition: fuse_common.h:640
+ + +
+ + + + diff --git a/doc/html/fuse__loop__mt_8c_source.html b/doc/html/fuse__loop__mt_8c_source.html new file mode 100644 index 0000000..2cc1597 --- /dev/null +++ b/doc/html/fuse__loop__mt_8c_source.html @@ -0,0 +1,66 @@ + + + + + + + +libfuse: lib/fuse_loop_mt.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_loop_mt.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Implementation of the multi-threaded FUSE session loop.
6 
7  This program can be distributed under the terms of the GNU LGPLv2.
8  See the file COPYING.LIB.
9 */
10 
11 #include "config.h"
12 #include "fuse_lowlevel.h"
13 #include "fuse_misc.h"
14 #include "fuse_kernel.h"
15 #include "fuse_i.h"
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <semaphore.h>
23 #include <errno.h>
24 #include <sys/time.h>
25 #include <sys/ioctl.h>
26 #include <assert.h>
27 
28 /* Environment var controlling the thread stack size */
29 #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
30 
31 struct fuse_worker {
32  struct fuse_worker *prev;
33  struct fuse_worker *next;
34  pthread_t thread_id;
35  size_t bufsize;
36 
37  // We need to include fuse_buf so that we can properly free
38  // it when a thread is terminated by pthread_cancel().
39  struct fuse_buf fbuf;
40  struct fuse_chan *ch;
41  struct fuse_mt *mt;
42 };
43 
44 struct fuse_mt {
45  pthread_mutex_t lock;
46  int numworker;
47  int numavail;
48  struct fuse_session *se;
49  struct fuse_worker main;
50  sem_t finish;
51  int exit;
52  int error;
53  int clone_fd;
54  int max_idle;
55 };
56 
57 static struct fuse_chan *fuse_chan_new(int fd)
58 {
59  struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
60  if (ch == NULL) {
61  fprintf(stderr, "fuse: failed to allocate channel\n");
62  return NULL;
63  }
64 
65  memset(ch, 0, sizeof(*ch));
66  ch->fd = fd;
67  ch->ctr = 1;
68  fuse_mutex_init(&ch->lock);
69 
70  return ch;
71 }
72 
73 struct fuse_chan *fuse_chan_get(struct fuse_chan *ch)
74 {
75  assert(ch->ctr > 0);
76  pthread_mutex_lock(&ch->lock);
77  ch->ctr++;
78  pthread_mutex_unlock(&ch->lock);
79 
80  return ch;
81 }
82 
83 void fuse_chan_put(struct fuse_chan *ch)
84 {
85  if (ch == NULL)
86  return;
87  pthread_mutex_lock(&ch->lock);
88  ch->ctr--;
89  if (!ch->ctr) {
90  pthread_mutex_unlock(&ch->lock);
91  close(ch->fd);
92  pthread_mutex_destroy(&ch->lock);
93  free(ch);
94  } else
95  pthread_mutex_unlock(&ch->lock);
96 }
97 
98 static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
99 {
100  struct fuse_worker *prev = next->prev;
101  w->next = next;
102  w->prev = prev;
103  prev->next = w;
104  next->prev = w;
105 }
106 
107 static void list_del_worker(struct fuse_worker *w)
108 {
109  struct fuse_worker *prev = w->prev;
110  struct fuse_worker *next = w->next;
111  prev->next = next;
112  next->prev = prev;
113 }
114 
115 static int fuse_loop_start_thread(struct fuse_mt *mt);
116 
117 static void *fuse_do_work(void *data)
118 {
119  struct fuse_worker *w = (struct fuse_worker *) data;
120  struct fuse_mt *mt = w->mt;
121 
122  while (!fuse_session_exited(mt->se)) {
123  int isforget = 0;
124  int res;
125 
126  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
127  res = fuse_session_receive_buf_int(mt->se, &w->fbuf, w->ch);
128  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
129  if (res == -EINTR)
130  continue;
131  if (res <= 0) {
132  if (res < 0) {
133  fuse_session_exit(mt->se);
134  mt->error = res;
135  }
136  break;
137  }
138 
139  pthread_mutex_lock(&mt->lock);
140  if (mt->exit) {
141  pthread_mutex_unlock(&mt->lock);
142  return NULL;
143  }
144 
145  /*
146  * This disgusting hack is needed so that zillions of threads
147  * are not created on a burst of FORGET messages
148  */
149  if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) {
150  struct fuse_in_header *in = w->fbuf.mem;
151 
152  if (in->opcode == FUSE_FORGET ||
153  in->opcode == FUSE_BATCH_FORGET)
154  isforget = 1;
155  }
156 
157  if (!isforget)
158  mt->numavail--;
159  if (mt->numavail == 0)
160  fuse_loop_start_thread(mt);
161  pthread_mutex_unlock(&mt->lock);
162 
163  fuse_session_process_buf_int(mt->se, &w->fbuf, w->ch);
164 
165  pthread_mutex_lock(&mt->lock);
166  if (!isforget)
167  mt->numavail++;
168  if (mt->numavail > mt->max_idle) {
169  if (mt->exit) {
170  pthread_mutex_unlock(&mt->lock);
171  return NULL;
172  }
173  list_del_worker(w);
174  mt->numavail--;
175  mt->numworker--;
176  pthread_mutex_unlock(&mt->lock);
177 
178  pthread_detach(w->thread_id);
179  free(w->fbuf.mem);
180  fuse_chan_put(w->ch);
181  free(w);
182  return NULL;
183  }
184  pthread_mutex_unlock(&mt->lock);
185  }
186 
187  sem_post(&mt->finish);
188 
189  return NULL;
190 }
191 
192 int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg)
193 {
194  sigset_t oldset;
195  sigset_t newset;
196  int res;
197  pthread_attr_t attr;
198  char *stack_size;
199 
200  /* Override default stack size */
201  pthread_attr_init(&attr);
202  stack_size = getenv(ENVNAME_THREAD_STACK);
203  if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size)))
204  fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size);
205 
206  /* Disallow signal reception in worker threads */
207  sigemptyset(&newset);
208  sigaddset(&newset, SIGTERM);
209  sigaddset(&newset, SIGINT);
210  sigaddset(&newset, SIGHUP);
211  sigaddset(&newset, SIGQUIT);
212  pthread_sigmask(SIG_BLOCK, &newset, &oldset);
213  res = pthread_create(thread_id, &attr, func, arg);
214  pthread_sigmask(SIG_SETMASK, &oldset, NULL);
215  pthread_attr_destroy(&attr);
216  if (res != 0) {
217  fprintf(stderr, "fuse: error creating thread: %s\n",
218  strerror(res));
219  return -1;
220  }
221 
222  return 0;
223 }
224 
225 static struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt)
226 {
227  int res;
228  int clonefd;
229  uint32_t masterfd;
230  struct fuse_chan *newch;
231  const char *devname = "/dev/fuse";
232 
233 #ifndef O_CLOEXEC
234 #define O_CLOEXEC 0
235 #endif
236  clonefd = open(devname, O_RDWR | O_CLOEXEC);
237  if (clonefd == -1) {
238  fprintf(stderr, "fuse: failed to open %s: %s\n", devname,
239  strerror(errno));
240  return NULL;
241  }
242  fcntl(clonefd, F_SETFD, FD_CLOEXEC);
243 
244  masterfd = mt->se->fd;
245  res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd);
246  if (res == -1) {
247  fprintf(stderr, "fuse: failed to clone device fd: %s\n",
248  strerror(errno));
249  close(clonefd);
250  return NULL;
251  }
252  newch = fuse_chan_new(clonefd);
253  if (newch == NULL)
254  close(clonefd);
255 
256  return newch;
257 }
258 
259 static int fuse_loop_start_thread(struct fuse_mt *mt)
260 {
261  int res;
262 
263  struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
264  if (!w) {
265  fprintf(stderr, "fuse: failed to allocate worker structure\n");
266  return -1;
267  }
268  memset(w, 0, sizeof(struct fuse_worker));
269  w->fbuf.mem = NULL;
270  w->mt = mt;
271 
272  w->ch = NULL;
273  if (mt->clone_fd) {
274  w->ch = fuse_clone_chan(mt);
275  if(!w->ch) {
276  /* Don't attempt this again */
277  fprintf(stderr, "fuse: trying to continue "
278  "without -o clone_fd.\n");
279  mt->clone_fd = 0;
280  }
281  }
282 
283  res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
284  if (res == -1) {
285  fuse_chan_put(w->ch);
286  free(w);
287  return -1;
288  }
289  list_add_worker(w, &mt->main);
290  mt->numavail ++;
291  mt->numworker ++;
292 
293  return 0;
294 }
295 
296 static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
297 {
298  pthread_join(w->thread_id, NULL);
299  pthread_mutex_lock(&mt->lock);
300  list_del_worker(w);
301  pthread_mutex_unlock(&mt->lock);
302  free(w->fbuf.mem);
303  fuse_chan_put(w->ch);
304  free(w);
305 }
306 
307 FUSE_SYMVER(".symver fuse_session_loop_mt_32,fuse_session_loop_mt@@FUSE_3.2");
308 int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config)
309 {
310  int err;
311  struct fuse_mt mt;
312  struct fuse_worker *w;
313 
314  memset(&mt, 0, sizeof(struct fuse_mt));
315  mt.se = se;
316  mt.clone_fd = config->clone_fd;
317  mt.error = 0;
318  mt.numworker = 0;
319  mt.numavail = 0;
320  mt.max_idle = config->max_idle_threads;
321  mt.main.thread_id = pthread_self();
322  mt.main.prev = mt.main.next = &mt.main;
323  sem_init(&mt.finish, 0, 0);
324  fuse_mutex_init(&mt.lock);
325 
326  pthread_mutex_lock(&mt.lock);
327  err = fuse_loop_start_thread(&mt);
328  pthread_mutex_unlock(&mt.lock);
329  if (!err) {
330  /* sem_wait() is interruptible */
331  while (!fuse_session_exited(se))
332  sem_wait(&mt.finish);
333 
334  pthread_mutex_lock(&mt.lock);
335  for (w = mt.main.next; w != &mt.main; w = w->next)
336  pthread_cancel(w->thread_id);
337  mt.exit = 1;
338  pthread_mutex_unlock(&mt.lock);
339 
340  while (mt.main.next != &mt.main)
341  fuse_join_worker(&mt, mt.main.next);
342 
343  err = mt.error;
344  }
345 
346  pthread_mutex_destroy(&mt.lock);
347  sem_destroy(&mt.finish);
348  if(se->error != 0)
349  err = se->error;
350  fuse_session_reset(se);
351  return err;
352 }
353 
354 int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
355 FUSE_SYMVER(".symver fuse_session_loop_mt_31,fuse_session_loop_mt@FUSE_3.0");
356 int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd)
357 {
358  struct fuse_loop_config config;
359  config.clone_fd = clone_fd;
360  config.max_idle_threads = 10;
361  return fuse_session_loop_mt_32(se, &config);
362 }
void fuse_session_exit(struct fuse_session *se)
+ +
unsigned int max_idle_threads
Definition: fuse_common.h:103
+
int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd)
Definition: fuse_loop_mt.c:356
+
int fuse_session_exited(struct fuse_session *se)
+
void fuse_session_reset(struct fuse_session *se)
+ + + + +
+ + + + diff --git a/doc/html/fuse__lowlevel_8c_source.html b/doc/html/fuse__lowlevel_8c_source.html new file mode 100644 index 0000000..1b4f858 --- /dev/null +++ b/doc/html/fuse__lowlevel_8c_source.html @@ -0,0 +1,168 @@ + + + + + + + +libfuse: lib/fuse_lowlevel.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_lowlevel.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Implementation of (most of) the low-level FUSE API. The session loop
6  functions are implemented in separate files.
7 
8  This program can be distributed under the terms of the GNU LGPLv2.
9  See the file COPYING.LIB
10 */
11 
12 #define _GNU_SOURCE
13 
14 #include "config.h"
15 #include "fuse_i.h"
16 #include "fuse_kernel.h"
17 #include "fuse_opt.h"
18 #include "fuse_misc.h"
19 #include "mount_util.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <limits.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <sys/file.h>
30 
31 #ifndef F_LINUX_SPECIFIC_BASE
32 #define F_LINUX_SPECIFIC_BASE 1024
33 #endif
34 #ifndef F_SETPIPE_SZ
35 #define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
36 #endif
37 
38 
39 #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
40 #define OFFSET_MAX 0x7fffffffffffffffLL
41 
42 #define container_of(ptr, type, member) ({ \
43  const typeof( ((type *)0)->member ) *__mptr = (ptr); \
44  (type *)( (char *)__mptr - offsetof(type,member) );})
45 
46 struct fuse_pollhandle {
47  uint64_t kh;
48  struct fuse_session *se;
49 };
50 
51 static size_t pagesize;
52 
53 static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
54 {
55  pagesize = getpagesize();
56 }
57 
58 static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
59 {
60  attr->ino = stbuf->st_ino;
61  attr->mode = stbuf->st_mode;
62  attr->nlink = stbuf->st_nlink;
63  attr->uid = stbuf->st_uid;
64  attr->gid = stbuf->st_gid;
65  attr->rdev = stbuf->st_rdev;
66  attr->size = stbuf->st_size;
67  attr->blksize = stbuf->st_blksize;
68  attr->blocks = stbuf->st_blocks;
69  attr->atime = stbuf->st_atime;
70  attr->mtime = stbuf->st_mtime;
71  attr->ctime = stbuf->st_ctime;
72  attr->atimensec = ST_ATIM_NSEC(stbuf);
73  attr->mtimensec = ST_MTIM_NSEC(stbuf);
74  attr->ctimensec = ST_CTIM_NSEC(stbuf);
75 }
76 
77 static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
78 {
79  stbuf->st_mode = attr->mode;
80  stbuf->st_uid = attr->uid;
81  stbuf->st_gid = attr->gid;
82  stbuf->st_size = attr->size;
83  stbuf->st_atime = attr->atime;
84  stbuf->st_mtime = attr->mtime;
85  stbuf->st_ctime = attr->ctime;
86  ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
87  ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
88  ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
89 }
90 
91 static size_t iov_length(const struct iovec *iov, size_t count)
92 {
93  size_t seg;
94  size_t ret = 0;
95 
96  for (seg = 0; seg < count; seg++)
97  ret += iov[seg].iov_len;
98  return ret;
99 }
100 
101 static void list_init_req(struct fuse_req *req)
102 {
103  req->next = req;
104  req->prev = req;
105 }
106 
107 static void list_del_req(struct fuse_req *req)
108 {
109  struct fuse_req *prev = req->prev;
110  struct fuse_req *next = req->next;
111  prev->next = next;
112  next->prev = prev;
113 }
114 
115 static void list_add_req(struct fuse_req *req, struct fuse_req *next)
116 {
117  struct fuse_req *prev = next->prev;
118  req->next = next;
119  req->prev = prev;
120  prev->next = req;
121  next->prev = req;
122 }
123 
124 static void destroy_req(fuse_req_t req)
125 {
126  pthread_mutex_destroy(&req->lock);
127  free(req);
128 }
129 
130 void fuse_free_req(fuse_req_t req)
131 {
132  int ctr;
133  struct fuse_session *se = req->se;
134 
135  pthread_mutex_lock(&se->lock);
136  req->u.ni.func = NULL;
137  req->u.ni.data = NULL;
138  list_del_req(req);
139  ctr = --req->ctr;
140  fuse_chan_put(req->ch);
141  req->ch = NULL;
142  pthread_mutex_unlock(&se->lock);
143  if (!ctr)
144  destroy_req(req);
145 }
146 
147 static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
148 {
149  struct fuse_req *req;
150 
151  req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
152  if (req == NULL) {
153  fprintf(stderr, "fuse: failed to allocate request\n");
154  } else {
155  req->se = se;
156  req->ctr = 1;
157  list_init_req(req);
158  fuse_mutex_init(&req->lock);
159  }
160 
161  return req;
162 }
163 
164 /* Send data. If *ch* is NULL, send via session master fd */
165 static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
166  struct iovec *iov, int count)
167 {
168  struct fuse_out_header *out = iov[0].iov_base;
169 
170  out->len = iov_length(iov, count);
171  if (se->debug) {
172  if (out->unique == 0) {
173  fprintf(stderr, "NOTIFY: code=%d length=%u\n",
174  out->error, out->len);
175  } else if (out->error) {
176  fprintf(stderr,
177  " unique: %llu, error: %i (%s), outsize: %i\n",
178  (unsigned long long) out->unique, out->error,
179  strerror(-out->error), out->len);
180  } else {
181  fprintf(stderr,
182  " unique: %llu, success, outsize: %i\n",
183  (unsigned long long) out->unique, out->len);
184  }
185  }
186 
187  ssize_t res = writev(ch ? ch->fd : se->fd,
188  iov, count);
189  int err = errno;
190 
191  if (res == -1) {
192  assert(se != NULL);
193 
194  /* ENOENT means the operation was interrupted */
195  if (!fuse_session_exited(se) && err != ENOENT)
196  perror("fuse: writing device");
197  return -err;
198  }
199 
200  return 0;
201 }
202 
203 
204 int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
205  int count)
206 {
207  struct fuse_out_header out;
208 
209  if (error <= -1000 || error > 0) {
210  fprintf(stderr, "fuse: bad error value: %i\n", error);
211  error = -ERANGE;
212  }
213 
214  out.unique = req->unique;
215  out.error = error;
216 
217  iov[0].iov_base = &out;
218  iov[0].iov_len = sizeof(struct fuse_out_header);
219 
220  return fuse_send_msg(req->se, req->ch, iov, count);
221 }
222 
223 static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
224  int count)
225 {
226  int res;
227 
228  res = fuse_send_reply_iov_nofree(req, error, iov, count);
229  fuse_free_req(req);
230  return res;
231 }
232 
233 static int send_reply(fuse_req_t req, int error, const void *arg,
234  size_t argsize)
235 {
236  struct iovec iov[2];
237  int count = 1;
238  if (argsize) {
239  iov[1].iov_base = (void *) arg;
240  iov[1].iov_len = argsize;
241  count++;
242  }
243  return send_reply_iov(req, error, iov, count);
244 }
245 
246 int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
247 {
248  int res;
249  struct iovec *padded_iov;
250 
251  padded_iov = malloc((count + 1) * sizeof(struct iovec));
252  if (padded_iov == NULL)
253  return fuse_reply_err(req, ENOMEM);
254 
255  memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
256  count++;
257 
258  res = send_reply_iov(req, 0, padded_iov, count);
259  free(padded_iov);
260 
261  return res;
262 }
263 
264 
265 /* `buf` is allowed to be empty so that the proper size may be
266  allocated by the caller */
267 size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
268  const char *name, const struct stat *stbuf, off_t off)
269 {
270  (void)req;
271  size_t namelen;
272  size_t entlen;
273  size_t entlen_padded;
274  struct fuse_dirent *dirent;
275 
276  namelen = strlen(name);
277  entlen = FUSE_NAME_OFFSET + namelen;
278  entlen_padded = FUSE_DIRENT_ALIGN(entlen);
279 
280  if ((buf == NULL) || (entlen_padded > bufsize))
281  return entlen_padded;
282 
283  dirent = (struct fuse_dirent*) buf;
284  dirent->ino = stbuf->st_ino;
285  dirent->off = off;
286  dirent->namelen = namelen;
287  dirent->type = (stbuf->st_mode & 0170000) >> 12;
288  strncpy(dirent->name, name, namelen);
289  memset(dirent->name + namelen, 0, entlen_padded - entlen);
290 
291  return entlen_padded;
292 }
293 
294 static void convert_statfs(const struct statvfs *stbuf,
295  struct fuse_kstatfs *kstatfs)
296 {
297  kstatfs->bsize = stbuf->f_bsize;
298  kstatfs->frsize = stbuf->f_frsize;
299  kstatfs->blocks = stbuf->f_blocks;
300  kstatfs->bfree = stbuf->f_bfree;
301  kstatfs->bavail = stbuf->f_bavail;
302  kstatfs->files = stbuf->f_files;
303  kstatfs->ffree = stbuf->f_ffree;
304  kstatfs->namelen = stbuf->f_namemax;
305 }
306 
307 static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
308 {
309  return send_reply(req, 0, arg, argsize);
310 }
311 
312 int fuse_reply_err(fuse_req_t req, int err)
313 {
314  return send_reply(req, -err, NULL, 0);
315 }
316 
318 {
319  fuse_free_req(req);
320 }
321 
322 static unsigned long calc_timeout_sec(double t)
323 {
324  if (t > (double) ULONG_MAX)
325  return ULONG_MAX;
326  else if (t < 0.0)
327  return 0;
328  else
329  return (unsigned long) t;
330 }
331 
332 static unsigned int calc_timeout_nsec(double t)
333 {
334  double f = t - (double) calc_timeout_sec(t);
335  if (f < 0.0)
336  return 0;
337  else if (f >= 0.999999999)
338  return 999999999;
339  else
340  return (unsigned int) (f * 1.0e9);
341 }
342 
343 static void fill_entry(struct fuse_entry_out *arg,
344  const struct fuse_entry_param *e)
345 {
346  arg->nodeid = e->ino;
347  arg->generation = e->generation;
348  arg->entry_valid = calc_timeout_sec(e->entry_timeout);
349  arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
350  arg->attr_valid = calc_timeout_sec(e->attr_timeout);
351  arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
352  convert_stat(&e->attr, &arg->attr);
353 }
354 
355 /* `buf` is allowed to be empty so that the proper size may be
356  allocated by the caller */
357 size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
358  const char *name,
359  const struct fuse_entry_param *e, off_t off)
360 {
361  (void)req;
362  size_t namelen;
363  size_t entlen;
364  size_t entlen_padded;
365 
366  namelen = strlen(name);
367  entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
368  entlen_padded = FUSE_DIRENT_ALIGN(entlen);
369  if ((buf == NULL) || (entlen_padded > bufsize))
370  return entlen_padded;
371 
372  struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
373  memset(&dp->entry_out, 0, sizeof(dp->entry_out));
374  fill_entry(&dp->entry_out, e);
375 
376  struct fuse_dirent *dirent = &dp->dirent;
377  dirent->ino = e->attr.st_ino;
378  dirent->off = off;
379  dirent->namelen = namelen;
380  dirent->type = (e->attr.st_mode & 0170000) >> 12;
381  strncpy(dirent->name, name, namelen);
382  memset(dirent->name + namelen, 0, entlen_padded - entlen);
383 
384  return entlen_padded;
385 }
386 
387 static void fill_open(struct fuse_open_out *arg,
388  const struct fuse_file_info *f)
389 {
390  arg->fh = f->fh;
391  if (f->direct_io)
392  arg->open_flags |= FOPEN_DIRECT_IO;
393  if (f->keep_cache)
394  arg->open_flags |= FOPEN_KEEP_CACHE;
395  if (f->nonseekable)
396  arg->open_flags |= FOPEN_NONSEEKABLE;
397 }
398 
400 {
401  struct fuse_entry_out arg;
402  size_t size = req->se->conn.proto_minor < 9 ?
403  FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
404 
405  /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
406  negative entry */
407  if (!e->ino && req->se->conn.proto_minor < 4)
408  return fuse_reply_err(req, ENOENT);
409 
410  memset(&arg, 0, sizeof(arg));
411  fill_entry(&arg, e);
412  return send_reply_ok(req, &arg, size);
413 }
414 
416  const struct fuse_file_info *f)
417 {
418  char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
419  size_t entrysize = req->se->conn.proto_minor < 9 ?
420  FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
421  struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
422  struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
423 
424  memset(buf, 0, sizeof(buf));
425  fill_entry(earg, e);
426  fill_open(oarg, f);
427  return send_reply_ok(req, buf,
428  entrysize + sizeof(struct fuse_open_out));
429 }
430 
431 int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
432  double attr_timeout)
433 {
434  struct fuse_attr_out arg;
435  size_t size = req->se->conn.proto_minor < 9 ?
436  FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
437 
438  memset(&arg, 0, sizeof(arg));
439  arg.attr_valid = calc_timeout_sec(attr_timeout);
440  arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
441  convert_stat(attr, &arg.attr);
442 
443  return send_reply_ok(req, &arg, size);
444 }
445 
446 int fuse_reply_readlink(fuse_req_t req, const char *linkname)
447 {
448  return send_reply_ok(req, linkname, strlen(linkname));
449 }
450 
451 int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
452 {
453  struct fuse_open_out arg;
454 
455  memset(&arg, 0, sizeof(arg));
456  fill_open(&arg, f);
457  return send_reply_ok(req, &arg, sizeof(arg));
458 }
459 
460 int fuse_reply_write(fuse_req_t req, size_t count)
461 {
462  struct fuse_write_out arg;
463 
464  memset(&arg, 0, sizeof(arg));
465  arg.size = count;
466 
467  return send_reply_ok(req, &arg, sizeof(arg));
468 }
469 
470 int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
471 {
472  return send_reply_ok(req, buf, size);
473 }
474 
475 static int fuse_send_data_iov_fallback(struct fuse_session *se,
476  struct fuse_chan *ch,
477  struct iovec *iov, int iov_count,
478  struct fuse_bufvec *buf,
479  size_t len)
480 {
481  struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
482  void *mbuf;
483  int res;
484 
485  /* Optimize common case */
486  if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
487  !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
488  /* FIXME: also avoid memory copy if there are multiple buffers
489  but none of them contain an fd */
490 
491  iov[iov_count].iov_base = buf->buf[0].mem;
492  iov[iov_count].iov_len = len;
493  iov_count++;
494  return fuse_send_msg(se, ch, iov, iov_count);
495  }
496 
497  res = posix_memalign(&mbuf, pagesize, len);
498  if (res != 0)
499  return res;
500 
501  mem_buf.buf[0].mem = mbuf;
502  res = fuse_buf_copy(&mem_buf, buf, 0);
503  if (res < 0) {
504  free(mbuf);
505  return -res;
506  }
507  len = res;
508 
509  iov[iov_count].iov_base = mbuf;
510  iov[iov_count].iov_len = len;
511  iov_count++;
512  res = fuse_send_msg(se, ch, iov, iov_count);
513  free(mbuf);
514 
515  return res;
516 }
517 
518 struct fuse_ll_pipe {
519  size_t size;
520  int can_grow;
521  int pipe[2];
522 };
523 
524 static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
525 {
526  close(llp->pipe[0]);
527  close(llp->pipe[1]);
528  free(llp);
529 }
530 
531 #ifdef HAVE_SPLICE
532 #if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
533 static int fuse_pipe(int fds[2])
534 {
535  int rv = pipe(fds);
536 
537  if (rv == -1)
538  return rv;
539 
540  if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
541  fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
542  fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
543  fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
544  close(fds[0]);
545  close(fds[1]);
546  rv = -1;
547  }
548  return rv;
549 }
550 #else
551 static int fuse_pipe(int fds[2])
552 {
553  return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
554 }
555 #endif
556 
557 static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
558 {
559  struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
560  if (llp == NULL) {
561  int res;
562 
563  llp = malloc(sizeof(struct fuse_ll_pipe));
564  if (llp == NULL)
565  return NULL;
566 
567  res = fuse_pipe(llp->pipe);
568  if (res == -1) {
569  free(llp);
570  return NULL;
571  }
572 
573  /*
574  *the default size is 16 pages on linux
575  */
576  llp->size = pagesize * 16;
577  llp->can_grow = 1;
578 
579  pthread_setspecific(se->pipe_key, llp);
580  }
581 
582  return llp;
583 }
584 #endif
585 
586 static void fuse_ll_clear_pipe(struct fuse_session *se)
587 {
588  struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
589  if (llp) {
590  pthread_setspecific(se->pipe_key, NULL);
591  fuse_ll_pipe_free(llp);
592  }
593 }
594 
595 #if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
596 static int read_back(int fd, char *buf, size_t len)
597 {
598  int res;
599 
600  res = read(fd, buf, len);
601  if (res == -1) {
602  fprintf(stderr, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno));
603  return -EIO;
604  }
605  if (res != len) {
606  fprintf(stderr, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len);
607  return -EIO;
608  }
609  return 0;
610 }
611 
612 static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
613  struct iovec *iov, int iov_count,
614  struct fuse_bufvec *buf, unsigned int flags)
615 {
616  int res;
617  size_t len = fuse_buf_size(buf);
618  struct fuse_out_header *out = iov[0].iov_base;
619  struct fuse_ll_pipe *llp;
620  int splice_flags;
621  size_t pipesize;
622  size_t total_fd_size;
623  size_t idx;
624  size_t headerlen;
625  struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
626 
627  if (se->broken_splice_nonblock)
628  goto fallback;
629 
630  if (flags & FUSE_BUF_NO_SPLICE)
631  goto fallback;
632 
633  total_fd_size = 0;
634  for (idx = buf->idx; idx < buf->count; idx++) {
635  if (buf->buf[idx].flags & FUSE_BUF_IS_FD) {
636  total_fd_size = buf->buf[idx].size;
637  if (idx == buf->idx)
638  total_fd_size -= buf->off;
639  }
640  }
641  if (total_fd_size < 2 * pagesize)
642  goto fallback;
643 
644  if (se->conn.proto_minor < 14 ||
645  !(se->conn.want & FUSE_CAP_SPLICE_WRITE))
646  goto fallback;
647 
648  llp = fuse_ll_get_pipe(se);
649  if (llp == NULL)
650  goto fallback;
651 
652 
653  headerlen = iov_length(iov, iov_count);
654 
655  out->len = headerlen + len;
656 
657  /*
658  * Heuristic for the required pipe size, does not work if the
659  * source contains less than page size fragments
660  */
661  pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
662 
663  if (llp->size < pipesize) {
664  if (llp->can_grow) {
665  res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
666  if (res == -1) {
667  llp->can_grow = 0;
668  goto fallback;
669  }
670  llp->size = res;
671  }
672  if (llp->size < pipesize)
673  goto fallback;
674  }
675 
676 
677  res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
678  if (res == -1)
679  goto fallback;
680 
681  if (res != headerlen) {
682  res = -EIO;
683  fprintf(stderr, "fuse: short vmsplice to pipe: %u/%zu\n", res,
684  headerlen);
685  goto clear_pipe;
686  }
687 
688  pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
689  pipe_buf.buf[0].fd = llp->pipe[1];
690 
691  res = fuse_buf_copy(&pipe_buf, buf,
693  if (res < 0) {
694  if (res == -EAGAIN || res == -EINVAL) {
695  /*
696  * Should only get EAGAIN on kernels with
697  * broken SPLICE_F_NONBLOCK support (<=
698  * 2.6.35) where this error or a short read is
699  * returned even if the pipe itself is not
700  * full
701  *
702  * EINVAL might mean that splice can't handle
703  * this combination of input and output.
704  */
705  if (res == -EAGAIN)
706  se->broken_splice_nonblock = 1;
707 
708  pthread_setspecific(se->pipe_key, NULL);
709  fuse_ll_pipe_free(llp);
710  goto fallback;
711  }
712  res = -res;
713  goto clear_pipe;
714  }
715 
716  if (res != 0 && res < len) {
717  struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
718  void *mbuf;
719  size_t now_len = res;
720  /*
721  * For regular files a short count is either
722  * 1) due to EOF, or
723  * 2) because of broken SPLICE_F_NONBLOCK (see above)
724  *
725  * For other inputs it's possible that we overflowed
726  * the pipe because of small buffer fragments.
727  */
728 
729  res = posix_memalign(&mbuf, pagesize, len);
730  if (res != 0)
731  goto clear_pipe;
732 
733  mem_buf.buf[0].mem = mbuf;
734  mem_buf.off = now_len;
735  res = fuse_buf_copy(&mem_buf, buf, 0);
736  if (res > 0) {
737  char *tmpbuf;
738  size_t extra_len = res;
739  /*
740  * Trickiest case: got more data. Need to get
741  * back the data from the pipe and then fall
742  * back to regular write.
743  */
744  tmpbuf = malloc(headerlen);
745  if (tmpbuf == NULL) {
746  free(mbuf);
747  res = ENOMEM;
748  goto clear_pipe;
749  }
750  res = read_back(llp->pipe[0], tmpbuf, headerlen);
751  free(tmpbuf);
752  if (res != 0) {
753  free(mbuf);
754  goto clear_pipe;
755  }
756  res = read_back(llp->pipe[0], mbuf, now_len);
757  if (res != 0) {
758  free(mbuf);
759  goto clear_pipe;
760  }
761  len = now_len + extra_len;
762  iov[iov_count].iov_base = mbuf;
763  iov[iov_count].iov_len = len;
764  iov_count++;
765  res = fuse_send_msg(se, ch, iov, iov_count);
766  free(mbuf);
767  return res;
768  }
769  free(mbuf);
770  res = now_len;
771  }
772  len = res;
773  out->len = headerlen + len;
774 
775  if (se->debug) {
776  fprintf(stderr,
777  " unique: %llu, success, outsize: %i (splice)\n",
778  (unsigned long long) out->unique, out->len);
779  }
780 
781  splice_flags = 0;
782  if ((flags & FUSE_BUF_SPLICE_MOVE) &&
783  (se->conn.want & FUSE_CAP_SPLICE_MOVE))
784  splice_flags |= SPLICE_F_MOVE;
785 
786  res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd,
787  NULL, out->len, splice_flags);
788  if (res == -1) {
789  res = -errno;
790  perror("fuse: splice from pipe");
791  goto clear_pipe;
792  }
793  if (res != out->len) {
794  res = -EIO;
795  fprintf(stderr, "fuse: short splice from pipe: %u/%u\n",
796  res, out->len);
797  goto clear_pipe;
798  }
799  return 0;
800 
801 clear_pipe:
802  fuse_ll_clear_pipe(se);
803  return res;
804 
805 fallback:
806  return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
807 }
808 #else
809 static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
810  struct iovec *iov, int iov_count,
811  struct fuse_bufvec *buf, unsigned int flags)
812 {
813  size_t len = fuse_buf_size(buf);
814  (void) flags;
815 
816  return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
817 }
818 #endif
819 
820 int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
821  enum fuse_buf_copy_flags flags)
822 {
823  struct iovec iov[2];
824  struct fuse_out_header out;
825  int res;
826 
827  iov[0].iov_base = &out;
828  iov[0].iov_len = sizeof(struct fuse_out_header);
829 
830  out.unique = req->unique;
831  out.error = 0;
832 
833  res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
834  if (res <= 0) {
835  fuse_free_req(req);
836  return res;
837  } else {
838  return fuse_reply_err(req, res);
839  }
840 }
841 
842 int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
843 {
844  struct fuse_statfs_out arg;
845  size_t size = req->se->conn.proto_minor < 4 ?
846  FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
847 
848  memset(&arg, 0, sizeof(arg));
849  convert_statfs(stbuf, &arg.st);
850 
851  return send_reply_ok(req, &arg, size);
852 }
853 
854 int fuse_reply_xattr(fuse_req_t req, size_t count)
855 {
856  struct fuse_getxattr_out arg;
857 
858  memset(&arg, 0, sizeof(arg));
859  arg.size = count;
860 
861  return send_reply_ok(req, &arg, sizeof(arg));
862 }
863 
864 int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
865 {
866  struct fuse_lk_out arg;
867 
868  memset(&arg, 0, sizeof(arg));
869  arg.lk.type = lock->l_type;
870  if (lock->l_type != F_UNLCK) {
871  arg.lk.start = lock->l_start;
872  if (lock->l_len == 0)
873  arg.lk.end = OFFSET_MAX;
874  else
875  arg.lk.end = lock->l_start + lock->l_len - 1;
876  }
877  arg.lk.pid = lock->l_pid;
878  return send_reply_ok(req, &arg, sizeof(arg));
879 }
880 
881 int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
882 {
883  struct fuse_bmap_out arg;
884 
885  memset(&arg, 0, sizeof(arg));
886  arg.block = idx;
887 
888  return send_reply_ok(req, &arg, sizeof(arg));
889 }
890 
891 static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
892  size_t count)
893 {
894  struct fuse_ioctl_iovec *fiov;
895  size_t i;
896 
897  fiov = malloc(sizeof(fiov[0]) * count);
898  if (!fiov)
899  return NULL;
900 
901  for (i = 0; i < count; i++) {
902  fiov[i].base = (uintptr_t) iov[i].iov_base;
903  fiov[i].len = iov[i].iov_len;
904  }
905 
906  return fiov;
907 }
908 
910  const struct iovec *in_iov, size_t in_count,
911  const struct iovec *out_iov, size_t out_count)
912 {
913  struct fuse_ioctl_out arg;
914  struct fuse_ioctl_iovec *in_fiov = NULL;
915  struct fuse_ioctl_iovec *out_fiov = NULL;
916  struct iovec iov[4];
917  size_t count = 1;
918  int res;
919 
920  memset(&arg, 0, sizeof(arg));
921  arg.flags |= FUSE_IOCTL_RETRY;
922  arg.in_iovs = in_count;
923  arg.out_iovs = out_count;
924  iov[count].iov_base = &arg;
925  iov[count].iov_len = sizeof(arg);
926  count++;
927 
928  if (req->se->conn.proto_minor < 16) {
929  if (in_count) {
930  iov[count].iov_base = (void *)in_iov;
931  iov[count].iov_len = sizeof(in_iov[0]) * in_count;
932  count++;
933  }
934 
935  if (out_count) {
936  iov[count].iov_base = (void *)out_iov;
937  iov[count].iov_len = sizeof(out_iov[0]) * out_count;
938  count++;
939  }
940  } else {
941  /* Can't handle non-compat 64bit ioctls on 32bit */
942  if (sizeof(void *) == 4 && req->ioctl_64bit) {
943  res = fuse_reply_err(req, EINVAL);
944  goto out;
945  }
946 
947  if (in_count) {
948  in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
949  if (!in_fiov)
950  goto enomem;
951 
952  iov[count].iov_base = (void *)in_fiov;
953  iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
954  count++;
955  }
956  if (out_count) {
957  out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
958  if (!out_fiov)
959  goto enomem;
960 
961  iov[count].iov_base = (void *)out_fiov;
962  iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
963  count++;
964  }
965  }
966 
967  res = send_reply_iov(req, 0, iov, count);
968 out:
969  free(in_fiov);
970  free(out_fiov);
971 
972  return res;
973 
974 enomem:
975  res = fuse_reply_err(req, ENOMEM);
976  goto out;
977 }
978 
979 int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
980 {
981  struct fuse_ioctl_out arg;
982  struct iovec iov[3];
983  size_t count = 1;
984 
985  memset(&arg, 0, sizeof(arg));
986  arg.result = result;
987  iov[count].iov_base = &arg;
988  iov[count].iov_len = sizeof(arg);
989  count++;
990 
991  if (size) {
992  iov[count].iov_base = (char *) buf;
993  iov[count].iov_len = size;
994  count++;
995  }
996 
997  return send_reply_iov(req, 0, iov, count);
998 }
999 
1000 int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
1001  int count)
1002 {
1003  struct iovec *padded_iov;
1004  struct fuse_ioctl_out arg;
1005  int res;
1006 
1007  padded_iov = malloc((count + 2) * sizeof(struct iovec));
1008  if (padded_iov == NULL)
1009  return fuse_reply_err(req, ENOMEM);
1010 
1011  memset(&arg, 0, sizeof(arg));
1012  arg.result = result;
1013  padded_iov[1].iov_base = &arg;
1014  padded_iov[1].iov_len = sizeof(arg);
1015 
1016  memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
1017 
1018  res = send_reply_iov(req, 0, padded_iov, count + 2);
1019  free(padded_iov);
1020 
1021  return res;
1022 }
1023 
1024 int fuse_reply_poll(fuse_req_t req, unsigned revents)
1025 {
1026  struct fuse_poll_out arg;
1027 
1028  memset(&arg, 0, sizeof(arg));
1029  arg.revents = revents;
1030 
1031  return send_reply_ok(req, &arg, sizeof(arg));
1032 }
1033 
1034 static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1035 {
1036  char *name = (char *) inarg;
1037 
1038  if (req->se->op.lookup)
1039  req->se->op.lookup(req, nodeid, name);
1040  else
1041  fuse_reply_err(req, ENOSYS);
1042 }
1043 
1044 static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1045 {
1046  struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
1047 
1048  if (req->se->op.forget)
1049  req->se->op.forget(req, nodeid, arg->nlookup);
1050  else
1051  fuse_reply_none(req);
1052 }
1053 
1054 static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
1055  const void *inarg)
1056 {
1057  struct fuse_batch_forget_in *arg = (void *) inarg;
1058  struct fuse_forget_one *param = (void *) PARAM(arg);
1059  unsigned int i;
1060 
1061  (void) nodeid;
1062 
1063  if (req->se->op.forget_multi) {
1064  req->se->op.forget_multi(req, arg->count,
1065  (struct fuse_forget_data *) param);
1066  } else if (req->se->op.forget) {
1067  for (i = 0; i < arg->count; i++) {
1068  struct fuse_forget_one *forget = &param[i];
1069  struct fuse_req *dummy_req;
1070 
1071  dummy_req = fuse_ll_alloc_req(req->se);
1072  if (dummy_req == NULL)
1073  break;
1074 
1075  dummy_req->unique = req->unique;
1076  dummy_req->ctx = req->ctx;
1077  dummy_req->ch = NULL;
1078 
1079  req->se->op.forget(dummy_req, forget->nodeid,
1080  forget->nlookup);
1081  }
1082  fuse_reply_none(req);
1083  } else {
1084  fuse_reply_none(req);
1085  }
1086 }
1087 
1088 static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1089 {
1090  struct fuse_file_info *fip = NULL;
1091  struct fuse_file_info fi;
1092 
1093  if (req->se->conn.proto_minor >= 9) {
1094  struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
1095 
1096  if (arg->getattr_flags & FUSE_GETATTR_FH) {
1097  memset(&fi, 0, sizeof(fi));
1098  fi.fh = arg->fh;
1099  fip = &fi;
1100  }
1101  }
1102 
1103  if (req->se->op.getattr)
1104  req->se->op.getattr(req, nodeid, fip);
1105  else
1106  fuse_reply_err(req, ENOSYS);
1107 }
1108 
1109 static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1110 {
1111  struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
1112 
1113  if (req->se->op.setattr) {
1114  struct fuse_file_info *fi = NULL;
1115  struct fuse_file_info fi_store;
1116  struct stat stbuf;
1117  memset(&stbuf, 0, sizeof(stbuf));
1118  convert_attr(arg, &stbuf);
1119  if (arg->valid & FATTR_FH) {
1120  arg->valid &= ~FATTR_FH;
1121  memset(&fi_store, 0, sizeof(fi_store));
1122  fi = &fi_store;
1123  fi->fh = arg->fh;
1124  }
1125  arg->valid &=
1126  FUSE_SET_ATTR_MODE |
1127  FUSE_SET_ATTR_UID |
1128  FUSE_SET_ATTR_GID |
1129  FUSE_SET_ATTR_SIZE |
1130  FUSE_SET_ATTR_ATIME |
1131  FUSE_SET_ATTR_MTIME |
1132  FUSE_SET_ATTR_ATIME_NOW |
1133  FUSE_SET_ATTR_MTIME_NOW |
1134  FUSE_SET_ATTR_CTIME;
1135 
1136  req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
1137  } else
1138  fuse_reply_err(req, ENOSYS);
1139 }
1140 
1141 static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1142 {
1143  struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
1144 
1145  if (req->se->op.access)
1146  req->se->op.access(req, nodeid, arg->mask);
1147  else
1148  fuse_reply_err(req, ENOSYS);
1149 }
1150 
1151 static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1152 {
1153  (void) inarg;
1154 
1155  if (req->se->op.readlink)
1156  req->se->op.readlink(req, nodeid);
1157  else
1158  fuse_reply_err(req, ENOSYS);
1159 }
1160 
1161 static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1162 {
1163  struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
1164  char *name = PARAM(arg);
1165 
1166  if (req->se->conn.proto_minor >= 12)
1167  req->ctx.umask = arg->umask;
1168  else
1169  name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
1170 
1171  if (req->se->op.mknod)
1172  req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
1173  else
1174  fuse_reply_err(req, ENOSYS);
1175 }
1176 
1177 static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1178 {
1179  struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
1180 
1181  if (req->se->conn.proto_minor >= 12)
1182  req->ctx.umask = arg->umask;
1183 
1184  if (req->se->op.mkdir)
1185  req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
1186  else
1187  fuse_reply_err(req, ENOSYS);
1188 }
1189 
1190 static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1191 {
1192  char *name = (char *) inarg;
1193 
1194  if (req->se->op.unlink)
1195  req->se->op.unlink(req, nodeid, name);
1196  else
1197  fuse_reply_err(req, ENOSYS);
1198 }
1199 
1200 static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1201 {
1202  char *name = (char *) inarg;
1203 
1204  if (req->se->op.rmdir)
1205  req->se->op.rmdir(req, nodeid, name);
1206  else
1207  fuse_reply_err(req, ENOSYS);
1208 }
1209 
1210 static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1211 {
1212  char *name = (char *) inarg;
1213  char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
1214 
1215  if (req->se->op.symlink)
1216  req->se->op.symlink(req, linkname, nodeid, name);
1217  else
1218  fuse_reply_err(req, ENOSYS);
1219 }
1220 
1221 static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1222 {
1223  struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
1224  char *oldname = PARAM(arg);
1225  char *newname = oldname + strlen(oldname) + 1;
1226 
1227  if (req->se->op.rename)
1228  req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1229  0);
1230  else
1231  fuse_reply_err(req, ENOSYS);
1232 }
1233 
1234 static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1235 {
1236  struct fuse_rename2_in *arg = (struct fuse_rename2_in *) inarg;
1237  char *oldname = PARAM(arg);
1238  char *newname = oldname + strlen(oldname) + 1;
1239 
1240  if (req->se->op.rename)
1241  req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1242  arg->flags);
1243  else
1244  fuse_reply_err(req, ENOSYS);
1245 }
1246 
1247 static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1248 {
1249  struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
1250 
1251  if (req->se->op.link)
1252  req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
1253  else
1254  fuse_reply_err(req, ENOSYS);
1255 }
1256 
1257 static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1258 {
1259  struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
1260 
1261  if (req->se->op.create) {
1262  struct fuse_file_info fi;
1263  char *name = PARAM(arg);
1264 
1265  memset(&fi, 0, sizeof(fi));
1266  fi.flags = arg->flags;
1267 
1268  if (req->se->conn.proto_minor >= 12)
1269  req->ctx.umask = arg->umask;
1270  else
1271  name = (char *) inarg + sizeof(struct fuse_open_in);
1272 
1273  req->se->op.create(req, nodeid, name, arg->mode, &fi);
1274  } else
1275  fuse_reply_err(req, ENOSYS);
1276 }
1277 
1278 static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1279 {
1280  struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
1281  struct fuse_file_info fi;
1282 
1283  memset(&fi, 0, sizeof(fi));
1284  fi.flags = arg->flags;
1285 
1286  if (req->se->op.open)
1287  req->se->op.open(req, nodeid, &fi);
1288  else
1289  fuse_reply_open(req, &fi);
1290 }
1291 
1292 static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1293 {
1294  struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1295 
1296  if (req->se->op.read) {
1297  struct fuse_file_info fi;
1298 
1299  memset(&fi, 0, sizeof(fi));
1300  fi.fh = arg->fh;
1301  if (req->se->conn.proto_minor >= 9) {
1302  fi.lock_owner = arg->lock_owner;
1303  fi.flags = arg->flags;
1304  }
1305  req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
1306  } else
1307  fuse_reply_err(req, ENOSYS);
1308 }
1309 
1310 static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1311 {
1312  struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
1313  struct fuse_file_info fi;
1314  char *param;
1315 
1316  memset(&fi, 0, sizeof(fi));
1317  fi.fh = arg->fh;
1318  fi.writepage = (arg->write_flags & 1) != 0;
1319 
1320  if (req->se->conn.proto_minor < 9) {
1321  param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1322  } else {
1323  fi.lock_owner = arg->lock_owner;
1324  fi.flags = arg->flags;
1325  param = PARAM(arg);
1326  }
1327 
1328  if (req->se->op.write)
1329  req->se->op.write(req, nodeid, param, arg->size,
1330  arg->offset, &fi);
1331  else
1332  fuse_reply_err(req, ENOSYS);
1333 }
1334 
1335 static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
1336  const struct fuse_buf *ibuf)
1337 {
1338  struct fuse_session *se = req->se;
1339  struct fuse_bufvec bufv = {
1340  .buf[0] = *ibuf,
1341  .count = 1,
1342  };
1343  struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
1344  struct fuse_file_info fi;
1345 
1346  memset(&fi, 0, sizeof(fi));
1347  fi.fh = arg->fh;
1348  fi.writepage = arg->write_flags & 1;
1349 
1350  if (se->conn.proto_minor < 9) {
1351  bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1352  bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1353  FUSE_COMPAT_WRITE_IN_SIZE;
1354  assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
1355  } else {
1356  fi.lock_owner = arg->lock_owner;
1357  fi.flags = arg->flags;
1358  if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
1359  bufv.buf[0].mem = PARAM(arg);
1360 
1361  bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1362  sizeof(struct fuse_write_in);
1363  }
1364  if (bufv.buf[0].size < arg->size) {
1365  fprintf(stderr, "fuse: do_write_buf: buffer size too small\n");
1366  fuse_reply_err(req, EIO);
1367  goto out;
1368  }
1369  bufv.buf[0].size = arg->size;
1370 
1371  se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
1372 
1373 out:
1374  /* Need to reset the pipe if ->write_buf() didn't consume all data */
1375  if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
1376  fuse_ll_clear_pipe(se);
1377 }
1378 
1379 static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1380 {
1381  struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
1382  struct fuse_file_info fi;
1383 
1384  memset(&fi, 0, sizeof(fi));
1385  fi.fh = arg->fh;
1386  fi.flush = 1;
1387  if (req->se->conn.proto_minor >= 7)
1388  fi.lock_owner = arg->lock_owner;
1389 
1390  if (req->se->op.flush)
1391  req->se->op.flush(req, nodeid, &fi);
1392  else
1393  fuse_reply_err(req, ENOSYS);
1394 }
1395 
1396 static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1397 {
1398  struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
1399  struct fuse_file_info fi;
1400 
1401  memset(&fi, 0, sizeof(fi));
1402  fi.flags = arg->flags;
1403  fi.fh = arg->fh;
1404  if (req->se->conn.proto_minor >= 8) {
1405  fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
1406  fi.lock_owner = arg->lock_owner;
1407  }
1408  if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
1409  fi.flock_release = 1;
1410  fi.lock_owner = arg->lock_owner;
1411  }
1412 
1413  if (req->se->op.release)
1414  req->se->op.release(req, nodeid, &fi);
1415  else
1416  fuse_reply_err(req, 0);
1417 }
1418 
1419 static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1420 {
1421  struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
1422  struct fuse_file_info fi;
1423 
1424  memset(&fi, 0, sizeof(fi));
1425  fi.fh = arg->fh;
1426 
1427  if (req->se->op.fsync)
1428  req->se->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi);
1429  else
1430  fuse_reply_err(req, ENOSYS);
1431 }
1432 
1433 static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1434 {
1435  struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
1436  struct fuse_file_info fi;
1437 
1438  memset(&fi, 0, sizeof(fi));
1439  fi.flags = arg->flags;
1440 
1441  if (req->se->op.opendir)
1442  req->se->op.opendir(req, nodeid, &fi);
1443  else
1444  fuse_reply_open(req, &fi);
1445 }
1446 
1447 static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1448 {
1449  struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1450  struct fuse_file_info fi;
1451 
1452  memset(&fi, 0, sizeof(fi));
1453  fi.fh = arg->fh;
1454 
1455  if (req->se->op.readdir)
1456  req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
1457  else
1458  fuse_reply_err(req, ENOSYS);
1459 }
1460 
1461 static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1462 {
1463  struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1464  struct fuse_file_info fi;
1465 
1466  memset(&fi, 0, sizeof(fi));
1467  fi.fh = arg->fh;
1468 
1469  if (req->se->op.readdirplus)
1470  req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
1471  else
1472  fuse_reply_err(req, ENOSYS);
1473 }
1474 
1475 static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1476 {
1477  struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
1478  struct fuse_file_info fi;
1479 
1480  memset(&fi, 0, sizeof(fi));
1481  fi.flags = arg->flags;
1482  fi.fh = arg->fh;
1483 
1484  if (req->se->op.releasedir)
1485  req->se->op.releasedir(req, nodeid, &fi);
1486  else
1487  fuse_reply_err(req, 0);
1488 }
1489 
1490 static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1491 {
1492  struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
1493  struct fuse_file_info fi;
1494 
1495  memset(&fi, 0, sizeof(fi));
1496  fi.fh = arg->fh;
1497 
1498  if (req->se->op.fsyncdir)
1499  req->se->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi);
1500  else
1501  fuse_reply_err(req, ENOSYS);
1502 }
1503 
1504 static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1505 {
1506  (void) nodeid;
1507  (void) inarg;
1508 
1509  if (req->se->op.statfs)
1510  req->se->op.statfs(req, nodeid);
1511  else {
1512  struct statvfs buf = {
1513  .f_namemax = 255,
1514  .f_bsize = 512,
1515  };
1516  fuse_reply_statfs(req, &buf);
1517  }
1518 }
1519 
1520 static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1521 {
1522  struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
1523  char *name = PARAM(arg);
1524  char *value = name + strlen(name) + 1;
1525 
1526  if (req->se->op.setxattr)
1527  req->se->op.setxattr(req, nodeid, name, value, arg->size,
1528  arg->flags);
1529  else
1530  fuse_reply_err(req, ENOSYS);
1531 }
1532 
1533 static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1534 {
1535  struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
1536 
1537  if (req->se->op.getxattr)
1538  req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
1539  else
1540  fuse_reply_err(req, ENOSYS);
1541 }
1542 
1543 static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1544 {
1545  struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
1546 
1547  if (req->se->op.listxattr)
1548  req->se->op.listxattr(req, nodeid, arg->size);
1549  else
1550  fuse_reply_err(req, ENOSYS);
1551 }
1552 
1553 static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1554 {
1555  char *name = (char *) inarg;
1556 
1557  if (req->se->op.removexattr)
1558  req->se->op.removexattr(req, nodeid, name);
1559  else
1560  fuse_reply_err(req, ENOSYS);
1561 }
1562 
1563 static void convert_fuse_file_lock(struct fuse_file_lock *fl,
1564  struct flock *flock)
1565 {
1566  memset(flock, 0, sizeof(struct flock));
1567  flock->l_type = fl->type;
1568  flock->l_whence = SEEK_SET;
1569  flock->l_start = fl->start;
1570  if (fl->end == OFFSET_MAX)
1571  flock->l_len = 0;
1572  else
1573  flock->l_len = fl->end - fl->start + 1;
1574  flock->l_pid = fl->pid;
1575 }
1576 
1577 static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1578 {
1579  struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
1580  struct fuse_file_info fi;
1581  struct flock flock;
1582 
1583  memset(&fi, 0, sizeof(fi));
1584  fi.fh = arg->fh;
1585  fi.lock_owner = arg->owner;
1586 
1587  convert_fuse_file_lock(&arg->lk, &flock);
1588  if (req->se->op.getlk)
1589  req->se->op.getlk(req, nodeid, &fi, &flock);
1590  else
1591  fuse_reply_err(req, ENOSYS);
1592 }
1593 
1594 static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
1595  const void *inarg, int sleep)
1596 {
1597  struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
1598  struct fuse_file_info fi;
1599  struct flock flock;
1600 
1601  memset(&fi, 0, sizeof(fi));
1602  fi.fh = arg->fh;
1603  fi.lock_owner = arg->owner;
1604 
1605  if (arg->lk_flags & FUSE_LK_FLOCK) {
1606  int op = 0;
1607 
1608  switch (arg->lk.type) {
1609  case F_RDLCK:
1610  op = LOCK_SH;
1611  break;
1612  case F_WRLCK:
1613  op = LOCK_EX;
1614  break;
1615  case F_UNLCK:
1616  op = LOCK_UN;
1617  break;
1618  }
1619  if (!sleep)
1620  op |= LOCK_NB;
1621 
1622  if (req->se->op.flock)
1623  req->se->op.flock(req, nodeid, &fi, op);
1624  else
1625  fuse_reply_err(req, ENOSYS);
1626  } else {
1627  convert_fuse_file_lock(&arg->lk, &flock);
1628  if (req->se->op.setlk)
1629  req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
1630  else
1631  fuse_reply_err(req, ENOSYS);
1632  }
1633 }
1634 
1635 static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1636 {
1637  do_setlk_common(req, nodeid, inarg, 0);
1638 }
1639 
1640 static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1641 {
1642  do_setlk_common(req, nodeid, inarg, 1);
1643 }
1644 
1645 static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
1646 {
1647  struct fuse_req *curr;
1648 
1649  for (curr = se->list.next; curr != &se->list; curr = curr->next) {
1650  if (curr->unique == req->u.i.unique) {
1651  fuse_interrupt_func_t func;
1652  void *data;
1653 
1654  curr->ctr++;
1655  pthread_mutex_unlock(&se->lock);
1656 
1657  /* Ugh, ugly locking */
1658  pthread_mutex_lock(&curr->lock);
1659  pthread_mutex_lock(&se->lock);
1660  curr->interrupted = 1;
1661  func = curr->u.ni.func;
1662  data = curr->u.ni.data;
1663  pthread_mutex_unlock(&se->lock);
1664  if (func)
1665  func(curr, data);
1666  pthread_mutex_unlock(&curr->lock);
1667 
1668  pthread_mutex_lock(&se->lock);
1669  curr->ctr--;
1670  if (!curr->ctr)
1671  destroy_req(curr);
1672 
1673  return 1;
1674  }
1675  }
1676  for (curr = se->interrupts.next; curr != &se->interrupts;
1677  curr = curr->next) {
1678  if (curr->u.i.unique == req->u.i.unique)
1679  return 1;
1680  }
1681  return 0;
1682 }
1683 
1684 static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1685 {
1686  struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
1687  struct fuse_session *se = req->se;
1688 
1689  (void) nodeid;
1690  if (se->debug)
1691  fprintf(stderr, "INTERRUPT: %llu\n",
1692  (unsigned long long) arg->unique);
1693 
1694  req->u.i.unique = arg->unique;
1695 
1696  pthread_mutex_lock(&se->lock);
1697  if (find_interrupted(se, req))
1698  destroy_req(req);
1699  else
1700  list_add_req(req, &se->interrupts);
1701  pthread_mutex_unlock(&se->lock);
1702 }
1703 
1704 static struct fuse_req *check_interrupt(struct fuse_session *se,
1705  struct fuse_req *req)
1706 {
1707  struct fuse_req *curr;
1708 
1709  for (curr = se->interrupts.next; curr != &se->interrupts;
1710  curr = curr->next) {
1711  if (curr->u.i.unique == req->unique) {
1712  req->interrupted = 1;
1713  list_del_req(curr);
1714  free(curr);
1715  return NULL;
1716  }
1717  }
1718  curr = se->interrupts.next;
1719  if (curr != &se->interrupts) {
1720  list_del_req(curr);
1721  list_init_req(curr);
1722  return curr;
1723  } else
1724  return NULL;
1725 }
1726 
1727 static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1728 {
1729  struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
1730 
1731  if (req->se->op.bmap)
1732  req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
1733  else
1734  fuse_reply_err(req, ENOSYS);
1735 }
1736 
1737 static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1738 {
1739  struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
1740  unsigned int flags = arg->flags;
1741  void *in_buf = arg->in_size ? PARAM(arg) : NULL;
1742  struct fuse_file_info fi;
1743 
1744  if (flags & FUSE_IOCTL_DIR &&
1745  !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
1746  fuse_reply_err(req, ENOTTY);
1747  return;
1748  }
1749 
1750  memset(&fi, 0, sizeof(fi));
1751  fi.fh = arg->fh;
1752 
1753  if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
1754  !(flags & FUSE_IOCTL_32BIT)) {
1755  req->ioctl_64bit = 1;
1756  }
1757 
1758  if (req->se->op.ioctl)
1759  req->se->op.ioctl(req, nodeid, arg->cmd,
1760  (void *)(uintptr_t)arg->arg, &fi, flags,
1761  in_buf, arg->in_size, arg->out_size);
1762  else
1763  fuse_reply_err(req, ENOSYS);
1764 }
1765 
1766 void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
1767 {
1768  free(ph);
1769 }
1770 
1771 static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1772 {
1773  struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
1774  struct fuse_file_info fi;
1775 
1776  memset(&fi, 0, sizeof(fi));
1777  fi.fh = arg->fh;
1778  fi.poll_events = arg->events;
1779 
1780  if (req->se->op.poll) {
1781  struct fuse_pollhandle *ph = NULL;
1782 
1783  if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
1784  ph = malloc(sizeof(struct fuse_pollhandle));
1785  if (ph == NULL) {
1786  fuse_reply_err(req, ENOMEM);
1787  return;
1788  }
1789  ph->kh = arg->kh;
1790  ph->se = req->se;
1791  }
1792 
1793  req->se->op.poll(req, nodeid, &fi, ph);
1794  } else {
1795  fuse_reply_err(req, ENOSYS);
1796  }
1797 }
1798 
1799 static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1800 {
1801  struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
1802  struct fuse_file_info fi;
1803 
1804  memset(&fi, 0, sizeof(fi));
1805  fi.fh = arg->fh;
1806 
1807  if (req->se->op.fallocate)
1808  req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
1809  else
1810  fuse_reply_err(req, ENOSYS);
1811 }
1812 
1813 static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void *inarg)
1814 {
1815  struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in *) inarg;
1816  struct fuse_file_info fi_in, fi_out;
1817 
1818  memset(&fi_in, 0, sizeof(fi_in));
1819  fi_in.fh = arg->fh_in;
1820 
1821  memset(&fi_out, 0, sizeof(fi_out));
1822  fi_out.fh = arg->fh_out;
1823 
1824 
1825  if (req->se->op.copy_file_range)
1826  req->se->op.copy_file_range(req, nodeid_in, arg->off_in,
1827  &fi_in, arg->nodeid_out,
1828  arg->off_out, &fi_out, arg->len,
1829  arg->flags);
1830  else
1831  fuse_reply_err(req, ENOSYS);
1832 }
1833 
1834 static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1835 {
1836  struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
1837  struct fuse_init_out outarg;
1838  struct fuse_session *se = req->se;
1839  size_t bufsize = se->bufsize;
1840  size_t outargsize = sizeof(outarg);
1841 
1842  (void) nodeid;
1843  if (se->debug) {
1844  fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor);
1845  if (arg->major == 7 && arg->minor >= 6) {
1846  fprintf(stderr, "flags=0x%08x\n", arg->flags);
1847  fprintf(stderr, "max_readahead=0x%08x\n",
1848  arg->max_readahead);
1849  }
1850  }
1851  se->conn.proto_major = arg->major;
1852  se->conn.proto_minor = arg->minor;
1853  se->conn.capable = 0;
1854  se->conn.want = 0;
1855 
1856  memset(&outarg, 0, sizeof(outarg));
1857  outarg.major = FUSE_KERNEL_VERSION;
1858  outarg.minor = FUSE_KERNEL_MINOR_VERSION;
1859 
1860  if (arg->major < 7) {
1861  fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
1862  arg->major, arg->minor);
1863  fuse_reply_err(req, EPROTO);
1864  return;
1865  }
1866 
1867  if (arg->major > 7) {
1868  /* Wait for a second INIT request with a 7.X version */
1869  send_reply_ok(req, &outarg, sizeof(outarg));
1870  return;
1871  }
1872 
1873  if (arg->minor >= 6) {
1874  if (arg->max_readahead < se->conn.max_readahead)
1875  se->conn.max_readahead = arg->max_readahead;
1876  if (arg->flags & FUSE_ASYNC_READ)
1877  se->conn.capable |= FUSE_CAP_ASYNC_READ;
1878  if (arg->flags & FUSE_POSIX_LOCKS)
1879  se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
1880  if (arg->flags & FUSE_ATOMIC_O_TRUNC)
1881  se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
1882  if (arg->flags & FUSE_EXPORT_SUPPORT)
1883  se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
1884  if (arg->flags & FUSE_DONT_MASK)
1885  se->conn.capable |= FUSE_CAP_DONT_MASK;
1886  if (arg->flags & FUSE_FLOCK_LOCKS)
1887  se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
1888  if (arg->flags & FUSE_AUTO_INVAL_DATA)
1889  se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
1890  if (arg->flags & FUSE_DO_READDIRPLUS)
1891  se->conn.capable |= FUSE_CAP_READDIRPLUS;
1892  if (arg->flags & FUSE_READDIRPLUS_AUTO)
1893  se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
1894  if (arg->flags & FUSE_ASYNC_DIO)
1895  se->conn.capable |= FUSE_CAP_ASYNC_DIO;
1896  if (arg->flags & FUSE_WRITEBACK_CACHE)
1897  se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
1898  if (arg->flags & FUSE_NO_OPEN_SUPPORT)
1899  se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
1900  if (arg->flags & FUSE_PARALLEL_DIROPS)
1901  se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
1902  if (arg->flags & FUSE_POSIX_ACL)
1903  se->conn.capable |= FUSE_CAP_POSIX_ACL;
1904  if (arg->flags & FUSE_HANDLE_KILLPRIV)
1905  se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
1906  } else {
1907  se->conn.max_readahead = 0;
1908  }
1909 
1910  if (se->conn.proto_minor >= 14) {
1911 #ifdef HAVE_SPLICE
1912 #ifdef HAVE_VMSPLICE
1913  se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
1914 #endif
1915  se->conn.capable |= FUSE_CAP_SPLICE_READ;
1916 #endif
1917  }
1918  if (se->conn.proto_minor >= 18)
1919  se->conn.capable |= FUSE_CAP_IOCTL_DIR;
1920 
1921  /* Default settings for modern filesystems.
1922  *
1923  * Most of these capabilities were disabled by default in
1924  * libfuse2 for backwards compatibility reasons. In libfuse3,
1925  * we can finally enable them by default (as long as they're
1926  * supported by the kernel).
1927  */
1928 #define LL_SET_DEFAULT(cond, cap) \
1929  if ((cond) && (se->conn.capable & (cap))) \
1930  se->conn.want |= (cap)
1931  LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
1932  LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
1933  LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
1934  LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
1935  LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
1936  LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
1937  LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
1938  LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
1939  LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
1941  LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
1942  LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
1943  LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
1945  se->conn.time_gran = 1;
1946 
1947  if (bufsize < FUSE_MIN_READ_BUFFER) {
1948  fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
1949  bufsize);
1950  bufsize = FUSE_MIN_READ_BUFFER;
1951  }
1952 
1953  bufsize -= 4096;
1954  if (bufsize < se->conn.max_write)
1955  se->conn.max_write = bufsize;
1956 
1957  se->got_init = 1;
1958  if (se->op.init)
1959  se->op.init(se->userdata, &se->conn);
1960 
1961  if (se->conn.want & (~se->conn.capable)) {
1962  fprintf(stderr, "fuse: error: filesystem requested capabilities "
1963  "0x%x that are not supported by kernel, aborting.\n",
1964  se->conn.want & (~se->conn.capable));
1965  fuse_reply_err(req, EPROTO);
1966  se->error = -EPROTO;
1967  fuse_session_exit(se);
1968  return;
1969  }
1970 
1971  unsigned max_read_mo = get_max_read(se->mo);
1972  if (se->conn.max_read != max_read_mo) {
1973  fprintf(stderr, "fuse: error: init() and fuse_session_new() "
1974  "requested different maximum read size (%u vs %u)\n",
1975  se->conn.max_read, max_read_mo);
1976  fuse_reply_err(req, EPROTO);
1977  se->error = -EPROTO;
1978  fuse_session_exit(se);
1979  return;
1980  }
1981 
1982  /* Always enable big writes, this is superseded
1983  by the max_write option */
1984  outarg.flags |= FUSE_BIG_WRITES;
1985 
1986  if (se->conn.want & FUSE_CAP_ASYNC_READ)
1987  outarg.flags |= FUSE_ASYNC_READ;
1988  if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
1989  outarg.flags |= FUSE_POSIX_LOCKS;
1990  if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
1991  outarg.flags |= FUSE_ATOMIC_O_TRUNC;
1992  if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
1993  outarg.flags |= FUSE_EXPORT_SUPPORT;
1994  if (se->conn.want & FUSE_CAP_DONT_MASK)
1995  outarg.flags |= FUSE_DONT_MASK;
1996  if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
1997  outarg.flags |= FUSE_FLOCK_LOCKS;
1998  if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
1999  outarg.flags |= FUSE_AUTO_INVAL_DATA;
2000  if (se->conn.want & FUSE_CAP_READDIRPLUS)
2001  outarg.flags |= FUSE_DO_READDIRPLUS;
2002  if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
2003  outarg.flags |= FUSE_READDIRPLUS_AUTO;
2004  if (se->conn.want & FUSE_CAP_ASYNC_DIO)
2005  outarg.flags |= FUSE_ASYNC_DIO;
2006  if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
2007  outarg.flags |= FUSE_WRITEBACK_CACHE;
2008  if (se->conn.want & FUSE_CAP_POSIX_ACL)
2009  outarg.flags |= FUSE_POSIX_ACL;
2010  outarg.max_readahead = se->conn.max_readahead;
2011  outarg.max_write = se->conn.max_write;
2012  if (se->conn.proto_minor >= 13) {
2013  if (se->conn.max_background >= (1 << 16))
2014  se->conn.max_background = (1 << 16) - 1;
2015  if (se->conn.congestion_threshold > se->conn.max_background)
2016  se->conn.congestion_threshold = se->conn.max_background;
2017  if (!se->conn.congestion_threshold) {
2018  se->conn.congestion_threshold =
2019  se->conn.max_background * 3 / 4;
2020  }
2021 
2022  outarg.max_background = se->conn.max_background;
2023  outarg.congestion_threshold = se->conn.congestion_threshold;
2024  }
2025  if (se->conn.proto_minor >= 23)
2026  outarg.time_gran = se->conn.time_gran;
2027 
2028  if (se->debug) {
2029  fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor);
2030  fprintf(stderr, " flags=0x%08x\n", outarg.flags);
2031  fprintf(stderr, " max_readahead=0x%08x\n",
2032  outarg.max_readahead);
2033  fprintf(stderr, " max_write=0x%08x\n", outarg.max_write);
2034  fprintf(stderr, " max_background=%i\n",
2035  outarg.max_background);
2036  fprintf(stderr, " congestion_threshold=%i\n",
2037  outarg.congestion_threshold);
2038  fprintf(stderr, " time_gran=%u\n",
2039  outarg.time_gran);
2040  }
2041  if (arg->minor < 5)
2042  outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
2043  else if (arg->minor < 23)
2044  outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
2045 
2046  send_reply_ok(req, &outarg, outargsize);
2047 }
2048 
2049 static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2050 {
2051  struct fuse_session *se = req->se;
2052 
2053  (void) nodeid;
2054  (void) inarg;
2055 
2056  se->got_destroy = 1;
2057  if (se->op.destroy)
2058  se->op.destroy(se->userdata);
2059 
2060  send_reply_ok(req, NULL, 0);
2061 }
2062 
2063 static void list_del_nreq(struct fuse_notify_req *nreq)
2064 {
2065  struct fuse_notify_req *prev = nreq->prev;
2066  struct fuse_notify_req *next = nreq->next;
2067  prev->next = next;
2068  next->prev = prev;
2069 }
2070 
2071 static void list_add_nreq(struct fuse_notify_req *nreq,
2072  struct fuse_notify_req *next)
2073 {
2074  struct fuse_notify_req *prev = next->prev;
2075  nreq->next = next;
2076  nreq->prev = prev;
2077  prev->next = nreq;
2078  next->prev = nreq;
2079 }
2080 
2081 static void list_init_nreq(struct fuse_notify_req *nreq)
2082 {
2083  nreq->next = nreq;
2084  nreq->prev = nreq;
2085 }
2086 
2087 static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
2088  const void *inarg, const struct fuse_buf *buf)
2089 {
2090  struct fuse_session *se = req->se;
2091  struct fuse_notify_req *nreq;
2092  struct fuse_notify_req *head;
2093 
2094  pthread_mutex_lock(&se->lock);
2095  head = &se->notify_list;
2096  for (nreq = head->next; nreq != head; nreq = nreq->next) {
2097  if (nreq->unique == req->unique) {
2098  list_del_nreq(nreq);
2099  break;
2100  }
2101  }
2102  pthread_mutex_unlock(&se->lock);
2103 
2104  if (nreq != head)
2105  nreq->reply(nreq, req, nodeid, inarg, buf);
2106 }
2107 
2108 static int send_notify_iov(struct fuse_session *se, int notify_code,
2109  struct iovec *iov, int count)
2110 {
2111  struct fuse_out_header out;
2112 
2113  if (!se->got_init)
2114  return -ENOTCONN;
2115 
2116  out.unique = 0;
2117  out.error = notify_code;
2118  iov[0].iov_base = &out;
2119  iov[0].iov_len = sizeof(struct fuse_out_header);
2120 
2121  return fuse_send_msg(se, NULL, iov, count);
2122 }
2123 
2124 int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
2125 {
2126  if (ph != NULL) {
2127  struct fuse_notify_poll_wakeup_out outarg;
2128  struct iovec iov[2];
2129 
2130  outarg.kh = ph->kh;
2131 
2132  iov[1].iov_base = &outarg;
2133  iov[1].iov_len = sizeof(outarg);
2134 
2135  return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
2136  } else {
2137  return 0;
2138  }
2139 }
2140 
2141 int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
2142  off_t off, off_t len)
2143 {
2144  struct fuse_notify_inval_inode_out outarg;
2145  struct iovec iov[2];
2146 
2147  if (!se)
2148  return -EINVAL;
2149 
2150  if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
2151  return -ENOSYS;
2152 
2153  outarg.ino = ino;
2154  outarg.off = off;
2155  outarg.len = len;
2156 
2157  iov[1].iov_base = &outarg;
2158  iov[1].iov_len = sizeof(outarg);
2159 
2160  return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
2161 }
2162 
2163 int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
2164  const char *name, size_t namelen)
2165 {
2166  struct fuse_notify_inval_entry_out outarg;
2167  struct iovec iov[3];
2168 
2169  if (!se)
2170  return -EINVAL;
2171 
2172  if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
2173  return -ENOSYS;
2174 
2175  outarg.parent = parent;
2176  outarg.namelen = namelen;
2177  outarg.padding = 0;
2178 
2179  iov[1].iov_base = &outarg;
2180  iov[1].iov_len = sizeof(outarg);
2181  iov[2].iov_base = (void *)name;
2182  iov[2].iov_len = namelen + 1;
2183 
2184  return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
2185 }
2186 
2187 int fuse_lowlevel_notify_delete(struct fuse_session *se,
2188  fuse_ino_t parent, fuse_ino_t child,
2189  const char *name, size_t namelen)
2190 {
2191  struct fuse_notify_delete_out outarg;
2192  struct iovec iov[3];
2193 
2194  if (!se)
2195  return -EINVAL;
2196 
2197  if (se->conn.proto_major < 6 || se->conn.proto_minor < 18)
2198  return -ENOSYS;
2199 
2200  outarg.parent = parent;
2201  outarg.child = child;
2202  outarg.namelen = namelen;
2203  outarg.padding = 0;
2204 
2205  iov[1].iov_base = &outarg;
2206  iov[1].iov_len = sizeof(outarg);
2207  iov[2].iov_base = (void *)name;
2208  iov[2].iov_len = namelen + 1;
2209 
2210  return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
2211 }
2212 
2213 int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
2214  off_t offset, struct fuse_bufvec *bufv,
2215  enum fuse_buf_copy_flags flags)
2216 {
2217  struct fuse_out_header out;
2218  struct fuse_notify_store_out outarg;
2219  struct iovec iov[3];
2220  size_t size = fuse_buf_size(bufv);
2221  int res;
2222 
2223  if (!se)
2224  return -EINVAL;
2225 
2226  if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
2227  return -ENOSYS;
2228 
2229  out.unique = 0;
2230  out.error = FUSE_NOTIFY_STORE;
2231 
2232  outarg.nodeid = ino;
2233  outarg.offset = offset;
2234  outarg.size = size;
2235  outarg.padding = 0;
2236 
2237  iov[0].iov_base = &out;
2238  iov[0].iov_len = sizeof(out);
2239  iov[1].iov_base = &outarg;
2240  iov[1].iov_len = sizeof(outarg);
2241 
2242  res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
2243  if (res > 0)
2244  res = -res;
2245 
2246  return res;
2247 }
2248 
2249 struct fuse_retrieve_req {
2250  struct fuse_notify_req nreq;
2251  void *cookie;
2252 };
2253 
2254 static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
2255  fuse_req_t req, fuse_ino_t ino,
2256  const void *inarg,
2257  const struct fuse_buf *ibuf)
2258 {
2259  struct fuse_session *se = req->se;
2260  struct fuse_retrieve_req *rreq =
2261  container_of(nreq, struct fuse_retrieve_req, nreq);
2262  const struct fuse_notify_retrieve_in *arg = inarg;
2263  struct fuse_bufvec bufv = {
2264  .buf[0] = *ibuf,
2265  .count = 1,
2266  };
2267 
2268  if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
2269  bufv.buf[0].mem = PARAM(arg);
2270 
2271  bufv.buf[0].size -= sizeof(struct fuse_in_header) +
2272  sizeof(struct fuse_notify_retrieve_in);
2273 
2274  if (bufv.buf[0].size < arg->size) {
2275  fprintf(stderr, "fuse: retrieve reply: buffer size too small\n");
2276  fuse_reply_none(req);
2277  goto out;
2278  }
2279  bufv.buf[0].size = arg->size;
2280 
2281  if (se->op.retrieve_reply) {
2282  se->op.retrieve_reply(req, rreq->cookie, ino,
2283  arg->offset, &bufv);
2284  } else {
2285  fuse_reply_none(req);
2286  }
2287 out:
2288  free(rreq);
2289  if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
2290  fuse_ll_clear_pipe(se);
2291 }
2292 
2293 int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
2294  size_t size, off_t offset, void *cookie)
2295 {
2296  struct fuse_notify_retrieve_out outarg;
2297  struct iovec iov[2];
2298  struct fuse_retrieve_req *rreq;
2299  int err;
2300 
2301  if (!se)
2302  return -EINVAL;
2303 
2304  if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
2305  return -ENOSYS;
2306 
2307  rreq = malloc(sizeof(*rreq));
2308  if (rreq == NULL)
2309  return -ENOMEM;
2310 
2311  pthread_mutex_lock(&se->lock);
2312  rreq->cookie = cookie;
2313  rreq->nreq.unique = se->notify_ctr++;
2314  rreq->nreq.reply = fuse_ll_retrieve_reply;
2315  list_add_nreq(&rreq->nreq, &se->notify_list);
2316  pthread_mutex_unlock(&se->lock);
2317 
2318  outarg.notify_unique = rreq->nreq.unique;
2319  outarg.nodeid = ino;
2320  outarg.offset = offset;
2321  outarg.size = size;
2322  outarg.padding = 0;
2323 
2324  iov[1].iov_base = &outarg;
2325  iov[1].iov_len = sizeof(outarg);
2326 
2327  err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
2328  if (err) {
2329  pthread_mutex_lock(&se->lock);
2330  list_del_nreq(&rreq->nreq);
2331  pthread_mutex_unlock(&se->lock);
2332  free(rreq);
2333  }
2334 
2335  return err;
2336 }
2337 
2339 {
2340  return req->se->userdata;
2341 }
2342 
2344 {
2345  return &req->ctx;
2346 }
2347 
2349  void *data)
2350 {
2351  pthread_mutex_lock(&req->lock);
2352  pthread_mutex_lock(&req->se->lock);
2353  req->u.ni.func = func;
2354  req->u.ni.data = data;
2355  pthread_mutex_unlock(&req->se->lock);
2356  if (req->interrupted && func)
2357  func(req, data);
2358  pthread_mutex_unlock(&req->lock);
2359 }
2360 
2362 {
2363  int interrupted;
2364 
2365  pthread_mutex_lock(&req->se->lock);
2366  interrupted = req->interrupted;
2367  pthread_mutex_unlock(&req->se->lock);
2368 
2369  return interrupted;
2370 }
2371 
2372 static struct {
2373  void (*func)(fuse_req_t, fuse_ino_t, const void *);
2374  const char *name;
2375 } fuse_ll_ops[] = {
2376  [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
2377  [FUSE_FORGET] = { do_forget, "FORGET" },
2378  [FUSE_GETATTR] = { do_getattr, "GETATTR" },
2379  [FUSE_SETATTR] = { do_setattr, "SETATTR" },
2380  [FUSE_READLINK] = { do_readlink, "READLINK" },
2381  [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
2382  [FUSE_MKNOD] = { do_mknod, "MKNOD" },
2383  [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
2384  [FUSE_UNLINK] = { do_unlink, "UNLINK" },
2385  [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
2386  [FUSE_RENAME] = { do_rename, "RENAME" },
2387  [FUSE_LINK] = { do_link, "LINK" },
2388  [FUSE_OPEN] = { do_open, "OPEN" },
2389  [FUSE_READ] = { do_read, "READ" },
2390  [FUSE_WRITE] = { do_write, "WRITE" },
2391  [FUSE_STATFS] = { do_statfs, "STATFS" },
2392  [FUSE_RELEASE] = { do_release, "RELEASE" },
2393  [FUSE_FSYNC] = { do_fsync, "FSYNC" },
2394  [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
2395  [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
2396  [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
2397  [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
2398  [FUSE_FLUSH] = { do_flush, "FLUSH" },
2399  [FUSE_INIT] = { do_init, "INIT" },
2400  [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
2401  [FUSE_READDIR] = { do_readdir, "READDIR" },
2402  [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
2403  [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
2404  [FUSE_GETLK] = { do_getlk, "GETLK" },
2405  [FUSE_SETLK] = { do_setlk, "SETLK" },
2406  [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
2407  [FUSE_ACCESS] = { do_access, "ACCESS" },
2408  [FUSE_CREATE] = { do_create, "CREATE" },
2409  [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
2410  [FUSE_BMAP] = { do_bmap, "BMAP" },
2411  [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
2412  [FUSE_POLL] = { do_poll, "POLL" },
2413  [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
2414  [FUSE_DESTROY] = { do_destroy, "DESTROY" },
2415  [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
2416  [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
2417  [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
2418  [FUSE_RENAME2] = { do_rename2, "RENAME2" },
2419  [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
2420  [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
2421 };
2422 
2423 #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
2424 
2425 static const char *opname(enum fuse_opcode opcode)
2426 {
2427  if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
2428  return "???";
2429  else
2430  return fuse_ll_ops[opcode].name;
2431 }
2432 
2433 static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
2434  struct fuse_bufvec *src)
2435 {
2436  ssize_t res = fuse_buf_copy(dst, src, 0);
2437  if (res < 0) {
2438  fprintf(stderr, "fuse: copy from pipe: %s\n", strerror(-res));
2439  return res;
2440  }
2441  if ((size_t)res < fuse_buf_size(dst)) {
2442  fprintf(stderr, "fuse: copy from pipe: short read\n");
2443  return -1;
2444  }
2445  return 0;
2446 }
2447 
2448 void fuse_session_process_buf(struct fuse_session *se,
2449  const struct fuse_buf *buf)
2450 {
2451  fuse_session_process_buf_int(se, buf, NULL);
2452 }
2453 
2454 void fuse_session_process_buf_int(struct fuse_session *se,
2455  const struct fuse_buf *buf, struct fuse_chan *ch)
2456 {
2457  const size_t write_header_size = sizeof(struct fuse_in_header) +
2458  sizeof(struct fuse_write_in);
2459  struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
2460  struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
2461  struct fuse_in_header *in;
2462  const void *inarg;
2463  struct fuse_req *req;
2464  void *mbuf = NULL;
2465  int err;
2466  int res;
2467 
2468  if (buf->flags & FUSE_BUF_IS_FD) {
2469  if (buf->size < tmpbuf.buf[0].size)
2470  tmpbuf.buf[0].size = buf->size;
2471 
2472  mbuf = malloc(tmpbuf.buf[0].size);
2473  if (mbuf == NULL) {
2474  fprintf(stderr, "fuse: failed to allocate header\n");
2475  goto clear_pipe;
2476  }
2477  tmpbuf.buf[0].mem = mbuf;
2478 
2479  res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
2480  if (res < 0)
2481  goto clear_pipe;
2482 
2483  in = mbuf;
2484  } else {
2485  in = buf->mem;
2486  }
2487 
2488  if (se->debug) {
2489  fprintf(stderr,
2490  "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
2491  (unsigned long long) in->unique,
2492  opname((enum fuse_opcode) in->opcode), in->opcode,
2493  (unsigned long long) in->nodeid, buf->size, in->pid);
2494  }
2495 
2496  req = fuse_ll_alloc_req(se);
2497  if (req == NULL) {
2498  struct fuse_out_header out = {
2499  .unique = in->unique,
2500  .error = -ENOMEM,
2501  };
2502  struct iovec iov = {
2503  .iov_base = &out,
2504  .iov_len = sizeof(struct fuse_out_header),
2505  };
2506 
2507  fuse_send_msg(se, ch, &iov, 1);
2508  goto clear_pipe;
2509  }
2510 
2511  req->unique = in->unique;
2512  req->ctx.uid = in->uid;
2513  req->ctx.gid = in->gid;
2514  req->ctx.pid = in->pid;
2515  req->ch = ch ? fuse_chan_get(ch) : NULL;
2516 
2517  err = EIO;
2518  if (!se->got_init) {
2519  enum fuse_opcode expected;
2520 
2521  expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
2522  if (in->opcode != expected)
2523  goto reply_err;
2524  } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
2525  goto reply_err;
2526 
2527  err = EACCES;
2528  /* Implement -o allow_root */
2529  if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
2530  in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
2531  in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
2532  in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
2533  in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
2534  in->opcode != FUSE_NOTIFY_REPLY &&
2535  in->opcode != FUSE_READDIRPLUS)
2536  goto reply_err;
2537 
2538  err = ENOSYS;
2539  if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
2540  goto reply_err;
2541  if (in->opcode != FUSE_INTERRUPT) {
2542  struct fuse_req *intr;
2543  pthread_mutex_lock(&se->lock);
2544  intr = check_interrupt(se, req);
2545  list_add_req(req, &se->list);
2546  pthread_mutex_unlock(&se->lock);
2547  if (intr)
2548  fuse_reply_err(intr, EAGAIN);
2549  }
2550 
2551  if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
2552  (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
2553  in->opcode != FUSE_NOTIFY_REPLY) {
2554  void *newmbuf;
2555 
2556  err = ENOMEM;
2557  newmbuf = realloc(mbuf, buf->size);
2558  if (newmbuf == NULL)
2559  goto reply_err;
2560  mbuf = newmbuf;
2561 
2562  tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
2563  tmpbuf.buf[0].mem = mbuf + write_header_size;
2564 
2565  res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
2566  err = -res;
2567  if (res < 0)
2568  goto reply_err;
2569 
2570  in = mbuf;
2571  }
2572 
2573  inarg = (void *) &in[1];
2574  if (in->opcode == FUSE_WRITE && se->op.write_buf)
2575  do_write_buf(req, in->nodeid, inarg, buf);
2576  else if (in->opcode == FUSE_NOTIFY_REPLY)
2577  do_notify_reply(req, in->nodeid, inarg, buf);
2578  else
2579  fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
2580 
2581 out_free:
2582  free(mbuf);
2583  return;
2584 
2585 reply_err:
2586  fuse_reply_err(req, err);
2587 clear_pipe:
2588  if (buf->flags & FUSE_BUF_IS_FD)
2589  fuse_ll_clear_pipe(se);
2590  goto out_free;
2591 }
2592 
2593 #define LL_OPTION(n,o,v) \
2594  { n, offsetof(struct fuse_session, o), v }
2595 
2596 static const struct fuse_opt fuse_ll_opts[] = {
2597  LL_OPTION("debug", debug, 1),
2598  LL_OPTION("-d", debug, 1),
2599  LL_OPTION("--debug", debug, 1),
2600  LL_OPTION("allow_root", deny_others, 1),
2601  FUSE_OPT_END
2602 };
2603 
2605 {
2606  printf("using FUSE kernel interface version %i.%i\n",
2607  FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
2608  fuse_mount_version();
2609 }
2610 
2612 {
2613  /* These are not all options, but the ones that are
2614  potentially of interest to an end-user */
2615  printf(
2616 " -o allow_other allow access by all users\n"
2617 " -o allow_root allow access by root\n"
2618 " -o auto_unmount auto unmount on process termination\n");
2619 }
2620 
2621 void fuse_session_destroy(struct fuse_session *se)
2622 {
2623  struct fuse_ll_pipe *llp;
2624 
2625  if (se->got_init && !se->got_destroy) {
2626  if (se->op.destroy)
2627  se->op.destroy(se->userdata);
2628  }
2629  llp = pthread_getspecific(se->pipe_key);
2630  if (llp != NULL)
2631  fuse_ll_pipe_free(llp);
2632  pthread_key_delete(se->pipe_key);
2633  pthread_mutex_destroy(&se->lock);
2634  free(se->cuse_data);
2635  if (se->fd != -1)
2636  close(se->fd);
2637  destroy_mount_opts(se->mo);
2638  free(se);
2639 }
2640 
2641 
2642 static void fuse_ll_pipe_destructor(void *data)
2643 {
2644  struct fuse_ll_pipe *llp = data;
2645  fuse_ll_pipe_free(llp);
2646 }
2647 
2648 int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
2649 {
2650  return fuse_session_receive_buf_int(se, buf, NULL);
2651 }
2652 
2653 int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
2654  struct fuse_chan *ch)
2655 {
2656  int err;
2657  ssize_t res;
2658 #ifdef HAVE_SPLICE
2659  size_t bufsize = se->bufsize;
2660  struct fuse_ll_pipe *llp;
2661  struct fuse_buf tmpbuf;
2662 
2663  if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ))
2664  goto fallback;
2665 
2666  llp = fuse_ll_get_pipe(se);
2667  if (llp == NULL)
2668  goto fallback;
2669 
2670  if (llp->size < bufsize) {
2671  if (llp->can_grow) {
2672  res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
2673  if (res == -1) {
2674  llp->can_grow = 0;
2675  goto fallback;
2676  }
2677  llp->size = res;
2678  }
2679  if (llp->size < bufsize)
2680  goto fallback;
2681  }
2682 
2683  res = splice(ch ? ch->fd : se->fd,
2684  NULL, llp->pipe[1], NULL, bufsize, 0);
2685  err = errno;
2686 
2687  if (fuse_session_exited(se))
2688  return 0;
2689 
2690  if (res == -1) {
2691  if (err == ENODEV) {
2692  /* Filesystem was unmounted, or connection was aborted
2693  via /sys/fs/fuse/connections */
2694  fuse_session_exit(se);
2695  return 0;
2696  }
2697  if (err != EINTR && err != EAGAIN)
2698  perror("fuse: splice from device");
2699  return -err;
2700  }
2701 
2702  if (res < sizeof(struct fuse_in_header)) {
2703  fprintf(stderr, "short splice from fuse device\n");
2704  return -EIO;
2705  }
2706 
2707  tmpbuf = (struct fuse_buf) {
2708  .size = res,
2709  .flags = FUSE_BUF_IS_FD,
2710  .fd = llp->pipe[0],
2711  };
2712 
2713  /*
2714  * Don't bother with zero copy for small requests.
2715  * fuse_loop_mt() needs to check for FORGET so this more than
2716  * just an optimization.
2717  */
2718  if (res < sizeof(struct fuse_in_header) +
2719  sizeof(struct fuse_write_in) + pagesize) {
2720  struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
2721  struct fuse_bufvec dst = { .count = 1 };
2722 
2723  if (!buf->mem) {
2724  buf->mem = malloc(se->bufsize);
2725  if (!buf->mem) {
2726  fprintf(stderr,
2727  "fuse: failed to allocate read buffer\n");
2728  return -ENOMEM;
2729  }
2730  }
2731  buf->size = se->bufsize;
2732  buf->flags = 0;
2733  dst.buf[0] = *buf;
2734 
2735  res = fuse_buf_copy(&dst, &src, 0);
2736  if (res < 0) {
2737  fprintf(stderr, "fuse: copy from pipe: %s\n",
2738  strerror(-res));
2739  fuse_ll_clear_pipe(se);
2740  return res;
2741  }
2742  if (res < tmpbuf.size) {
2743  fprintf(stderr, "fuse: copy from pipe: short read\n");
2744  fuse_ll_clear_pipe(se);
2745  return -EIO;
2746  }
2747  assert(res == tmpbuf.size);
2748 
2749  } else {
2750  /* Don't overwrite buf->mem, as that would cause a leak */
2751  buf->fd = tmpbuf.fd;
2752  buf->flags = tmpbuf.flags;
2753  }
2754  buf->size = tmpbuf.size;
2755 
2756  return res;
2757 
2758 fallback:
2759 #endif
2760  if (!buf->mem) {
2761  buf->mem = malloc(se->bufsize);
2762  if (!buf->mem) {
2763  fprintf(stderr,
2764  "fuse: failed to allocate read buffer\n");
2765  return -ENOMEM;
2766  }
2767  }
2768 
2769 restart:
2770  res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize);
2771  err = errno;
2772 
2773  if (fuse_session_exited(se))
2774  return 0;
2775  if (res == -1) {
2776  /* ENOENT means the operation was interrupted, it's safe
2777  to restart */
2778  if (err == ENOENT)
2779  goto restart;
2780 
2781  if (err == ENODEV) {
2782  /* Filesystem was unmounted, or connection was aborted
2783  via /sys/fs/fuse/connections */
2784  fuse_session_exit(se);
2785  return 0;
2786  }
2787  /* Errors occurring during normal operation: EINTR (read
2788  interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
2789  umounted) */
2790  if (err != EINTR && err != EAGAIN)
2791  perror("fuse: reading device");
2792  return -err;
2793  }
2794  if ((size_t) res < sizeof(struct fuse_in_header)) {
2795  fprintf(stderr, "short read on fuse device\n");
2796  return -EIO;
2797  }
2798 
2799  buf->size = res;
2800 
2801  return res;
2802 }
2803 
2804 #define KERNEL_BUF_PAGES 32
2805 
2806 /* room needed in buffer to accommodate header */
2807 #define HEADER_SIZE 0x1000
2808 
2809 struct fuse_session *fuse_session_new(struct fuse_args *args,
2810  const struct fuse_lowlevel_ops *op,
2811  size_t op_size, void *userdata)
2812 {
2813  int err;
2814  struct fuse_session *se;
2815  struct mount_opts *mo;
2816 
2817  if (sizeof(struct fuse_lowlevel_ops) < op_size) {
2818  fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
2819  op_size = sizeof(struct fuse_lowlevel_ops);
2820  }
2821 
2822  if (args->argc == 0) {
2823  fprintf(stderr, "fuse: empty argv passed to fuse_session_new().\n");
2824  return NULL;
2825  }
2826 
2827  se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
2828  if (se == NULL) {
2829  fprintf(stderr, "fuse: failed to allocate fuse object\n");
2830  goto out1;
2831  }
2832  se->fd = -1;
2833  se->conn.max_write = UINT_MAX;
2834  se->conn.max_readahead = UINT_MAX;
2835 
2836  /* Parse options */
2837  if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
2838  goto out2;
2839  if(se->deny_others) {
2840  /* Allowing access only by root is done by instructing
2841  * kernel to allow access by everyone, and then restricting
2842  * access to root and mountpoint owner in libfuse.
2843  */
2844  // We may be adding the option a second time, but
2845  // that doesn't hurt.
2846  if(fuse_opt_add_arg(args, "-oallow_other") == -1)
2847  goto out2;
2848  }
2849  mo = parse_mount_opts(args);
2850  if (mo == NULL)
2851  goto out3;
2852 
2853  if(args->argc == 1 &&
2854  args->argv[0][0] == '-') {
2855  fprintf(stderr, "fuse: warning: argv[0] looks like an option, but "
2856  "will be ignored\n");
2857  } else if (args->argc != 1) {
2858  int i;
2859  fprintf(stderr, "fuse: unknown option(s): `");
2860  for(i = 1; i < args->argc-1; i++)
2861  fprintf(stderr, "%s ", args->argv[i]);
2862  fprintf(stderr, "%s'\n", args->argv[i]);
2863  goto out4;
2864  }
2865 
2866  if (se->debug)
2867  fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
2868 
2869  se->bufsize = KERNEL_BUF_PAGES * getpagesize() + HEADER_SIZE;
2870 
2871  list_init_req(&se->list);
2872  list_init_req(&se->interrupts);
2873  list_init_nreq(&se->notify_list);
2874  se->notify_ctr = 1;
2875  fuse_mutex_init(&se->lock);
2876 
2877  err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
2878  if (err) {
2879  fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
2880  strerror(err));
2881  goto out5;
2882  }
2883 
2884  memcpy(&se->op, op, op_size);
2885  se->owner = getuid();
2886  se->userdata = userdata;
2887 
2888  se->mo = mo;
2889  return se;
2890 
2891 out5:
2892  pthread_mutex_destroy(&se->lock);
2893 out4:
2894  fuse_opt_free_args(args);
2895 out3:
2896  free(mo);
2897 out2:
2898  free(se);
2899 out1:
2900  return NULL;
2901 }
2902 
2903 int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
2904 {
2905  int fd;
2906 
2907  /*
2908  * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
2909  * would ensue.
2910  */
2911  do {
2912  fd = open("/dev/null", O_RDWR);
2913  if (fd > 2)
2914  close(fd);
2915  } while (fd >= 0 && fd <= 2);
2916 
2917  /*
2918  * To allow FUSE daemons to run without privileges, the caller may open
2919  * /dev/fuse before launching the file system and pass on the file
2920  * descriptor by specifying /dev/fd/N as the mount point. Note that the
2921  * parent process takes care of performing the mount in this case.
2922  */
2923  fd = fuse_mnt_parse_fuse_fd(mountpoint);
2924  if (fd != -1) {
2925  if (fcntl(fd, F_GETFD) == -1) {
2926  fprintf(stderr,
2927  "fuse: Invalid file descriptor /dev/fd/%u\n",
2928  fd);
2929  return -1;
2930  }
2931  se->fd = fd;
2932  return 0;
2933  }
2934 
2935  /* Open channel */
2936  fd = fuse_kern_mount(mountpoint, se->mo);
2937  if (fd == -1)
2938  return -1;
2939  se->fd = fd;
2940 
2941  /* Save mountpoint */
2942  se->mountpoint = strdup(mountpoint);
2943  if (se->mountpoint == NULL)
2944  goto error_out;
2945 
2946  return 0;
2947 
2948 error_out:
2949  fuse_kern_unmount(mountpoint, fd);
2950  return -1;
2951 }
2952 
2953 int fuse_session_fd(struct fuse_session *se)
2954 {
2955  return se->fd;
2956 }
2957 
2958 void fuse_session_unmount(struct fuse_session *se)
2959 {
2960  if (se->mountpoint != NULL) {
2961  fuse_kern_unmount(se->mountpoint, se->fd);
2962  free(se->mountpoint);
2963  se->mountpoint = NULL;
2964  }
2965 }
2966 
2967 #ifdef linux
2968 int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
2969 {
2970  char *buf;
2971  size_t bufsize = 1024;
2972  char path[128];
2973  int ret;
2974  int fd;
2975  unsigned long pid = req->ctx.pid;
2976  char *s;
2977 
2978  sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
2979 
2980 retry:
2981  buf = malloc(bufsize);
2982  if (buf == NULL)
2983  return -ENOMEM;
2984 
2985  ret = -EIO;
2986  fd = open(path, O_RDONLY);
2987  if (fd == -1)
2988  goto out_free;
2989 
2990  ret = read(fd, buf, bufsize);
2991  close(fd);
2992  if (ret < 0) {
2993  ret = -EIO;
2994  goto out_free;
2995  }
2996 
2997  if ((size_t)ret == bufsize) {
2998  free(buf);
2999  bufsize *= 4;
3000  goto retry;
3001  }
3002 
3003  ret = -EIO;
3004  s = strstr(buf, "\nGroups:");
3005  if (s == NULL)
3006  goto out_free;
3007 
3008  s += 8;
3009  ret = 0;
3010  while (1) {
3011  char *end;
3012  unsigned long val = strtoul(s, &end, 0);
3013  if (end == s)
3014  break;
3015 
3016  s = end;
3017  if (ret < size)
3018  list[ret] = val;
3019  ret++;
3020  }
3021 
3022 out_free:
3023  free(buf);
3024  return ret;
3025 }
3026 #else /* linux */
3027 /*
3028  * This is currently not implemented on other than Linux...
3029  */
3030 int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
3031 {
3032  (void) req; (void) size; (void) list;
3033  return -ENOSYS;
3034 }
3035 #endif
3036 
3037 void fuse_session_exit(struct fuse_session *se)
3038 {
3039  se->exited = 1;
3040 }
3041 
3042 void fuse_session_reset(struct fuse_session *se)
3043 {
3044  se->exited = 0;
3045  se->error = 0;
3046 }
3047 
3048 int fuse_session_exited(struct fuse_session *se)
3049 {
3050  return se->exited;
3051 }
void fuse_session_destroy(struct fuse_session *se)
+
int fuse_reply_err(fuse_req_t req, int err)
+
size_t off
Definition: fuse_common.h:679
+
#define FUSE_CAP_IOCTL_DIR
Definition: fuse_common.h:197
+
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
+
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
+
void fuse_session_exit(struct fuse_session *se)
+
uint64_t fh
Definition: fuse_common.h:72
+
int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
+
int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
+
unsigned int writepage
Definition: fuse_common.h:43
+
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
+
void fuse_lowlevel_help(void)
+
int argc
Definition: fuse_opt.h:111
+
unsigned int direct_io
Definition: fuse_common.h:46
+ +
#define FUSE_CAP_HANDLE_KILLPRIV
Definition: fuse_common.h:317
+
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
+
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
+
uint32_t poll_events
Definition: fuse_common.h:79
+
int fuse_session_fd(struct fuse_session *se)
+
const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
+ +
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
+
#define FUSE_CAP_ASYNC_READ
Definition: fuse_common.h:120
+
int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
+
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+
struct stat attr
Definition: fuse_lowlevel.h:91
+
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
+
void * fuse_req_userdata(fuse_req_t req)
+ +
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
+
int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
+
unsigned int keep_cache
Definition: fuse_common.h:51
+
Definition: fuse_lowlevel.h:59
+
#define FUSE_CAP_EXPORT_SUPPORT
Definition: fuse_common.h:144
+
fuse_ino_t ino
Definition: fuse_lowlevel.h:67
+
uint64_t lock_owner
Definition: fuse_common.h:75
+
int fuse_reply_xattr(fuse_req_t req, size_t count)
+
int fuse_session_exited(struct fuse_session *se)
+
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+
#define FUSE_CAP_READDIRPLUS_AUTO
Definition: fuse_common.h:246
+
#define FUSE_CAP_SPLICE_WRITE
Definition: fuse_common.h:160
+
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
+
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
+ +
int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
+
#define FUSE_CAP_NO_OPEN_SUPPORT
Definition: fuse_common.h:279
+
int fuse_req_interrupted(fuse_req_t req)
+
void fuse_session_reset(struct fuse_session *se)
+
void fuse_lowlevel_version(void)
+
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
+
void fuse_reply_none(fuse_req_t req)
+
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+ + +
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+
#define FUSE_CAP_SPLICE_MOVE
Definition: fuse_common.h:168
+
size_t idx
Definition: fuse_common.h:674
+ +
size_t count
Definition: fuse_common.h:669
+
#define FUSE_CAP_AUTO_INVAL_DATA
Definition: fuse_common.h:219
+
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
+ +
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
+
#define FUSE_CAP_SPLICE_READ
Definition: fuse_common.h:177
+
void fuse_session_unmount(struct fuse_session *se)
+
unsigned int nonseekable
Definition: fuse_common.h:60
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+
enum fuse_buf_flags flags
Definition: fuse_common.h:633
+
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
+
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
+
unsigned int flush
Definition: fuse_common.h:56
+ +
#define FUSE_CAP_FLOCK_LOCKS
Definition: fuse_common.h:190
+
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
+
char ** argv
Definition: fuse_opt.h:114
+
#define FUSE_CAP_ASYNC_DIO
Definition: fuse_common.h:257
+
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
+
uint64_t generation
Definition: fuse_lowlevel.h:82
+
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
+
int fuse_reply_write(fuse_req_t req, size_t count)
+
void * mem
Definition: fuse_common.h:640
+
#define FUSE_CAP_WRITEBACK_CACHE
Definition: fuse_common.h:266
+
#define FUSE_CAP_POSIX_LOCKS
Definition: fuse_common.h:128
+
#define FUSE_CAP_POSIX_ACL
Definition: fuse_common.h:308
+
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
+ + +
struct fuse_buf buf[1]
Definition: fuse_common.h:684
+ +
#define FUSE_CAP_ATOMIC_O_TRUNC
Definition: fuse_common.h:137
+ +
#define FUSE_CAP_READDIRPLUS
Definition: fuse_common.h:227
+
#define FUSE_CAP_PARALLEL_DIROPS
Definition: fuse_common.h:289
+
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
+
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:281
+
size_t size
Definition: fuse_common.h:628
+
double entry_timeout
+
fuse_buf_copy_flags
Definition: fuse_common.h:579
+ +
double attr_timeout
Definition: fuse_lowlevel.h:97
+
int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
+ +
int fuse_reply_readlink(fuse_req_t req, const char *link)
+
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+
int fuse_reply_poll(fuse_req_t req, unsigned revents)
+
void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
+
#define FUSE_CAP_DONT_MASK
Definition: fuse_common.h:152
+
+ + + + diff --git a/doc/html/fuse__lowlevel_8h.html b/doc/html/fuse__lowlevel_8h.html index db0b106..506a22a 100644 --- a/doc/html/fuse__lowlevel_8h.html +++ b/doc/html/fuse__lowlevel_8h.html @@ -3,8 +3,9 @@ - -fuse: include/fuse_lowlevel.h File Reference + + +libfuse: include/fuse_lowlevel.h File Reference @@ -16,8 +17,8 @@ - @@ -25,20 +26,15 @@
-
fuse +
+
libfuse
- - - + + + + +
-
#include "fuse_common.h"
+
#include "fuse_common.h"
#include <utime.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/uio.h>
-#include "fuse_lowlevel_compat.h"
-
+ +

Go to the source code of this file.

+
@@ -71,10 +68,6 @@ Data Structures - - - -

Data Structures

struct  fuse_entry_param
 
struct  fuse_lowlevel_ops
 
struct  fuse_session_ops
 
struct  fuse_chan_ops
 
@@ -83,12 +76,12 @@ Macros

Macros

- - + + - - + +

Typedefs

typedef unsigned long fuse_ino_t
 
typedef uint64_t fuse_ino_t
 
typedef struct fuse_req * fuse_req_t
 
typedef void(* fuse_interrupt_func_t )(fuse_req_t req, void *data)
 
typedef void(* fuse_interrupt_func_t) (fuse_req_t req, void *data)
 
@@ -124,6 +117,8 @@ Functions + + @@ -134,78 +129,68 @@ Functions - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + +

Functions

 
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 fuse_add_direntry_plus (fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
 
int fuse_reply_ioctl_retry (fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
 
int fuse_reply_ioctl (fuse_req_t req, int result, const void *buf, size_t size)
 
int fuse_lowlevel_notify_poll (struct fuse_pollhandle *ph)
 
int fuse_lowlevel_notify_inval_inode (struct fuse_chan *ch, fuse_ino_t ino, off_t off, off_t len)
 
int fuse_lowlevel_notify_inval_entry (struct fuse_chan *ch, fuse_ino_t parent, const char *name, size_t namelen)
 
int fuse_lowlevel_notify_delete (struct fuse_chan *ch, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
 
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)
 
int fuse_lowlevel_notify_retrieve (struct fuse_chan *ch, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
 
int fuse_lowlevel_notify_inval_inode (struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
 
int fuse_lowlevel_notify_inval_entry (struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
 
int fuse_lowlevel_notify_delete (struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
 
int fuse_lowlevel_notify_store (struct fuse_session *se, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
 
int fuse_lowlevel_notify_retrieve (struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
 
void * fuse_req_userdata (fuse_req_t req)
 
const struct fuse_ctxfuse_req_ctx (fuse_req_t req)
 
int fuse_req_getgroups (fuse_req_t req, int size, gid_t list[])
 
void fuse_req_interrupt_func (fuse_req_t req, fuse_interrupt_func_t func, void *data)
void fuse_req_interrupt_func (fuse_req_t req, fuse_interrupt_func_t func, void *data)
 
int fuse_req_interrupted (fuse_req_t req)
 
struct fuse_session * fuse_lowlevel_new (struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
 
struct fuse_session * fuse_session_new (struct fuse_session_ops *op, void *data)
 
void fuse_session_add_chan (struct fuse_session *se, struct fuse_chan *ch)
 
void fuse_session_remove_chan (struct fuse_chan *ch)
 
struct fuse_chan * fuse_session_next_chan (struct fuse_session *se, struct fuse_chan *ch)
 
void fuse_session_process (struct fuse_session *se, const char *buf, size_t len, struct fuse_chan *ch)
 
void fuse_session_process_buf (struct fuse_session *se, const struct fuse_buf *buf, struct fuse_chan *ch)
 
int fuse_session_receive_buf (struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan **chp)
 
void fuse_session_destroy (struct fuse_session *se)
 
void fuse_lowlevel_version (void)
 
void fuse_lowlevel_help (void)
 
void fuse_cmdline_help (void)
 
int fuse_parse_cmdline (struct fuse_args *args, struct fuse_cmdline_opts *opts)
 
struct fuse_session * fuse_session_new (struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
 
int fuse_session_mount (struct fuse_session *se, const char *mountpoint)
 
int fuse_session_loop (struct fuse_session *se)
 
int fuse_session_loop_mt_31 (struct fuse_session *se, int clone_fd)
 
void fuse_session_exit (struct fuse_session *se)
 
void fuse_session_reset (struct fuse_session *se)
 
int fuse_session_exited (struct fuse_session *se)
 
void * fuse_session_data (struct fuse_session *se)
 
int fuse_session_loop (struct fuse_session *se)
 
int fuse_session_loop_mt (struct fuse_session *se)
 
struct fuse_chan * fuse_chan_new (struct fuse_chan_ops *op, int fd, size_t bufsize, void *data)
 
int fuse_chan_fd (struct fuse_chan *ch)
 
size_t fuse_chan_bufsize (struct fuse_chan *ch)
 
void * fuse_chan_data (struct fuse_chan *ch)
 
struct fuse_session * fuse_chan_session (struct fuse_chan *ch)
 
int fuse_chan_recv (struct fuse_chan **ch, char *buf, size_t size)
 
int fuse_chan_send (struct fuse_chan *ch, const struct iovec iov[], size_t count)
 
void fuse_chan_destroy (struct fuse_chan *ch)
 
void fuse_session_unmount (struct fuse_session *se)
 
void fuse_session_destroy (struct fuse_session *se)
 
int fuse_session_fd (struct fuse_session *se)
 
void fuse_session_process_buf (struct fuse_session *se, const struct fuse_buf *buf)
 
int fuse_session_receive_buf (struct fuse_session *se, struct fuse_buf *buf)
 

Detailed Description

Low level API

-

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 24 (default) or 25

+

IMPORTANT: you should define FUSE_USE_VERSION before including this header. To use the newest API define it to 31 (recommended for any new application).

+ +

Definition in file fuse_lowlevel.h.

Macro Definition Documentation

- + +

◆ FUSE_ROOT_ID

+
@@ -216,28 +201,36 @@ Functions

The node ID of the root inode

+

Definition at line 43 of file fuse_lowlevel.h.

+

Typedef Documentation

- + +

◆ fuse_ino_t

+
- +
typedef unsigned long fuse_ino_ttypedef uint64_t fuse_ino_t

Inode number type

+

Definition at line 46 of file fuse_lowlevel.h.

+
- + +

◆ fuse_interrupt_func_t

+
- +
typedef void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)typedef void(* fuse_interrupt_func_t) (fuse_req_t req, void *data)
@@ -250,9 +243,13 @@ Functions +

Definition at line 1760 of file fuse_lowlevel.h.

+
- + +

◆ fuse_req_t

+
@@ -263,10 +260,14 @@ Functions

Request pointer type

+

Definition at line 49 of file fuse_lowlevel.h.

+

Function Documentation

- + +

◆ fuse_add_direntry()

+
@@ -316,7 +317,7 @@ Functions

Add a directory entry to the buffer

Buffer needs to be large enough to hold the entry. If it's not, then the entry is not filled in but the size of the entry is still returned. The caller can check this by comparing the bufsize parameter with the returned entry size. If the entry size is larger than the buffer size, the operation failed.

From the 'stbuf' argument the st_ino field and bits 12-15 of the st_mode field are used. The other fields are ignored.

-

Note: offsets do not necessarily represent physical offsets, and could be any marker, that enables the implementation to find a specific point in the directory stream.

+

off should be any non-zero value that the filesystem can use to identify the current point in the directory stream. It does not need to be the actual physical position. A value of zero is reserved to mean "from the beginning", and should therefore never be used (the first call to fuse_add_direntry should be passed the offset of the second directory entry).

Parameters
@@ -330,118 +331,27 @@ Functions
Returns
the space needed for the entry
- - - -
-
-
reqrequest handle
- - - - - - - -
size_t fuse_chan_bufsize (struct fuse_chan * ch)
-
-

Query the minimal receive buffer size

-
Parameters
- - -
chthe channel
-
-
-
Returns
the buffer size passed to fuse_chan_new()
+

Definition at line 267 of file fuse_lowlevel.c.

- -
-
- - - - - - - - -
void* fuse_chan_data (struct fuse_chan * ch)
-
-

Query the user data

-
Parameters
- - -
chthe channel
-
-
-
Returns
the user data passed to fuse_chan_new()
+ +

◆ fuse_add_direntry_plus()

-
-
-
- + - - - - -
void fuse_chan_destroy size_t fuse_add_direntry_plus (struct fuse_chan * ch)
-
-

Destroy a channel

-
Parameters
- - -
chthe channel
-
-
- -
-
- -
-
- - - - - - - - -
int fuse_chan_fd (struct fuse_chan * ch)
-
-

Query the file descriptor of the channel

-
Parameters
- - -
chthe channel
-
-
-
Returns
the file descriptor passed to fuse_chan_new()
- -
-
- -
-
- - - - - - + + - - + + @@ -452,51 +362,20 @@ Functions - - - - - - - - -
struct fuse_chan* fuse_chan_new (struct fuse_chan_opsop, fuse_req_t req,
int fd, char * buf,
void * data 
)
-
-

Create a new channel

-
Parameters
- - - - - -
opchannel operations
fdfile descriptor of the channel
bufsizethe minimal receive buffer size
datauser data
-
-
-
Returns
the new channel object, or NULL on failure
- -
-
- -
-
- - - - - - + + - - + + - - + + @@ -505,156 +384,89 @@ Functions
int fuse_chan_recv (struct fuse_chan ** ch, const char * name,
char * buf, const struct fuse_entry_parame,
size_t size off_t off 
-

Receive a raw request

-

A return value of -ENODEV means, that the filesystem was unmounted

+

Add a directory entry to the buffer with the attributes

+

See documentation of fuse_add_direntry() for more details.

Parameters
- - - + + + + + +
chpointer to the channel
bufthe buffer to store the request in
sizethe size of the buffer
reqrequest handle
bufthe point where the new entry will be added to the buffer
bufsizeremaining size of the buffer
namethe name of the entry
ethe directory entry
offthe offset of the next entry
-
Returns
the actual size of the raw request, or -errno on error
+
Returns
the space needed for the entry
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - -
int fuse_chan_send (struct fuse_chan * ch,
const struct iovec iov[],
size_t count 
)
-
-

Send a raw reply

-

A return value of -ENOENT means, that the request was interrupted, and the reply was discarded

-
Parameters
- - - - -
chthe channel
iovvector of blocks
countthe number of blocks in vector
-
-
-
Returns
zero on success, -errno on failure
+

Definition at line 357 of file fuse_lowlevel.c.

- + +

◆ fuse_cmdline_help()

+
- + - - + +
struct fuse_session* fuse_chan_session void fuse_cmdline_help (struct fuse_chan * ch)void )
-

Query the session to which this channel is assigned

-
Parameters
- - -
chthe channel
-
-
-
Returns
the session, or NULL if the channel is not assigned
+

Print available options for fuse_parse_cmdline().

+ +

Definition at line 129 of file helper.c.

- + +

◆ fuse_lowlevel_help()

+
- + - - - - - + + - - - - - - - - - - - - - - - - - - -
struct fuse_session* fuse_lowlevel_new void fuse_lowlevel_help (struct fuse_argsargs,
void ) const struct fuse_lowlevel_opsop,
size_t op_size,
void * userdata 
)
-

Create a low level session

-
Parameters
- - - - - -
argsargument vector
opthe low level filesystem operations
op_sizesizeof(struct fuse_lowlevel_ops)
userdatauser data
-
-
-
Returns
the created session object, or NULL on failure
+

Print available low-level options to stdout. This is not an exhaustive list, but includes only those options that may be of interest to an end-user of a file system.

+ +

Definition at line 2611 of file fuse_lowlevel.c.

- + +

◆ fuse_lowlevel_notify_delete()

+
- - + + - + - + @@ -676,11 +488,14 @@ Functions
int fuse_lowlevel_notify_delete (struct fuse_chan * ch, struct fuse_session * se,
fuse_ino_t fuse_ino_t  parent,
fuse_ino_t fuse_ino_t  child,
-

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.

+

This function behaves like fuse_lowlevel_notify_inval_entry() with the following additional effect (at least as of Linux kernel 4.8):

+

If the provided child inode matches the inode that is currently associated with the cached dentry, and if there are any inotify watches registered for the dentry, then the watchers are informed that the dentry has been deleted.

+

To avoid a deadlock this function must not be called while executing a related filesytem operation or while holding a lock that could be needed to execute such an operation (see the description of fuse_lowlevel_notify_inval_entry() for more details).

+

When called correctly, this function will never block.

+

Added in FUSE protocol version 7.18. If the kernel does not support this (or a newer) version, the function will return -ENOSYS and do nothing.

Parameters
- + @@ -690,22 +505,26 @@ Functions
Returns
zero for success, -errno for failure
+

Definition at line 2187 of file fuse_lowlevel.c.

+ - + +

◆ fuse_lowlevel_notify_inval_entry()

+
chthe channel through which to send the notification
sethe session object
parentinode number
childinode number
namefile name
- - + + - + @@ -728,10 +547,12 @@ Functions
int fuse_lowlevel_notify_inval_entry (struct fuse_chan * ch, struct fuse_session * se,
fuse_ino_t fuse_ino_t  parent,

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.

+

To avoid a deadlock this function must not be called while executing a related filesytem operation or while holding a lock that could be needed to execute such an operation. As of kernel 4.18, a "related operation" is a lookup(), symlink(), mknod(), mkdir(), unlink(), rename(), link() or create() request for the parent, and a setattr(), unlink(), rmdir(), rename(), setxattr(), removexattr(), readdir() or readdirplus() request for the inode itself.

+

When called correctly, this function will never block.

+

Added in FUSE protocol version 7.12. If the kernel does not support this (or a newer) version, the function will return -ENOSYS and do nothing.

Parameters
- + @@ -740,22 +561,26 @@ Functions
Returns
zero for success, -errno for failure
+

Definition at line 2163 of file fuse_lowlevel.c.

+ - + +

◆ fuse_lowlevel_notify_inval_inode()

+
chthe channel through which to send the invalidation
sethe session object
parentinode number
namefile name
namelenstrlen() of file name
- - + + - + @@ -777,10 +602,13 @@ Functions
int fuse_lowlevel_notify_inval_inode (struct fuse_chan * ch, struct fuse_session * se,
fuse_ino_t fuse_ino_t  ino,
-

Notify to invalidate cache for an inode

+

Notify to invalidate cache for an inode.

+

Added in FUSE protocol version 7.12. If the kernel does not support this (or a newer) version, the function will return -ENOSYS and do nothing.

+

If the filesystem has writeback caching enabled, invalidating an inode will first trigger a writeback of all dirty pages. The call will block until all writeback requests have completed and the inode has been invalidated. It will, however, not wait for completion of pending writeback requests that have been issued before.

+

If there are no dirty pages, this function will never block.

Parameters
- + @@ -789,9 +617,13 @@ Functions
Returns
zero for success, -errno for failure
+

Definition at line 2141 of file fuse_lowlevel.c.

+ - + +

◆ fuse_lowlevel_notify_poll()

+
chthe channel through which to send the invalidation
sethe session object
inothe inode number
offthe offset in the inode where to start invalidating or negative to invalidate attributes only
lenthe amount of cache to invalidate or 0 for all
@@ -813,22 +645,26 @@ Functions +

Definition at line 2124 of file fuse_lowlevel.c.

+ - + +

◆ fuse_lowlevel_notify_retrieve()

+
- - + + - + @@ -861,9 +697,10 @@ Functions

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.

+

Added in FUSE protocol version 7.15. If the kernel does not support this (or a newer) version, the function will return -ENOSYS and do nothing.

Parameters
int fuse_lowlevel_notify_retrieve (struct fuse_chan * ch, struct fuse_session * se,
fuse_ino_t fuse_ino_t  ino,
- + @@ -873,22 +710,26 @@ Functions
Returns
zero for success, -errno for failure
+

Definition at line 2293 of file fuse_lowlevel.c.

+ - + +

◆ fuse_lowlevel_notify_store()

+
chthe channel through which to send the invalidation
sethe session object
inothe inode number
sizethe number of bytes to retrieve
offsetthe starting offset into the file to retrieve from
- - + + - + @@ -920,9 +761,10 @@ Functions

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.

+

Added in FUSE protocol version 7.15. If the kernel does not support this (or a newer) version, the function will return -ENOSYS and do nothing.

Parameters
int fuse_lowlevel_notify_store (struct fuse_chan * ch, struct fuse_session * se,
fuse_ino_t fuse_ino_t  ino,
- + @@ -932,9 +774,75 @@ Functions
Returns
zero for success, -errno for failure
+

Definition at line 2213 of file fuse_lowlevel.c.

+ - + +

◆ fuse_lowlevel_version()

+ +
+
+
chthe channel through which to send the invalidation
sethe session object
inothe inode number
offsetthe starting offset into the file to store to
bufvbuffer vector
+ + + + + + + +
void fuse_lowlevel_version (void )
+
+

Print low-level version information to stdout.

+ +

Definition at line 2604 of file fuse_lowlevel.c.

+ +
+
+ +

◆ fuse_parse_cmdline()

+ +
+
+ + + + + + + + + + + + + + + + + + +
int fuse_parse_cmdline (struct fuse_argsargs,
struct fuse_cmdline_opts * opts 
)
+
+

Utility function to parse common options for simple file systems using the low-level API. A help text that describes the available options can be printed with fuse_cmdline_help. A single non-option argument is treated as the mountpoint. Multiple non-option arguments will result in an error.

+

If neither -o subtype= or -o fsname= options are given, a new subtype option will be added and set to the basename of the program (the fsname will remain unset, and then defaults to "fuse").

+

Known options will be removed from args, unknown options will remain.

+
Parameters
+ + + +
argsargument vector (input+output)
optsoutput argument for parsed options
+
+
+
Returns
0 on success, -1 on failure
+ +

Definition at line 202 of file helper.c.

+ +
+
+ +

◆ fuse_reply_attr()

+
@@ -975,9 +883,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 431 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_bmap()

+
@@ -1011,9 +923,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 881 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_buf()

+
@@ -1054,9 +970,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 470 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_create()

+
@@ -1099,9 +1019,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 415 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_data()

+
@@ -1131,7 +1055,23 @@ Functions

Reply with data copied/moved from buffer(s)

+

Zero copy data transfer ("splicing") will be used under the following circumstances:

+
    +
  1. FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.want, and
  2. +
  3. the kernel supports splicing from the fuse device (FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.capable), and
  4. +
  5. flags does not contain FUSE_BUF_NO_SPLICE
  6. +
  7. The amount of data that is provided in file-descriptor backed buffers (i.e., buffers for which bufv[n].flags == FUSE_BUF_FD) is at least twice the page size.
  8. +
+

In order for SPLICE_F_MOVE to be used, the following additional conditions have to be fulfilled:

+
    +
  1. FUSE_CAP_SPLICE_MOVE is set in fuse_conn_info.want, and
  2. +
  3. the kernel supports it (i.e, FUSE_CAP_SPLICE_MOVE is set in fuse_conn_info.capable), and
  4. +
  5. flags contains FUSE_BUF_SPLICE_MOVE
  6. +
+

Note that, if splice is used, the data is actually spliced twice: once into a temporary pipe (to prepend header data), and then again into the kernel. If some of the provided buffers are memory-backed, the data in them is copied in step one and spliced in step two.

+

The FUSE_BUF_SPLICE_FORCE_SPLICE and FUSE_BUF_SPLICE_NONBLOCK flags are silently ignored.

Possible requests: read, readdir, getxattr, listxattr

+

Side effects: when used to return data from a readdirplus() (but not readdir()) call, increments the lookup count of each returned entry by one on success.

Parameters
@@ -1142,9 +1082,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 820 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_entry()

+
reqrequest handle
@@ -1179,9 +1123,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 399 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_err()

+
@@ -1204,9 +1152,11 @@ Functions
-

Reply with an error code or success

+

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

+

Whereever possible, error codes should be chosen from the list of documented error conditions in the corresponding system calls manpage.

+

An error code of ENOSYS is sometimes treated specially. This is indicated in the documentation of the affected handler functions.

+

The following requests may be answered with a zero error code: unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, removexattr, setlk.

Parameters
@@ -1216,9 +1166,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 312 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_ioctl()

+
reqrequest handle
@@ -1265,9 +1219,13 @@ Functions +

Definition at line 979 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_ioctl_iov()

+
@@ -1314,9 +1272,13 @@ Functions +

Definition at line 1000 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_ioctl_retry()

+
@@ -1371,9 +1333,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 909 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_iov()

+
@@ -1414,9 +1380,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 246 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_lock()

+
@@ -1450,9 +1420,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 864 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_none()

+
@@ -1466,7 +1440,7 @@ Functions

Don't send reply

-

Possible requests: forget

+

Possible requests: forget forget_multi retrieve_reply

Parameters
@@ -1474,9 +1448,13 @@ Functions +

Definition at line 317 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_open()

+
reqrequest handle
@@ -1511,9 +1489,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 451 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_poll()

+
@@ -1545,9 +1527,13 @@ Functions +

Definition at line 1024 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_readlink()

+
@@ -1581,9 +1567,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 446 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_statfs()

+
@@ -1617,9 +1607,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 842 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_write()

+
@@ -1653,9 +1647,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 460 of file fuse_lowlevel.c.

+ - + +

◆ fuse_reply_xattr()

+
@@ -1689,9 +1687,13 @@ Functions
Returns
zero for success, -errno for failure to send reply
+

Definition at line 854 of file fuse_lowlevel.c.

+ - + +

◆ fuse_req_ctx()

+
@@ -1714,9 +1716,13 @@ Functions
Returns
the context structure
+

Definition at line 2343 of file fuse_lowlevel.c.

+ - + +

◆ fuse_req_getgroups()

+
@@ -1759,9 +1765,13 @@ Functions
Returns
the total number of supplementary group IDs or -errno on failure
+

Definition at line 3030 of file fuse_lowlevel.c.

+ - + +

◆ fuse_req_interrupt_func()

+
@@ -1774,7 +1784,7 @@ Functions - + @@ -1801,9 +1811,13 @@ Functions +

Definition at line 2348 of file fuse_lowlevel.c.

+ - + +

◆ fuse_req_interrupted()

+
fuse_interrupt_func_t fuse_interrupt_func_t  func,
@@ -1825,9 +1839,13 @@ Functions
Returns
1 if the request has been interrupted, 0 otherwise
+

Definition at line 2361 of file fuse_lowlevel.c.

+ - + +

◆ fuse_req_userdata()

+
@@ -1847,71 +1865,15 @@ Functions
-
Returns
the user data passed to fuse_lowlevel_new()
+
Returns
the user data passed to fuse_session_new()
-
-
- -
-
- - - - - - - - - - - - - - - - - - -
void fuse_session_add_chan (struct fuse_session * se,
struct fuse_chan * ch 
)
-
-

Assign a channel to a session

-

Note: currently only a single channel may be assigned. This may change in the future

-

If a session is destroyed, the assigned channel is also destroyed

-
Parameters
- - - -
sethe session
chthe channel
-
-
+

Definition at line 2338 of file fuse_lowlevel.c.

- -
-
- - - - - - - - -
void* fuse_session_data (struct fuse_session * se)
-
-

Get the user data provided to the session

-
Parameters
- - -
sethe session
-
-
-
Returns
the user data
+ +

◆ fuse_session_destroy()

-
-
-
@@ -1932,9 +1894,13 @@ Functions +

Definition at line 2621 of file fuse_lowlevel.c.

+ - + +

◆ fuse_session_exit()

+
@@ -1947,7 +1913,8 @@ Functions
-

Exit a session

+

Flag a session as terminated.

+

This function is invoked by the POSIX signal handlers, when registered using fuse_set_signal_handlers(). It will cause any running event loops to terminate on the next opportunity.

Parameters
@@ -1955,9 +1922,13 @@ Functions +

Definition at line 3037 of file fuse_lowlevel.c.

+ - + +

◆ fuse_session_exited()

+
sethe session
@@ -1970,7 +1941,7 @@ Functions
-

Query the exited status of a session

+

Query the terminated flag of a session

Parameters
@@ -1979,14 +1950,18 @@ Functions
Returns
1 if exited, 0 if not exited
+

Definition at line 3048 of file fuse_lowlevel.c.

+ - + +

◆ fuse_session_fd()

+
sethe session
- + @@ -1994,23 +1969,29 @@ Functions
int fuse_session_loop int fuse_session_fd ( struct fuse_session *  se)
-

Enter a single threaded event loop

+

Return file descriptor for communication with kernel.

+

The file selector can be used to integrate FUSE with a custom event loop. Whenever data is available for reading on the provided fd, the event loop should call fuse_session_receive_buf followed by fuse_session_process_buf to process the request.

+

The returned file descriptor is valid until fuse_session_unmount is called.

Parameters
sethe session
-
Returns
0 on success, -1 on error
+
Returns
a file descriptor
+ +

Definition at line 2953 of file fuse_lowlevel.c.

- + +

◆ fuse_session_loop()

+
- + @@ -2018,32 +1999,39 @@ Functions
int fuse_session_loop_mt int fuse_session_loop ( struct fuse_session *  se)
-

Enter a multi-threaded event loop

+

Enter a single threaded, blocking event loop.

+

When the event loop terminates because the connection to the FUSE kernel module has been closed, this function returns zero. This happens when the filesystem is unmounted regularly (by the filesystem owner or root running the umount(8) or fusermount(1) command), or if connection is explicitly severed by writing 1 to theabort file in /sys/fs/fuse/connections/NNN. The only way to distinguish between these two conditions is to check if the filesystem is still mounted after the session loop returns.

+

When some error occurs during request processing, the function returns a negated errno(3) value.

+

If the loop has been terminated because of a signal handler installed by fuse_set_signal_handlers(), this function returns the (positive) signal value that triggered the exit.

Parameters
sethe session
-
Returns
0 on success, -1 on error
+
Returns
0, -errno, or a signal value
+ +

Definition at line 19 of file fuse_loop.c.

- + +

◆ fuse_session_loop_mt_31()

+
- + - - + + - - + + @@ -2052,24 +2040,29 @@ Functions
struct fuse_session* fuse_session_new int fuse_session_loop_mt_31 (struct fuse_session_opsop, struct fuse_session * se,
void * data int clone_fd 
-

Create a new session

+

Enter a multi-threaded event loop.

+

For a description of the return value and the conditions when the event loop exits, refer to the documentation of fuse_session_loop().

Parameters
- - + +
opsession operations
datauser data
sethe session
configsession loop configuration
-
Returns
new session object, or NULL on failure
+
Returns
see fuse_session_loop()
+ +

Definition at line 356 of file fuse_loop_mt.c.

- + +

◆ fuse_session_mount()

+
- + @@ -2077,8 +2070,8 @@ Functions - - + + @@ -2087,46 +2080,49 @@ Functions
struct fuse_chan* fuse_session_next_chan int fuse_session_mount ( struct fuse_session *  se,
struct fuse_chan * ch const char * mountpoint 
-

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.

+

Mount a FUSE file system.

Parameters
- - + +
sethe session
chthe previous channel, or NULL
mountpointthe mount point path
sesession object
-
Returns
the next channel, or NULL if no more channels exist
+
Returns
0 on success, -1 on failure.
+ +

Definition at line 2903 of file fuse_lowlevel.c.

- + +

◆ fuse_session_new()

+
- + - - + + - - + + - + - - + + @@ -2135,20 +2131,29 @@ Functions
void fuse_session_process struct fuse_session* fuse_session_new (struct fuse_session * se, struct fuse_argsargs,
const char * buf, const struct fuse_lowlevel_opsop,
size_t len, op_size,
struct fuse_chan * ch void * userdata 
-

Process a raw request

+

Create a low level session.

+

Returns a session structure suitable for passing to fuse_session_mount() and fuse_session_loop().

+

This function accepts most file-system independent mount options (like context, nodev, ro - see mount(8)), as well as the general fuse mount options listed in mount.fuse(8) (e.g. -o allow_root and -o default_permissions, but not -o use_ino). Instead of -o debug, debugging may also enabled with -d or --debug.

+

If not all options are known, an error message is written to stderr and the function returns NULL.

+

Option parsing skips argv[0], which is assumed to contain the program name. To prevent accidentally passing an option in argv[0], this element must always be present (even if no options are specified). It may be set to the empty string ('\0') if no reasonable value can be provided.

Parameters
- - - - + + + +
sethe session
bufbuffer containing the raw request
lenrequest length
chchannel on which the request was received
argsargument vector
opthe (low-level) filesystem operations
op_sizesizeof(struct fuse_lowlevel_ops)
userdatauser data
+
Returns
the fuse session on success, NULL on failure
+ +

Definition at line 2809 of file fuse_lowlevel.c.

- + +

◆ fuse_session_process_buf()

+
@@ -2162,13 +2167,7 @@ Functions - - - - - - - + @@ -2178,19 +2177,22 @@ Functions
const struct fuse_bufbuf,
struct fuse_chan * ch buf 

Process a raw request supplied in a generic buffer

-

This is a more generic version of fuse_session_process(). The fuse_buf may contain a memory buffer or a pipe file descriptor.

+

The fuse_buf may contain a memory buffer or a pipe file descriptor.

Parameters
-
sethe session
bufthe fuse_buf containing the request
chchannel on which the request was received
+

Definition at line 2448 of file fuse_lowlevel.c.

+
- + +

◆ fuse_session_receive_buf()

+
@@ -2204,13 +2206,7 @@ Functions - - - - - - - + @@ -2219,50 +2215,56 @@ Functions
struct fuse_bufbuf,
struct fuse_chan ** chp buf 
-

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.

+

Read a raw request from the kernel into the supplied buffer.

+

Depending on file system options, system capabilities, and request size the request is either read into a memory buffer or spliced into a temporary pipe.

Parameters
-
sethe session
bufthe fuse_buf to store the request in
chppointer to the channel
Returns
the actual size of the raw request, or -errno on error
+

Definition at line 2648 of file fuse_lowlevel.c.

+
- + +

◆ fuse_session_reset()

+
- + - - + +
void fuse_session_remove_chan void fuse_session_reset (struct fuse_chan * ch)struct fuse_session * se)
-

Remove a channel from a session

-

If the channel is not assigned to a session, then this is a no-op

+

Reset the terminated flag of a session

Parameters
- +
chthe channel to remove
sethe session
+

Definition at line 3042 of file fuse_lowlevel.c.

+
- + +

◆ fuse_session_unmount()

+
- + @@ -2270,7 +2272,10 @@ Functions
void fuse_session_reset void fuse_session_unmount ( struct fuse_session *  se)
-

Reset the exited status of a session

+

Ensure that file system is unmounted.

+

In regular operation, the file system is typically unmounted by the user calling umount(8) or fusermount(1), which then terminates the FUSE session loop. However, the session loop may also terminate as a result of an explicit call to fuse_session_exit() (e.g. by a signal handler installed by fuse_set_signal_handler()). In this case the filesystem remains mounted, but any attempt to access it will block (while the filesystem process is still running) or give an ESHUTDOWN error (after the filesystem process has terminated).

+

If the communication channel with the FUSE kernel module is still open (i.e., if the session loop was terminated by an explicit call to fuse_session_exit()), this function will close it and unmount the filesystem. If the communication channel has been closed by the kernel, this method will do (almost) nothing.

+

NOTE: The above semantics mean that if the connection to the kernel is terminated via the /sys/fs/fuse/connections/NNN/abort file, this method will not unmount the filesystem.

Parameters
@@ -2278,14 +2283,16 @@ Functions +

Definition at line 2958 of file fuse_lowlevel.c.

+ diff --git a/doc/html/fuse__lowlevel_8h_source.html b/doc/html/fuse__lowlevel_8h_source.html new file mode 100644 index 0000000..f9df461 --- /dev/null +++ b/doc/html/fuse__lowlevel_8h_source.html @@ -0,0 +1,131 @@ + + + + + + + +libfuse: include/fuse_lowlevel.h Source File + + + + + + +
+
+
sethe session
+ + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_lowlevel.h
+
+
+Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU LGPLv2.
6  See the file COPYING.LIB.
7 */
8 
9 #ifndef FUSE_LOWLEVEL_H_
10 #define FUSE_LOWLEVEL_H_
11 
21 #ifndef FUSE_USE_VERSION
22 #error FUSE_USE_VERSION not defined
23 #endif
24 
25 #include "fuse_common.h"
26 
27 #include <utime.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/statvfs.h>
32 #include <sys/uio.h>
33 
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
38 /* ----------------------------------------------------------- *
39  * Miscellaneous definitions *
40  * ----------------------------------------------------------- */
41 
43 #define FUSE_ROOT_ID 1
44 
46 typedef uint64_t fuse_ino_t;
47 
49 typedef struct fuse_req *fuse_req_t;
50 
56 struct fuse_session;
57 
67  fuse_ino_t ino;
68 
82  uint64_t generation;
83 
91  struct stat attr;
92 
97  double attr_timeout;
98 
104 };
105 
114 struct fuse_ctx {
116  uid_t uid;
117 
119  gid_t gid;
120 
122  pid_t pid;
123 
125  mode_t umask;
126 };
127 
128 struct fuse_forget_data {
129  fuse_ino_t ino;
130  uint64_t nlookup;
131 };
132 
133 /* 'to_set' flags in setattr */
134 #define FUSE_SET_ATTR_MODE (1 << 0)
135 #define FUSE_SET_ATTR_UID (1 << 1)
136 #define FUSE_SET_ATTR_GID (1 << 2)
137 #define FUSE_SET_ATTR_SIZE (1 << 3)
138 #define FUSE_SET_ATTR_ATIME (1 << 4)
139 #define FUSE_SET_ATTR_MTIME (1 << 5)
140 #define FUSE_SET_ATTR_ATIME_NOW (1 << 7)
141 #define FUSE_SET_ATTR_MTIME_NOW (1 << 8)
142 #define FUSE_SET_ATTR_CTIME (1 << 10)
143 
144 /* ----------------------------------------------------------- *
145  * Request methods and replies *
146  * ----------------------------------------------------------- */
147 
192  void (*init) (void *userdata, struct fuse_conn_info *conn);
193 
205  void (*destroy) (void *userdata);
206 
218  void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
219 
256  void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup);
257 
277  void (*getattr) (fuse_req_t req, fuse_ino_t ino,
278  struct fuse_file_info *fi);
279 
308  void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
309  int to_set, struct fuse_file_info *fi);
310 
321  void (*readlink) (fuse_req_t req, fuse_ino_t ino);
322 
339  void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
340  mode_t mode, dev_t rdev);
341 
354  void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
355  mode_t mode);
356 
372  void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
373 
389  void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
390 
403  void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
404  const char *name);
405 
435  void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
436  fuse_ino_t newparent, const char *newname,
437  unsigned int flags);
438 
451  void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
452  const char *newname);
453 
510  void (*open) (fuse_req_t req, fuse_ino_t ino,
511  struct fuse_file_info *fi);
512 
538  void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
539  struct fuse_file_info *fi);
540 
567  void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
568  size_t size, off_t off, struct fuse_file_info *fi);
569 
604  void (*flush) (fuse_req_t req, fuse_ino_t ino,
605  struct fuse_file_info *fi);
606 
631  void (*release) (fuse_req_t req, fuse_ino_t ino,
632  struct fuse_file_info *fi);
633 
653  void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
654  struct fuse_file_info *fi);
655 
677  void (*opendir) (fuse_req_t req, fuse_ino_t ino,
678  struct fuse_file_info *fi);
679 
707  void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
708  struct fuse_file_info *fi);
709 
726  void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
727  struct fuse_file_info *fi);
728 
751  void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
752  struct fuse_file_info *fi);
753 
764  void (*statfs) (fuse_req_t req, fuse_ino_t ino);
765 
777  void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
778  const char *value, size_t size, int flags);
779 
808  void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
809  size_t size);
810 
839  void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
840 
856  void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
857 
878  void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
879 
907  void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
908  mode_t mode, struct fuse_file_info *fi);
909 
922  void (*getlk) (fuse_req_t req, fuse_ino_t ino,
923  struct fuse_file_info *fi, struct flock *lock);
924 
947  void (*setlk) (fuse_req_t req, fuse_ino_t ino,
948  struct fuse_file_info *fi,
949  struct flock *lock, int sleep);
950 
971  void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
972  uint64_t idx);
973 
999  void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
1000  struct fuse_file_info *fi, unsigned flags,
1001  const void *in_buf, size_t in_bufsz, size_t out_bufsz);
1002 
1032  void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
1033  struct fuse_pollhandle *ph);
1034 
1062  void (*write_buf) (fuse_req_t req, fuse_ino_t ino,
1063  struct fuse_bufvec *bufv, off_t off,
1064  struct fuse_file_info *fi);
1065 
1078  void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino,
1079  off_t offset, struct fuse_bufvec *bufv);
1080 
1092  void (*forget_multi) (fuse_req_t req, size_t count,
1093  struct fuse_forget_data *forgets);
1094 
1110  void (*flock) (fuse_req_t req, fuse_ino_t ino,
1111  struct fuse_file_info *fi, int op);
1112 
1133  void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode,
1134  off_t offset, off_t length, struct fuse_file_info *fi);
1135 
1161  void (*readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1162  struct fuse_file_info *fi);
1163 
1194  void (*copy_file_range) (fuse_req_t req, fuse_ino_t ino_in,
1195  off_t off_in, struct fuse_file_info *fi_in,
1196  fuse_ino_t ino_out, off_t off_out,
1197  struct fuse_file_info *fi_out, size_t len,
1198  int flags);
1199 };
1200 
1222 int fuse_reply_err(fuse_req_t req, int err);
1223 
1234 void fuse_reply_none(fuse_req_t req);
1235 
1249 int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
1250 
1268 int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
1269  const struct fuse_file_info *fi);
1270 
1282 int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
1283  double attr_timeout);
1284 
1295 int fuse_reply_readlink(fuse_req_t req, const char *link);
1296 
1310 int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi);
1311 
1322 int fuse_reply_write(fuse_req_t req, size_t count);
1323 
1335 int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
1336 
1380 int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
1381  enum fuse_buf_copy_flags flags);
1382 
1394 int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count);
1395 
1406 int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf);
1407 
1418 int fuse_reply_xattr(fuse_req_t req, size_t count);
1419 
1430 int fuse_reply_lock(fuse_req_t req, const struct flock *lock);
1431 
1442 int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
1443 
1444 /* ----------------------------------------------------------- *
1445  * Filling a buffer in readdir *
1446  * ----------------------------------------------------------- */
1447 
1475 size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
1476  const char *name, const struct stat *stbuf,
1477  off_t off);
1478 
1492 size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
1493  const char *name,
1494  const struct fuse_entry_param *e, off_t off);
1495 
1511 int fuse_reply_ioctl_retry(fuse_req_t req,
1512  const struct iovec *in_iov, size_t in_count,
1513  const struct iovec *out_iov, size_t out_count);
1514 
1526 int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
1527 
1539 int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
1540  int count);
1541 
1548 int fuse_reply_poll(fuse_req_t req, unsigned revents);
1549 
1550 /* ----------------------------------------------------------- *
1551  * Notification *
1552  * ----------------------------------------------------------- */
1553 
1561 int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
1562 
1586 int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
1587  off_t off, off_t len);
1588 
1614 int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
1615  const char *name, size_t namelen);
1616 
1645 int fuse_lowlevel_notify_delete(struct fuse_session *se,
1646  fuse_ino_t parent, fuse_ino_t child,
1647  const char *name, size_t namelen);
1648 
1674 int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
1675  off_t offset, struct fuse_bufvec *bufv,
1676  enum fuse_buf_copy_flags flags);
1706 int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
1707  size_t size, off_t offset, void *cookie);
1708 
1709 
1710 /* ----------------------------------------------------------- *
1711  * Utility functions *
1712  * ----------------------------------------------------------- */
1713 
1720 void *fuse_req_userdata(fuse_req_t req);
1721 
1731 const struct fuse_ctx *fuse_req_ctx(fuse_req_t req);
1732 
1752 int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]);
1753 
1760 typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data);
1761 
1773 void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
1774  void *data);
1775 
1782 int fuse_req_interrupted(fuse_req_t req);
1783 
1784 
1785 /* ----------------------------------------------------------- *
1786  * Inquiry functions *
1787  * ----------------------------------------------------------- */
1788 
1792 void fuse_lowlevel_version(void);
1793 
1799 void fuse_lowlevel_help(void);
1800 
1804 void fuse_cmdline_help(void);
1805 
1806 /* ----------------------------------------------------------- *
1807  * Filesystem setup & teardown *
1808  * ----------------------------------------------------------- */
1809 
1810 struct fuse_cmdline_opts {
1811  int singlethread;
1812  int foreground;
1813  int debug;
1814  int nodefault_subtype;
1815  char *mountpoint;
1816  int show_version;
1817  int show_help;
1818  int clone_fd;
1819  unsigned int max_idle_threads;
1820 };
1821 
1840 int fuse_parse_cmdline(struct fuse_args *args,
1841  struct fuse_cmdline_opts *opts);
1842 
1871 struct fuse_session *fuse_session_new(struct fuse_args *args,
1872  const struct fuse_lowlevel_ops *op,
1873  size_t op_size, void *userdata);
1874 
1883 int fuse_session_mount(struct fuse_session *se, const char *mountpoint);
1884 
1907 int fuse_session_loop(struct fuse_session *se);
1908 
1920 #if FUSE_USE_VERSION < 32
1921 int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
1922 #define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd)
1923 #else
1924 int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config);
1925 #endif
1926 
1936 void fuse_session_exit(struct fuse_session *se);
1937 
1943 void fuse_session_reset(struct fuse_session *se);
1944 
1951 int fuse_session_exited(struct fuse_session *se);
1952 
1977 void fuse_session_unmount(struct fuse_session *se);
1978 
1984 void fuse_session_destroy(struct fuse_session *se);
1985 
1986 /* ----------------------------------------------------------- *
1987  * Custom event loop support *
1988  * ----------------------------------------------------------- */
1989 
2004 int fuse_session_fd(struct fuse_session *se);
2005 
2014 void fuse_session_process_buf(struct fuse_session *se,
2015  const struct fuse_buf *buf);
2016 
2028 int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf);
2029 
2030 #ifdef __cplusplus
2031 }
2032 #endif
2033 
2034 #endif /* FUSE_LOWLEVEL_H_ */
void fuse_session_destroy(struct fuse_session *se)
+
int fuse_reply_err(fuse_req_t req, int err)
+
size_t off
Definition: fuse_common.h:679
+
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
+
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
+
void fuse_session_exit(struct fuse_session *se)
+
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
+
int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
+ +
int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
+
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
+
void fuse_lowlevel_help(void)
+
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
+
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
+
int fuse_session_fd(struct fuse_session *se)
+
const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
+
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
+
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)
+
mode_t umask
+
void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
+
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+
struct stat attr
Definition: fuse_lowlevel.h:91
+
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
+
void * fuse_req_userdata(fuse_req_t req)
+
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
+ +
int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
+
int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd)
Definition: fuse_loop_mt.c:356
+
Definition: fuse_lowlevel.h:59
+
fuse_ino_t ino
Definition: fuse_lowlevel.h:67
+
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
+
int fuse_reply_xattr(fuse_req_t req, size_t count)
+ +
void fuse_cmdline_help(void)
Definition: helper.c:129
+
int fuse_session_exited(struct fuse_session *se)
+
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
+ + +
int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
+
int fuse_req_interrupted(fuse_req_t req)
+
void fuse_session_reset(struct fuse_session *se)
+
void fuse_lowlevel_version(void)
+
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
+
void fuse_reply_none(fuse_req_t req)
+
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+ + + + +
size_t count
Definition: fuse_common.h:669
+
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
+
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
+
void fuse_session_unmount(struct fuse_session *se)
+
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
+
unsigned int flush
Definition: fuse_common.h:56
+
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
+
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
+
uint64_t generation
Definition: fuse_lowlevel.h:82
+
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
+
int fuse_reply_write(fuse_req_t req, size_t count)
+
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
+ + + +
double entry_timeout
+
fuse_buf_copy_flags
Definition: fuse_common.h:579
+
double attr_timeout
Definition: fuse_lowlevel.h:97
+
int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
+ +
int fuse_reply_readlink(fuse_req_t req, const char *link)
+
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+
int fuse_reply_poll(fuse_req_t req, unsigned revents)
+
void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
+
+ + + + diff --git a/doc/html/fuse__misc_8h_source.html b/doc/html/fuse__misc_8h_source.html new file mode 100644 index 0000000..74bcf16 --- /dev/null +++ b/doc/html/fuse__misc_8h_source.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: lib/fuse_misc.h Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_misc.h
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU LGPLv2.
6  See the file COPYING.LIB
7 */
8 
9 #include <pthread.h>
10 
11 /*
12  Versioned symbols cannot be used in some cases because it
13  - confuse the dynamic linker in uClibc
14  - not supported on MacOSX (in MachO binary format)
15 */
16 #if (!defined(__UCLIBC__) && !defined(__APPLE__))
17 #define FUSE_SYMVER(x) __asm__(x)
18 #else
19 #define FUSE_SYMVER(x)
20 #endif
21 
22 #ifndef USE_UCLIBC
23 #define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL)
24 #else
25 /* Is this hack still needed? */
26 static inline void fuse_mutex_init(pthread_mutex_t *mut)
27 {
28  pthread_mutexattr_t attr;
29  pthread_mutexattr_init(&attr);
30  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
31  pthread_mutex_init(mut, &attr);
32  pthread_mutexattr_destroy(&attr);
33 }
34 #endif
35 
36 #ifdef HAVE_STRUCT_STAT_ST_ATIM
37 /* Linux */
38 #define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec)
39 #define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec)
40 #define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec)
41 #define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val)
42 #define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctim.tv_nsec = (val)
43 #define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val)
44 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
45 /* FreeBSD */
46 #define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec)
47 #define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec)
48 #define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
49 #define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
50 #define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctimespec.tv_nsec = (val)
51 #define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
52 #else
53 #define ST_ATIM_NSEC(stbuf) 0
54 #define ST_CTIM_NSEC(stbuf) 0
55 #define ST_MTIM_NSEC(stbuf) 0
56 #define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0)
57 #define ST_CTIM_NSEC_SET(stbuf, val) do { } while (0)
58 #define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0)
59 #endif
+ + + + diff --git a/doc/html/fuse__opt_8c_source.html b/doc/html/fuse__opt_8c_source.html new file mode 100644 index 0000000..d37d90c --- /dev/null +++ b/doc/html/fuse__opt_8c_source.html @@ -0,0 +1,77 @@ + + + + + + + +libfuse: lib/fuse_opt.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_opt.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Implementation of option parsing routines (dealing with `struct
6  fuse_args`).
7 
8  This program can be distributed under the terms of the GNU LGPLv2.
9  See the file COPYING.LIB
10 */
11 
12 #include "config.h"
13 #include "fuse_opt.h"
14 #include "fuse_misc.h"
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <assert.h>
20 
21 struct fuse_opt_context {
22  void *data;
23  const struct fuse_opt *opt;
24  fuse_opt_proc_t proc;
25  int argctr;
26  int argc;
27  char **argv;
28  struct fuse_args outargs;
29  char *opts;
30  int nonopt;
31 };
32 
33 void fuse_opt_free_args(struct fuse_args *args)
34 {
35  if (args) {
36  if (args->argv && args->allocated) {
37  int i;
38  for (i = 0; i < args->argc; i++)
39  free(args->argv[i]);
40  free(args->argv);
41  }
42  args->argc = 0;
43  args->argv = NULL;
44  args->allocated = 0;
45  }
46 }
47 
48 static int alloc_failed(void)
49 {
50  fprintf(stderr, "fuse: memory allocation failed\n");
51  return -1;
52 }
53 
54 int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
55 {
56  char **newargv;
57  char *newarg;
58 
59  assert(!args->argv || args->allocated);
60 
61  newarg = strdup(arg);
62  if (!newarg)
63  return alloc_failed();
64 
65  newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
66  if (!newargv) {
67  free(newarg);
68  return alloc_failed();
69  }
70 
71  args->argv = newargv;
72  args->allocated = 1;
73  args->argv[args->argc++] = newarg;
74  args->argv[args->argc] = NULL;
75  return 0;
76 }
77 
78 static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
79  const char *arg)
80 {
81  assert(pos <= args->argc);
82  if (fuse_opt_add_arg(args, arg) == -1)
83  return -1;
84 
85  if (pos != args->argc - 1) {
86  char *newarg = args->argv[args->argc - 1];
87  memmove(&args->argv[pos + 1], &args->argv[pos],
88  sizeof(char *) * (args->argc - pos - 1));
89  args->argv[pos] = newarg;
90  }
91  return 0;
92 }
93 
94 int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
95 {
96  return fuse_opt_insert_arg_common(args, pos, arg);
97 }
98 
99 static int next_arg(struct fuse_opt_context *ctx, const char *opt)
100 {
101  if (ctx->argctr + 1 >= ctx->argc) {
102  fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
103  return -1;
104  }
105  ctx->argctr++;
106  return 0;
107 }
108 
109 static int add_arg(struct fuse_opt_context *ctx, const char *arg)
110 {
111  return fuse_opt_add_arg(&ctx->outargs, arg);
112 }
113 
114 static int add_opt_common(char **opts, const char *opt, int esc)
115 {
116  unsigned oldlen = *opts ? strlen(*opts) : 0;
117  char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
118 
119  if (!d)
120  return alloc_failed();
121 
122  *opts = d;
123  if (oldlen) {
124  d += oldlen;
125  *d++ = ',';
126  }
127 
128  for (; *opt; opt++) {
129  if (esc && (*opt == ',' || *opt == '\\'))
130  *d++ = '\\';
131  *d++ = *opt;
132  }
133  *d = '\0';
134 
135  return 0;
136 }
137 
138 int fuse_opt_add_opt(char **opts, const char *opt)
139 {
140  return add_opt_common(opts, opt, 0);
141 }
142 
143 int fuse_opt_add_opt_escaped(char **opts, const char *opt)
144 {
145  return add_opt_common(opts, opt, 1);
146 }
147 
148 static int add_opt(struct fuse_opt_context *ctx, const char *opt)
149 {
150  return add_opt_common(&ctx->opts, opt, 1);
151 }
152 
153 static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
154  int iso)
155 {
156  if (key == FUSE_OPT_KEY_DISCARD)
157  return 0;
158 
159  if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
160  int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
161  if (res == -1 || !res)
162  return res;
163  }
164  if (iso)
165  return add_opt(ctx, arg);
166  else
167  return add_arg(ctx, arg);
168 }
169 
170 static int match_template(const char *t, const char *arg, unsigned *sepp)
171 {
172  int arglen = strlen(arg);
173  const char *sep = strchr(t, '=');
174  sep = sep ? sep : strchr(t, ' ');
175  if (sep && (!sep[1] || sep[1] == '%')) {
176  int tlen = sep - t;
177  if (sep[0] == '=')
178  tlen ++;
179  if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
180  *sepp = sep - t;
181  return 1;
182  }
183  }
184  if (strcmp(t, arg) == 0) {
185  *sepp = 0;
186  return 1;
187  }
188  return 0;
189 }
190 
191 static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
192  const char *arg, unsigned *sepp)
193 {
194  for (; opt && opt->templ; opt++)
195  if (match_template(opt->templ, arg, sepp))
196  return opt;
197  return NULL;
198 }
199 
200 int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
201 {
202  unsigned dummy;
203  return find_opt(opts, opt, &dummy) ? 1 : 0;
204 }
205 
206 static int process_opt_param(void *var, const char *format, const char *param,
207  const char *arg)
208 {
209  assert(format[0] == '%');
210  if (format[1] == 's') {
211  char **s = var;
212  char *copy = strdup(param);
213  if (!copy)
214  return alloc_failed();
215 
216  free(*s);
217  *s = copy;
218  } else {
219  if (sscanf(param, format, var) != 1) {
220  fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
221  return -1;
222  }
223  }
224  return 0;
225 }
226 
227 static int process_opt(struct fuse_opt_context *ctx,
228  const struct fuse_opt *opt, unsigned sep,
229  const char *arg, int iso)
230 {
231  if (opt->offset == -1U) {
232  if (call_proc(ctx, arg, opt->value, iso) == -1)
233  return -1;
234  } else {
235  void *var = ctx->data + opt->offset;
236  if (sep && opt->templ[sep + 1]) {
237  const char *param = arg + sep;
238  if (opt->templ[sep] == '=')
239  param ++;
240  if (process_opt_param(var, opt->templ + sep + 1,
241  param, arg) == -1)
242  return -1;
243  } else
244  *(int *)var = opt->value;
245  }
246  return 0;
247 }
248 
249 static int process_opt_sep_arg(struct fuse_opt_context *ctx,
250  const struct fuse_opt *opt, unsigned sep,
251  const char *arg, int iso)
252 {
253  int res;
254  char *newarg;
255  char *param;
256 
257  if (next_arg(ctx, arg) == -1)
258  return -1;
259 
260  param = ctx->argv[ctx->argctr];
261  newarg = malloc(sep + strlen(param) + 1);
262  if (!newarg)
263  return alloc_failed();
264 
265  memcpy(newarg, arg, sep);
266  strcpy(newarg + sep, param);
267  res = process_opt(ctx, opt, sep, newarg, iso);
268  free(newarg);
269 
270  return res;
271 }
272 
273 static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
274 {
275  unsigned sep;
276  const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
277  if (opt) {
278  for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
279  int res;
280  if (sep && opt->templ[sep] == ' ' && !arg[sep])
281  res = process_opt_sep_arg(ctx, opt, sep, arg,
282  iso);
283  else
284  res = process_opt(ctx, opt, sep, arg, iso);
285  if (res == -1)
286  return -1;
287  }
288  return 0;
289  } else
290  return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
291 }
292 
293 static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
294 {
295  char *s = opts;
296  char *d = s;
297  int end = 0;
298 
299  while (!end) {
300  if (*s == '\0')
301  end = 1;
302  if (*s == ',' || end) {
303  int res;
304 
305  *d = '\0';
306  res = process_gopt(ctx, opts, 1);
307  if (res == -1)
308  return -1;
309  d = opts;
310  } else {
311  if (s[0] == '\\' && s[1] != '\0') {
312  s++;
313  if (s[0] >= '0' && s[0] <= '3' &&
314  s[1] >= '0' && s[1] <= '7' &&
315  s[2] >= '0' && s[2] <= '7') {
316  *d++ = (s[0] - '0') * 0100 +
317  (s[1] - '0') * 0010 +
318  (s[2] - '0');
319  s += 2;
320  } else {
321  *d++ = *s;
322  }
323  } else {
324  *d++ = *s;
325  }
326  }
327  s++;
328  }
329 
330  return 0;
331 }
332 
333 static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
334 {
335  int res;
336  char *copy = strdup(opts);
337 
338  if (!copy) {
339  fprintf(stderr, "fuse: memory allocation failed\n");
340  return -1;
341  }
342  res = process_real_option_group(ctx, copy);
343  free(copy);
344  return res;
345 }
346 
347 static int process_one(struct fuse_opt_context *ctx, const char *arg)
348 {
349  if (ctx->nonopt || arg[0] != '-')
350  return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
351  else if (arg[1] == 'o') {
352  if (arg[2])
353  return process_option_group(ctx, arg + 2);
354  else {
355  if (next_arg(ctx, arg) == -1)
356  return -1;
357 
358  return process_option_group(ctx,
359  ctx->argv[ctx->argctr]);
360  }
361  } else if (arg[1] == '-' && !arg[2]) {
362  if (add_arg(ctx, arg) == -1)
363  return -1;
364  ctx->nonopt = ctx->outargs.argc;
365  return 0;
366  } else
367  return process_gopt(ctx, arg, 0);
368 }
369 
370 static int opt_parse(struct fuse_opt_context *ctx)
371 {
372  if (ctx->argc) {
373  if (add_arg(ctx, ctx->argv[0]) == -1)
374  return -1;
375  }
376 
377  for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
378  if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
379  return -1;
380 
381  if (ctx->opts) {
382  if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
383  fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
384  return -1;
385  }
386 
387  /* If option separator ("--") is the last argument, remove it */
388  if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
389  strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
390  free(ctx->outargs.argv[ctx->outargs.argc - 1]);
391  ctx->outargs.argv[--ctx->outargs.argc] = NULL;
392  }
393 
394  return 0;
395 }
396 
397 int fuse_opt_parse(struct fuse_args *args, void *data,
398  const struct fuse_opt opts[], fuse_opt_proc_t proc)
399 {
400  int res;
401  struct fuse_opt_context ctx = {
402  .data = data,
403  .opt = opts,
404  .proc = proc,
405  };
406 
407  if (!args || !args->argv || !args->argc)
408  return 0;
409 
410  ctx.argc = args->argc;
411  ctx.argv = args->argv;
412 
413  res = opt_parse(&ctx);
414  if (res != -1) {
415  struct fuse_args tmp = *args;
416  *args = ctx.outargs;
417  ctx.outargs = tmp;
418  }
419  free(ctx.opts);
420  fuse_opt_free_args(&ctx.outargs);
421  return res;
422 }
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
Definition: fuse_opt.c:143
+
int argc
Definition: fuse_opt.h:111
+
unsigned long offset
Definition: fuse_opt.h:85
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
int allocated
Definition: fuse_opt.h:117
+
int value
Definition: fuse_opt.h:91
+
int fuse_opt_match(const struct fuse_opt opts[], const char *opt)
+
const char * templ
Definition: fuse_opt.h:79
+
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
+
#define FUSE_OPT_KEY_DISCARD
Definition: fuse_opt.h:153
+
#define FUSE_OPT_KEY_OPT
Definition: fuse_opt.h:129
+
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+ +
#define FUSE_OPT_KEY_KEEP
Definition: fuse_opt.h:145
+
int fuse_opt_add_opt(char **opts, const char *opt)
Definition: fuse_opt.c:138
+
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
Definition: fuse_opt.c:94
+
#define FUSE_OPT_KEY_NONOPT
Definition: fuse_opt.h:137
+
char ** argv
Definition: fuse_opt.h:114
+ + +
int(* fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs)
Definition: fuse_opt.h:180
+
+ + + + diff --git a/doc/html/fuse__opt_8h.html b/doc/html/fuse__opt_8h.html index df14b5b..8d094be 100644 --- a/doc/html/fuse__opt_8h.html +++ b/doc/html/fuse__opt_8h.html @@ -3,8 +3,9 @@ - -fuse: include/fuse_opt.h File Reference + + +libfuse: include/fuse_opt.h File Reference @@ -16,8 +17,8 @@ - @@ -25,20 +26,15 @@
-
fuse +
+
libfuse
- - - + + + + +
+ +

Go to the source code of this file.

@@ -64,11 +62,11 @@ Data Structures

Data Structures

- + - + @@ -81,12 +79,12 @@ Macros

Macros

#define FUSE_OPT_KEY(templ, key)   { templ, -1U, key }
#define FUSE_OPT_KEY(templ, key)   { templ, -1U, key }
 
#define FUSE_OPT_END   { NULL, 0, 0 }
 
#define FUSE_ARGS_INIT(argc, argv)   { argc, argv, 0 }
#define FUSE_ARGS_INIT(argc, argv)   { argc, argv, 0 }
 
#define FUSE_OPT_KEY_OPT   -1
 
- - + +

Typedefs

typedef int(* fuse_opt_proc_t )(void *data, const char *arg, int key, struct fuse_args *outargs)
 
typedef int(* fuse_opt_proc_t) (void *data, const char *arg, int key, struct fuse_args *outargs)
 
- + @@ -103,8 +101,12 @@ Functions

Functions

int fuse_opt_parse (struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
int fuse_opt_parse (struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
 
int fuse_opt_add_opt (char **opts, const char *opt)
 

Detailed Description

This file defines the option parsing interface of FUSE

+ +

Definition in file fuse_opt.h.

Macro Definition Documentation

- + +

◆ FUSE_ARGS_INIT

+
@@ -129,9 +131,13 @@ Functions

Initializer for 'struct fuse_args'

+

Definition at line 123 of file fuse_opt.h.

+
- + +

◆ FUSE_OPT_END

+
@@ -142,9 +148,13 @@ Functions

Last option. An array of 'struct fuse_opt' must end with a NULL template value

+

Definition at line 104 of file fuse_opt.h.

+
- + +

◆ FUSE_OPT_KEY

+
@@ -169,9 +179,13 @@ Functions

Key option. In case of a match, the processing function will be called with the specified key.

+

Definition at line 98 of file fuse_opt.h.

+
- + +

◆ FUSE_OPT_KEY_DISCARD

+
@@ -183,9 +197,13 @@ Functions

Special key value for options to discard

Argument is not passed to processing function, but behave as if the processing function returned zero

+

Definition at line 153 of file fuse_opt.h.

+ - + +

◆ FUSE_OPT_KEY_KEEP

+
@@ -197,9 +215,13 @@ Functions

Special key value for options to keep

Argument is not passed to processing function, but behave as if the processing function returned 1

+

Definition at line 145 of file fuse_opt.h.

+ - + +

◆ FUSE_OPT_KEY_NONOPT

+
@@ -211,9 +233,13 @@ Functions

Key value passed to the processing function for all non-options

Non-options are the arguments beginning with a character other than '-' or all arguments after the special '–' option

+

Definition at line 137 of file fuse_opt.h.

+ - + +

◆ FUSE_OPT_KEY_OPT

+
@@ -224,15 +250,19 @@ Functions

Key value passed to the processing function if an option did not match any template

+

Definition at line 129 of file fuse_opt.h.

+

Typedef Documentation

- + +

◆ fuse_opt_proc_t

+
- +
typedef int(* fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs)typedef int(* fuse_opt_proc_t) (void *data, const char *arg, int key, struct fuse_args *outargs)
@@ -256,10 +286,14 @@ Functions
Returns
-1 on error, 0 if arg is to be discarded, 1 if arg should be kept
+

Definition at line 180 of file fuse_opt.h.

+

Function Documentation

- + +

◆ fuse_opt_add_arg()

+
@@ -292,9 +326,13 @@ Functions
Returns
-1 on allocation error, 0 on success
+

Definition at line 54 of file fuse_opt.c.

+ - + +

◆ fuse_opt_add_opt()

+
@@ -327,9 +365,13 @@ Functions
Returns
-1 on allocation error, 0 on success
+

Definition at line 138 of file fuse_opt.c.

+ - + +

◆ fuse_opt_add_opt_escaped()

+
@@ -362,9 +404,13 @@ Functions
Returns
-1 on allocation error, 0 on success
+

Definition at line 143 of file fuse_opt.c.

+ - + +

◆ fuse_opt_free_args()

+
@@ -386,9 +432,13 @@ Functions +

Definition at line 33 of file fuse_opt.c.

+ - + +

◆ fuse_opt_insert_arg()

+
@@ -429,9 +479,13 @@ Functions
Returns
-1 on allocation error, 0 on success
+

Definition at line 94 of file fuse_opt.c.

+ - + +

◆ fuse_opt_match()

+
@@ -466,7 +520,9 @@ Functions - + +

◆ fuse_opt_parse()

+
@@ -491,7 +547,7 @@ Functions - + @@ -517,14 +573,16 @@ Functions
Returns
-1 on error, 0 on success
+

Definition at line 397 of file fuse_opt.c.

+ diff --git a/doc/html/fuse__opt_8h_source.html b/doc/html/fuse__opt_8h_source.html new file mode 100644 index 0000000..d937052 --- /dev/null +++ b/doc/html/fuse__opt_8h_source.html @@ -0,0 +1,72 @@ + + + + + + + +libfuse: include/fuse_opt.h Source File + + + + + + +
+
+
fuse_opt_proc_t fuse_opt_proc_t  proc 
+ + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_opt.h
+
+
+Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU LGPLv2.
6  See the file COPYING.LIB.
7 */
8 
9 #ifndef FUSE_OPT_H_
10 #define FUSE_OPT_H_
11 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
77 struct fuse_opt {
79  const char *templ;
80 
85  unsigned long offset;
86 
91  int value;
92 };
93 
98 #define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
99 
104 #define FUSE_OPT_END { NULL, 0, 0 }
105 
109 struct fuse_args {
111  int argc;
112 
114  char **argv;
115 
118 };
119 
123 #define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
124 
129 #define FUSE_OPT_KEY_OPT -1
130 
137 #define FUSE_OPT_KEY_NONOPT -2
138 
145 #define FUSE_OPT_KEY_KEEP -3
146 
153 #define FUSE_OPT_KEY_DISCARD -4
154 
180 typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
181  struct fuse_args *outargs);
182 
203 int fuse_opt_parse(struct fuse_args *args, void *data,
204  const struct fuse_opt opts[], fuse_opt_proc_t proc);
205 
213 int fuse_opt_add_opt(char **opts, const char *opt);
214 
222 int fuse_opt_add_opt_escaped(char **opts, const char *opt);
223 
231 int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
232 
246 int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg);
247 
255 void fuse_opt_free_args(struct fuse_args *args);
256 
257 
265 int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
266 
267 #ifdef __cplusplus
268 }
269 #endif
270 
271 #endif /* FUSE_OPT_H_ */
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
Definition: fuse_opt.c:143
+
int argc
Definition: fuse_opt.h:111
+
unsigned long offset
Definition: fuse_opt.h:85
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
int allocated
Definition: fuse_opt.h:117
+
int value
Definition: fuse_opt.h:91
+
int fuse_opt_match(const struct fuse_opt opts[], const char *opt)
+
const char * templ
Definition: fuse_opt.h:79
+
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
+
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+
int fuse_opt_add_opt(char **opts, const char *opt)
Definition: fuse_opt.c:138
+
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
Definition: fuse_opt.c:94
+
char ** argv
Definition: fuse_opt.h:114
+ + +
int(* fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs)
Definition: fuse_opt.h:180
+
+ + + + diff --git a/doc/html/fuse__signals_8c_source.html b/doc/html/fuse__signals_8c_source.html new file mode 100644 index 0000000..68cfb14 --- /dev/null +++ b/doc/html/fuse__signals_8c_source.html @@ -0,0 +1,60 @@ + + + + + + + +libfuse: lib/fuse_signals.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fuse_signals.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Utility functions for setting signal handlers.
6 
7  This program can be distributed under the terms of the GNU LGPLv2.
8  See the file COPYING.LIB
9 */
10 
11 #include "config.h"
12 #include "fuse_lowlevel.h"
13 #include "fuse_i.h"
14 
15 #include <stdio.h>
16 #include <string.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 
20 static struct fuse_session *fuse_instance;
21 
22 static void exit_handler(int sig)
23 {
24  if (fuse_instance) {
25  fuse_session_exit(fuse_instance);
26  if(sig <= 0) {
27  fprintf(stderr, "assertion error: signal value <= 0\n");
28  abort();
29  }
30  fuse_instance->error = sig;
31  }
32 }
33 
34 static void do_nothing(int sig)
35 {
36  (void) sig;
37 }
38 
39 static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
40 {
41  struct sigaction sa;
42  struct sigaction old_sa;
43 
44  memset(&sa, 0, sizeof(struct sigaction));
45  sa.sa_handler = remove ? SIG_DFL : handler;
46  sigemptyset(&(sa.sa_mask));
47  sa.sa_flags = 0;
48 
49  if (sigaction(sig, NULL, &old_sa) == -1) {
50  perror("fuse: cannot get old signal handler");
51  return -1;
52  }
53 
54  if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
55  sigaction(sig, &sa, NULL) == -1) {
56  perror("fuse: cannot set signal handler");
57  return -1;
58  }
59  return 0;
60 }
61 
62 int fuse_set_signal_handlers(struct fuse_session *se)
63 {
64  /* If we used SIG_IGN instead of the do_nothing function,
65  then we would be unable to tell if we set SIG_IGN (and
66  thus should reset to SIG_DFL in fuse_remove_signal_handlers)
67  or if it was already set to SIG_IGN (and should be left
68  untouched. */
69  if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
70  set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
71  set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
72  set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1)
73  return -1;
74 
75  fuse_instance = se;
76  return 0;
77 }
78 
79 void fuse_remove_signal_handlers(struct fuse_session *se)
80 {
81  if (fuse_instance != se)
82  fprintf(stderr,
83  "fuse: fuse_remove_signal_handlers: unknown session\n");
84  else
85  fuse_instance = NULL;
86 
87  set_one_signal_handler(SIGHUP, exit_handler, 1);
88  set_one_signal_handler(SIGINT, exit_handler, 1);
89  set_one_signal_handler(SIGTERM, exit_handler, 1);
90  set_one_signal_handler(SIGPIPE, do_nothing, 1);
91 }
void fuse_session_exit(struct fuse_session *se)
+
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
+
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
+ +
+ + + + diff --git a/doc/html/fusermount_8c_source.html b/doc/html/fusermount_8c_source.html new file mode 100644 index 0000000..9ac34d5 --- /dev/null +++ b/doc/html/fusermount_8c_source.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: util/fusermount.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
fusermount.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU GPL.
6  See the file COPYING.
7 */
8 /* This program does the mounting and unmounting of FUSE filesystems */
9 
10 #define _GNU_SOURCE /* for clone */
11 #include <config.h>
12 
13 #include "mount_util.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <getopt.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <pwd.h>
23 #include <paths.h>
24 #include <mntent.h>
25 #include <sys/wait.h>
26 #include <sys/stat.h>
27 #include <sys/mount.h>
28 #include <sys/fsuid.h>
29 #include <sys/socket.h>
30 #include <sys/utsname.h>
31 #include <sched.h>
32 #include <stdbool.h>
33 #include <sys/vfs.h>
34 
35 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
36 
37 #define FUSE_DEV "/dev/fuse"
38 
39 #ifndef MS_DIRSYNC
40 #define MS_DIRSYNC 128
41 #endif
42 #ifndef MS_REC
43 #define MS_REC 16384
44 #endif
45 #ifndef MS_PRIVATE
46 #define MS_PRIVATE (1<<18)
47 #endif
48 
49 #ifndef UMOUNT_DETACH
50 #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
51 #endif
52 #ifndef UMOUNT_NOFOLLOW
53 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
54 #endif
55 #ifndef UMOUNT_UNUSED
56 #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
57 #endif
58 
59 static const char *progname;
60 
61 static int user_allow_other = 0;
62 static int mount_max = 1000;
63 
64 static int auto_unmount = 0;
65 
66 static const char *get_user_name(void)
67 {
68  struct passwd *pw = getpwuid(getuid());
69  if (pw != NULL && pw->pw_name != NULL)
70  return pw->pw_name;
71  else {
72  fprintf(stderr, "%s: could not determine username\n", progname);
73  return NULL;
74  }
75 }
76 
77 static uid_t oldfsuid;
78 static gid_t oldfsgid;
79 
80 static void drop_privs(void)
81 {
82  if (getuid() != 0) {
83  oldfsuid = setfsuid(getuid());
84  oldfsgid = setfsgid(getgid());
85  }
86 }
87 
88 static void restore_privs(void)
89 {
90  if (getuid() != 0) {
91  setfsuid(oldfsuid);
92  setfsgid(oldfsgid);
93  }
94 }
95 
96 #ifndef IGNORE_MTAB
97 /*
98  * Make sure that /etc/mtab is checked and updated atomically
99  */
100 static int lock_umount(void)
101 {
102  const char *mtab_lock = _PATH_MOUNTED ".fuselock";
103  int mtablock;
104  int res;
105  struct stat mtab_stat;
106 
107  /* /etc/mtab could be a symlink to /proc/mounts */
108  if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
109  return -1;
110 
111  mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
112  if (mtablock == -1) {
113  fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
114  progname, strerror(errno));
115  return -1;
116  }
117  res = lockf(mtablock, F_LOCK, 0);
118  if (res < 0) {
119  fprintf(stderr, "%s: error getting lock: %s\n", progname,
120  strerror(errno));
121  close(mtablock);
122  return -1;
123  }
124 
125  return mtablock;
126 }
127 
128 static void unlock_umount(int mtablock)
129 {
130  if (mtablock >= 0) {
131  int res;
132 
133  res = lockf(mtablock, F_ULOCK, 0);
134  if (res < 0) {
135  fprintf(stderr, "%s: error releasing lock: %s\n",
136  progname, strerror(errno));
137  }
138  close(mtablock);
139  }
140 }
141 
142 static int add_mount(const char *source, const char *mnt, const char *type,
143  const char *opts)
144 {
145  return fuse_mnt_add_mount(progname, source, mnt, type, opts);
146 }
147 
148 static int may_unmount(const char *mnt, int quiet)
149 {
150  struct mntent *entp;
151  FILE *fp;
152  const char *user = NULL;
153  char uidstr[32];
154  unsigned uidlen = 0;
155  int found;
156  const char *mtab = _PATH_MOUNTED;
157 
158  user = get_user_name();
159  if (user == NULL)
160  return -1;
161 
162  fp = setmntent(mtab, "r");
163  if (fp == NULL) {
164  fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
165  strerror(errno));
166  return -1;
167  }
168 
169  uidlen = sprintf(uidstr, "%u", getuid());
170 
171  found = 0;
172  while ((entp = getmntent(fp)) != NULL) {
173  if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
174  (strcmp(entp->mnt_type, "fuse") == 0 ||
175  strcmp(entp->mnt_type, "fuseblk") == 0 ||
176  strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
177  strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
178  char *p = strstr(entp->mnt_opts, "user=");
179  if (p &&
180  (p == entp->mnt_opts || *(p-1) == ',') &&
181  strcmp(p + 5, user) == 0) {
182  found = 1;
183  break;
184  }
185  /* /etc/mtab is a link pointing to
186  /proc/mounts: */
187  else if ((p =
188  strstr(entp->mnt_opts, "user_id=")) &&
189  (p == entp->mnt_opts ||
190  *(p-1) == ',') &&
191  strncmp(p + 8, uidstr, uidlen) == 0 &&
192  (*(p+8+uidlen) == ',' ||
193  *(p+8+uidlen) == '\0')) {
194  found = 1;
195  break;
196  }
197  }
198  }
199  endmntent(fp);
200 
201  if (!found) {
202  if (!quiet)
203  fprintf(stderr,
204  "%s: entry for %s not found in %s\n",
205  progname, mnt, mtab);
206  return -1;
207  }
208 
209  return 0;
210 }
211 
212 /*
213  * Check whether the file specified in "fusermount3 -u" is really a
214  * mountpoint and not a symlink. This is necessary otherwise the user
215  * could move the mountpoint away and replace it with a symlink
216  * pointing to an arbitrary mount, thereby tricking fusermount3 into
217  * unmounting that (umount(2) will follow symlinks).
218  *
219  * This is the child process running in a separate mount namespace, so
220  * we don't mess with the global namespace and if the process is
221  * killed for any reason, mounts are automatically cleaned up.
222  *
223  * First make sure nothing is propagated back into the parent
224  * namespace by marking all mounts "private".
225  *
226  * Then bind mount parent onto a stable base where the user can't move
227  * it around.
228  *
229  * Finally check /proc/mounts for an entry matching the requested
230  * mountpoint. If it's found then we are OK, and the user can't move
231  * it around within the parent directory as rename() will return
232  * EBUSY. Be careful to ignore any mounts that existed before the
233  * bind.
234  */
235 static int check_is_mount_child(void *p)
236 {
237  const char **a = p;
238  const char *last = a[0];
239  const char *mnt = a[1];
240  const char *type = a[2];
241  int res;
242  const char *procmounts = "/proc/mounts";
243  int found;
244  FILE *fp;
245  struct mntent *entp;
246  int count;
247 
248  res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
249  if (res == -1) {
250  fprintf(stderr, "%s: failed to mark mounts private: %s\n",
251  progname, strerror(errno));
252  return 1;
253  }
254 
255  fp = setmntent(procmounts, "r");
256  if (fp == NULL) {
257  fprintf(stderr, "%s: failed to open %s: %s\n", progname,
258  procmounts, strerror(errno));
259  return 1;
260  }
261 
262  count = 0;
263  while (getmntent(fp) != NULL)
264  count++;
265  endmntent(fp);
266 
267  fp = setmntent(procmounts, "r");
268  if (fp == NULL) {
269  fprintf(stderr, "%s: failed to open %s: %s\n", progname,
270  procmounts, strerror(errno));
271  return 1;
272  }
273 
274  res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
275  if (res == -1) {
276  fprintf(stderr, "%s: failed to bind parent to /: %s\n",
277  progname, strerror(errno));
278  return 1;
279  }
280 
281  found = 0;
282  while ((entp = getmntent(fp)) != NULL) {
283  if (count > 0) {
284  count--;
285  continue;
286  }
287  if (entp->mnt_dir[0] == '/' &&
288  strcmp(entp->mnt_dir + 1, last) == 0 &&
289  (!type || strcmp(entp->mnt_type, type) == 0)) {
290  found = 1;
291  break;
292  }
293  }
294  endmntent(fp);
295 
296  if (!found) {
297  fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
298  return 1;
299  }
300 
301  return 0;
302 }
303 
304 static pid_t clone_newns(void *a)
305 {
306  char buf[131072];
307  char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
308 
309 #ifdef __ia64__
310  extern int __clone2(int (*fn)(void *),
311  void *child_stack_base, size_t stack_size,
312  int flags, void *arg, pid_t *ptid,
313  void *tls, pid_t *ctid);
314 
315  return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
316  CLONE_NEWNS, a, NULL, NULL, NULL);
317 #else
318  return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
319 #endif
320 }
321 
322 static int check_is_mount(const char *last, const char *mnt, const char *type)
323 {
324  pid_t pid, p;
325  int status;
326  const char *a[3] = { last, mnt, type };
327 
328  pid = clone_newns((void *) a);
329  if (pid == (pid_t) -1) {
330  fprintf(stderr, "%s: failed to clone namespace: %s\n",
331  progname, strerror(errno));
332  return -1;
333  }
334  p = waitpid(pid, &status, __WCLONE);
335  if (p == (pid_t) -1) {
336  fprintf(stderr, "%s: waitpid failed: %s\n",
337  progname, strerror(errno));
338  return -1;
339  }
340  if (!WIFEXITED(status)) {
341  fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
342  progname, status);
343  return -1;
344  }
345  if (WEXITSTATUS(status) != 0)
346  return -1;
347 
348  return 0;
349 }
350 
351 static int chdir_to_parent(char *copy, const char **lastp)
352 {
353  char *tmp;
354  const char *parent;
355  char buf[65536];
356  int res;
357 
358  tmp = strrchr(copy, '/');
359  if (tmp == NULL || tmp[1] == '\0') {
360  fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
361  progname, copy);
362  return -1;
363  }
364  if (tmp != copy) {
365  *tmp = '\0';
366  parent = copy;
367  *lastp = tmp + 1;
368  } else if (tmp[1] != '\0') {
369  *lastp = tmp + 1;
370  parent = "/";
371  } else {
372  *lastp = ".";
373  parent = "/";
374  }
375 
376  res = chdir(parent);
377  if (res == -1) {
378  fprintf(stderr, "%s: failed to chdir to %s: %s\n",
379  progname, parent, strerror(errno));
380  return -1;
381  }
382 
383  if (getcwd(buf, sizeof(buf)) == NULL) {
384  fprintf(stderr, "%s: failed to obtain current directory: %s\n",
385  progname, strerror(errno));
386  return -1;
387  }
388  if (strcmp(buf, parent) != 0) {
389  fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
390  parent, buf);
391  return -1;
392 
393  }
394 
395  return 0;
396 }
397 
398 /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
399 static int umount_nofollow_support(void)
400 {
401  int res = umount2("", UMOUNT_UNUSED);
402  if (res != -1 || errno != EINVAL)
403  return 0;
404 
405  res = umount2("", UMOUNT_NOFOLLOW);
406  if (res != -1 || errno != ENOENT)
407  return 0;
408 
409  return 1;
410 }
411 
412 static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
413 {
414  int res;
415  char *copy;
416  const char *last;
417  int umount_flags = lazy ? UMOUNT_DETACH : 0;
418 
419  if (getuid() != 0) {
420  res = may_unmount(mnt, quiet);
421  if (res == -1)
422  return -1;
423  }
424 
425  copy = strdup(mnt);
426  if (copy == NULL) {
427  fprintf(stderr, "%s: failed to allocate memory\n", progname);
428  return -1;
429  }
430 
431  res = chdir_to_parent(copy, &last);
432  if (res == -1)
433  goto out;
434 
435  if (umount_nofollow_support()) {
436  umount_flags |= UMOUNT_NOFOLLOW;
437  } else {
438  res = check_is_mount(last, mnt, NULL);
439  if (res == -1)
440  goto out;
441  }
442 
443  res = umount2(last, umount_flags);
444  if (res == -1 && !quiet) {
445  fprintf(stderr, "%s: failed to unmount %s: %s\n",
446  progname, mnt, strerror(errno));
447  }
448 
449 out:
450  free(copy);
451  if (res == -1)
452  return -1;
453 
454  res = chdir("/");
455  if (res == -1) {
456  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
457  return -1;
458  }
459 
460  return fuse_mnt_remove_mount(progname, mnt);
461 }
462 
463 static int unmount_fuse(const char *mnt, int quiet, int lazy)
464 {
465  int res;
466  int mtablock = lock_umount();
467 
468  res = unmount_fuse_locked(mnt, quiet, lazy);
469  unlock_umount(mtablock);
470 
471  return res;
472 }
473 
474 static int count_fuse_fs(void)
475 {
476  struct mntent *entp;
477  int count = 0;
478  const char *mtab = _PATH_MOUNTED;
479  FILE *fp = setmntent(mtab, "r");
480  if (fp == NULL) {
481  fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
482  strerror(errno));
483  return -1;
484  }
485  while ((entp = getmntent(fp)) != NULL) {
486  if (strcmp(entp->mnt_type, "fuse") == 0 ||
487  strncmp(entp->mnt_type, "fuse.", 5) == 0)
488  count ++;
489  }
490  endmntent(fp);
491  return count;
492 }
493 
494 
495 #else /* IGNORE_MTAB */
496 static int count_fuse_fs(void)
497 {
498  return 0;
499 }
500 
501 static int add_mount(const char *source, const char *mnt, const char *type,
502  const char *opts)
503 {
504  (void) source;
505  (void) mnt;
506  (void) type;
507  (void) opts;
508  return 0;
509 }
510 
511 static int unmount_fuse(const char *mnt, int quiet, int lazy)
512 {
513  (void) quiet;
514  return fuse_mnt_umount(progname, mnt, mnt, lazy);
515 }
516 #endif /* IGNORE_MTAB */
517 
518 static void strip_line(char *line)
519 {
520  char *s = strchr(line, '#');
521  if (s != NULL)
522  s[0] = '\0';
523  for (s = line + strlen(line) - 1;
524  s >= line && isspace((unsigned char) *s); s--);
525  s[1] = '\0';
526  for (s = line; isspace((unsigned char) *s); s++);
527  if (s != line)
528  memmove(line, s, strlen(s)+1);
529 }
530 
531 static void parse_line(char *line, int linenum)
532 {
533  int tmp;
534  if (strcmp(line, "user_allow_other") == 0)
535  user_allow_other = 1;
536  else if (sscanf(line, "mount_max = %i", &tmp) == 1)
537  mount_max = tmp;
538  else if(line[0])
539  fprintf(stderr,
540  "%s: unknown parameter in %s at line %i: '%s'\n",
541  progname, FUSE_CONF, linenum, line);
542 }
543 
544 static void read_conf(void)
545 {
546  FILE *fp = fopen(FUSE_CONF, "r");
547  if (fp != NULL) {
548  int linenum = 1;
549  char line[256];
550  int isnewline = 1;
551  while (fgets(line, sizeof(line), fp) != NULL) {
552  if (isnewline) {
553  if (line[strlen(line)-1] == '\n') {
554  strip_line(line);
555  parse_line(line, linenum);
556  } else {
557  isnewline = 0;
558  }
559  } else if(line[strlen(line)-1] == '\n') {
560  fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
561 
562  isnewline = 1;
563  }
564  if (isnewline)
565  linenum ++;
566  }
567  if (!isnewline) {
568  fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
569 
570  }
571  if (ferror(fp)) {
572  fprintf(stderr, "%s: reading %s: read failed\n", progname, FUSE_CONF);
573  exit(1);
574  }
575  fclose(fp);
576  } else if (errno != ENOENT) {
577  bool fatal = (errno != EACCES && errno != ELOOP &&
578  errno != ENAMETOOLONG && errno != ENOTDIR &&
579  errno != EOVERFLOW);
580  fprintf(stderr, "%s: failed to open %s: %s\n",
581  progname, FUSE_CONF, strerror(errno));
582  if (fatal)
583  exit(1);
584  }
585 }
586 
587 static int begins_with(const char *s, const char *beg)
588 {
589  if (strncmp(s, beg, strlen(beg)) == 0)
590  return 1;
591  else
592  return 0;
593 }
594 
595 struct mount_flags {
596  const char *opt;
597  unsigned long flag;
598  int on;
599  int safe;
600 };
601 
602 static struct mount_flags mount_flags[] = {
603  {"rw", MS_RDONLY, 0, 1},
604  {"ro", MS_RDONLY, 1, 1},
605  {"suid", MS_NOSUID, 0, 0},
606  {"nosuid", MS_NOSUID, 1, 1},
607  {"dev", MS_NODEV, 0, 0},
608  {"nodev", MS_NODEV, 1, 1},
609  {"exec", MS_NOEXEC, 0, 1},
610  {"noexec", MS_NOEXEC, 1, 1},
611  {"async", MS_SYNCHRONOUS, 0, 1},
612  {"sync", MS_SYNCHRONOUS, 1, 1},
613  {"atime", MS_NOATIME, 0, 1},
614  {"noatime", MS_NOATIME, 1, 1},
615  {"dirsync", MS_DIRSYNC, 1, 1},
616  {NULL, 0, 0, 0}
617 };
618 
619 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
620 {
621  int i;
622 
623  for (i = 0; mount_flags[i].opt != NULL; i++) {
624  const char *opt = mount_flags[i].opt;
625  if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
626  *on = mount_flags[i].on;
627  *flag = mount_flags[i].flag;
628  if (!mount_flags[i].safe && getuid() != 0) {
629  *flag = 0;
630  fprintf(stderr,
631  "%s: unsafe option %s ignored\n",
632  progname, opt);
633  }
634  return 1;
635  }
636  }
637  return 0;
638 }
639 
640 static int add_option(char **optsp, const char *opt, unsigned expand)
641 {
642  char *newopts;
643  if (*optsp == NULL)
644  newopts = strdup(opt);
645  else {
646  unsigned oldsize = strlen(*optsp);
647  unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
648  newopts = (char *) realloc(*optsp, newsize);
649  if (newopts)
650  sprintf(newopts + oldsize, ",%s", opt);
651  }
652  if (newopts == NULL) {
653  fprintf(stderr, "%s: failed to allocate memory\n", progname);
654  return -1;
655  }
656  *optsp = newopts;
657  return 0;
658 }
659 
660 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
661 {
662  int i;
663  int l;
664 
665  if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
666  return -1;
667 
668  for (i = 0; mount_flags[i].opt != NULL; i++) {
669  if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
670  add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
671  return -1;
672  }
673 
674  if (add_option(mnt_optsp, opts, 0) == -1)
675  return -1;
676  /* remove comma from end of opts*/
677  l = strlen(*mnt_optsp);
678  if ((*mnt_optsp)[l-1] == ',')
679  (*mnt_optsp)[l-1] = '\0';
680  if (getuid() != 0) {
681  const char *user = get_user_name();
682  if (user == NULL)
683  return -1;
684 
685  if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
686  return -1;
687  strcat(*mnt_optsp, user);
688  }
689  return 0;
690 }
691 
692 static int opt_eq(const char *s, unsigned len, const char *opt)
693 {
694  if(strlen(opt) == len && strncmp(s, opt, len) == 0)
695  return 1;
696  else
697  return 0;
698 }
699 
700 static int get_string_opt(const char *s, unsigned len, const char *opt,
701  char **val)
702 {
703  int i;
704  unsigned opt_len = strlen(opt);
705  char *d;
706 
707  if (*val)
708  free(*val);
709  *val = (char *) malloc(len - opt_len + 1);
710  if (!*val) {
711  fprintf(stderr, "%s: failed to allocate memory\n", progname);
712  return 0;
713  }
714 
715  d = *val;
716  s += opt_len;
717  len -= opt_len;
718  for (i = 0; i < len; i++) {
719  if (s[i] == '\\' && i + 1 < len)
720  i++;
721  *d++ = s[i];
722  }
723  *d = '\0';
724  return 1;
725 }
726 
727 /* The kernel silently truncates the "data" argument to PAGE_SIZE-1 characters.
728  * This can be dangerous if it e.g. truncates the option "group_id=1000" to
729  * "group_id=1".
730  * This wrapper detects this case and bails out with an error.
731  */
732 static int mount_notrunc(const char *source, const char *target,
733  const char *filesystemtype, unsigned long mountflags,
734  const char *data) {
735  if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
736  fprintf(stderr, "%s: mount options too long\n", progname);
737  errno = EINVAL;
738  return -1;
739  }
740  return mount(source, target, filesystemtype, mountflags, data);
741 }
742 
743 
744 static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
745  int fd, const char *opts, const char *dev, char **sourcep,
746  char **mnt_optsp)
747 {
748  int res;
749  int flags = MS_NOSUID | MS_NODEV;
750  char *optbuf;
751  char *mnt_opts = NULL;
752  const char *s;
753  char *d;
754  char *fsname = NULL;
755  char *subtype = NULL;
756  char *source = NULL;
757  char *type = NULL;
758  int blkdev = 0;
759 
760  optbuf = (char *) malloc(strlen(opts) + 128);
761  if (!optbuf) {
762  fprintf(stderr, "%s: failed to allocate memory\n", progname);
763  return -1;
764  }
765 
766  for (s = opts, d = optbuf; *s;) {
767  unsigned len;
768  const char *fsname_str = "fsname=";
769  const char *subtype_str = "subtype=";
770  bool escape_ok = begins_with(s, fsname_str) ||
771  begins_with(s, subtype_str);
772  for (len = 0; s[len]; len++) {
773  if (escape_ok && s[len] == '\\' && s[len + 1])
774  len++;
775  else if (s[len] == ',')
776  break;
777  }
778  if (begins_with(s, fsname_str)) {
779  if (!get_string_opt(s, len, fsname_str, &fsname))
780  goto err;
781  } else if (begins_with(s, subtype_str)) {
782  if (!get_string_opt(s, len, subtype_str, &subtype))
783  goto err;
784  } else if (opt_eq(s, len, "blkdev")) {
785  if (getuid() != 0) {
786  fprintf(stderr,
787  "%s: option blkdev is privileged\n",
788  progname);
789  goto err;
790  }
791  blkdev = 1;
792  } else if (opt_eq(s, len, "auto_unmount")) {
793  auto_unmount = 1;
794  } else if (!begins_with(s, "fd=") &&
795  !begins_with(s, "rootmode=") &&
796  !begins_with(s, "user_id=") &&
797  !begins_with(s, "group_id=")) {
798  int on;
799  int flag;
800  int skip_option = 0;
801  if (opt_eq(s, len, "large_read")) {
802  struct utsname utsname;
803  unsigned kmaj, kmin;
804  res = uname(&utsname);
805  if (res == 0 &&
806  sscanf(utsname.release, "%u.%u",
807  &kmaj, &kmin) == 2 &&
808  (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
809  fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
810  skip_option = 1;
811  }
812  }
813  if (getuid() != 0 && !user_allow_other &&
814  (opt_eq(s, len, "allow_other") ||
815  opt_eq(s, len, "allow_root"))) {
816  fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
817  goto err;
818  }
819  if (!skip_option) {
820  if (find_mount_flag(s, len, &on, &flag)) {
821  if (on)
822  flags |= flag;
823  else
824  flags &= ~flag;
825  } else if (opt_eq(s, len, "default_permissions") ||
826  opt_eq(s, len, "allow_other") ||
827  begins_with(s, "max_read=") ||
828  begins_with(s, "blksize=")) {
829  memcpy(d, s, len);
830  d += len;
831  *d++ = ',';
832  } else {
833  fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, s);
834  exit(1);
835  }
836  }
837  }
838  s += len;
839  if (*s)
840  s++;
841  }
842  *d = '\0';
843  res = get_mnt_opts(flags, optbuf, &mnt_opts);
844  if (res == -1)
845  goto err;
846 
847  sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
848  fd, rootmode, getuid(), getgid());
849 
850  source = malloc((fsname ? strlen(fsname) : 0) +
851  (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
852 
853  type = malloc((subtype ? strlen(subtype) : 0) + 32);
854  if (!type || !source) {
855  fprintf(stderr, "%s: failed to allocate memory\n", progname);
856  goto err;
857  }
858 
859  if (subtype)
860  sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
861  else
862  strcpy(type, blkdev ? "fuseblk" : "fuse");
863 
864  if (fsname)
865  strcpy(source, fsname);
866  else
867  strcpy(source, subtype ? subtype : dev);
868 
869  res = mount_notrunc(source, mnt, type, flags, optbuf);
870  if (res == -1 && errno == ENODEV && subtype) {
871  /* Probably missing subtype support */
872  strcpy(type, blkdev ? "fuseblk" : "fuse");
873  if (fsname) {
874  if (!blkdev)
875  sprintf(source, "%s#%s", subtype, fsname);
876  } else {
877  strcpy(source, type);
878  }
879 
880  res = mount_notrunc(source, mnt, type, flags, optbuf);
881  }
882  if (res == -1 && errno == EINVAL) {
883  /* It could be an old version not supporting group_id */
884  sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
885  fd, rootmode, getuid());
886  res = mount_notrunc(source, mnt, type, flags, optbuf);
887  }
888  if (res == -1) {
889  int errno_save = errno;
890  if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
891  fprintf(stderr, "%s: 'fuseblk' support missing\n",
892  progname);
893  else
894  fprintf(stderr, "%s: mount failed: %s\n", progname,
895  strerror(errno_save));
896  goto err;
897  }
898  *sourcep = source;
899  *typep = type;
900  *mnt_optsp = mnt_opts;
901  free(fsname);
902  free(optbuf);
903 
904  return 0;
905 
906 err:
907  free(fsname);
908  free(subtype);
909  free(source);
910  free(type);
911  free(mnt_opts);
912  free(optbuf);
913  return -1;
914 }
915 
916 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
917 {
918  int res;
919  const char *mnt = *mntp;
920  const char *origmnt = mnt;
921  struct statfs fs_buf;
922  size_t i;
923 
924  res = lstat(mnt, stbuf);
925  if (res == -1) {
926  fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
927  progname, mnt, strerror(errno));
928  return -1;
929  }
930 
931  /* No permission checking is done for root */
932  if (getuid() == 0)
933  return 0;
934 
935  if (S_ISDIR(stbuf->st_mode)) {
936  res = chdir(mnt);
937  if (res == -1) {
938  fprintf(stderr,
939  "%s: failed to chdir to mountpoint: %s\n",
940  progname, strerror(errno));
941  return -1;
942  }
943  mnt = *mntp = ".";
944  res = lstat(mnt, stbuf);
945  if (res == -1) {
946  fprintf(stderr,
947  "%s: failed to access mountpoint %s: %s\n",
948  progname, origmnt, strerror(errno));
949  return -1;
950  }
951 
952  if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
953  fprintf(stderr, "%s: mountpoint %s not owned by user\n",
954  progname, origmnt);
955  return -1;
956  }
957 
958  res = access(mnt, W_OK);
959  if (res == -1) {
960  fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
961  progname, origmnt);
962  return -1;
963  }
964  } else if (S_ISREG(stbuf->st_mode)) {
965  static char procfile[256];
966  *mountpoint_fd = open(mnt, O_WRONLY);
967  if (*mountpoint_fd == -1) {
968  fprintf(stderr, "%s: failed to open %s: %s\n",
969  progname, mnt, strerror(errno));
970  return -1;
971  }
972  res = fstat(*mountpoint_fd, stbuf);
973  if (res == -1) {
974  fprintf(stderr,
975  "%s: failed to access mountpoint %s: %s\n",
976  progname, mnt, strerror(errno));
977  return -1;
978  }
979  if (!S_ISREG(stbuf->st_mode)) {
980  fprintf(stderr,
981  "%s: mountpoint %s is no longer a regular file\n",
982  progname, mnt);
983  return -1;
984  }
985 
986  sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
987  *mntp = procfile;
988  } else {
989  fprintf(stderr,
990  "%s: mountpoint %s is not a directory or a regular file\n",
991  progname, mnt);
992  return -1;
993  }
994 
995  /* Do not permit mounting over anything in procfs - it has a couple
996  * places to which we have "write access" without being supposed to be
997  * able to just put anything we want there.
998  * Luckily, without allow_other, we can't get other users to actually
999  * use any fake information we try to put there anyway.
1000  * Use a whitelist to be safe. */
1001  if (statfs(*mntp, &fs_buf)) {
1002  fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
1003  progname, mnt, strerror(errno));
1004  return -1;
1005  }
1006 
1007  /* Define permitted filesystems for the mount target. This was
1008  * originally the same list as used by the ecryptfs mount helper
1009  * (https://bazaar.launchpad.net/~ecryptfs/ecryptfs/trunk/view/head:/src/utils/mount.ecryptfs_private.c#L225)
1010  * but got expanded as we found more filesystems that needed to be
1011  * overlayed. */
1012  typeof(fs_buf.f_type) f_type_whitelist[] = {
1013  0x61756673 /* AUFS_SUPER_MAGIC */,
1014  0x00000187 /* AUTOFS_SUPER_MAGIC */,
1015  0xCA451A4E /* BCACHEFS_STATFS_MAGIC */,
1016  0x9123683E /* BTRFS_SUPER_MAGIC */,
1017  0x00C36400 /* CEPH_SUPER_MAGIC */,
1018  0xFF534D42 /* CIFS_MAGIC_NUMBER */,
1019  0X00004D44 /* MSDOS_SUPER_MAGIC */,
1020  0x0000F15F /* ECRYPTFS_SUPER_MAGIC */,
1021  0x0000EF53 /* EXT[234]_SUPER_MAGIC */,
1022  0xF2F52010 /* F2FS_SUPER_MAGIC */,
1023  0x65735546 /* FUSE_SUPER_MAGIC */,
1024  0x01161970 /* GFS2_MAGIC */,
1025  0x47504653 /* GPFS_SUPER_MAGIC */,
1026  0x3153464A /* JFS_SUPER_MAGIC */,
1027  0x000072B6 /* JFFS2_SUPER_MAGIC */,
1028  0x0BD00BD0 /* LL_SUPER_MAGIC */,
1029  0x0000564C /* NCP_SUPER_MAGIC */,
1030  0x00006969 /* NFS_SUPER_MAGIC */,
1031  0x00003434 /* NILFS_SUPER_MAGIC */,
1032  0x5346544E /* NTFS_SB_MAGIC */,
1033  0x794C7630 /* OVERLAYFS_SUPER_MAGIC */,
1034  0x52654973 /* REISERFS_SUPER_MAGIC */,
1035  0x73717368 /* SQUASHFS_MAGIC */,
1036  0x01021994 /* TMPFS_MAGIC */,
1037  0x24051905 /* UBIFS_SUPER_MAGIC */,
1038  0x58465342 /* XFS_SB_MAGIC */,
1039  0x2FC12FC1 /* ZFS_SUPER_MAGIC */,
1040  };
1041  for (i = 0; i < sizeof(f_type_whitelist)/sizeof(f_type_whitelist[0]); i++) {
1042  if (f_type_whitelist[i] == fs_buf.f_type)
1043  return 0;
1044  }
1045 
1046  fprintf(stderr, "%s: mounting over filesystem type %#010lx is forbidden\n",
1047  progname, (unsigned long)fs_buf.f_type);
1048  return -1;
1049 }
1050 
1051 static int try_open(const char *dev, char **devp, int silent)
1052 {
1053  int fd = open(dev, O_RDWR);
1054  if (fd != -1) {
1055  *devp = strdup(dev);
1056  if (*devp == NULL) {
1057  fprintf(stderr, "%s: failed to allocate memory\n",
1058  progname);
1059  close(fd);
1060  fd = -1;
1061  }
1062  } else if (errno == ENODEV ||
1063  errno == ENOENT)/* check for ENOENT too, for the udev case */
1064  return -2;
1065  else if (!silent) {
1066  fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
1067  strerror(errno));
1068  }
1069  return fd;
1070 }
1071 
1072 static int try_open_fuse_device(char **devp)
1073 {
1074  int fd;
1075 
1076  drop_privs();
1077  fd = try_open(FUSE_DEV, devp, 0);
1078  restore_privs();
1079  return fd;
1080 }
1081 
1082 static int open_fuse_device(char **devp)
1083 {
1084  int fd = try_open_fuse_device(devp);
1085  if (fd >= -1)
1086  return fd;
1087 
1088  fprintf(stderr,
1089  "%s: fuse device not found, try 'modprobe fuse' first\n",
1090  progname);
1091 
1092  return -1;
1093 }
1094 
1095 
1096 static int mount_fuse(const char *mnt, const char *opts, const char **type)
1097 {
1098  int res;
1099  int fd;
1100  char *dev;
1101  struct stat stbuf;
1102  char *source = NULL;
1103  char *mnt_opts = NULL;
1104  const char *real_mnt = mnt;
1105  int mountpoint_fd = -1;
1106 
1107  fd = open_fuse_device(&dev);
1108  if (fd == -1)
1109  return -1;
1110 
1111  drop_privs();
1112  read_conf();
1113 
1114  if (getuid() != 0 && mount_max != -1) {
1115  int mount_count = count_fuse_fs();
1116  if (mount_count >= mount_max) {
1117  fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1118  goto fail_close_fd;
1119  }
1120  }
1121 
1122  res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1123  restore_privs();
1124  if (res != -1)
1125  res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT,
1126  fd, opts, dev, &source, &mnt_opts);
1127 
1128  if (mountpoint_fd != -1)
1129  close(mountpoint_fd);
1130 
1131  if (res == -1)
1132  goto fail_close_fd;
1133 
1134  res = chdir("/");
1135  if (res == -1) {
1136  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1137  goto fail_close_fd;
1138  }
1139 
1140  if (geteuid() == 0) {
1141  res = add_mount(source, mnt, *type, mnt_opts);
1142  if (res == -1) {
1143  /* Can't clean up mount in a non-racy way */
1144  goto fail_close_fd;
1145  }
1146  }
1147 
1148 out_free:
1149  free(source);
1150  free(mnt_opts);
1151  free(dev);
1152 
1153  return fd;
1154 
1155 fail_close_fd:
1156  close(fd);
1157  fd = -1;
1158  goto out_free;
1159 }
1160 
1161 static int send_fd(int sock_fd, int fd)
1162 {
1163  int retval;
1164  struct msghdr msg;
1165  struct cmsghdr *p_cmsg;
1166  struct iovec vec;
1167  size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1168  int *p_fds;
1169  char sendchar = 0;
1170 
1171  msg.msg_control = cmsgbuf;
1172  msg.msg_controllen = sizeof(cmsgbuf);
1173  p_cmsg = CMSG_FIRSTHDR(&msg);
1174  p_cmsg->cmsg_level = SOL_SOCKET;
1175  p_cmsg->cmsg_type = SCM_RIGHTS;
1176  p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1177  p_fds = (int *) CMSG_DATA(p_cmsg);
1178  *p_fds = fd;
1179  msg.msg_controllen = p_cmsg->cmsg_len;
1180  msg.msg_name = NULL;
1181  msg.msg_namelen = 0;
1182  msg.msg_iov = &vec;
1183  msg.msg_iovlen = 1;
1184  msg.msg_flags = 0;
1185  /* "To pass file descriptors or credentials you need to send/read at
1186  * least one byte" (man 7 unix) */
1187  vec.iov_base = &sendchar;
1188  vec.iov_len = sizeof(sendchar);
1189  while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1190  if (retval != 1) {
1191  perror("sending file descriptor");
1192  return -1;
1193  }
1194  return 0;
1195 }
1196 
1197 /* The parent fuse process has died: decide whether to auto_unmount.
1198  *
1199  * In the normal case (umount or fusermount -u), the filesystem
1200  * has already been unmounted. If we simply unmount again we can
1201  * cause problems with stacked mounts (e.g. autofs).
1202  *
1203  * So we unmount here only in abnormal case where fuse process has
1204  * died without unmount happening. To detect this, we first look in
1205  * the mount table to make sure the mountpoint is still mounted and
1206  * has proper type. If so, we then see if opening the mount dir is
1207  * returning 'Transport endpoint is not connected'.
1208  *
1209  * The order of these is important, because if autofs is in use,
1210  * opening the dir to check for ENOTCONN will cause a new mount
1211  * in the normal case where filesystem has been unmounted cleanly.
1212  */
1213 static int should_auto_unmount(const char *mnt, const char *type)
1214 {
1215  char *copy;
1216  const char *last;
1217  int result = 0;
1218  int fd;
1219 
1220  copy = strdup(mnt);
1221  if (copy == NULL) {
1222  fprintf(stderr, "%s: failed to allocate memory\n", progname);
1223  return 0;
1224  }
1225 
1226  if (chdir_to_parent(copy, &last) == -1)
1227  goto out;
1228  if (check_is_mount(last, mnt, type) == -1)
1229  goto out;
1230 
1231  fd = open(mnt, O_RDONLY);
1232  if (fd != -1) {
1233  close(fd);
1234  } else {
1235  result = errno == ENOTCONN;
1236  }
1237 out:
1238  free(copy);
1239  return result;
1240 }
1241 
1242 static void usage(void)
1243 {
1244  printf("%s: [options] mountpoint\n"
1245  "Options:\n"
1246  " -h print help\n"
1247  " -V print version\n"
1248  " -o opt[,opt...] mount options\n"
1249  " -u unmount\n"
1250  " -q quiet\n"
1251  " -z lazy unmount\n",
1252  progname);
1253  exit(1);
1254 }
1255 
1256 static void show_version(void)
1257 {
1258  printf("fusermount3 version: %s\n", PACKAGE_VERSION);
1259  exit(0);
1260 }
1261 
1262 int main(int argc, char *argv[])
1263 {
1264  sigset_t sigset;
1265  int ch;
1266  int fd;
1267  int res;
1268  char *origmnt;
1269  char *mnt;
1270  static int unmount = 0;
1271  static int lazy = 0;
1272  static int quiet = 0;
1273  char *commfd;
1274  int cfd;
1275  const char *opts = "";
1276  const char *type = NULL;
1277 
1278  static const struct option long_opts[] = {
1279  {"unmount", no_argument, NULL, 'u'},
1280  {"lazy", no_argument, NULL, 'z'},
1281  {"quiet", no_argument, NULL, 'q'},
1282  {"help", no_argument, NULL, 'h'},
1283  {"version", no_argument, NULL, 'V'},
1284  {0, 0, 0, 0}};
1285 
1286  progname = strdup(argv[0]);
1287  if (progname == NULL) {
1288  fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1289  exit(1);
1290  }
1291 
1292  while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1293  NULL)) != -1) {
1294  switch (ch) {
1295  case 'h':
1296  usage();
1297  break;
1298 
1299  case 'V':
1300  show_version();
1301  break;
1302 
1303  case 'o':
1304  opts = optarg;
1305  break;
1306 
1307  case 'u':
1308  unmount = 1;
1309  break;
1310 
1311  case 'z':
1312  lazy = 1;
1313  break;
1314 
1315  case 'q':
1316  quiet = 1;
1317  break;
1318 
1319  default:
1320  exit(1);
1321  }
1322  }
1323 
1324  if (lazy && !unmount) {
1325  fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1326  exit(1);
1327  }
1328 
1329  if (optind >= argc) {
1330  fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1331  exit(1);
1332  } else if (argc > optind + 1) {
1333  fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1334  progname);
1335  exit(1);
1336  }
1337 
1338  origmnt = argv[optind];
1339 
1340  drop_privs();
1341  mnt = fuse_mnt_resolve_path(progname, origmnt);
1342  if (mnt != NULL) {
1343  res = chdir("/");
1344  if (res == -1) {
1345  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1346  goto err_out;
1347  }
1348  }
1349  restore_privs();
1350  if (mnt == NULL)
1351  exit(1);
1352 
1353  umask(033);
1354  if (unmount)
1355  goto do_unmount;
1356 
1357  commfd = getenv(FUSE_COMMFD_ENV);
1358  if (commfd == NULL) {
1359  fprintf(stderr, "%s: old style mounting not supported\n",
1360  progname);
1361  goto err_out;
1362  }
1363 
1364  fd = mount_fuse(mnt, opts, &type);
1365  if (fd == -1)
1366  goto err_out;
1367 
1368  cfd = atoi(commfd);
1369  res = send_fd(cfd, fd);
1370  if (res == -1)
1371  goto err_out;
1372  close(fd);
1373 
1374  if (!auto_unmount) {
1375  free(mnt);
1376  return 0;
1377  }
1378 
1379  /* Become a daemon and wait for the parent to exit or die.
1380  ie For the control socket to get closed.
1381  btw We don't want to use daemon() function here because
1382  it forks and messes with the file descriptors. */
1383  setsid();
1384  res = chdir("/");
1385  if (res == -1) {
1386  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1387  goto err_out;
1388  }
1389 
1390  sigfillset(&sigset);
1391  sigprocmask(SIG_BLOCK, &sigset, NULL);
1392 
1393  lazy = 1;
1394  quiet = 1;
1395 
1396  while (1) {
1397  unsigned char buf[16];
1398  int n = recv(cfd, buf, sizeof(buf), 0);
1399  if (!n)
1400  break;
1401 
1402  if (n < 0) {
1403  if (errno == EINTR)
1404  continue;
1405  break;
1406  }
1407  }
1408 
1409  if (!should_auto_unmount(mnt, type)) {
1410  goto success_out;
1411  }
1412 
1413 do_unmount:
1414  if (geteuid() == 0)
1415  res = unmount_fuse(mnt, quiet, lazy);
1416  else {
1417  res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1418  if (res == -1 && !quiet)
1419  fprintf(stderr,
1420  "%s: failed to unmount %s: %s\n",
1421  progname, mnt, strerror(errno));
1422  }
1423  if (res == -1)
1424  goto err_out;
1425 
1426 success_out:
1427  free(mnt);
1428  return 0;
1429 
1430 err_out:
1431  free(mnt);
1432  exit(1);
1433 }
+ + + + diff --git a/doc/html/globals.html b/doc/html/globals.html index e19f1d7..e1aba7f 100644 --- a/doc/html/globals.html +++ b/doc/html/globals.html @@ -3,8 +3,9 @@ - -fuse: Globals + + +libfuse: Globals @@ -16,8 +17,8 @@ - @@ -25,43 +26,29 @@
-
fuse +
+
libfuse
- - - - - + + + + +
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
-

- f -

diff --git a/doc/html/globals_defs.html b/doc/html/globals_defs.html index 6bc9538..d545bb8 100644 --- a/doc/html/globals_defs.html +++ b/doc/html/globals_defs.html @@ -3,8 +3,9 @@ - -fuse: Globals + + +libfuse: Globals @@ -16,8 +17,8 @@ - @@ -25,44 +26,85 @@
-
fuse +
+
libfuse
- - - - + + + + +
diff --git a/doc/html/globals_enum.html b/doc/html/globals_enum.html index 8464b43..db74df8 100644 --- a/doc/html/globals_enum.html +++ b/doc/html/globals_enum.html @@ -3,8 +3,9 @@ - -fuse: Globals + + +libfuse: Globals @@ -16,8 +17,8 @@ - @@ -25,30 +26,15 @@
-
fuse +
+
libfuse
- - - - + + + + +
 
diff --git a/doc/html/globals_eval.html b/doc/html/globals_eval.html index 33b730c..0ad5f27 100644 --- a/doc/html/globals_eval.html +++ b/doc/html/globals_eval.html @@ -3,8 +3,9 @@ - -fuse: Globals + + +libfuse: Globals @@ -16,8 +17,8 @@ - @@ -25,30 +26,15 @@
-
fuse +
+
libfuse
- - - - + + + + +
 
    @@ -73,13 +59,19 @@
  • FUSE_BUF_SPLICE_NONBLOCK : fuse_common.h
  • +
  • FUSE_FILL_DIR_PLUS +: fuse.h +
  • +
  • FUSE_READDIR_PLUS +: fuse.h +
diff --git a/doc/html/globals_func.html b/doc/html/globals_func.html index 6153e77..75621b2 100644 --- a/doc/html/globals_func.html +++ b/doc/html/globals_func.html @@ -3,8 +3,9 @@ - -fuse: Globals + + +libfuse: Globals @@ -16,8 +17,8 @@ - @@ -25,76 +26,41 @@
-
fuse +
+
libfuse
- - - - - + + + + +
  -

- f -

diff --git a/doc/html/globals_type.html b/doc/html/globals_type.html index 7c9ccde..181e6db 100644 --- a/doc/html/globals_type.html +++ b/doc/html/globals_type.html @@ -3,8 +3,9 @@ - -fuse: Globals + + +libfuse: Globals @@ -16,8 +17,8 @@ - @@ -25,47 +26,32 @@
-
fuse +
+
libfuse
- - - - + + + + +
 
diff --git a/doc/html/hello_8c.html b/doc/html/hello_8c.html new file mode 100644 index 0000000..487d44c --- /dev/null +++ b/doc/html/hello_8c.html @@ -0,0 +1,71 @@ + + + + + + + +libfuse: example/hello.c File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
hello.c File Reference
+
+
+
#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <assert.h>
+
+

Go to the source code of this file.

+

Detailed Description

+

minimal example filesystem using high-level API

+

Compile with:

gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello
+

Source code

+
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#define FUSE_USE_VERSION 31
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <assert.h>
/*
* Command line options
*
* We can't set default values for the char* fields here because
* fuse_opt_parse would attempt to free() them when the user specifies
* different values on the command line.
*/
static struct options {
const char *filename;
const char *contents;
int show_help;
} options;
#define OPTION(t, p) \
{ t, offsetof(struct options, p), 1 }
static const struct fuse_opt option_spec[] = {
OPTION("--name=%s", filename),
OPTION("--contents=%s", contents),
OPTION("-h", show_help),
OPTION("--help", show_help),
};
static void *hello_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
cfg->kernel_cache = 1;
return NULL;
}
static int hello_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
(void) fi;
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path+1, options.filename) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(options.contents);
} else
res = -ENOENT;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
(void) offset;
(void) fi;
(void) flags;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
filler(buf, options.filename, NULL, 0, 0);
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path+1, options.filename) != 0)
return -ENOENT;
if ((fi->flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path+1, options.filename) != 0)
return -ENOENT;
len = strlen(options.contents);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, options.contents + offset, size);
} else
size = 0;
return size;
}
static struct fuse_operations hello_oper = {
.init = hello_init,
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
static void show_help(const char *progname)
{
printf("usage: %s [options] <mountpoint>\n\n", progname);
printf("File-system specific options:\n"
" --name=<s> Name of the \"hello\" file\n"
" (default: \"hello\")\n"
" --contents=<s> Contents \"hello\" file\n"
" (default \"Hello, World!\\n\")\n"
"\n");
}
int main(int argc, char *argv[])
{
int ret;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
/* Set defaults -- we have to use strdup so that
fuse_opt_parse can free the defaults if other
values are specified */
options.filename = strdup("hello");
options.contents = strdup("Hello World!\n");
/* Parse options */
if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
return 1;
/* When --help is specified, first print our own file-system
specific help text, then signal fuse_main to show
additional help (by adding `--help` to the options again)
without usage: line (by setting argv[0] to the empty
string) */
if (options.show_help) {
show_help(argv[0]);
assert(fuse_opt_add_arg(&args, "--help") == 0);
args.argv[0][0] = '\0';
}
ret = fuse_main(args.argc, args.argv, &hello_oper, NULL);
return ret;
}
+

Definition in file hello.c.

+
+ + + + diff --git a/doc/html/hello_8c_source.html b/doc/html/hello_8c_source.html new file mode 100644 index 0000000..bc82343 --- /dev/null +++ b/doc/html/hello_8c_source.html @@ -0,0 +1,77 @@ + + + + + + + +libfuse: example/hello.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
hello.c
+
+
+Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU GPL.
6  See the file COPYING.
7 */
8 
22 #define FUSE_USE_VERSION 31
23 
24 #include <fuse.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stddef.h>
30 #include <assert.h>
31 
32 /*
33  * Command line options
34  *
35  * We can't set default values for the char* fields here because
36  * fuse_opt_parse would attempt to free() them when the user specifies
37  * different values on the command line.
38  */
39 static struct options {
40  const char *filename;
41  const char *contents;
42  int show_help;
43 } options;
44 
45 #define OPTION(t, p) \
46  { t, offsetof(struct options, p), 1 }
47 static const struct fuse_opt option_spec[] = {
48  OPTION("--name=%s", filename),
49  OPTION("--contents=%s", contents),
50  OPTION("-h", show_help),
51  OPTION("--help", show_help),
53 };
54 
55 static void *hello_init(struct fuse_conn_info *conn,
56  struct fuse_config *cfg)
57 {
58  (void) conn;
59  cfg->kernel_cache = 1;
60  return NULL;
61 }
62 
63 static int hello_getattr(const char *path, struct stat *stbuf,
64  struct fuse_file_info *fi)
65 {
66  (void) fi;
67  int res = 0;
68 
69  memset(stbuf, 0, sizeof(struct stat));
70  if (strcmp(path, "/") == 0) {
71  stbuf->st_mode = S_IFDIR | 0755;
72  stbuf->st_nlink = 2;
73  } else if (strcmp(path+1, options.filename) == 0) {
74  stbuf->st_mode = S_IFREG | 0444;
75  stbuf->st_nlink = 1;
76  stbuf->st_size = strlen(options.contents);
77  } else
78  res = -ENOENT;
79 
80  return res;
81 }
82 
83 static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
84  off_t offset, struct fuse_file_info *fi,
85  enum fuse_readdir_flags flags)
86 {
87  (void) offset;
88  (void) fi;
89  (void) flags;
90 
91  if (strcmp(path, "/") != 0)
92  return -ENOENT;
93 
94  filler(buf, ".", NULL, 0, 0);
95  filler(buf, "..", NULL, 0, 0);
96  filler(buf, options.filename, NULL, 0, 0);
97 
98  return 0;
99 }
100 
101 static int hello_open(const char *path, struct fuse_file_info *fi)
102 {
103  if (strcmp(path+1, options.filename) != 0)
104  return -ENOENT;
105 
106  if ((fi->flags & O_ACCMODE) != O_RDONLY)
107  return -EACCES;
108 
109  return 0;
110 }
111 
112 static int hello_read(const char *path, char *buf, size_t size, off_t offset,
113  struct fuse_file_info *fi)
114 {
115  size_t len;
116  (void) fi;
117  if(strcmp(path+1, options.filename) != 0)
118  return -ENOENT;
119 
120  len = strlen(options.contents);
121  if (offset < len) {
122  if (offset + size > len)
123  size = len - offset;
124  memcpy(buf, options.contents + offset, size);
125  } else
126  size = 0;
127 
128  return size;
129 }
130 
131 static struct fuse_operations hello_oper = {
132  .init = hello_init,
133  .getattr = hello_getattr,
134  .readdir = hello_readdir,
135  .open = hello_open,
136  .read = hello_read,
137 };
138 
139 static void show_help(const char *progname)
140 {
141  printf("usage: %s [options] <mountpoint>\n\n", progname);
142  printf("File-system specific options:\n"
143  " --name=<s> Name of the \"hello\" file\n"
144  " (default: \"hello\")\n"
145  " --contents=<s> Contents \"hello\" file\n"
146  " (default \"Hello, World!\\n\")\n"
147  "\n");
148 }
149 
150 int main(int argc, char *argv[])
151 {
152  int ret;
153  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
154 
155  /* Set defaults -- we have to use strdup so that
156  fuse_opt_parse can free the defaults if other
157  values are specified */
158  options.filename = strdup("hello");
159  options.contents = strdup("Hello World!\n");
160 
161  /* Parse options */
162  if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
163  return 1;
164 
165  /* When --help is specified, first print our own file-system
166  specific help text, then signal fuse_main to show
167  additional help (by adding `--help` to the options again)
168  without usage: line (by setting argv[0] to the empty
169  string) */
170  if (options.show_help) {
171  show_help(argv[0]);
172  assert(fuse_opt_add_arg(&args, "--help") == 0);
173  args.argv[0][0] = '\0';
174  }
175 
176  ret = fuse_main(args.argc, args.argv, &hello_oper, NULL);
177  fuse_opt_free_args(&args);
178  return ret;
179 }
+
int argc
Definition: fuse_opt.h:111
+
unsigned long offset
Definition: fuse_opt.h:85
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
fuse_readdir_flags
Definition: fuse.h:42
+
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
+ +
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
Definition: fuse.h:572
+ + +
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+ +
char ** argv
Definition: fuse_opt.h:114
+
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:82
+ + + +
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
+
int kernel_cache
Definition: fuse.h:237
+
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:855
+
+ + + + diff --git a/doc/html/hello__ll_8c.html b/doc/html/hello__ll_8c.html new file mode 100644 index 0000000..56bde00 --- /dev/null +++ b/doc/html/hello__ll_8c.html @@ -0,0 +1,72 @@ + + + + + + + +libfuse: example/hello_ll.c File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
hello_ll.c File Reference
+
+
+
#include <fuse_lowlevel.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+
+

Go to the source code of this file.

+

Detailed Description

+

minimal example filesystem using low-level API

+

Compile with:

gcc -Wall hello_ll.c `pkg-config fuse3 --cflags --libs` -o hello_ll
+

Source code

+
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#define FUSE_USE_VERSION 31
#include <fuse_lowlevel.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
static const char *hello_str = "Hello World!\n";
static const char *hello_name = "hello";
static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
{
stbuf->st_ino = ino;
switch (ino) {
case 1:
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
break;
case 2:
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
break;
default:
return -1;
}
return 0;
}
static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
struct stat stbuf;
(void) fi;
memset(&stbuf, 0, sizeof(stbuf));
if (hello_stat(ino, &stbuf) == -1)
fuse_reply_err(req, ENOENT);
else
fuse_reply_attr(req, &stbuf, 1.0);
}
static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
struct fuse_entry_param e;
if (parent != 1 || strcmp(name, hello_name) != 0)
fuse_reply_err(req, ENOENT);
else {
memset(&e, 0, sizeof(e));
e.ino = 2;
e.attr_timeout = 1.0;
e.entry_timeout = 1.0;
hello_stat(e.ino, &e.attr);
fuse_reply_entry(req, &e);
}
}
struct dirbuf {
char *p;
size_t size;
};
static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
{
struct stat stbuf;
size_t oldsize = b->size;
b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
b->p = (char *) realloc(b->p, b->size);
memset(&stbuf, 0, sizeof(stbuf));
stbuf.st_ino = ino;
fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
b->size);
}
#define min(x, y) ((x) < (y) ? (x) : (y))
static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
off_t off, size_t maxsize)
{
if (off < bufsize)
return fuse_reply_buf(req, buf + off,
min(bufsize - off, maxsize));
else
return fuse_reply_buf(req, NULL, 0);
}
static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
(void) fi;
if (ino != 1)
fuse_reply_err(req, ENOTDIR);
else {
struct dirbuf b;
memset(&b, 0, sizeof(b));
dirbuf_add(req, &b, ".", 1);
dirbuf_add(req, &b, "..", 1);
dirbuf_add(req, &b, hello_name, 2);
reply_buf_limited(req, b.p, b.size, off, size);
free(b.p);
}
}
static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
if (ino != 2)
fuse_reply_err(req, EISDIR);
else if ((fi->flags & 3) != O_RDONLY)
fuse_reply_err(req, EACCES);
else
fuse_reply_open(req, fi);
}
static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
(void) fi;
assert(ino == 2);
reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
}
static struct fuse_lowlevel_ops hello_ll_oper = {
.lookup = hello_ll_lookup,
.getattr = hello_ll_getattr,
.readdir = hello_ll_readdir,
.open = hello_ll_open,
.read = hello_ll_read,
};
int main(int argc, char *argv[])
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_session *se;
struct fuse_cmdline_opts opts;
int ret = -1;
if (fuse_parse_cmdline(&args, &opts) != 0)
return 1;
if (opts.show_help) {
printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
ret = 0;
goto err_out1;
} else if (opts.show_version) {
printf("FUSE library version %s\n", fuse_pkgversion());
ret = 0;
goto err_out1;
}
se = fuse_session_new(&args, &hello_ll_oper,
sizeof(hello_ll_oper), NULL);
if (se == NULL)
goto err_out1;
goto err_out2;
if (fuse_session_mount(se, opts.mountpoint) != 0)
goto err_out3;
fuse_daemonize(opts.foreground);
/* Block until ctrl+c or fusermount -u */
if (opts.singlethread)
ret = fuse_session_loop(se);
else
ret = fuse_session_loop_mt(se, opts.clone_fd);
err_out3:
err_out2:
err_out1:
free(opts.mountpoint);
return ret ? 1 : 0;
}
+

Definition in file hello_ll.c.

+
+ + + + diff --git a/doc/html/hello__ll_8c_source.html b/doc/html/hello__ll_8c_source.html new file mode 100644 index 0000000..63e1974 --- /dev/null +++ b/doc/html/hello__ll_8c_source.html @@ -0,0 +1,86 @@ + + + + + + + +libfuse: example/hello_ll.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
hello_ll.c
+
+
+Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU GPL.
6  See the file COPYING.
7 */
8 
21 #define FUSE_USE_VERSION 31
22 
23 #include <fuse_lowlevel.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <assert.h>
31 
32 static const char *hello_str = "Hello World!\n";
33 static const char *hello_name = "hello";
34 
35 static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
36 {
37  stbuf->st_ino = ino;
38  switch (ino) {
39  case 1:
40  stbuf->st_mode = S_IFDIR | 0755;
41  stbuf->st_nlink = 2;
42  break;
43 
44  case 2:
45  stbuf->st_mode = S_IFREG | 0444;
46  stbuf->st_nlink = 1;
47  stbuf->st_size = strlen(hello_str);
48  break;
49 
50  default:
51  return -1;
52  }
53  return 0;
54 }
55 
56 static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
57  struct fuse_file_info *fi)
58 {
59  struct stat stbuf;
60 
61  (void) fi;
62 
63  memset(&stbuf, 0, sizeof(stbuf));
64  if (hello_stat(ino, &stbuf) == -1)
65  fuse_reply_err(req, ENOENT);
66  else
67  fuse_reply_attr(req, &stbuf, 1.0);
68 }
69 
70 static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
71 {
72  struct fuse_entry_param e;
73 
74  if (parent != 1 || strcmp(name, hello_name) != 0)
75  fuse_reply_err(req, ENOENT);
76  else {
77  memset(&e, 0, sizeof(e));
78  e.ino = 2;
79  e.attr_timeout = 1.0;
80  e.entry_timeout = 1.0;
81  hello_stat(e.ino, &e.attr);
82 
83  fuse_reply_entry(req, &e);
84  }
85 }
86 
87 struct dirbuf {
88  char *p;
89  size_t size;
90 };
91 
92 static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
93  fuse_ino_t ino)
94 {
95  struct stat stbuf;
96  size_t oldsize = b->size;
97  b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
98  b->p = (char *) realloc(b->p, b->size);
99  memset(&stbuf, 0, sizeof(stbuf));
100  stbuf.st_ino = ino;
101  fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
102  b->size);
103 }
104 
105 #define min(x, y) ((x) < (y) ? (x) : (y))
106 
107 static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
108  off_t off, size_t maxsize)
109 {
110  if (off < bufsize)
111  return fuse_reply_buf(req, buf + off,
112  min(bufsize - off, maxsize));
113  else
114  return fuse_reply_buf(req, NULL, 0);
115 }
116 
117 static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
118  off_t off, struct fuse_file_info *fi)
119 {
120  (void) fi;
121 
122  if (ino != 1)
123  fuse_reply_err(req, ENOTDIR);
124  else {
125  struct dirbuf b;
126 
127  memset(&b, 0, sizeof(b));
128  dirbuf_add(req, &b, ".", 1);
129  dirbuf_add(req, &b, "..", 1);
130  dirbuf_add(req, &b, hello_name, 2);
131  reply_buf_limited(req, b.p, b.size, off, size);
132  free(b.p);
133  }
134 }
135 
136 static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
137  struct fuse_file_info *fi)
138 {
139  if (ino != 2)
140  fuse_reply_err(req, EISDIR);
141  else if ((fi->flags & 3) != O_RDONLY)
142  fuse_reply_err(req, EACCES);
143  else
144  fuse_reply_open(req, fi);
145 }
146 
147 static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
148  off_t off, struct fuse_file_info *fi)
149 {
150  (void) fi;
151 
152  assert(ino == 2);
153  reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
154 }
155 
156 static struct fuse_lowlevel_ops hello_ll_oper = {
157  .lookup = hello_ll_lookup,
158  .getattr = hello_ll_getattr,
159  .readdir = hello_ll_readdir,
160  .open = hello_ll_open,
161  .read = hello_ll_read,
162 };
163 
164 int main(int argc, char *argv[])
165 {
166  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
167  struct fuse_session *se;
168  struct fuse_cmdline_opts opts;
169  int ret = -1;
170 
171  if (fuse_parse_cmdline(&args, &opts) != 0)
172  return 1;
173  if (opts.show_help) {
174  printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
177  ret = 0;
178  goto err_out1;
179  } else if (opts.show_version) {
180  printf("FUSE library version %s\n", fuse_pkgversion());
182  ret = 0;
183  goto err_out1;
184  }
185 
186  se = fuse_session_new(&args, &hello_ll_oper,
187  sizeof(hello_ll_oper), NULL);
188  if (se == NULL)
189  goto err_out1;
190 
191  if (fuse_set_signal_handlers(se) != 0)
192  goto err_out2;
193 
194  if (fuse_session_mount(se, opts.mountpoint) != 0)
195  goto err_out3;
196 
197  fuse_daemonize(opts.foreground);
198 
199  /* Block until ctrl+c or fusermount -u */
200  if (opts.singlethread)
201  ret = fuse_session_loop(se);
202  else
203  ret = fuse_session_loop_mt(se, opts.clone_fd);
204 
206 err_out3:
208 err_out2:
210 err_out1:
211  free(opts.mountpoint);
212  fuse_opt_free_args(&args);
213 
214  return ret ? 1 : 0;
215 }
void fuse_session_destroy(struct fuse_session *se)
+
int fuse_reply_err(fuse_req_t req, int err)
+
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
+
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
+
void fuse_lowlevel_help(void)
+
int fuse_daemonize(int foreground)
Definition: helper.c:225
+
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
+
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
+
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
+
Definition: fuse_lowlevel.h:59
+
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
+
void fuse_cmdline_help(void)
Definition: helper.c:129
+
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
+
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
+ +
void fuse_lowlevel_version(void)
+ +
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
+
void fuse_session_unmount(struct fuse_session *se)
+
void(* lookup)(fuse_req_t req, fuse_ino_t parent, const char *name)
+
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
+
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
+ + + +
const char * fuse_pkgversion(void)
Definition: fuse.c:5071
+
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
+
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+
+ + + + diff --git a/doc/html/helper_8c_source.html b/doc/html/helper_8c_source.html new file mode 100644 index 0000000..4462ff9 --- /dev/null +++ b/doc/html/helper_8c_source.html @@ -0,0 +1,107 @@ + + + + + + + +libfuse: lib/helper.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
helper.c
+
+
+
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Helper functions to create (simple) standalone programs. With the
6  aid of these functions it should be possible to create full FUSE
7  file system by implementing nothing but the request handlers.
8 
9  This program can be distributed under the terms of the GNU LGPLv2.
10  See the file COPYING.LIB.
11 */
12 
13 #include "config.h"
14 #include "fuse_i.h"
15 #include "fuse_misc.h"
16 #include "fuse_opt.h"
17 #include "fuse_lowlevel.h"
18 #include "mount_util.h"
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <errno.h>
27 #include <sys/param.h>
28 
29 #define FUSE_HELPER_OPT(t, p) \
30  { t, offsetof(struct fuse_cmdline_opts, p), 1 }
31 
32 static const struct fuse_opt fuse_helper_opts[] = {
33  FUSE_HELPER_OPT("-h", show_help),
34  FUSE_HELPER_OPT("--help", show_help),
35  FUSE_HELPER_OPT("-V", show_version),
36  FUSE_HELPER_OPT("--version", show_version),
37  FUSE_HELPER_OPT("-d", debug),
38  FUSE_HELPER_OPT("debug", debug),
39  FUSE_HELPER_OPT("-d", foreground),
40  FUSE_HELPER_OPT("debug", foreground),
43  FUSE_HELPER_OPT("-f", foreground),
44  FUSE_HELPER_OPT("-s", singlethread),
45  FUSE_HELPER_OPT("fsname=", nodefault_subtype),
46  FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
47 #ifndef __FreeBSD__
48  FUSE_HELPER_OPT("subtype=", nodefault_subtype),
49  FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
50 #endif
51  FUSE_HELPER_OPT("clone_fd", clone_fd),
52  FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
54 };
55 
56 struct fuse_conn_info_opts {
57  int atomic_o_trunc;
58  int no_remote_posix_lock;
59  int no_remote_flock;
60  int splice_write;
61  int splice_move;
62  int splice_read;
63  int no_splice_write;
64  int no_splice_move;
65  int no_splice_read;
66  int auto_inval_data;
67  int no_auto_inval_data;
68  int no_readdirplus;
69  int no_readdirplus_auto;
70  int async_dio;
71  int no_async_dio;
72  int writeback_cache;
73  int no_writeback_cache;
74  int async_read;
75  int sync_read;
76  unsigned max_write;
77  unsigned max_readahead;
78  unsigned max_background;
79  unsigned congestion_threshold;
80  unsigned time_gran;
81  int set_max_write;
82  int set_max_readahead;
83  int set_max_background;
84  int set_congestion_threshold;
85  int set_time_gran;
86 };
87 
88 #define CONN_OPTION(t, p, v) \
89  { t, offsetof(struct fuse_conn_info_opts, p), v }
90 static const struct fuse_opt conn_info_opt_spec[] = {
91  CONN_OPTION("max_write=%u", max_write, 0),
92  CONN_OPTION("max_write=", set_max_write, 1),
93  CONN_OPTION("max_readahead=%u", max_readahead, 0),
94  CONN_OPTION("max_readahead=", set_max_readahead, 1),
95  CONN_OPTION("max_background=%u", max_background, 0),
96  CONN_OPTION("max_background=", set_max_background, 1),
97  CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
98  CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
99  CONN_OPTION("sync_read", sync_read, 1),
100  CONN_OPTION("async_read", async_read, 1),
101  CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
102  CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
103  CONN_OPTION("no_remote_lock", no_remote_flock, 1),
104  CONN_OPTION("no_remote_flock", no_remote_flock, 1),
105  CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
106  CONN_OPTION("splice_write", splice_write, 1),
107  CONN_OPTION("no_splice_write", no_splice_write, 1),
108  CONN_OPTION("splice_move", splice_move, 1),
109  CONN_OPTION("no_splice_move", no_splice_move, 1),
110  CONN_OPTION("splice_read", splice_read, 1),
111  CONN_OPTION("no_splice_read", no_splice_read, 1),
112  CONN_OPTION("auto_inval_data", auto_inval_data, 1),
113  CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
114  CONN_OPTION("readdirplus=no", no_readdirplus, 1),
115  CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
116  CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
117  CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
118  CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
119  CONN_OPTION("async_dio", async_dio, 1),
120  CONN_OPTION("no_async_dio", no_async_dio, 1),
121  CONN_OPTION("writeback_cache", writeback_cache, 1),
122  CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
123  CONN_OPTION("time_gran=%u", time_gran, 0),
124  CONN_OPTION("time_gran=", set_time_gran, 1),
126 };
127 
128 
130 {
131  printf(" -h --help print help\n"
132  " -V --version print version\n"
133  " -d -o debug enable debug output (implies -f)\n"
134  " -f foreground operation\n"
135  " -s disable multi-threaded operation\n"
136  " -o clone_fd use separate fuse device fd for each thread\n"
137  " (may improve performance)\n"
138  " -o max_idle_threads the maximum number of idle worker threads\n"
139  " allowed (default: 10)\n");
140 }
141 
142 static int fuse_helper_opt_proc(void *data, const char *arg, int key,
143  struct fuse_args *outargs)
144 {
145  (void) outargs;
146  struct fuse_cmdline_opts *opts = data;
147 
148  switch (key) {
149  case FUSE_OPT_KEY_NONOPT:
150  if (!opts->mountpoint) {
151  if (fuse_mnt_parse_fuse_fd(arg) != -1) {
152  return fuse_opt_add_opt(&opts->mountpoint, arg);
153  }
154 
155  char mountpoint[PATH_MAX] = "";
156  if (realpath(arg, mountpoint) == NULL) {
157  fprintf(stderr,
158  "fuse: bad mount point `%s': %s\n",
159  arg, strerror(errno));
160  return -1;
161  }
162  return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
163  } else {
164  fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
165  return -1;
166  }
167 
168  default:
169  /* Pass through unknown options */
170  return 1;
171  }
172 }
173 
174 /* Under FreeBSD, there is no subtype option so this
175  function actually sets the fsname */
176 static int add_default_subtype(const char *progname, struct fuse_args *args)
177 {
178  int res;
179  char *subtype_opt;
180 
181  const char *basename = strrchr(progname, '/');
182  if (basename == NULL)
183  basename = progname;
184  else if (basename[1] != '\0')
185  basename++;
186 
187  subtype_opt = (char *) malloc(strlen(basename) + 64);
188  if (subtype_opt == NULL) {
189  fprintf(stderr, "fuse: memory allocation failed\n");
190  return -1;
191  }
192 #ifdef __FreeBSD__
193  sprintf(subtype_opt, "-ofsname=%s", basename);
194 #else
195  sprintf(subtype_opt, "-osubtype=%s", basename);
196 #endif
197  res = fuse_opt_add_arg(args, subtype_opt);
198  free(subtype_opt);
199  return res;
200 }
201 
202 int fuse_parse_cmdline(struct fuse_args *args,
203  struct fuse_cmdline_opts *opts)
204 {
205  memset(opts, 0, sizeof(struct fuse_cmdline_opts));
206 
207  opts->max_idle_threads = 10;
208 
209  if (fuse_opt_parse(args, opts, fuse_helper_opts,
210  fuse_helper_opt_proc) == -1)
211  return -1;
212 
213  /* *Linux*: if neither -o subtype nor -o fsname are specified,
214  set subtype to program's basename.
215  *FreeBSD*: if fsname is not specified, set to program's
216  basename. */
217  if (!opts->nodefault_subtype)
218  if (add_default_subtype(args->argv[0], args) == -1)
219  return -1;
220 
221  return 0;
222 }
223 
224 
225 int fuse_daemonize(int foreground)
226 {
227  if (!foreground) {
228  int nullfd;
229  int waiter[2];
230  char completed;
231 
232  if (pipe(waiter)) {
233  perror("fuse_daemonize: pipe");
234  return -1;
235  }
236 
237  /*
238  * demonize current process by forking it and killing the
239  * parent. This makes current process as a child of 'init'.
240  */
241  switch(fork()) {
242  case -1:
243  perror("fuse_daemonize: fork");
244  return -1;
245  case 0:
246  break;
247  default:
248  (void) read(waiter[0], &completed, sizeof(completed));
249  _exit(0);
250  }
251 
252  if (setsid() == -1) {
253  perror("fuse_daemonize: setsid");
254  return -1;
255  }
256 
257  (void) chdir("/");
258 
259  nullfd = open("/dev/null", O_RDWR, 0);
260  if (nullfd != -1) {
261  (void) dup2(nullfd, 0);
262  (void) dup2(nullfd, 1);
263  (void) dup2(nullfd, 2);
264  if (nullfd > 2)
265  close(nullfd);
266  }
267 
268  /* Propagate completion of daemon initialization */
269  completed = 1;
270  (void) write(waiter[1], &completed, sizeof(completed));
271  close(waiter[0]);
272  close(waiter[1]);
273  } else {
274  (void) chdir("/");
275  }
276  return 0;
277 }
278 
279 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
280  size_t op_size, void *user_data)
281 {
282  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
283  struct fuse *fuse;
284  struct fuse_cmdline_opts opts;
285  int res;
286 
287  if (fuse_parse_cmdline(&args, &opts) != 0)
288  return 1;
289 
290  if (opts.show_version) {
291  printf("FUSE library version %s\n", PACKAGE_VERSION);
293  res = 0;
294  goto out1;
295  }
296 
297  if (opts.show_help) {
298  if(args.argv[0][0] != '\0')
299  printf("usage: %s [options] <mountpoint>\n\n",
300  args.argv[0]);
301  printf("FUSE options:\n");
303  fuse_lib_help(&args);
304  res = 0;
305  goto out1;
306  }
307 
308  if (!opts.show_help &&
309  !opts.mountpoint) {
310  fprintf(stderr, "error: no mountpoint specified\n");
311  res = 2;
312  goto out1;
313  }
314 
315 
316  fuse = fuse_new_31(&args, op, op_size, user_data);
317  if (fuse == NULL) {
318  res = 3;
319  goto out1;
320  }
321 
322  if (fuse_mount(fuse,opts.mountpoint) != 0) {
323  res = 4;
324  goto out2;
325  }
326 
327  if (fuse_daemonize(opts.foreground) != 0) {
328  res = 5;
329  goto out3;
330  }
331 
332  struct fuse_session *se = fuse_get_session(fuse);
333  if (fuse_set_signal_handlers(se) != 0) {
334  res = 6;
335  goto out3;
336  }
337 
338  if (opts.singlethread)
339  res = fuse_loop(fuse);
340  else {
341  struct fuse_loop_config loop_config;
342  loop_config.clone_fd = opts.clone_fd;
343  loop_config.max_idle_threads = opts.max_idle_threads;
344  res = fuse_loop_mt_32(fuse, &loop_config);
345  }
346  if (res)
347  res = 7;
348 
350 out3:
351  fuse_unmount(fuse);
352 out2:
353  fuse_destroy(fuse);
354 out1:
355  free(opts.mountpoint);
356  fuse_opt_free_args(&args);
357  return res;
358 }
359 
360 
361 void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
362  struct fuse_conn_info *conn)
363 {
364  if(opts->set_max_write)
365  conn->max_write = opts->max_write;
366  if(opts->set_max_background)
367  conn->max_background = opts->max_background;
368  if(opts->set_congestion_threshold)
369  conn->congestion_threshold = opts->congestion_threshold;
370  if(opts->set_time_gran)
371  conn->time_gran = opts->time_gran;
372  if(opts->set_max_readahead)
373  conn->max_readahead = opts->max_readahead;
374 
375 #define LL_ENABLE(cond,cap) \
376  if (cond) conn->want |= (cap)
377 #define LL_DISABLE(cond,cap) \
378  if (cond) conn->want &= ~(cap)
379 
380  LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
381  LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
382 
383  LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
384  LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
385 
386  LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
387  LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
388 
389  LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
390  LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
391 
392  LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
393  LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
394 
395  LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
396  LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
397 
398  LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
399  LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
400 
401  LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
402  LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
403 
404  LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
405  LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
406 }
407 
408 struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args)
409 {
410  struct fuse_conn_info_opts *opts;
411 
412  opts = calloc(1, sizeof(struct fuse_conn_info_opts));
413  if(opts == NULL) {
414  fprintf(stderr, "calloc failed\n");
415  return NULL;
416  }
417  if(fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
418  free(opts);
419  return NULL;
420  }
421  return opts;
422 }
423 
424 int fuse_open_channel(const char *mountpoint, const char* options)
425 {
426  struct mount_opts *opts = NULL;
427  int fd = -1;
428  const char *argv[] = { "", "-o", options };
429  int argc = sizeof(argv) / sizeof(argv[0]);
430  struct fuse_args args = FUSE_ARGS_INIT(argc, (char**) argv);
431 
432  opts = parse_mount_opts(&args);
433  if (opts == NULL)
434  return -1;
435 
436  fd = fuse_kern_mount(mountpoint, opts);
437  destroy_mount_opts(opts);
438 
439  return fd;
440 }
+
unsigned max_write
Definition: fuse_common.h:357
+
int fuse_daemonize(int foreground)
Definition: helper.c:225
+
#define FUSE_CAP_ASYNC_READ
Definition: fuse_common.h:120
+
unsigned int max_idle_threads
Definition: fuse_common.h:103
+
int fuse_loop(struct fuse *f)
Definition: fuse.c:4516
+
unsigned max_background
Definition: fuse_common.h:419
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
+
void fuse_cmdline_help(void)
Definition: helper.c:129
+
#define FUSE_CAP_READDIRPLUS_AUTO
Definition: fuse_common.h:246
+
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
+
#define FUSE_CAP_SPLICE_WRITE
Definition: fuse_common.h:160
+
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
+
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
+
void fuse_destroy(struct fuse *f)
Definition: fuse.c:5007
+
struct fuse_conn_info_opts * fuse_parse_conn_info_opts(struct fuse_args *args)
Definition: helper.c:408
+
void fuse_lowlevel_version(void)
+ +
void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn)
Definition: helper.c:361
+ +
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+
#define FUSE_CAP_SPLICE_MOVE
Definition: fuse_common.h:168
+
int fuse_open_channel(const char *mountpoint, const char *options)
Definition: helper.c:424
+
#define FUSE_CAP_AUTO_INVAL_DATA
Definition: fuse_common.h:219
+ +
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
+
#define FUSE_CAP_SPLICE_READ
Definition: fuse_common.h:177
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+
unsigned congestion_threshold
Definition: fuse_common.h:429
+
struct fuse_session * fuse_get_session(struct fuse *f)
Definition: fuse.c:4459
+
#define FUSE_OPT_KEY_KEEP
Definition: fuse_opt.h:145
+
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *private_data)
Definition: helper.c:279
+
int fuse_opt_add_opt(char **opts, const char *opt)
Definition: fuse_opt.c:138
+
#define FUSE_CAP_FLOCK_LOCKS
Definition: fuse_common.h:190
+
unsigned max_readahead
Definition: fuse_common.h:376
+
void fuse_lib_help(struct fuse_args *args)
Definition: fuse.c:4650
+
#define FUSE_OPT_KEY_NONOPT
Definition: fuse_opt.h:137
+
char ** argv
Definition: fuse_opt.h:114
+
#define FUSE_CAP_ASYNC_DIO
Definition: fuse_common.h:257
+
#define FUSE_CAP_WRITEBACK_CACHE
Definition: fuse_common.h:266
+
int fuse_mount(struct fuse *f, const char *mountpoint)
Definition: fuse.c:5057
+
#define FUSE_CAP_POSIX_LOCKS
Definition: fuse_common.h:128
+ + +
void fuse_unmount(struct fuse *f)
Definition: fuse.c:5062
+ +
#define FUSE_CAP_READDIRPLUS
Definition: fuse_common.h:227
+
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
+ +
unsigned time_gran
Definition: fuse_common.h:446
+
+ + + + diff --git a/doc/html/iconv_8c_source.html b/doc/html/iconv_8c_source.html new file mode 100644 index 0000000..a2eb935 --- /dev/null +++ b/doc/html/iconv_8c_source.html @@ -0,0 +1,75 @@ + + + + + + + +libfuse: lib/modules/iconv.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
iconv.c
+
+
+
1 /*
2  fuse iconv module: file name charset conversion
3  Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  This program can be distributed under the terms of the GNU LGPLv2.
6  See the file COPYING.LIB
7 */
8 
9 #include <config.h>
10 
11 #include <fuse.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <iconv.h>
18 #include <pthread.h>
19 #include <locale.h>
20 #include <langinfo.h>
21 
22 struct iconv {
23  struct fuse_fs *next;
24  pthread_mutex_t lock;
25  char *from_code;
26  char *to_code;
27  iconv_t tofs;
28  iconv_t fromfs;
29 };
30 
31 struct iconv_dh {
32  struct iconv *ic;
33  void *prev_buf;
34  fuse_fill_dir_t prev_filler;
35 };
36 
37 static struct iconv *iconv_get(void)
38 {
40 }
41 
42 static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp,
43  int fromfs)
44 {
45  size_t pathlen;
46  size_t newpathlen;
47  char *newpath;
48  size_t plen;
49  char *p;
50  size_t res;
51  int err;
52 
53  if (path == NULL) {
54  *newpathp = NULL;
55  return 0;
56  }
57 
58  pathlen = strlen(path);
59  newpathlen = pathlen * 4;
60  newpath = malloc(newpathlen + 1);
61  if (!newpath)
62  return -ENOMEM;
63 
64  plen = newpathlen;
65  p = newpath;
66  pthread_mutex_lock(&ic->lock);
67  do {
68  res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path,
69  &pathlen, &p, &plen);
70  if (res == (size_t) -1) {
71  char *tmp;
72  size_t inc;
73 
74  err = -EILSEQ;
75  if (errno != E2BIG)
76  goto err;
77 
78  inc = (pathlen + 1) * 4;
79  newpathlen += inc;
80  tmp = realloc(newpath, newpathlen + 1);
81  err = -ENOMEM;
82  if (!tmp)
83  goto err;
84 
85  p = tmp + (p - newpath);
86  plen += inc;
87  newpath = tmp;
88  }
89  } while (res == (size_t) -1);
90  pthread_mutex_unlock(&ic->lock);
91  *p = '\0';
92  *newpathp = newpath;
93  return 0;
94 
95 err:
96  iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL);
97  pthread_mutex_unlock(&ic->lock);
98  free(newpath);
99  return err;
100 }
101 
102 static int iconv_getattr(const char *path, struct stat *stbuf,
103  struct fuse_file_info *fi)
104 {
105  struct iconv *ic = iconv_get();
106  char *newpath;
107  int err = iconv_convpath(ic, path, &newpath, 0);
108  if (!err) {
109  err = fuse_fs_getattr(ic->next, newpath, stbuf, fi);
110  free(newpath);
111  }
112  return err;
113 }
114 
115 static int iconv_access(const char *path, int mask)
116 {
117  struct iconv *ic = iconv_get();
118  char *newpath;
119  int err = iconv_convpath(ic, path, &newpath, 0);
120  if (!err) {
121  err = fuse_fs_access(ic->next, newpath, mask);
122  free(newpath);
123  }
124  return err;
125 }
126 
127 static int iconv_readlink(const char *path, char *buf, size_t size)
128 {
129  struct iconv *ic = iconv_get();
130  char *newpath;
131  int err = iconv_convpath(ic, path, &newpath, 0);
132  if (!err) {
133  err = fuse_fs_readlink(ic->next, newpath, buf, size);
134  if (!err) {
135  char *newlink;
136  err = iconv_convpath(ic, buf, &newlink, 1);
137  if (!err) {
138  strncpy(buf, newlink, size - 1);
139  buf[size - 1] = '\0';
140  free(newlink);
141  }
142  }
143  free(newpath);
144  }
145  return err;
146 }
147 
148 static int iconv_opendir(const char *path, struct fuse_file_info *fi)
149 {
150  struct iconv *ic = iconv_get();
151  char *newpath;
152  int err = iconv_convpath(ic, path, &newpath, 0);
153  if (!err) {
154  err = fuse_fs_opendir(ic->next, newpath, fi);
155  free(newpath);
156  }
157  return err;
158 }
159 
160 static int iconv_dir_fill(void *buf, const char *name,
161  const struct stat *stbuf, off_t off,
162  enum fuse_fill_dir_flags flags)
163 {
164  struct iconv_dh *dh = buf;
165  char *newname;
166  int res = 0;
167  if (iconv_convpath(dh->ic, name, &newname, 1) == 0) {
168  res = dh->prev_filler(dh->prev_buf, newname, stbuf, off, flags);
169  free(newname);
170  }
171  return res;
172 }
173 
174 static int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
175  off_t offset, struct fuse_file_info *fi,
176  enum fuse_readdir_flags flags)
177 {
178  struct iconv *ic = iconv_get();
179  char *newpath;
180  int err = iconv_convpath(ic, path, &newpath, 0);
181  if (!err) {
182  struct iconv_dh dh;
183  dh.ic = ic;
184  dh.prev_buf = buf;
185  dh.prev_filler = filler;
186  err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill,
187  offset, fi, flags);
188  free(newpath);
189  }
190  return err;
191 }
192 
193 static int iconv_releasedir(const char *path, struct fuse_file_info *fi)
194 {
195  struct iconv *ic = iconv_get();
196  char *newpath;
197  int err = iconv_convpath(ic, path, &newpath, 0);
198  if (!err) {
199  err = fuse_fs_releasedir(ic->next, newpath, fi);
200  free(newpath);
201  }
202  return err;
203 }
204 
205 static int iconv_mknod(const char *path, mode_t mode, dev_t rdev)
206 {
207  struct iconv *ic = iconv_get();
208  char *newpath;
209  int err = iconv_convpath(ic, path, &newpath, 0);
210  if (!err) {
211  err = fuse_fs_mknod(ic->next, newpath, mode, rdev);
212  free(newpath);
213  }
214  return err;
215 }
216 
217 static int iconv_mkdir(const char *path, mode_t mode)
218 {
219  struct iconv *ic = iconv_get();
220  char *newpath;
221  int err = iconv_convpath(ic, path, &newpath, 0);
222  if (!err) {
223  err = fuse_fs_mkdir(ic->next, newpath, mode);
224  free(newpath);
225  }
226  return err;
227 }
228 
229 static int iconv_unlink(const char *path)
230 {
231  struct iconv *ic = iconv_get();
232  char *newpath;
233  int err = iconv_convpath(ic, path, &newpath, 0);
234  if (!err) {
235  err = fuse_fs_unlink(ic->next, newpath);
236  free(newpath);
237  }
238  return err;
239 }
240 
241 static int iconv_rmdir(const char *path)
242 {
243  struct iconv *ic = iconv_get();
244  char *newpath;
245  int err = iconv_convpath(ic, path, &newpath, 0);
246  if (!err) {
247  err = fuse_fs_rmdir(ic->next, newpath);
248  free(newpath);
249  }
250  return err;
251 }
252 
253 static int iconv_symlink(const char *from, const char *to)
254 {
255  struct iconv *ic = iconv_get();
256  char *newfrom;
257  char *newto;
258  int err = iconv_convpath(ic, from, &newfrom, 0);
259  if (!err) {
260  err = iconv_convpath(ic, to, &newto, 0);
261  if (!err) {
262  err = fuse_fs_symlink(ic->next, newfrom, newto);
263  free(newto);
264  }
265  free(newfrom);
266  }
267  return err;
268 }
269 
270 static int iconv_rename(const char *from, const char *to, unsigned int flags)
271 {
272  struct iconv *ic = iconv_get();
273  char *newfrom;
274  char *newto;
275  int err = iconv_convpath(ic, from, &newfrom, 0);
276  if (!err) {
277  err = iconv_convpath(ic, to, &newto, 0);
278  if (!err) {
279  err = fuse_fs_rename(ic->next, newfrom, newto, flags);
280  free(newto);
281  }
282  free(newfrom);
283  }
284  return err;
285 }
286 
287 static int iconv_link(const char *from, const char *to)
288 {
289  struct iconv *ic = iconv_get();
290  char *newfrom;
291  char *newto;
292  int err = iconv_convpath(ic, from, &newfrom, 0);
293  if (!err) {
294  err = iconv_convpath(ic, to, &newto, 0);
295  if (!err) {
296  err = fuse_fs_link(ic->next, newfrom, newto);
297  free(newto);
298  }
299  free(newfrom);
300  }
301  return err;
302 }
303 
304 static int iconv_chmod(const char *path, mode_t mode,
305  struct fuse_file_info *fi)
306 {
307  struct iconv *ic = iconv_get();
308  char *newpath;
309  int err = iconv_convpath(ic, path, &newpath, 0);
310  if (!err) {
311  err = fuse_fs_chmod(ic->next, newpath, mode, fi);
312  free(newpath);
313  }
314  return err;
315 }
316 
317 static int iconv_chown(const char *path, uid_t uid, gid_t gid,
318  struct fuse_file_info *fi)
319 {
320  struct iconv *ic = iconv_get();
321  char *newpath;
322  int err = iconv_convpath(ic, path, &newpath, 0);
323  if (!err) {
324  err = fuse_fs_chown(ic->next, newpath, uid, gid, fi);
325  free(newpath);
326  }
327  return err;
328 }
329 
330 static int iconv_truncate(const char *path, off_t size,
331  struct fuse_file_info *fi)
332 {
333  struct iconv *ic = iconv_get();
334  char *newpath;
335  int err = iconv_convpath(ic, path, &newpath, 0);
336  if (!err) {
337  err = fuse_fs_truncate(ic->next, newpath, size, fi);
338  free(newpath);
339  }
340  return err;
341 }
342 
343 static int iconv_utimens(const char *path, const struct timespec ts[2],
344  struct fuse_file_info *fi)
345 {
346  struct iconv *ic = iconv_get();
347  char *newpath;
348  int err = iconv_convpath(ic, path, &newpath, 0);
349  if (!err) {
350  err = fuse_fs_utimens(ic->next, newpath, ts, fi);
351  free(newpath);
352  }
353  return err;
354 }
355 
356 static int iconv_create(const char *path, mode_t mode,
357  struct fuse_file_info *fi)
358 {
359  struct iconv *ic = iconv_get();
360  char *newpath;
361  int err = iconv_convpath(ic, path, &newpath, 0);
362  if (!err) {
363  err = fuse_fs_create(ic->next, newpath, mode, fi);
364  free(newpath);
365  }
366  return err;
367 }
368 
369 static int iconv_open_file(const char *path, struct fuse_file_info *fi)
370 {
371  struct iconv *ic = iconv_get();
372  char *newpath;
373  int err = iconv_convpath(ic, path, &newpath, 0);
374  if (!err) {
375  err = fuse_fs_open(ic->next, newpath, fi);
376  free(newpath);
377  }
378  return err;
379 }
380 
381 static int iconv_read_buf(const char *path, struct fuse_bufvec **bufp,
382  size_t size, off_t offset, struct fuse_file_info *fi)
383 {
384  struct iconv *ic = iconv_get();
385  char *newpath;
386  int err = iconv_convpath(ic, path, &newpath, 0);
387  if (!err) {
388  err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi);
389  free(newpath);
390  }
391  return err;
392 }
393 
394 static int iconv_write_buf(const char *path, struct fuse_bufvec *buf,
395  off_t offset, struct fuse_file_info *fi)
396 {
397  struct iconv *ic = iconv_get();
398  char *newpath;
399  int err = iconv_convpath(ic, path, &newpath, 0);
400  if (!err) {
401  err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi);
402  free(newpath);
403  }
404  return err;
405 }
406 
407 static int iconv_statfs(const char *path, struct statvfs *stbuf)
408 {
409  struct iconv *ic = iconv_get();
410  char *newpath;
411  int err = iconv_convpath(ic, path, &newpath, 0);
412  if (!err) {
413  err = fuse_fs_statfs(ic->next, newpath, stbuf);
414  free(newpath);
415  }
416  return err;
417 }
418 
419 static int iconv_flush(const char *path, struct fuse_file_info *fi)
420 {
421  struct iconv *ic = iconv_get();
422  char *newpath;
423  int err = iconv_convpath(ic, path, &newpath, 0);
424  if (!err) {
425  err = fuse_fs_flush(ic->next, newpath, fi);
426  free(newpath);
427  }
428  return err;
429 }
430 
431 static int iconv_release(const char *path, struct fuse_file_info *fi)
432 {
433  struct iconv *ic = iconv_get();
434  char *newpath;
435  int err = iconv_convpath(ic, path, &newpath, 0);
436  if (!err) {
437  err = fuse_fs_release(ic->next, newpath, fi);
438  free(newpath);
439  }
440  return err;
441 }
442 
443 static int iconv_fsync(const char *path, int isdatasync,
444  struct fuse_file_info *fi)
445 {
446  struct iconv *ic = iconv_get();
447  char *newpath;
448  int err = iconv_convpath(ic, path, &newpath, 0);
449  if (!err) {
450  err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi);
451  free(newpath);
452  }
453  return err;
454 }
455 
456 static int iconv_fsyncdir(const char *path, int isdatasync,
457  struct fuse_file_info *fi)
458 {
459  struct iconv *ic = iconv_get();
460  char *newpath;
461  int err = iconv_convpath(ic, path, &newpath, 0);
462  if (!err) {
463  err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi);
464  free(newpath);
465  }
466  return err;
467 }
468 
469 static int iconv_setxattr(const char *path, const char *name,
470  const char *value, size_t size, int flags)
471 {
472  struct iconv *ic = iconv_get();
473  char *newpath;
474  int err = iconv_convpath(ic, path, &newpath, 0);
475  if (!err) {
476  err = fuse_fs_setxattr(ic->next, newpath, name, value, size,
477  flags);
478  free(newpath);
479  }
480  return err;
481 }
482 
483 static int iconv_getxattr(const char *path, const char *name, char *value,
484  size_t size)
485 {
486  struct iconv *ic = iconv_get();
487  char *newpath;
488  int err = iconv_convpath(ic, path, &newpath, 0);
489  if (!err) {
490  err = fuse_fs_getxattr(ic->next, newpath, name, value, size);
491  free(newpath);
492  }
493  return err;
494 }
495 
496 static int iconv_listxattr(const char *path, char *list, size_t size)
497 {
498  struct iconv *ic = iconv_get();
499  char *newpath;
500  int err = iconv_convpath(ic, path, &newpath, 0);
501  if (!err) {
502  err = fuse_fs_listxattr(ic->next, newpath, list, size);
503  free(newpath);
504  }
505  return err;
506 }
507 
508 static int iconv_removexattr(const char *path, const char *name)
509 {
510  struct iconv *ic = iconv_get();
511  char *newpath;
512  int err = iconv_convpath(ic, path, &newpath, 0);
513  if (!err) {
514  err = fuse_fs_removexattr(ic->next, newpath, name);
515  free(newpath);
516  }
517  return err;
518 }
519 
520 static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd,
521  struct flock *lock)
522 {
523  struct iconv *ic = iconv_get();
524  char *newpath;
525  int err = iconv_convpath(ic, path, &newpath, 0);
526  if (!err) {
527  err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock);
528  free(newpath);
529  }
530  return err;
531 }
532 
533 static int iconv_flock(const char *path, struct fuse_file_info *fi, int op)
534 {
535  struct iconv *ic = iconv_get();
536  char *newpath;
537  int err = iconv_convpath(ic, path, &newpath, 0);
538  if (!err) {
539  err = fuse_fs_flock(ic->next, newpath, fi, op);
540  free(newpath);
541  }
542  return err;
543 }
544 
545 static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx)
546 {
547  struct iconv *ic = iconv_get();
548  char *newpath;
549  int err = iconv_convpath(ic, path, &newpath, 0);
550  if (!err) {
551  err = fuse_fs_bmap(ic->next, newpath, blocksize, idx);
552  free(newpath);
553  }
554  return err;
555 }
556 
557 static void *iconv_init(struct fuse_conn_info *conn,
558  struct fuse_config *cfg)
559 {
560  struct iconv *ic = iconv_get();
561  fuse_fs_init(ic->next, conn, cfg);
562  /* Don't touch cfg->nullpath_ok, we can work with
563  either */
564  return ic;
565 }
566 
567 static void iconv_destroy(void *data)
568 {
569  struct iconv *ic = data;
570  fuse_fs_destroy(ic->next);
571  iconv_close(ic->tofs);
572  iconv_close(ic->fromfs);
573  pthread_mutex_destroy(&ic->lock);
574  free(ic->from_code);
575  free(ic->to_code);
576  free(ic);
577 }
578 
579 static const struct fuse_operations iconv_oper = {
580  .destroy = iconv_destroy,
581  .init = iconv_init,
582  .getattr = iconv_getattr,
583  .access = iconv_access,
584  .readlink = iconv_readlink,
585  .opendir = iconv_opendir,
586  .readdir = iconv_readdir,
587  .releasedir = iconv_releasedir,
588  .mknod = iconv_mknod,
589  .mkdir = iconv_mkdir,
590  .symlink = iconv_symlink,
591  .unlink = iconv_unlink,
592  .rmdir = iconv_rmdir,
593  .rename = iconv_rename,
594  .link = iconv_link,
595  .chmod = iconv_chmod,
596  .chown = iconv_chown,
597  .truncate = iconv_truncate,
598  .utimens = iconv_utimens,
599  .create = iconv_create,
600  .open = iconv_open_file,
601  .read_buf = iconv_read_buf,
602  .write_buf = iconv_write_buf,
603  .statfs = iconv_statfs,
604  .flush = iconv_flush,
605  .release = iconv_release,
606  .fsync = iconv_fsync,
607  .fsyncdir = iconv_fsyncdir,
608  .setxattr = iconv_setxattr,
609  .getxattr = iconv_getxattr,
610  .listxattr = iconv_listxattr,
611  .removexattr = iconv_removexattr,
612  .lock = iconv_lock,
613  .flock = iconv_flock,
614  .bmap = iconv_bmap,
615 };
616 
617 static const struct fuse_opt iconv_opts[] = {
618  FUSE_OPT_KEY("-h", 0),
619  FUSE_OPT_KEY("--help", 0),
620  { "from_code=%s", offsetof(struct iconv, from_code), 0 },
621  { "to_code=%s", offsetof(struct iconv, to_code), 1 },
623 };
624 
625 static void iconv_help(void)
626 {
627  char *old = strdup(setlocale(LC_CTYPE, ""));
628  char *charmap = strdup(nl_langinfo(CODESET));
629  setlocale(LC_CTYPE, old);
630  free(old);
631  printf(
632 " -o from_code=CHARSET original encoding of file names (default: UTF-8)\n"
633 " -o to_code=CHARSET new encoding of the file names (default: %s)\n",
634  charmap);
635  free(charmap);
636 }
637 
638 static int iconv_opt_proc(void *data, const char *arg, int key,
639  struct fuse_args *outargs)
640 {
641  (void) data; (void) arg; (void) outargs;
642 
643  if (!key) {
644  iconv_help();
645  return -1;
646  }
647 
648  return 1;
649 }
650 
651 static struct fuse_fs *iconv_new(struct fuse_args *args,
652  struct fuse_fs *next[])
653 {
654  struct fuse_fs *fs;
655  struct iconv *ic;
656  char *old = NULL;
657  const char *from;
658  const char *to;
659 
660  ic = calloc(1, sizeof(struct iconv));
661  if (ic == NULL) {
662  fprintf(stderr, "fuse-iconv: memory allocation failed\n");
663  return NULL;
664  }
665 
666  if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1)
667  goto out_free;
668 
669  if (!next[0] || next[1]) {
670  fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n");
671  goto out_free;
672  }
673 
674  from = ic->from_code ? ic->from_code : "UTF-8";
675  to = ic->to_code ? ic->to_code : "";
676  /* FIXME: detect charset equivalence? */
677  if (!to[0])
678  old = strdup(setlocale(LC_CTYPE, ""));
679  ic->tofs = iconv_open(from, to);
680  if (ic->tofs == (iconv_t) -1) {
681  fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
682  to, from);
683  goto out_free;
684  }
685  ic->fromfs = iconv_open(to, from);
686  if (ic->tofs == (iconv_t) -1) {
687  fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n",
688  from, to);
689  goto out_iconv_close_to;
690  }
691  if (old) {
692  setlocale(LC_CTYPE, old);
693  free(old);
694  }
695 
696  ic->next = next[0];
697  fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic);
698  if (!fs)
699  goto out_iconv_close_from;
700 
701  return fs;
702 
703 out_iconv_close_from:
704  iconv_close(ic->fromfs);
705 out_iconv_close_to:
706  iconv_close(ic->tofs);
707 out_free:
708  free(ic->from_code);
709  free(ic->to_code);
710  free(ic);
711  if (old) {
712  setlocale(LC_CTYPE, old);
713  free(old);
714  }
715  return NULL;
716 }
717 
718 FUSE_REGISTER_MODULE(iconv, iconv_new);
+
fuse_fill_dir_flags
Definition: fuse.h:54
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
fuse_readdir_flags
Definition: fuse.h:42
+ + + +
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
+
#define FUSE_REGISTER_MODULE(name_, factory_)
Definition: fuse.h:1238
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+
void * private_data
Definition: fuse.h:791
+
struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
Definition: fuse.c:4760
+ +
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:82
+ + + +
struct fuse_context * fuse_get_context(void)
Definition: fuse.c:4557
+
void(* destroy)(void *private_data)
Definition: fuse.h:580
+
+ + + + diff --git a/doc/html/index.html b/doc/html/index.html index 5e24019..ad75b1a 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -3,8 +3,9 @@ - -fuse: Main Page + + +libfuse: libfuse API documentation @@ -16,8 +17,8 @@ - @@ -25,26 +26,41 @@
-
fuse +
+
libfuse
- - + + + + +
-
fuse Documentation
+
libfuse API documentation
-
+

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. 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.

+

Getting started

+

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.

+

The high-level API that is primarily specified in fuse.h. The low-level API that is primarily documented in fuse_lowlevel.h.

+

Examples

+

FUSE comes with several examples in the examples directory. A good starting point are hello.c (for the high-level API) and hello_ll.c (for the low-level API).

+

FUSE internals

+

The authoritative source of information about libfuse internals (including the protocol used for communication with the FUSE kernel module) is the source code.

+

However, some people have kindly documented different aspects of FUSE in a more beginner friendly way. While this information is increasingly out of date, it still provides a good overview:

+ +
diff --git a/doc/html/invalidate__path_8c.html b/doc/html/invalidate__path_8c.html new file mode 100644 index 0000000..f6a1f0c --- /dev/null +++ b/doc/html/invalidate__path_8c.html @@ -0,0 +1,77 @@ + + + + + + + +libfuse: example/invalidate_path.c File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
invalidate_path.c File Reference
+
+
+
#include <fuse.h>
+#include <fuse_lowlevel.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <pthread.h>
+
+

Go to the source code of this file.

+

Detailed Description

+

This example implements a file system with two files:

    +
  • 'current-time', whose contents change dynamically: it always contains the current time (same as in notify_inval_inode.c).
  • +
  • 'growing', whose size changes dynamically, growing by 1 byte after each update. This aims to check if cached file metadata is also invalidated.
  • +
+

Compilation

+
gcc -Wall
+

Definition in file invalidate_path.c.

+
+ + + + diff --git a/doc/html/invalidate__path_8c_source.html b/doc/html/invalidate__path_8c_source.html new file mode 100644 index 0000000..bd2cbae --- /dev/null +++ b/doc/html/invalidate__path_8c_source.html @@ -0,0 +1,91 @@ + + + + + + + +libfuse: example/invalidate_path.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
invalidate_path.c
+
+
+Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
4  (C) 2017 EditShare LLC <slawek.rudnicki@editshare.com>
5 
6  This program can be distributed under the terms of the GNU GPL.
7  See the file COPYING.
8  */
9 
28 #define FUSE_USE_VERSION 31
29 
30 #include <fuse.h>
31 #include <fuse_lowlevel.h> /* for fuse_cmdline_opts */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <assert.h>
39 #include <stddef.h>
40 #include <unistd.h>
41 #include <pthread.h>
42 
43 /* We can't actually tell the kernel that there is no
44  timeout, so we just send a big value */
45 #define NO_TIMEOUT 500000
46 
47 #define MAX_STR_LEN 128
48 #define TIME_FILE_NAME "current_time"
49 #define TIME_FILE_INO 2
50 #define GROW_FILE_NAME "growing"
51 #define GROW_FILE_INO 3
52 
53 static char time_file_contents[MAX_STR_LEN];
54 static size_t grow_file_size;
55 
56 /* Command line parsing */
57 struct options {
58  int no_notify;
59  int update_interval;
60 };
61 static struct options options = {
62  .no_notify = 0,
63  .update_interval = 1,
64 };
65 
66 #define OPTION(t, p) { t, offsetof(struct options, p), 1 }
67 static const struct fuse_opt option_spec[] = {
68  OPTION("--no-notify", no_notify),
69  OPTION("--update-interval=%d", update_interval),
71 };
72 
73 static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
74 {
75  (void) conn;
76  cfg->entry_timeout = NO_TIMEOUT;
77  cfg->attr_timeout = NO_TIMEOUT;
78  cfg->negative_timeout = 0;
79 
80  return NULL;
81 }
82 
83 static int xmp_getattr(const char *path,
84  struct stat *stbuf, struct fuse_file_info* fi) {
85  (void) fi;
86  if (strcmp(path, "/") == 0) {
87  stbuf->st_ino = 1;
88  stbuf->st_mode = S_IFDIR | 0755;
89  stbuf->st_nlink = 1;
90  } else if (strcmp(path, "/" TIME_FILE_NAME) == 0) {
91  stbuf->st_ino = TIME_FILE_INO;
92  stbuf->st_mode = S_IFREG | 0444;
93  stbuf->st_nlink = 1;
94  stbuf->st_size = strlen(time_file_contents);
95  } else if (strcmp(path, "/" GROW_FILE_NAME) == 0) {
96  stbuf->st_ino = GROW_FILE_INO;
97  stbuf->st_mode = S_IFREG | 0444;
98  stbuf->st_nlink = 1;
99  stbuf->st_size = grow_file_size;
100  } else {
101  return -ENOENT;
102  }
103 
104  return 0;
105 }
106 
107 static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
108  off_t offset, struct fuse_file_info *fi,
109  enum fuse_readdir_flags flags) {
110  (void) fi;
111  (void) offset;
112  (void) flags;
113  if (strcmp(path, "/") != 0) {
114  return -ENOTDIR;
115  } else {
116  (void) filler;
117  (void) buf;
118  struct stat file_stat;
119  xmp_getattr("/" TIME_FILE_NAME, &file_stat, NULL);
120  filler(buf, TIME_FILE_NAME, &file_stat, 0, 0);
121  xmp_getattr("/" GROW_FILE_NAME, &file_stat, NULL);
122  filler(buf, GROW_FILE_NAME, &file_stat, 0, 0);
123  return 0;
124  }
125 }
126 
127 static int xmp_open(const char *path, struct fuse_file_info *fi) {
128  (void) path;
129  /* Make cache persistent even if file is closed,
130  this makes it easier to see the effects */
131  fi->keep_cache = 1;
132  return 0;
133 }
134 
135 static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
136  struct fuse_file_info *fi) {
137  (void) fi;
138  (void) offset;
139  if (strcmp(path, "/" TIME_FILE_NAME) == 0) {
140  int file_length = strlen(time_file_contents);
141  int to_copy = offset + size <= file_length
142  ? size
143  : file_length - offset;
144  memcpy(buf, time_file_contents, to_copy);
145  return to_copy;
146  } else {
147  assert(strcmp(path, "/" GROW_FILE_NAME) == 0);
148  int to_copy = offset + size <= grow_file_size
149  ? size
150  : grow_file_size - offset;
151  memset(buf, 'x', to_copy);
152  return to_copy;
153  }
154 }
155 
156 static struct fuse_operations xmp_oper = {
157  .init = xmp_init,
158  .getattr = xmp_getattr,
159  .readdir = xmp_readdir,
160  .open = xmp_open,
161  .read = xmp_read,
162 };
163 
164 static void update_fs(void) {
165  static int count = 0;
166  struct tm *now;
167  time_t t;
168  t = time(NULL);
169  now = localtime(&t);
170  assert(now != NULL);
171 
172  int time_file_size = strftime(time_file_contents, MAX_STR_LEN,
173  "The current time is %H:%M:%S\n", now);
174  assert(time_file_size != 0);
175 
176  grow_file_size = count++;
177 }
178 
179 static int invalidate(struct fuse *fuse, const char *path) {
180  int status = fuse_invalidate_path(fuse, path);
181  if (status == -ENOENT) {
182  return 0;
183  } else {
184  return status;
185  }
186 }
187 
188 static void* update_fs_loop(void *data) {
189  struct fuse *fuse = (struct fuse*) data;
190 
191  while (1) {
192  update_fs();
193  if (!options.no_notify) {
194  assert(invalidate(fuse, "/" TIME_FILE_NAME) == 0);
195  assert(invalidate(fuse, "/" GROW_FILE_NAME) == 0);
196  }
197  sleep(options.update_interval);
198  }
199  return NULL;
200 }
201 
202 static void show_help(const char *progname)
203 {
204  printf("usage: %s [options] <mountpoint>\n\n", progname);
205  printf("File-system specific options:\n"
206  " --update-interval=<secs> Update-rate of file system contents\n"
207  " --no-notify Disable kernel notifications\n"
208  "\n");
209 }
210 
211 int main(int argc, char *argv[]) {
212  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
213  struct fuse *fuse;
214  struct fuse_cmdline_opts opts;
215  int res;
216 
217  /* Initialize the files */
218  update_fs();
219 
220  if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
221  return 1;
222 
223  if (fuse_parse_cmdline(&args, &opts) != 0)
224  return 1;
225 
226  if (opts.show_version) {
227  printf("FUSE library version %s\n", fuse_pkgversion());
229  res = 0;
230  goto out1;
231  } else if (opts.show_help) {
232  show_help(argv[0]);
234  fuse_lib_help(&args);
235  res = 0;
236  goto out1;
237  } else if (!opts.mountpoint) {
238  fprintf(stderr, "error: no mountpoint specified\n");
239  res = 1;
240  goto out1;
241  }
242 
243  fuse = fuse_new(&args, &xmp_oper, sizeof(xmp_oper), NULL);
244  if (fuse == NULL) {
245  res = 1;
246  goto out1;
247  }
248 
249  if (fuse_mount(fuse,opts.mountpoint) != 0) {
250  res = 1;
251  goto out2;
252  }
253 
254  if (fuse_daemonize(opts.foreground) != 0) {
255  res = 1;
256  goto out3;
257  }
258 
259  pthread_t updater; /* Start thread to update file contents */
260  int ret = pthread_create(&updater, NULL, update_fs_loop, (void *) fuse);
261  if (ret != 0) {
262  fprintf(stderr, "pthread_create failed with %s\n", strerror(ret));
263  return 1;
264  };
265 
266  struct fuse_session *se = fuse_get_session(fuse);
267  if (fuse_set_signal_handlers(se) != 0) {
268  res = 1;
269  goto out3;
270  }
271 
272  if (opts.singlethread)
273  res = fuse_loop(fuse);
274  else
275  res = fuse_loop_mt(fuse, opts.clone_fd);
276  if (res)
277  res = 1;
278 
280 out3:
281  fuse_unmount(fuse);
282 out2:
283  fuse_destroy(fuse);
284 out1:
285  free(opts.mountpoint);
286  fuse_opt_free_args(&args);
287  return res;
288 }
+
int fuse_daemonize(int foreground)
Definition: helper.c:225
+
unsigned long offset
Definition: fuse_opt.h:85
+
int fuse_loop(struct fuse *f)
Definition: fuse.c:4516
+
struct fuse * fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data)
+
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:397
+
unsigned int keep_cache
Definition: fuse_common.h:51
+
fuse_readdir_flags
Definition: fuse.h:42
+
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
+
void fuse_cmdline_help(void)
Definition: helper.c:129
+
double negative_timeout
Definition: fuse.h:129
+
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
+
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
+ +
void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
Definition: fuse.h:572
+
void fuse_destroy(struct fuse *f)
Definition: fuse.c:5007
+
void fuse_lowlevel_version(void)
+ +
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
+
#define FUSE_OPT_END
Definition: fuse_opt.h:104
+
struct fuse_session * fuse_get_session(struct fuse *f)
Definition: fuse.c:4459
+
int fuse_invalidate_path(struct fuse *f, const char *path)
Definition: fuse.c:4586
+
double attr_timeout
Definition: fuse.h:135
+ +
void fuse_lib_help(struct fuse_args *args)
Definition: fuse.c:4650
+
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:82
+ +
int fuse_mount(struct fuse *f, const char *mountpoint)
Definition: fuse.c:5057
+ + +
void fuse_unmount(struct fuse *f)
Definition: fuse.c:5062
+ +
const char * fuse_pkgversion(void)
Definition: fuse.c:5071
+
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
+
double entry_timeout
Definition: fuse.h:119
+
+ + + + diff --git a/doc/html/ioctl_8c.html b/doc/html/ioctl_8c.html new file mode 100644 index 0000000..45f2dcb --- /dev/null +++ b/doc/html/ioctl_8c.html @@ -0,0 +1,72 @@ + + + + + + + +libfuse: example/ioctl.c File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
ioctl.c File Reference
+
+
+
#include <fuse.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include "ioctl.h"
+
+

Go to the source code of this file.

+

Detailed Description

+

This example illustrates how to write a FUSE file system that can process (a restricted set of) ioctls. It can be tested with the ioctl_client.c program.

+

Compile with:

gcc -Wall ioctl.c `pkg-config fuse3 --cflags --libs` -o ioctl
+

Source code

+
/*
FUSE fioc: FUSE ioctl example
Copyright (C) 2008 SUSE Linux Products GmbH
Copyright (C) 2008 Tejun Heo <teheo@suse.de>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#define FUSE_USE_VERSION 31
#include <fuse.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include "ioctl.h"
#define FIOC_NAME "fioc"
enum {
FIOC_NONE,
FIOC_ROOT,
FIOC_FILE,
};
static void *fioc_buf;
static size_t fioc_size;
static int fioc_resize(size_t new_size)
{
void *new_buf;
if (new_size == fioc_size)
return 0;
new_buf = realloc(fioc_buf, new_size);
if (!new_buf && new_size)
return -ENOMEM;
if (new_size > fioc_size)
memset(new_buf + fioc_size, 0, new_size - fioc_size);
fioc_buf = new_buf;
fioc_size = new_size;
return 0;
}
static int fioc_expand(size_t new_size)
{
if (new_size > fioc_size)
return fioc_resize(new_size);
return 0;
}
static int fioc_file_type(const char *path)
{
if (strcmp(path, "/") == 0)
return FIOC_ROOT;
if (strcmp(path, "/" FIOC_NAME) == 0)
return FIOC_FILE;
return FIOC_NONE;
}
static int fioc_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
(void) fi;
stbuf->st_uid = getuid();
stbuf->st_gid = getgid();
stbuf->st_atime = stbuf->st_mtime = time(NULL);
switch (fioc_file_type(path)) {
case FIOC_ROOT:
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
break;
case FIOC_FILE:
stbuf->st_mode = S_IFREG | 0644;
stbuf->st_nlink = 1;
stbuf->st_size = fioc_size;
break;
case FIOC_NONE:
return -ENOENT;
}
return 0;
}
static int fioc_open(const char *path, struct fuse_file_info *fi)
{
(void) fi;
if (fioc_file_type(path) != FIOC_NONE)
return 0;
return -ENOENT;
}
static int fioc_do_read(char *buf, size_t size, off_t offset)
{
if (offset >= fioc_size)
return 0;
if (size > fioc_size - offset)
size = fioc_size - offset;
memcpy(buf, fioc_buf + offset, size);
return size;
}
static int fioc_read(const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
(void) fi;
if (fioc_file_type(path) != FIOC_FILE)
return -EINVAL;
return fioc_do_read(buf, size, offset);
}
static int fioc_do_write(const char *buf, size_t size, off_t offset)
{
if (fioc_expand(offset + size))
return -ENOMEM;
memcpy(fioc_buf + offset, buf, size);
return size;
}
static int fioc_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
(void) fi;
if (fioc_file_type(path) != FIOC_FILE)
return -EINVAL;
return fioc_do_write(buf, size, offset);
}
static int fioc_truncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
(void) fi;
if (fioc_file_type(path) != FIOC_FILE)
return -EINVAL;
return fioc_resize(size);
}
static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
(void) fi;
(void) offset;
(void) flags;
if (fioc_file_type(path) != FIOC_ROOT)
return -ENOENT;
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
filler(buf, FIOC_NAME, NULL, 0, 0);
return 0;
}
static int fioc_ioctl(const char *path, int cmd, void *arg,
struct fuse_file_info *fi, unsigned int flags, void *data)
{
(void) arg;
(void) fi;
(void) flags;
if (fioc_file_type(path) != FIOC_FILE)
return -EINVAL;
if (flags & FUSE_IOCTL_COMPAT)
return -ENOSYS;
switch (cmd) {
case FIOC_GET_SIZE:
*(size_t *)data = fioc_size;
return 0;
case FIOC_SET_SIZE:
fioc_resize(*(size_t *)data);
return 0;
}
return -EINVAL;
}
static struct fuse_operations fioc_oper = {
.getattr = fioc_getattr,
.readdir = fioc_readdir,
.truncate = fioc_truncate,
.open = fioc_open,
.read = fioc_read,
.write = fioc_write,
.ioctl = fioc_ioctl,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &fioc_oper, NULL);
}
+

Definition in file ioctl.c.

+
+ + + + diff --git a/doc/html/ioctl_8c_source.html b/doc/html/ioctl_8c_source.html new file mode 100644 index 0000000..d0ca726 --- /dev/null +++ b/doc/html/ioctl_8c_source.html @@ -0,0 +1,65 @@ + + + + + + + +libfuse: example/ioctl.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
ioctl.c
+
+
+Go to the documentation of this file.
1 /*
2  FUSE fioc: FUSE ioctl example
3  Copyright (C) 2008 SUSE Linux Products GmbH
4  Copyright (C) 2008 Tejun Heo <teheo@suse.de>
5 
6  This program can be distributed under the terms of the GNU GPL.
7  See the file COPYING.
8 */
9 
25 #define FUSE_USE_VERSION 31
26 
27 #include <fuse.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <errno.h>
34 
35 #include "ioctl.h"
36 
37 #define FIOC_NAME "fioc"
38 
39 enum {
40  FIOC_NONE,
41  FIOC_ROOT,
42  FIOC_FILE,
43 };
44 
45 static void *fioc_buf;
46 static size_t fioc_size;
47 
48 static int fioc_resize(size_t new_size)
49 {
50  void *new_buf;
51 
52  if (new_size == fioc_size)
53  return 0;
54 
55  new_buf = realloc(fioc_buf, new_size);
56  if (!new_buf && new_size)
57  return -ENOMEM;
58 
59  if (new_size > fioc_size)
60  memset(new_buf + fioc_size, 0, new_size - fioc_size);
61 
62  fioc_buf = new_buf;
63  fioc_size = new_size;
64 
65  return 0;
66 }
67 
68 static int fioc_expand(size_t new_size)
69 {
70  if (new_size > fioc_size)
71  return fioc_resize(new_size);
72  return 0;
73 }
74 
75 static int fioc_file_type(const char *path)
76 {
77  if (strcmp(path, "/") == 0)
78  return FIOC_ROOT;
79  if (strcmp(path, "/" FIOC_NAME) == 0)
80  return FIOC_FILE;
81  return FIOC_NONE;
82 }
83 
84 static int fioc_getattr(const char *path, struct stat *stbuf,
85  struct fuse_file_info *fi)
86 {
87  (void) fi;
88  stbuf->st_uid = getuid();
89  stbuf->st_gid = getgid();
90  stbuf->st_atime = stbuf->st_mtime = time(NULL);
91 
92  switch (fioc_file_type(path)) {
93  case FIOC_ROOT:
94  stbuf->st_mode = S_IFDIR | 0755;
95  stbuf->st_nlink = 2;
96  break;
97  case FIOC_FILE:
98  stbuf->st_mode = S_IFREG | 0644;
99  stbuf->st_nlink = 1;
100  stbuf->st_size = fioc_size;
101  break;
102  case FIOC_NONE:
103  return -ENOENT;
104  }
105 
106  return 0;
107 }
108 
109 static int fioc_open(const char *path, struct fuse_file_info *fi)
110 {
111  (void) fi;
112 
113  if (fioc_file_type(path) != FIOC_NONE)
114  return 0;
115  return -ENOENT;
116 }
117 
118 static int fioc_do_read(char *buf, size_t size, off_t offset)
119 {
120  if (offset >= fioc_size)
121  return 0;
122 
123  if (size > fioc_size - offset)
124  size = fioc_size - offset;
125 
126  memcpy(buf, fioc_buf + offset, size);
127 
128  return size;
129 }
130 
131 static int fioc_read(const char *path, char *buf, size_t size,
132  off_t offset, struct fuse_file_info *fi)
133 {
134  (void) fi;
135 
136  if (fioc_file_type(path) != FIOC_FILE)
137  return -EINVAL;
138 
139  return fioc_do_read(buf, size, offset);
140 }
141 
142 static int fioc_do_write(const char *buf, size_t size, off_t offset)
143 {
144  if (fioc_expand(offset + size))
145  return -ENOMEM;
146 
147  memcpy(fioc_buf + offset, buf, size);
148 
149  return size;
150 }
151 
152 static int fioc_write(const char *path, const char *buf, size_t size,
153  off_t offset, struct fuse_file_info *fi)
154 {
155  (void) fi;
156 
157  if (fioc_file_type(path) != FIOC_FILE)
158  return -EINVAL;
159 
160  return fioc_do_write(buf, size, offset);
161 }
162 
163 static int fioc_truncate(const char *path, off_t size,
164  struct fuse_file_info *fi)
165 {
166  (void) fi;
167  if (fioc_file_type(path) != FIOC_FILE)
168  return -EINVAL;
169 
170  return fioc_resize(size);
171 }
172 
173 static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
174  off_t offset, struct fuse_file_info *fi,
175  enum fuse_readdir_flags flags)
176 {
177  (void) fi;
178  (void) offset;
179  (void) flags;
180 
181  if (fioc_file_type(path) != FIOC_ROOT)
182  return -ENOENT;
183 
184  filler(buf, ".", NULL, 0, 0);
185  filler(buf, "..", NULL, 0, 0);
186  filler(buf, FIOC_NAME, NULL, 0, 0);
187 
188  return 0;
189 }
190 
191 static int fioc_ioctl(const char *path, int cmd, void *arg,
192  struct fuse_file_info *fi, unsigned int flags, void *data)
193 {
194  (void) arg;
195  (void) fi;
196  (void) flags;
197 
198  if (fioc_file_type(path) != FIOC_FILE)
199  return -EINVAL;
200 
201  if (flags & FUSE_IOCTL_COMPAT)
202  return -ENOSYS;
203 
204  switch (cmd) {
205  case FIOC_GET_SIZE:
206  *(size_t *)data = fioc_size;
207  return 0;
208 
209  case FIOC_SET_SIZE:
210  fioc_resize(*(size_t *)data);
211  return 0;
212  }
213 
214  return -EINVAL;
215 }
216 
217 static struct fuse_operations fioc_oper = {
218  .getattr = fioc_getattr,
219  .readdir = fioc_readdir,
220  .truncate = fioc_truncate,
221  .open = fioc_open,
222  .read = fioc_read,
223  .write = fioc_write,
224  .ioctl = fioc_ioctl,
225 };
226 
227 int main(int argc, char *argv[])
228 {
229  return fuse_main(argc, argv, &fioc_oper, NULL);
230 }
fuse_readdir_flags
Definition: fuse.h:42
+ + +
int(* getattr)(const char *, struct stat *, struct fuse_file_info *fi)
Definition: fuse.h:311
+
#define FUSE_IOCTL_COMPAT
Definition: fuse_common.h:329
+ +
int(* fuse_fill_dir_t)(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags)
Definition: fuse.h:82
+ +
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:855
+
+ + + + diff --git a/doc/html/ioctl_8h.html b/doc/html/ioctl_8h.html new file mode 100644 index 0000000..293541b --- /dev/null +++ b/doc/html/ioctl_8h.html @@ -0,0 +1,65 @@ + + + + + + + +libfuse: example/ioctl.h File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
ioctl.h File Reference
+
+
+
#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+
+

Go to the source code of this file.

+

Detailed Description

+

Header file to share definitions between the ioctl.c example file system and the ioctl_client.c test program.

+
/*
FUSE-ioctl: ioctl support for FUSE
Copyright (C) 2008 SUSE Linux Products GmbH
Copyright (C) 2008 Tejun Heo <teheo@suse.de>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
enum {
FIOC_GET_SIZE = _IOR('E', 0, size_t),
FIOC_SET_SIZE = _IOW('E', 1, size_t),
/*
* The following two ioctls don't follow usual encoding rules
* and transfer variable amount of data.
*/
FIOC_READ = _IO('E', 2),
FIOC_WRITE = _IO('E', 3),
};
struct fioc_rw_arg {
off_t offset;
void *buf;
size_t size;
size_t prev_size; /* out param for previous total size */
size_t new_size; /* out param for new total size */
};
+

Definition in file ioctl.h.

+
+ + + + diff --git a/doc/html/ioctl_8h_source.html b/doc/html/ioctl_8h_source.html new file mode 100644 index 0000000..1259500 --- /dev/null +++ b/doc/html/ioctl_8h_source.html @@ -0,0 +1,56 @@ + + + + + + + +libfuse: example/ioctl.h Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
ioctl.h
+
+
+Go to the documentation of this file.
1 /*
2  FUSE-ioctl: ioctl support for FUSE
3  Copyright (C) 2008 SUSE Linux Products GmbH
4  Copyright (C) 2008 Tejun Heo <teheo@suse.de>
5 
6  This program can be distributed under the terms of the GNU GPL.
7  See the file COPYING.
8 */
9 
20 #include <sys/types.h>
21 #include <sys/uio.h>
22 #include <sys/ioctl.h>
23 
24 enum {
25  FIOC_GET_SIZE = _IOR('E', 0, size_t),
26  FIOC_SET_SIZE = _IOW('E', 1, size_t),
27 
28  /*
29  * The following two ioctls don't follow usual encoding rules
30  * and transfer variable amount of data.
31  */
32  FIOC_READ = _IO('E', 2),
33  FIOC_WRITE = _IO('E', 3),
34 };
35 
36 struct fioc_rw_arg {
37  off_t offset;
38  void *buf;
39  size_t size;
40  size_t prev_size; /* out param for previous total size */
41  size_t new_size; /* out param for new total size */
42 };
+ + + + diff --git a/doc/html/ioctl__client_8c.html b/doc/html/ioctl__client_8c.html new file mode 100644 index 0000000..a4879bd --- /dev/null +++ b/doc/html/ioctl__client_8c.html @@ -0,0 +1,73 @@ + + + + + + + +libfuse: example/ioctl_client.c File Reference + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
ioctl_client.c File Reference
+
+
+
#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include "ioctl.h"
+
+

Go to the source code of this file.

+

Detailed Description

+

This program tests the ioctl.c example file systsem.

+

Compile with:

gcc -Wall ioctl_client.c -o ioctl_client
+

Source code

+
/*
FUSE fioclient: FUSE ioctl example client
Copyright (C) 2008 SUSE Linux Products GmbH
Copyright (C) 2008 Tejun Heo <teheo@suse.de>
This program tests the ioctl.c example file systsem.
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include "ioctl.h"
const char *usage =
"Usage: fioclient FIOC_FILE [size]\n"
"\n"
"Get size if <size> is omitted, set size otherwise\n"
"\n";
int main(int argc, char **argv)
{
size_t size;
int fd;
if (argc < 2) {
fprintf(stderr, "%s", usage);
return 1;
}
fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
if (argc == 2) {
if (ioctl(fd, FIOC_GET_SIZE, &size)) {
perror("ioctl");
return 1;
}
printf("%zu\n", size);
} else {
size = strtoul(argv[2], NULL, 0);
if (ioctl(fd, FIOC_SET_SIZE, &size)) {
perror("ioctl");
return 1;
}
}
return 0;
}
+

Definition in file ioctl_client.c.

+
+ + + + diff --git a/doc/html/ioctl__client_8c_source.html b/doc/html/ioctl__client_8c_source.html new file mode 100644 index 0000000..d1df595 --- /dev/null +++ b/doc/html/ioctl__client_8c_source.html @@ -0,0 +1,57 @@ + + + + + + + +libfuse: example/ioctl_client.c Source File + + + + + + +
+
+ + + + + + +
+
libfuse +
+
+
+ + + + + + + +
+
+
+
ioctl_client.c
+
+
+Go to the documentation of this file.
1 /*
2  FUSE fioclient: FUSE ioctl example client
3  Copyright (C) 2008 SUSE Linux Products GmbH
4  Copyright (C) 2008 Tejun Heo <teheo@suse.de>
5 
6  This program tests the ioctl.c example file systsem.
7 
8  This program can be distributed under the terms of the GNU GPL.
9  See the file COPYING.
10 */
11 
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <sys/ioctl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include "ioctl.h"
33 
34 const char *usage =
35 "Usage: fioclient FIOC_FILE [size]\n"
36 "\n"
37 "Get size if <size> is omitted, set size otherwise\n"
38 "\n";
39 
40 int main(int argc, char **argv)
41 {
42  size_t size;
43  int fd;
44 
45  if (argc < 2) {
46  fprintf(stderr, "%s", usage);
47  return 1;
48  }
49 
50  fd = open(argv[1], O_RDWR);
51  if (fd < 0) {
52  perror("open");
53  return 1;
54  }
55 
56  if (argc == 2) {
57  if (ioctl(fd, FIOC_GET_SIZE, &size)) {
58  perror("ioctl");
59  return 1;
60  }
61  printf("%zu\n", size);
62  } else {
63  size = strtoul(argv[2], NULL, 0);
64  if (ioctl(fd, FIOC_SET_SIZE, &size)) {
65  perror("ioctl");
66  return 1;
67  }
68  }
69  return 0;
70 }
+
+ + + + diff --git a/doc/html/jquery.js b/doc/html/jquery.js new file mode 100644 index 0000000..3f1abfb --- /dev/null +++ b/doc/html/jquery.js @@ -0,0 +1,87 @@ +/* + * jQuery JavaScript Library v1.7.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Nov 21 21:11:03 2011 -0500 + */ +(function(bb,L){var av=bb.document,bu=bb.navigator,bl=bb.location;var b=(function(){var bF=function(b0,b1){return new bF.fn.init(b0,b1,bD)},bU=bb.jQuery,bH=bb.$,bD,bY=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,bM=/\S/,bI=/^\s+/,bE=/\s+$/,bA=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bN=/^[\],:{}\s]*$/,bW=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,bP=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bJ=/(?:^|:|,)(?:\s*\[)+/g,by=/(webkit)[ \/]([\w.]+)/,bR=/(opera)(?:.*version)?[ \/]([\w.]+)/,bQ=/(msie) ([\w.]+)/,bS=/(mozilla)(?:.*? rv:([\w.]+))?/,bB=/-([a-z]|[0-9])/ig,bZ=/^-ms-/,bT=function(b0,b1){return(b1+"").toUpperCase()},bX=bu.userAgent,bV,bC,e,bL=Object.prototype.toString,bG=Object.prototype.hasOwnProperty,bz=Array.prototype.push,bK=Array.prototype.slice,bO=String.prototype.trim,bv=Array.prototype.indexOf,bx={};bF.fn=bF.prototype={constructor:bF,init:function(b0,b4,b3){var b2,b5,b1,b6;if(!b0){return this}if(b0.nodeType){this.context=this[0]=b0;this.length=1;return this}if(b0==="body"&&!b4&&av.body){this.context=av;this[0]=av.body;this.selector=b0;this.length=1;return this}if(typeof b0==="string"){if(b0.charAt(0)==="<"&&b0.charAt(b0.length-1)===">"&&b0.length>=3){b2=[null,b0,null]}else{b2=bY.exec(b0)}if(b2&&(b2[1]||!b4)){if(b2[1]){b4=b4 instanceof bF?b4[0]:b4;b6=(b4?b4.ownerDocument||b4:av);b1=bA.exec(b0);if(b1){if(bF.isPlainObject(b4)){b0=[av.createElement(b1[1])];bF.fn.attr.call(b0,b4,true)}else{b0=[b6.createElement(b1[1])]}}else{b1=bF.buildFragment([b2[1]],[b6]);b0=(b1.cacheable?bF.clone(b1.fragment):b1.fragment).childNodes}return bF.merge(this,b0)}else{b5=av.getElementById(b2[2]);if(b5&&b5.parentNode){if(b5.id!==b2[2]){return b3.find(b0)}this.length=1;this[0]=b5}this.context=av;this.selector=b0;return this}}else{if(!b4||b4.jquery){return(b4||b3).find(b0)}else{return this.constructor(b4).find(b0)}}}else{if(bF.isFunction(b0)){return b3.ready(b0)}}if(b0.selector!==L){this.selector=b0.selector;this.context=b0.context}return bF.makeArray(b0,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return bK.call(this,0)},get:function(b0){return b0==null?this.toArray():(b0<0?this[this.length+b0]:this[b0])},pushStack:function(b1,b3,b0){var b2=this.constructor();if(bF.isArray(b1)){bz.apply(b2,b1)}else{bF.merge(b2,b1)}b2.prevObject=this;b2.context=this.context;if(b3==="find"){b2.selector=this.selector+(this.selector?" ":"")+b0}else{if(b3){b2.selector=this.selector+"."+b3+"("+b0+")"}}return b2},each:function(b1,b0){return bF.each(this,b1,b0)},ready:function(b0){bF.bindReady();bC.add(b0);return this},eq:function(b0){b0=+b0;return b0===-1?this.slice(b0):this.slice(b0,b0+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bK.apply(this,arguments),"slice",bK.call(arguments).join(","))},map:function(b0){return this.pushStack(bF.map(this,function(b2,b1){return b0.call(b2,b1,b2)}))},end:function(){return this.prevObject||this.constructor(null)},push:bz,sort:[].sort,splice:[].splice};bF.fn.init.prototype=bF.fn;bF.extend=bF.fn.extend=function(){var b9,b2,b0,b1,b6,b7,b5=arguments[0]||{},b4=1,b3=arguments.length,b8=false;if(typeof b5==="boolean"){b8=b5;b5=arguments[1]||{};b4=2}if(typeof b5!=="object"&&!bF.isFunction(b5)){b5={}}if(b3===b4){b5=this;--b4}for(;b40){return}bC.fireWith(av,[bF]);if(bF.fn.trigger){bF(av).trigger("ready").off("ready")}}},bindReady:function(){if(bC){return}bC=bF.Callbacks("once memory");if(av.readyState==="complete"){return setTimeout(bF.ready,1)}if(av.addEventListener){av.addEventListener("DOMContentLoaded",e,false);bb.addEventListener("load",bF.ready,false)}else{if(av.attachEvent){av.attachEvent("onreadystatechange",e);bb.attachEvent("onload",bF.ready);var b0=false;try{b0=bb.frameElement==null}catch(b1){}if(av.documentElement.doScroll&&b0){bw()}}}},isFunction:function(b0){return bF.type(b0)==="function"},isArray:Array.isArray||function(b0){return bF.type(b0)==="array"},isWindow:function(b0){return b0&&typeof b0==="object"&&"setInterval" in b0},isNumeric:function(b0){return !isNaN(parseFloat(b0))&&isFinite(b0)},type:function(b0){return b0==null?String(b0):bx[bL.call(b0)]||"object"},isPlainObject:function(b2){if(!b2||bF.type(b2)!=="object"||b2.nodeType||bF.isWindow(b2)){return false}try{if(b2.constructor&&!bG.call(b2,"constructor")&&!bG.call(b2.constructor.prototype,"isPrototypeOf")){return false}}catch(b1){return false}var b0;for(b0 in b2){}return b0===L||bG.call(b2,b0)},isEmptyObject:function(b1){for(var b0 in b1){return false}return true},error:function(b0){throw new Error(b0)},parseJSON:function(b0){if(typeof b0!=="string"||!b0){return null}b0=bF.trim(b0);if(bb.JSON&&bb.JSON.parse){return bb.JSON.parse(b0)}if(bN.test(b0.replace(bW,"@").replace(bP,"]").replace(bJ,""))){return(new Function("return "+b0))()}bF.error("Invalid JSON: "+b0)},parseXML:function(b2){var b0,b1;try{if(bb.DOMParser){b1=new DOMParser();b0=b1.parseFromString(b2,"text/xml")}else{b0=new ActiveXObject("Microsoft.XMLDOM");b0.async="false";b0.loadXML(b2)}}catch(b3){b0=L}if(!b0||!b0.documentElement||b0.getElementsByTagName("parsererror").length){bF.error("Invalid XML: "+b2)}return b0},noop:function(){},globalEval:function(b0){if(b0&&bM.test(b0)){(bb.execScript||function(b1){bb["eval"].call(bb,b1)})(b0)}},camelCase:function(b0){return b0.replace(bZ,"ms-").replace(bB,bT)},nodeName:function(b1,b0){return b1.nodeName&&b1.nodeName.toUpperCase()===b0.toUpperCase()},each:function(b3,b6,b2){var b1,b4=0,b5=b3.length,b0=b5===L||bF.isFunction(b3);if(b2){if(b0){for(b1 in b3){if(b6.apply(b3[b1],b2)===false){break}}}else{for(;b40&&b0[0]&&b0[b1-1])||b1===0||bF.isArray(b0));if(b3){for(;b21?aJ.call(arguments,0):bG;if(!(--bw)){bC.resolveWith(bC,bx)}}}function bz(bF){return function(bG){bB[bF]=arguments.length>1?aJ.call(arguments,0):bG;bC.notifyWith(bE,bB)}}if(e>1){for(;bv
a";bI=bv.getElementsByTagName("*");bF=bv.getElementsByTagName("a")[0];if(!bI||!bI.length||!bF){return{}}bG=av.createElement("select");bx=bG.appendChild(av.createElement("option"));bE=bv.getElementsByTagName("input")[0];bJ={leadingWhitespace:(bv.firstChild.nodeType===3),tbody:!bv.getElementsByTagName("tbody").length,htmlSerialize:!!bv.getElementsByTagName("link").length,style:/top/.test(bF.getAttribute("style")),hrefNormalized:(bF.getAttribute("href")==="/a"),opacity:/^0.55/.test(bF.style.opacity),cssFloat:!!bF.style.cssFloat,checkOn:(bE.value==="on"),optSelected:bx.selected,getSetAttribute:bv.className!=="t",enctype:!!av.createElement("form").enctype,html5Clone:av.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true};bE.checked=true;bJ.noCloneChecked=bE.cloneNode(true).checked;bG.disabled=true;bJ.optDisabled=!bx.disabled;try{delete bv.test}catch(bC){bJ.deleteExpando=false}if(!bv.addEventListener&&bv.attachEvent&&bv.fireEvent){bv.attachEvent("onclick",function(){bJ.noCloneEvent=false});bv.cloneNode(true).fireEvent("onclick")}bE=av.createElement("input");bE.value="t";bE.setAttribute("type","radio");bJ.radioValue=bE.value==="t";bE.setAttribute("checked","checked");bv.appendChild(bE);bD=av.createDocumentFragment();bD.appendChild(bv.lastChild);bJ.checkClone=bD.cloneNode(true).cloneNode(true).lastChild.checked;bJ.appendChecked=bE.checked;bD.removeChild(bE);bD.appendChild(bv);bv.innerHTML="";if(bb.getComputedStyle){bA=av.createElement("div");bA.style.width="0";bA.style.marginRight="0";bv.style.width="2px";bv.appendChild(bA);bJ.reliableMarginRight=(parseInt((bb.getComputedStyle(bA,null)||{marginRight:0}).marginRight,10)||0)===0}if(bv.attachEvent){for(by in {submit:1,change:1,focusin:1}){bB="on"+by;bw=(bB in bv);if(!bw){bv.setAttribute(bB,"return;");bw=(typeof bv[bB]==="function")}bJ[by+"Bubbles"]=bw}}bD.removeChild(bv);bD=bG=bx=bA=bv=bE=null;b(function(){var bM,bU,bV,bT,bN,bO,bL,bS,bR,e,bP,bQ=av.getElementsByTagName("body")[0];if(!bQ){return}bL=1;bS="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";bR="visibility:hidden;border:0;";e="style='"+bS+"border:5px solid #000;padding:0;'";bP="
";bM=av.createElement("div");bM.style.cssText=bR+"width:0;height:0;position:static;top:0;margin-top:"+bL+"px";bQ.insertBefore(bM,bQ.firstChild);bv=av.createElement("div");bM.appendChild(bv);bv.innerHTML="
t
";bz=bv.getElementsByTagName("td");bw=(bz[0].offsetHeight===0);bz[0].style.display="";bz[1].style.display="none";bJ.reliableHiddenOffsets=bw&&(bz[0].offsetHeight===0);bv.innerHTML="";bv.style.width=bv.style.paddingLeft="1px";b.boxModel=bJ.boxModel=bv.offsetWidth===2;if(typeof bv.style.zoom!=="undefined"){bv.style.display="inline";bv.style.zoom=1;bJ.inlineBlockNeedsLayout=(bv.offsetWidth===2);bv.style.display="";bv.innerHTML="
";bJ.shrinkWrapBlocks=(bv.offsetWidth!==2)}bv.style.cssText=bS+bR;bv.innerHTML=bP;bU=bv.firstChild;bV=bU.firstChild;bN=bU.nextSibling.firstChild.firstChild;bO={doesNotAddBorder:(bV.offsetTop!==5),doesAddBorderForTableAndCells:(bN.offsetTop===5)};bV.style.position="fixed";bV.style.top="20px";bO.fixedPosition=(bV.offsetTop===20||bV.offsetTop===15);bV.style.position=bV.style.top="";bU.style.overflow="hidden";bU.style.position="relative";bO.subtractsBorderForOverflowNotVisible=(bV.offsetTop===-5);bO.doesNotIncludeMarginInBodyOffset=(bQ.offsetTop!==bL);bQ.removeChild(bM);bv=bM=null;b.extend(bJ,bO)});return bJ})();var aS=/^(?:\{.*\}|\[.*\])$/,aA=/([A-Z])/g;b.extend({cache:{},uuid:0,expando:"jQuery"+(b.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?b.cache[e[b.expando]]:e[b.expando];return !!e&&!S(e)},data:function(bx,bv,bz,by){if(!b.acceptData(bx)){return}var bG,bA,bD,bE=b.expando,bC=typeof bv==="string",bF=bx.nodeType,e=bF?b.cache:bx,bw=bF?bx[bE]:bx[bE]&&bE,bB=bv==="events";if((!bw||!e[bw]||(!bB&&!by&&!e[bw].data))&&bC&&bz===L){return}if(!bw){if(bF){bx[bE]=bw=++b.uuid}else{bw=bE}}if(!e[bw]){e[bw]={};if(!bF){e[bw].toJSON=b.noop}}if(typeof bv==="object"||typeof bv==="function"){if(by){e[bw]=b.extend(e[bw],bv)}else{e[bw].data=b.extend(e[bw].data,bv)}}bG=bA=e[bw];if(!by){if(!bA.data){bA.data={}}bA=bA.data}if(bz!==L){bA[b.camelCase(bv)]=bz}if(bB&&!bA[bv]){return bG.events}if(bC){bD=bA[bv];if(bD==null){bD=bA[b.camelCase(bv)]}}else{bD=bA}return bD},removeData:function(bx,bv,by){if(!b.acceptData(bx)){return}var bB,bA,bz,bC=b.expando,bD=bx.nodeType,e=bD?b.cache:bx,bw=bD?bx[bC]:bC;if(!e[bw]){return}if(bv){bB=by?e[bw]:e[bw].data;if(bB){if(!b.isArray(bv)){if(bv in bB){bv=[bv]}else{bv=b.camelCase(bv);if(bv in bB){bv=[bv]}else{bv=bv.split(" ")}}}for(bA=0,bz=bv.length;bA-1){return true}}return false},val:function(bx){var e,bv,by,bw=this[0];if(!arguments.length){if(bw){e=b.valHooks[bw.nodeName.toLowerCase()]||b.valHooks[bw.type];if(e&&"get" in e&&(bv=e.get(bw,"value"))!==L){return bv}bv=bw.value;return typeof bv==="string"?bv.replace(aU,""):bv==null?"":bv}return}by=b.isFunction(bx);return this.each(function(bA){var bz=b(this),bB;if(this.nodeType!==1){return}if(by){bB=bx.call(this,bA,bz.val())}else{bB=bx}if(bB==null){bB=""}else{if(typeof bB==="number"){bB+=""}else{if(b.isArray(bB)){bB=b.map(bB,function(bC){return bC==null?"":bC+""})}}}e=b.valHooks[this.nodeName.toLowerCase()]||b.valHooks[this.type];if(!e||!("set" in e)||e.set(this,bB,"value")===L){this.value=bB}})}});b.extend({valHooks:{option:{get:function(e){var bv=e.attributes.value;return !bv||bv.specified?e.value:e.text}},select:{get:function(e){var bA,bv,bz,bx,by=e.selectedIndex,bB=[],bC=e.options,bw=e.type==="select-one";if(by<0){return null}bv=bw?by:0;bz=bw?by+1:bC.length;for(;bv=0});if(!e.length){bv.selectedIndex=-1}return e}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bA,bx,bB,bz){var bw,e,by,bv=bA.nodeType;if(!bA||bv===3||bv===8||bv===2){return}if(bz&&bx in b.attrFn){return b(bA)[bx](bB)}if(typeof bA.getAttribute==="undefined"){return b.prop(bA,bx,bB)}by=bv!==1||!b.isXMLDoc(bA);if(by){bx=bx.toLowerCase();e=b.attrHooks[bx]||(ao.test(bx)?aY:be)}if(bB!==L){if(bB===null){b.removeAttr(bA,bx);return}else{if(e&&"set" in e&&by&&(bw=e.set(bA,bB,bx))!==L){return bw}else{bA.setAttribute(bx,""+bB);return bB}}}else{if(e&&"get" in e&&by&&(bw=e.get(bA,bx))!==null){return bw}else{bw=bA.getAttribute(bx);return bw===null?L:bw}}},removeAttr:function(bx,bz){var by,bA,bv,e,bw=0;if(bz&&bx.nodeType===1){bA=bz.toLowerCase().split(af);e=bA.length;for(;bw=0)}}})});var bd=/^(?:textarea|input|select)$/i,n=/^([^\.]*)?(?:\.(.+))?$/,J=/\bhover(\.\S+)?\b/,aO=/^key/,bf=/^(?:mouse|contextmenu)|click/,T=/^(?:focusinfocus|focusoutblur)$/,U=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,Y=function(e){var bv=U.exec(e);if(bv){bv[1]=(bv[1]||"").toLowerCase();bv[3]=bv[3]&&new RegExp("(?:^|\\s)"+bv[3]+"(?:\\s|$)")}return bv},j=function(bw,e){var bv=bw.attributes||{};return((!e[1]||bw.nodeName.toLowerCase()===e[1])&&(!e[2]||(bv.id||{}).value===e[2])&&(!e[3]||e[3].test((bv["class"]||{}).value)))},bt=function(e){return b.event.special.hover?e:e.replace(J,"mouseenter$1 mouseleave$1")};b.event={add:function(bx,bC,bJ,bA,by){var bD,bB,bK,bI,bH,bF,e,bG,bv,bz,bw,bE;if(bx.nodeType===3||bx.nodeType===8||!bC||!bJ||!(bD=b._data(bx))){return}if(bJ.handler){bv=bJ;bJ=bv.handler}if(!bJ.guid){bJ.guid=b.guid++}bK=bD.events;if(!bK){bD.events=bK={}}bB=bD.handle;if(!bB){bD.handle=bB=function(bL){return typeof b!=="undefined"&&(!bL||b.event.triggered!==bL.type)?b.event.dispatch.apply(bB.elem,arguments):L};bB.elem=bx}bC=b.trim(bt(bC)).split(" ");for(bI=0;bI=0){bG=bG.slice(0,-1);bw=true}if(bG.indexOf(".")>=0){bx=bG.split(".");bG=bx.shift();bx.sort()}if((!bA||b.event.customEvent[bG])&&!b.event.global[bG]){return}bv=typeof bv==="object"?bv[b.expando]?bv:new b.Event(bG,bv):new b.Event(bG);bv.type=bG;bv.isTrigger=true;bv.exclusive=bw;bv.namespace=bx.join(".");bv.namespace_re=bv.namespace?new RegExp("(^|\\.)"+bx.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;by=bG.indexOf(":")<0?"on"+bG:"";if(!bA){e=b.cache;for(bC in e){if(e[bC].events&&e[bC].events[bG]){b.event.trigger(bv,bD,e[bC].handle.elem,true)}}return}bv.result=L;if(!bv.target){bv.target=bA}bD=bD!=null?b.makeArray(bD):[];bD.unshift(bv);bF=b.event.special[bG]||{};if(bF.trigger&&bF.trigger.apply(bA,bD)===false){return}bB=[[bA,bF.bindType||bG]];if(!bJ&&!bF.noBubble&&!b.isWindow(bA)){bI=bF.delegateType||bG;bH=T.test(bI+bG)?bA:bA.parentNode;bz=null;for(;bH;bH=bH.parentNode){bB.push([bH,bI]);bz=bH}if(bz&&bz===bA.ownerDocument){bB.push([bz.defaultView||bz.parentWindow||bb,bI])}}for(bC=0;bCbA){bH.push({elem:this,matches:bz.slice(bA)})}for(bC=0;bC0?this.on(e,null,bx,bw):this.trigger(e)};if(b.attrFn){b.attrFn[e]=true}if(aO.test(e)){b.event.fixHooks[e]=b.event.keyHooks}if(bf.test(e)){b.event.fixHooks[e]=b.event.mouseHooks}}); +/* + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var bH=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bC="sizcache"+(Math.random()+"").replace(".",""),bI=0,bL=Object.prototype.toString,bB=false,bA=true,bK=/\\/g,bO=/\r\n/g,bQ=/\W/;[0,0].sort(function(){bA=false;return 0});var by=function(bV,e,bY,bZ){bY=bY||[];e=e||av;var b1=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bV||typeof bV!=="string"){return bY}var bS,b3,b6,bR,b2,b5,b4,bX,bU=true,bT=by.isXML(e),bW=[],b0=bV;do{bH.exec("");bS=bH.exec(b0);if(bS){b0=bS[3];bW.push(bS[1]);if(bS[2]){bR=bS[3];break}}}while(bS);if(bW.length>1&&bD.exec(bV)){if(bW.length===2&&bE.relative[bW[0]]){b3=bM(bW[0]+bW[1],e,bZ)}else{b3=bE.relative[bW[0]]?[e]:by(bW.shift(),e);while(bW.length){bV=bW.shift();if(bE.relative[bV]){bV+=bW.shift()}b3=bM(bV,b3,bZ)}}}else{if(!bZ&&bW.length>1&&e.nodeType===9&&!bT&&bE.match.ID.test(bW[0])&&!bE.match.ID.test(bW[bW.length-1])){b2=by.find(bW.shift(),e,bT);e=b2.expr?by.filter(b2.expr,b2.set)[0]:b2.set[0]}if(e){b2=bZ?{expr:bW.pop(),set:bF(bZ)}:by.find(bW.pop(),bW.length===1&&(bW[0]==="~"||bW[0]==="+")&&e.parentNode?e.parentNode:e,bT);b3=b2.expr?by.filter(b2.expr,b2.set):b2.set;if(bW.length>0){b6=bF(b3)}else{bU=false}while(bW.length){b5=bW.pop();b4=b5;if(!bE.relative[b5]){b5=""}else{b4=bW.pop()}if(b4==null){b4=e}bE.relative[b5](b6,b4,bT)}}else{b6=bW=[]}}if(!b6){b6=b3}if(!b6){by.error(b5||bV)}if(bL.call(b6)==="[object Array]"){if(!bU){bY.push.apply(bY,b6)}else{if(e&&e.nodeType===1){for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&(b6[bX]===true||b6[bX].nodeType===1&&by.contains(e,b6[bX]))){bY.push(b3[bX])}}}else{for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&b6[bX].nodeType===1){bY.push(b3[bX])}}}}}else{bF(b6,bY)}if(bR){by(bR,b1,bY,bZ);by.uniqueSort(bY)}return bY};by.uniqueSort=function(bR){if(bJ){bB=bA;bR.sort(bJ);if(bB){for(var e=1;e0};by.find=function(bX,e,bY){var bW,bS,bU,bT,bV,bR;if(!bX){return[]}for(bS=0,bU=bE.order.length;bS":function(bW,bR){var bV,bU=typeof bR==="string",bS=0,e=bW.length;if(bU&&!bQ.test(bR)){bR=bR.toLowerCase();for(;bS=0)){if(!bS){e.push(bV)}}else{if(bS){bR[bU]=false}}}}return false},ID:function(e){return e[1].replace(bK,"")},TAG:function(bR,e){return bR[1].replace(bK,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){by.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bR=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bR[1]+(bR[2]||1))-0;e[3]=bR[3]-0}else{if(e[2]){by.error(e[0])}}e[0]=bI++;return e},ATTR:function(bU,bR,bS,e,bV,bW){var bT=bU[1]=bU[1].replace(bK,"");if(!bW&&bE.attrMap[bT]){bU[1]=bE.attrMap[bT]}bU[4]=(bU[4]||bU[5]||"").replace(bK,"");if(bU[2]==="~="){bU[4]=" "+bU[4]+" "}return bU},PSEUDO:function(bU,bR,bS,e,bV){if(bU[1]==="not"){if((bH.exec(bU[3])||"").length>1||/^\w/.test(bU[3])){bU[3]=by(bU[3],null,null,bR)}else{var bT=by.filter(bU[3],bR,bS,true^bV);if(!bS){e.push.apply(e,bT)}return false}}else{if(bE.match.POS.test(bU[0])||bE.match.CHILD.test(bU[0])){return true}}return bU},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bS,bR,e){return !!by(e[3],bS).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(bS){var e=bS.getAttribute("type"),bR=bS.type;return bS.nodeName.toLowerCase()==="input"&&"text"===bR&&(e===bR||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===bR.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===bR.type},button:function(bR){var e=bR.nodeName.toLowerCase();return e==="input"&&"button"===bR.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(bR,e){return e===0},last:function(bS,bR,e,bT){return bR===bT.length-1},even:function(bR,e){return e%2===0},odd:function(bR,e){return e%2===1},lt:function(bS,bR,e){return bRe[3]-0},nth:function(bS,bR,e){return e[3]-0===bR},eq:function(bS,bR,e){return e[3]-0===bR}},filter:{PSEUDO:function(bS,bX,bW,bY){var e=bX[1],bR=bE.filters[e];if(bR){return bR(bS,bW,bX,bY)}else{if(e==="contains"){return(bS.textContent||bS.innerText||bw([bS])||"").indexOf(bX[3])>=0}else{if(e==="not"){var bT=bX[3];for(var bV=0,bU=bT.length;bV=0)}}},ID:function(bR,e){return bR.nodeType===1&&bR.getAttribute("id")===e},TAG:function(bR,e){return(e==="*"&&bR.nodeType===1)||!!bR.nodeName&&bR.nodeName.toLowerCase()===e},CLASS:function(bR,e){return(" "+(bR.className||bR.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bV,bT){var bS=bT[1],e=by.attr?by.attr(bV,bS):bE.attrHandle[bS]?bE.attrHandle[bS](bV):bV[bS]!=null?bV[bS]:bV.getAttribute(bS),bW=e+"",bU=bT[2],bR=bT[4];return e==null?bU==="!=":!bU&&by.attr?e!=null:bU==="="?bW===bR:bU==="*="?bW.indexOf(bR)>=0:bU==="~="?(" "+bW+" ").indexOf(bR)>=0:!bR?bW&&e!==false:bU==="!="?bW!==bR:bU==="^="?bW.indexOf(bR)===0:bU==="$="?bW.substr(bW.length-bR.length)===bR:bU==="|="?bW===bR||bW.substr(0,bR.length+1)===bR+"-":false},POS:function(bU,bR,bS,bV){var e=bR[2],bT=bE.setFilters[e];if(bT){return bT(bU,bS,bR,bV)}}}};var bD=bE.match.POS,bx=function(bR,e){return"\\"+(e-0+1)};for(var bz in bE.match){bE.match[bz]=new RegExp(bE.match[bz].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bE.leftMatch[bz]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bE.match[bz].source.replace(/\\(\d+)/g,bx))}var bF=function(bR,e){bR=Array.prototype.slice.call(bR,0);if(e){e.push.apply(e,bR);return e}return bR};try{Array.prototype.slice.call(av.documentElement.childNodes,0)[0].nodeType}catch(bP){bF=function(bU,bT){var bS=0,bR=bT||[];if(bL.call(bU)==="[object Array]"){Array.prototype.push.apply(bR,bU)}else{if(typeof bU.length==="number"){for(var e=bU.length;bS";e.insertBefore(bR,e.firstChild);if(av.getElementById(bS)){bE.find.ID=function(bU,bV,bW){if(typeof bV.getElementById!=="undefined"&&!bW){var bT=bV.getElementById(bU[1]);return bT?bT.id===bU[1]||typeof bT.getAttributeNode!=="undefined"&&bT.getAttributeNode("id").nodeValue===bU[1]?[bT]:L:[]}};bE.filter.ID=function(bV,bT){var bU=typeof bV.getAttributeNode!=="undefined"&&bV.getAttributeNode("id");return bV.nodeType===1&&bU&&bU.nodeValue===bT}}e.removeChild(bR);e=bR=null})();(function(){var e=av.createElement("div");e.appendChild(av.createComment(""));if(e.getElementsByTagName("*").length>0){bE.find.TAG=function(bR,bV){var bU=bV.getElementsByTagName(bR[1]);if(bR[1]==="*"){var bT=[];for(var bS=0;bU[bS];bS++){if(bU[bS].nodeType===1){bT.push(bU[bS])}}bU=bT}return bU}}e.innerHTML="";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bE.attrHandle.href=function(bR){return bR.getAttribute("href",2)}}e=null})();if(av.querySelectorAll){(function(){var e=by,bT=av.createElement("div"),bS="__sizzle__";bT.innerHTML="

";if(bT.querySelectorAll&&bT.querySelectorAll(".TEST").length===0){return}by=function(b4,bV,bZ,b3){bV=bV||av;if(!b3&&!by.isXML(bV)){var b2=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b4);if(b2&&(bV.nodeType===1||bV.nodeType===9)){if(b2[1]){return bF(bV.getElementsByTagName(b4),bZ)}else{if(b2[2]&&bE.find.CLASS&&bV.getElementsByClassName){return bF(bV.getElementsByClassName(b2[2]),bZ)}}}if(bV.nodeType===9){if(b4==="body"&&bV.body){return bF([bV.body],bZ)}else{if(b2&&b2[3]){var bY=bV.getElementById(b2[3]);if(bY&&bY.parentNode){if(bY.id===b2[3]){return bF([bY],bZ)}}else{return bF([],bZ)}}}try{return bF(bV.querySelectorAll(b4),bZ)}catch(b0){}}else{if(bV.nodeType===1&&bV.nodeName.toLowerCase()!=="object"){var bW=bV,bX=bV.getAttribute("id"),bU=bX||bS,b6=bV.parentNode,b5=/^\s*[+~]/.test(b4);if(!bX){bV.setAttribute("id",bU)}else{bU=bU.replace(/'/g,"\\$&")}if(b5&&b6){bV=bV.parentNode}try{if(!b5||b6){return bF(bV.querySelectorAll("[id='"+bU+"'] "+b4),bZ)}}catch(b1){}finally{if(!bX){bW.removeAttribute("id")}}}}}return e(b4,bV,bZ,b3)};for(var bR in e){by[bR]=e[bR]}bT=null})()}(function(){var e=av.documentElement,bS=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(bS){var bU=!bS.call(av.createElement("div"),"div"),bR=false;try{bS.call(av.documentElement,"[test!='']:sizzle")}catch(bT){bR=true}by.matchesSelector=function(bW,bY){bY=bY.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!by.isXML(bW)){try{if(bR||!bE.match.PSEUDO.test(bY)&&!/!=/.test(bY)){var bV=bS.call(bW,bY);if(bV||!bU||bW.document&&bW.document.nodeType!==11){return bV}}}catch(bX){}}return by(bY,null,null,[bW]).length>0}}})();(function(){var e=av.createElement("div");e.innerHTML="
";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bE.order.splice(1,0,"CLASS");bE.find.CLASS=function(bR,bS,bT){if(typeof bS.getElementsByClassName!=="undefined"&&!bT){return bS.getElementsByClassName(bR[1])}};e=null})();function bv(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT0){bU=e;break}}}e=e[bR]}bZ[bT]=bU}}}if(av.documentElement.contains){by.contains=function(bR,e){return bR!==e&&(bR.contains?bR.contains(e):true)}}else{if(av.documentElement.compareDocumentPosition){by.contains=function(bR,e){return !!(bR.compareDocumentPosition(e)&16)}}else{by.contains=function(){return false}}}by.isXML=function(e){var bR=(e?e.ownerDocument||e:0).documentElement;return bR?bR.nodeName!=="HTML":false};var bM=function(bS,e,bW){var bV,bX=[],bU="",bY=e.nodeType?[e]:e;while((bV=bE.match.PSEUDO.exec(bS))){bU+=bV[0];bS=bS.replace(bE.match.PSEUDO,"")}bS=bE.relative[bS]?bS+"*":bS;for(var bT=0,bR=bY.length;bT0){for(bB=bA;bB=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(by,bx){var bv=[],bw,e,bz=this[0];if(b.isArray(by)){var bB=1;while(bz&&bz.ownerDocument&&bz!==bx){for(bw=0;bw-1:b.find.matchesSelector(bz,by)){bv.push(bz);break}else{bz=bz.parentNode;if(!bz||!bz.ownerDocument||bz===bx||bz.nodeType===11){break}}}}bv=bv.length>1?b.unique(bv):bv;return this.pushStack(bv,"closest",by)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return b.inArray(this[0],b(e))}return b.inArray(e.jquery?e[0]:e,this)},add:function(e,bv){var bx=typeof e==="string"?b(e,bv):b.makeArray(e&&e.nodeType?[e]:e),bw=b.merge(this.get(),bx);return this.pushStack(C(bx[0])||C(bw[0])?bw:b.unique(bw))},andSelf:function(){return this.add(this.prevObject)}});function C(e){return !e||!e.parentNode||e.parentNode.nodeType===11}b.each({parent:function(bv){var e=bv.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(bv,e,bw){return b.dir(bv,"parentNode",bw)},next:function(e){return b.nth(e,2,"nextSibling")},prev:function(e){return b.nth(e,2,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(bv,e,bw){return b.dir(bv,"nextSibling",bw)},prevUntil:function(bv,e,bw){return b.dir(bv,"previousSibling",bw)},siblings:function(e){return b.sibling(e.parentNode.firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.makeArray(e.childNodes)}},function(e,bv){b.fn[e]=function(by,bw){var bx=b.map(this,bv,by);if(!ab.test(e)){bw=by}if(bw&&typeof bw==="string"){bx=b.filter(bw,bx)}bx=this.length>1&&!ay[e]?b.unique(bx):bx;if((this.length>1||a9.test(bw))&&aq.test(e)){bx=bx.reverse()}return this.pushStack(bx,e,P.call(arguments).join(","))}});b.extend({filter:function(bw,e,bv){if(bv){bw=":not("+bw+")"}return e.length===1?b.find.matchesSelector(e[0],bw)?[e[0]]:[]:b.find.matches(bw,e)},dir:function(bw,bv,by){var e=[],bx=bw[bv];while(bx&&bx.nodeType!==9&&(by===L||bx.nodeType!==1||!b(bx).is(by))){if(bx.nodeType===1){e.push(bx)}bx=bx[bv]}return e},nth:function(by,e,bw,bx){e=e||1;var bv=0;for(;by;by=by[bw]){if(by.nodeType===1&&++bv===e){break}}return by},sibling:function(bw,bv){var e=[];for(;bw;bw=bw.nextSibling){if(bw.nodeType===1&&bw!==bv){e.push(bw)}}return e}});function aG(bx,bw,e){bw=bw||0;if(b.isFunction(bw)){return b.grep(bx,function(bz,by){var bA=!!bw.call(bz,by,bz);return bA===e})}else{if(bw.nodeType){return b.grep(bx,function(bz,by){return(bz===bw)===e})}else{if(typeof bw==="string"){var bv=b.grep(bx,function(by){return by.nodeType===1});if(bp.test(bw)){return b.filter(bw,bv,!e)}else{bw=b.filter(bw,bv)}}}}return b.grep(bx,function(bz,by){return(b.inArray(bz,bw)>=0)===e})}function a(e){var bw=aR.split("|"),bv=e.createDocumentFragment();if(bv.createElement){while(bw.length){bv.createElement(bw.pop())}}return bv}var aR="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ag=/ jQuery\d+="(?:\d+|null)"/g,ar=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,d=/<([\w:]+)/,w=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},ac=a(av);ax.optgroup=ax.option;ax.tbody=ax.tfoot=ax.colgroup=ax.caption=ax.thead;ax.th=ax.td;if(!b.support.htmlSerialize){ax._default=[1,"div
","
"]}b.fn.extend({text:function(e){if(b.isFunction(e)){return this.each(function(bw){var bv=b(this);bv.text(e.call(this,bw,bv.text()))})}if(typeof e!=="object"&&e!==L){return this.empty().append((this[0]&&this[0].ownerDocument||av).createTextNode(e))}return b.text(this)},wrapAll:function(e){if(b.isFunction(e)){return this.each(function(bw){b(this).wrapAll(e.call(this,bw))})}if(this[0]){var bv=b(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bv.insertBefore(this[0])}bv.map(function(){var bw=this;while(bw.firstChild&&bw.firstChild.nodeType===1){bw=bw.firstChild}return bw}).append(this)}return this},wrapInner:function(e){if(b.isFunction(e)){return this.each(function(bv){b(this).wrapInner(e.call(this,bv))})}return this.each(function(){var bv=b(this),bw=bv.contents();if(bw.length){bw.wrapAll(e)}else{bv.append(e)}})},wrap:function(e){var bv=b.isFunction(e);return this.each(function(bw){b(this).wrapAll(bv?e.call(this,bw):e)})},unwrap:function(){return this.parent().each(function(){if(!b.nodeName(this,"body")){b(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this)})}else{if(arguments.length){var e=b.clean(arguments);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,b.clean(arguments));return e}}},remove:function(e,bx){for(var bv=0,bw;(bw=this[bv])!=null;bv++){if(!e||b.filter(e,[bw]).length){if(!bx&&bw.nodeType===1){b.cleanData(bw.getElementsByTagName("*"));b.cleanData([bw])}if(bw.parentNode){bw.parentNode.removeChild(bw)}}}return this},empty:function(){for(var e=0,bv;(bv=this[e])!=null;e++){if(bv.nodeType===1){b.cleanData(bv.getElementsByTagName("*"))}while(bv.firstChild){bv.removeChild(bv.firstChild)}}return this},clone:function(bv,e){bv=bv==null?false:bv;e=e==null?bv:e;return this.map(function(){return b.clone(this,bv,e)})},html:function(bx){if(bx===L){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(ag,""):null}else{if(typeof bx==="string"&&!ae.test(bx)&&(b.support.leadingWhitespace||!ar.test(bx))&&!ax[(d.exec(bx)||["",""])[1].toLowerCase()]){bx=bx.replace(R,"<$1>");try{for(var bw=0,bv=this.length;bw1&&bw0?this.clone(true):this).get();b(bC[bA])[bv](by);bz=bz.concat(by)}return this.pushStack(bz,e,bC.selector)}}});function bg(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function az(e){if(e.type==="checkbox"||e.type==="radio"){e.defaultChecked=e.checked}}function E(e){var bv=(e.nodeName||"").toLowerCase();if(bv==="input"){az(e)}else{if(bv!=="script"&&typeof e.getElementsByTagName!=="undefined"){b.grep(e.getElementsByTagName("input"),az)}}}function al(e){var bv=av.createElement("div");ac.appendChild(bv);bv.innerHTML=e.outerHTML;return bv.firstChild}b.extend({clone:function(by,bA,bw){var e,bv,bx,bz=b.support.html5Clone||!ah.test("<"+by.nodeName)?by.cloneNode(true):al(by);if((!b.support.noCloneEvent||!b.support.noCloneChecked)&&(by.nodeType===1||by.nodeType===11)&&!b.isXMLDoc(by)){ai(by,bz);e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){if(bv[bx]){ai(e[bx],bv[bx])}}}if(bA){t(by,bz);if(bw){e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){t(e[bx],bv[bx])}}}e=bv=null;return bz},clean:function(bw,by,bH,bA){var bF;by=by||av;if(typeof by.createElement==="undefined"){by=by.ownerDocument||by[0]&&by[0].ownerDocument||av}var bI=[],bB;for(var bE=0,bz;(bz=bw[bE])!=null;bE++){if(typeof bz==="number"){bz+=""}if(!bz){continue}if(typeof bz==="string"){if(!W.test(bz)){bz=by.createTextNode(bz)}else{bz=bz.replace(R,"<$1>");var bK=(d.exec(bz)||["",""])[1].toLowerCase(),bx=ax[bK]||ax._default,bD=bx[0],bv=by.createElement("div");if(by===av){ac.appendChild(bv)}else{a(by).appendChild(bv)}bv.innerHTML=bx[1]+bz+bx[2];while(bD--){bv=bv.lastChild}if(!b.support.tbody){var e=w.test(bz),bC=bK==="table"&&!e?bv.firstChild&&bv.firstChild.childNodes:bx[1]===""&&!e?bv.childNodes:[];for(bB=bC.length-1;bB>=0;--bB){if(b.nodeName(bC[bB],"tbody")&&!bC[bB].childNodes.length){bC[bB].parentNode.removeChild(bC[bB])}}}if(!b.support.leadingWhitespace&&ar.test(bz)){bv.insertBefore(by.createTextNode(ar.exec(bz)[0]),bv.firstChild)}bz=bv.childNodes}}var bG;if(!b.support.appendChecked){if(bz[0]&&typeof(bG=bz.length)==="number"){for(bB=0;bB=0){return bx+"px"}}else{return bx}}}});if(!b.support.opacity){b.cssHooks.opacity={get:function(bv,e){return au.test((e&&bv.currentStyle?bv.currentStyle.filter:bv.style.filter)||"")?(parseFloat(RegExp.$1)/100)+"":e?"1":""},set:function(by,bz){var bx=by.style,bv=by.currentStyle,e=b.isNumeric(bz)?"alpha(opacity="+bz*100+")":"",bw=bv&&bv.filter||bx.filter||"";bx.zoom=1;if(bz>=1&&b.trim(bw.replace(ak,""))===""){bx.removeAttribute("filter");if(bv&&!bv.filter){return}}bx.filter=ak.test(bw)?bw.replace(ak,e):bw+" "+e}}}b(function(){if(!b.support.reliableMarginRight){b.cssHooks.marginRight={get:function(bw,bv){var e;b.swap(bw,{display:"inline-block"},function(){if(bv){e=Z(bw,"margin-right","marginRight")}else{e=bw.style.marginRight}});return e}}}});if(av.defaultView&&av.defaultView.getComputedStyle){aI=function(by,bw){var bv,bx,e;bw=bw.replace(z,"-$1").toLowerCase();if((bx=by.ownerDocument.defaultView)&&(e=bx.getComputedStyle(by,null))){bv=e.getPropertyValue(bw);if(bv===""&&!b.contains(by.ownerDocument.documentElement,by)){bv=b.style(by,bw)}}return bv}}if(av.documentElement.currentStyle){aX=function(bz,bw){var bA,e,by,bv=bz.currentStyle&&bz.currentStyle[bw],bx=bz.style;if(bv===null&&bx&&(by=bx[bw])){bv=by}if(!bc.test(bv)&&bn.test(bv)){bA=bx.left;e=bz.runtimeStyle&&bz.runtimeStyle.left;if(e){bz.runtimeStyle.left=bz.currentStyle.left}bx.left=bw==="fontSize"?"1em":(bv||0);bv=bx.pixelLeft+"px";bx.left=bA;if(e){bz.runtimeStyle.left=e}}return bv===""?"auto":bv}}Z=aI||aX;function p(by,bw,bv){var bA=bw==="width"?by.offsetWidth:by.offsetHeight,bz=bw==="width"?an:a1,bx=0,e=bz.length;if(bA>0){if(bv!=="border"){for(;bx)<[^<]*)*<\/script>/gi,q=/^(?:select|textarea)/i,h=/\s+/,br=/([?&])_=[^&]*/,K=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,A=b.fn.load,aa={},r={},aE,s,aV=["*/"]+["*"];try{aE=bl.href}catch(aw){aE=av.createElement("a");aE.href="";aE=aE.href}s=K.exec(aE.toLowerCase())||[];function f(e){return function(by,bA){if(typeof by!=="string"){bA=by;by="*"}if(b.isFunction(bA)){var bx=by.toLowerCase().split(h),bw=0,bz=bx.length,bv,bB,bC;for(;bw=0){var e=bw.slice(by,bw.length);bw=bw.slice(0,by)}var bx="GET";if(bz){if(b.isFunction(bz)){bA=bz;bz=L}else{if(typeof bz==="object"){bz=b.param(bz,b.ajaxSettings.traditional);bx="POST"}}}var bv=this;b.ajax({url:bw,type:bx,dataType:"html",data:bz,complete:function(bC,bB,bD){bD=bC.responseText;if(bC.isResolved()){bC.done(function(bE){bD=bE});bv.html(e?b("
").append(bD.replace(a6,"")).find(e):bD)}if(bA){bv.each(bA,[bD,bB,bC])}}});return this},serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?b.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||q.test(this.nodeName)||aZ.test(this.type))}).map(function(e,bv){var bw=b(this).val();return bw==null?null:b.isArray(bw)?b.map(bw,function(by,bx){return{name:bv.name,value:by.replace(bs,"\r\n")}}):{name:bv.name,value:bw.replace(bs,"\r\n")}}).get()}});b.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bv){b.fn[bv]=function(bw){return this.on(bv,bw)}});b.each(["get","post"],function(e,bv){b[bv]=function(bw,by,bz,bx){if(b.isFunction(by)){bx=bx||bz;bz=by;by=L}return b.ajax({type:bv,url:bw,data:by,success:bz,dataType:bx})}});b.extend({getScript:function(e,bv){return b.get(e,L,bv,"script")},getJSON:function(e,bv,bw){return b.get(e,bv,bw,"json")},ajaxSetup:function(bv,e){if(e){am(bv,b.ajaxSettings)}else{e=bv;bv=b.ajaxSettings}am(bv,e);return bv},ajaxSettings:{url:aE,isLocal:aM.test(s[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aV},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":bb.String,"text html":true,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:f(aa),ajaxTransport:f(r),ajax:function(bz,bx){if(typeof bz==="object"){bx=bz;bz=L}bx=bx||{};var bD=b.ajaxSetup({},bx),bS=bD.context||bD,bG=bS!==bD&&(bS.nodeType||bS instanceof b)?b(bS):b.event,bR=b.Deferred(),bN=b.Callbacks("once memory"),bB=bD.statusCode||{},bC,bH={},bO={},bQ,by,bL,bE,bI,bA=0,bw,bK,bJ={readyState:0,setRequestHeader:function(bT,bU){if(!bA){var e=bT.toLowerCase();bT=bO[e]=bO[e]||bT;bH[bT]=bU}return this},getAllResponseHeaders:function(){return bA===2?bQ:null},getResponseHeader:function(bT){var e;if(bA===2){if(!by){by={};while((e=aD.exec(bQ))){by[e[1].toLowerCase()]=e[2]}}e=by[bT.toLowerCase()]}return e===L?null:e},overrideMimeType:function(e){if(!bA){bD.mimeType=e}return this},abort:function(e){e=e||"abort";if(bL){bL.abort(e)}bF(0,e);return this}};function bF(bZ,bU,b0,bW){if(bA===2){return}bA=2;if(bE){clearTimeout(bE)}bL=L;bQ=bW||"";bJ.readyState=bZ>0?4:0;var bT,b4,b3,bX=bU,bY=b0?bj(bD,bJ,b0):L,bV,b2;if(bZ>=200&&bZ<300||bZ===304){if(bD.ifModified){if((bV=bJ.getResponseHeader("Last-Modified"))){b.lastModified[bC]=bV}if((b2=bJ.getResponseHeader("Etag"))){b.etag[bC]=b2}}if(bZ===304){bX="notmodified";bT=true}else{try{b4=G(bD,bY);bX="success";bT=true}catch(b1){bX="parsererror";b3=b1}}}else{b3=bX;if(!bX||bZ){bX="error";if(bZ<0){bZ=0}}}bJ.status=bZ;bJ.statusText=""+(bU||bX);if(bT){bR.resolveWith(bS,[b4,bX,bJ])}else{bR.rejectWith(bS,[bJ,bX,b3])}bJ.statusCode(bB);bB=L;if(bw){bG.trigger("ajax"+(bT?"Success":"Error"),[bJ,bD,bT?b4:b3])}bN.fireWith(bS,[bJ,bX]);if(bw){bG.trigger("ajaxComplete",[bJ,bD]);if(!(--b.active)){b.event.trigger("ajaxStop")}}}bR.promise(bJ);bJ.success=bJ.done;bJ.error=bJ.fail;bJ.complete=bN.add;bJ.statusCode=function(bT){if(bT){var e;if(bA<2){for(e in bT){bB[e]=[bB[e],bT[e]]}}else{e=bT[bJ.status];bJ.then(e,e)}}return this};bD.url=((bz||bD.url)+"").replace(bq,"").replace(c,s[1]+"//");bD.dataTypes=b.trim(bD.dataType||"*").toLowerCase().split(h);if(bD.crossDomain==null){bI=K.exec(bD.url.toLowerCase());bD.crossDomain=!!(bI&&(bI[1]!=s[1]||bI[2]!=s[2]||(bI[3]||(bI[1]==="http:"?80:443))!=(s[3]||(s[1]==="http:"?80:443))))}if(bD.data&&bD.processData&&typeof bD.data!=="string"){bD.data=b.param(bD.data,bD.traditional)}aW(aa,bD,bx,bJ);if(bA===2){return false}bw=bD.global;bD.type=bD.type.toUpperCase();bD.hasContent=!aQ.test(bD.type);if(bw&&b.active++===0){b.event.trigger("ajaxStart")}if(!bD.hasContent){if(bD.data){bD.url+=(M.test(bD.url)?"&":"?")+bD.data;delete bD.data}bC=bD.url;if(bD.cache===false){var bv=b.now(),bP=bD.url.replace(br,"$1_="+bv);bD.url=bP+((bP===bD.url)?(M.test(bD.url)?"&":"?")+"_="+bv:"")}}if(bD.data&&bD.hasContent&&bD.contentType!==false||bx.contentType){bJ.setRequestHeader("Content-Type",bD.contentType)}if(bD.ifModified){bC=bC||bD.url;if(b.lastModified[bC]){bJ.setRequestHeader("If-Modified-Since",b.lastModified[bC])}if(b.etag[bC]){bJ.setRequestHeader("If-None-Match",b.etag[bC])}}bJ.setRequestHeader("Accept",bD.dataTypes[0]&&bD.accepts[bD.dataTypes[0]]?bD.accepts[bD.dataTypes[0]]+(bD.dataTypes[0]!=="*"?", "+aV+"; q=0.01":""):bD.accepts["*"]);for(bK in bD.headers){bJ.setRequestHeader(bK,bD.headers[bK])}if(bD.beforeSend&&(bD.beforeSend.call(bS,bJ,bD)===false||bA===2)){bJ.abort();return false}for(bK in {success:1,error:1,complete:1}){bJ[bK](bD[bK])}bL=aW(r,bD,bx,bJ);if(!bL){bF(-1,"No Transport")}else{bJ.readyState=1;if(bw){bG.trigger("ajaxSend",[bJ,bD])}if(bD.async&&bD.timeout>0){bE=setTimeout(function(){bJ.abort("timeout")},bD.timeout)}try{bA=1;bL.send(bH,bF)}catch(bM){if(bA<2){bF(-1,bM)}else{throw bM}}}return bJ},param:function(e,bw){var bv=[],by=function(bz,bA){bA=b.isFunction(bA)?bA():bA;bv[bv.length]=encodeURIComponent(bz)+"="+encodeURIComponent(bA)};if(bw===L){bw=b.ajaxSettings.traditional}if(b.isArray(e)||(e.jquery&&!b.isPlainObject(e))){b.each(e,function(){by(this.name,this.value)})}else{for(var bx in e){v(bx,e[bx],bw,by)}}return bv.join("&").replace(k,"+")}});function v(bw,by,bv,bx){if(b.isArray(by)){b.each(by,function(bA,bz){if(bv||ap.test(bw)){bx(bw,bz)}else{v(bw+"["+(typeof bz==="object"||b.isArray(bz)?bA:"")+"]",bz,bv,bx)}})}else{if(!bv&&by!=null&&typeof by==="object"){for(var e in by){v(bw+"["+e+"]",by[e],bv,bx)}}else{bx(bw,by)}}}b.extend({active:0,lastModified:{},etag:{}});function bj(bD,bC,bz){var bv=bD.contents,bB=bD.dataTypes,bw=bD.responseFields,by,bA,bx,e;for(bA in bw){if(bA in bz){bC[bw[bA]]=bz[bA]}}while(bB[0]==="*"){bB.shift();if(by===L){by=bD.mimeType||bC.getResponseHeader("content-type")}}if(by){for(bA in bv){if(bv[bA]&&bv[bA].test(by)){bB.unshift(bA);break}}}if(bB[0] in bz){bx=bB[0]}else{for(bA in bz){if(!bB[0]||bD.converters[bA+" "+bB[0]]){bx=bA;break}if(!e){e=bA}}bx=bx||e}if(bx){if(bx!==bB[0]){bB.unshift(bx)}return bz[bx]}}function G(bH,bz){if(bH.dataFilter){bz=bH.dataFilter(bz,bH.dataType)}var bD=bH.dataTypes,bG={},bA,bE,bw=bD.length,bB,bC=bD[0],bx,by,bF,bv,e;for(bA=1;bA=bw.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();bw.animatedProperties[this.prop]=true;for(bA in bw.animatedProperties){if(bw.animatedProperties[bA]!==true){e=false}}if(e){if(bw.overflow!=null&&!b.support.shrinkWrapBlocks){b.each(["","X","Y"],function(bC,bD){bz.style["overflow"+bD]=bw.overflow[bC]})}if(bw.hide){b(bz).hide()}if(bw.hide||bw.show){for(bA in bw.animatedProperties){b.style(bz,bA,bw.orig[bA]);b.removeData(bz,"fxshow"+bA,true);b.removeData(bz,"toggle"+bA,true)}}bv=bw.complete;if(bv){bw.complete=false;bv.call(bz)}}return false}else{if(bw.duration==Infinity){this.now=bx}else{bB=bx-this.startTime;this.state=bB/bw.duration;this.pos=b.easing[bw.animatedProperties[this.prop]](this.state,bB,0,1,bw.duration);this.now=this.start+((this.end-this.start)*this.pos)}this.update()}return true}};b.extend(b.fx,{tick:function(){var bw,bv=b.timers,e=0;for(;e").appendTo(e),bw=bv.css("display");bv.remove();if(bw==="none"||bw===""){if(!a8){a8=av.createElement("iframe");a8.frameBorder=a8.width=a8.height=0}e.appendChild(a8);if(!m||!a8.createElement){m=(a8.contentWindow||a8.contentDocument).document;m.write((av.compatMode==="CSS1Compat"?"":"")+"");m.close()}bv=m.createElement(bx);m.body.appendChild(bv);bw=b.css(bv,"display");e.removeChild(a8)}Q[bx]=bw}return Q[bx]}var V=/^t(?:able|d|h)$/i,ad=/^(?:body|html)$/i;if("getBoundingClientRect" in av.documentElement){b.fn.offset=function(bI){var by=this[0],bB;if(bI){return this.each(function(e){b.offset.setOffset(this,bI,e)})}if(!by||!by.ownerDocument){return null}if(by===by.ownerDocument.body){return b.offset.bodyOffset(by)}try{bB=by.getBoundingClientRect()}catch(bF){}var bH=by.ownerDocument,bw=bH.documentElement;if(!bB||!b.contains(bw,by)){return bB?{top:bB.top,left:bB.left}:{top:0,left:0}}var bC=bH.body,bD=aK(bH),bA=bw.clientTop||bC.clientTop||0,bE=bw.clientLeft||bC.clientLeft||0,bv=bD.pageYOffset||b.support.boxModel&&bw.scrollTop||bC.scrollTop,bz=bD.pageXOffset||b.support.boxModel&&bw.scrollLeft||bC.scrollLeft,bG=bB.top+bv-bA,bx=bB.left+bz-bE;return{top:bG,left:bx}}}else{b.fn.offset=function(bF){var bz=this[0];if(bF){return this.each(function(bG){b.offset.setOffset(this,bF,bG)})}if(!bz||!bz.ownerDocument){return null}if(bz===bz.ownerDocument.body){return b.offset.bodyOffset(bz)}var bC,bw=bz.offsetParent,bv=bz,bE=bz.ownerDocument,bx=bE.documentElement,bA=bE.body,bB=bE.defaultView,e=bB?bB.getComputedStyle(bz,null):bz.currentStyle,bD=bz.offsetTop,by=bz.offsetLeft;while((bz=bz.parentNode)&&bz!==bA&&bz!==bx){if(b.support.fixedPosition&&e.position==="fixed"){break}bC=bB?bB.getComputedStyle(bz,null):bz.currentStyle;bD-=bz.scrollTop;by-=bz.scrollLeft;if(bz===bw){bD+=bz.offsetTop;by+=bz.offsetLeft;if(b.support.doesNotAddBorder&&!(b.support.doesAddBorderForTableAndCells&&V.test(bz.nodeName))){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}bv=bw;bw=bz.offsetParent}if(b.support.subtractsBorderForOverflowNotVisible&&bC.overflow!=="visible"){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}e=bC}if(e.position==="relative"||e.position==="static"){bD+=bA.offsetTop;by+=bA.offsetLeft}if(b.support.fixedPosition&&e.position==="fixed"){bD+=Math.max(bx.scrollTop,bA.scrollTop);by+=Math.max(bx.scrollLeft,bA.scrollLeft)}return{top:bD,left:by}}}b.offset={bodyOffset:function(e){var bw=e.offsetTop,bv=e.offsetLeft;if(b.support.doesNotIncludeMarginInBodyOffset){bw+=parseFloat(b.css(e,"marginTop"))||0;bv+=parseFloat(b.css(e,"marginLeft"))||0}return{top:bw,left:bv}},setOffset:function(bx,bG,bA){var bB=b.css(bx,"position");if(bB==="static"){bx.style.position="relative"}var bz=b(bx),bv=bz.offset(),e=b.css(bx,"top"),bE=b.css(bx,"left"),bF=(bB==="absolute"||bB==="fixed")&&b.inArray("auto",[e,bE])>-1,bD={},bC={},bw,by;if(bF){bC=bz.position();bw=bC.top;by=bC.left}else{bw=parseFloat(e)||0;by=parseFloat(bE)||0}if(b.isFunction(bG)){bG=bG.call(bx,bA,bv)}if(bG.top!=null){bD.top=(bG.top-bv.top)+bw}if(bG.left!=null){bD.left=(bG.left-bv.left)+by}if("using" in bG){bG.using.call(bx,bD)}else{bz.css(bD)}}};b.fn.extend({position:function(){if(!this[0]){return null}var bw=this[0],bv=this.offsetParent(),bx=this.offset(),e=ad.test(bv[0].nodeName)?{top:0,left:0}:bv.offset();bx.top-=parseFloat(b.css(bw,"marginTop"))||0;bx.left-=parseFloat(b.css(bw,"marginLeft"))||0;e.top+=parseFloat(b.css(bv[0],"borderTopWidth"))||0;e.left+=parseFloat(b.css(bv[0],"borderLeftWidth"))||0;return{top:bx.top-e.top,left:bx.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||av.body;while(e&&(!ad.test(e.nodeName)&&b.css(e,"position")==="static")){e=e.offsetParent}return e})}});b.each(["Left","Top"],function(bv,e){var bw="scroll"+e;b.fn[bw]=function(bz){var bx,by;if(bz===L){bx=this[0];if(!bx){return null}by=aK(bx);return by?("pageXOffset" in by)?by[bv?"pageYOffset":"pageXOffset"]:b.support.boxModel&&by.document.documentElement[bw]||by.document.body[bw]:bx[bw]}return this.each(function(){by=aK(this);if(by){by.scrollTo(!bv?bz:b(by).scrollLeft(),bv?bz:b(by).scrollTop())}else{this[bw]=bz}})}});function aK(e){return b.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}b.each(["Height","Width"],function(bv,e){var bw=e.toLowerCase();b.fn["inner"+e]=function(){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,"padding")):this[bw]():null};b.fn["outer"+e]=function(by){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,by?"margin":"border")):this[bw]():null};b.fn[bw]=function(bz){var bA=this[0];if(!bA){return bz==null?null:this}if(b.isFunction(bz)){return this.each(function(bE){var bD=b(this);bD[bw](bz.call(this,bE,bD[bw]()))})}if(b.isWindow(bA)){var bB=bA.document.documentElement["client"+e],bx=bA.document.body;return bA.document.compatMode==="CSS1Compat"&&bB||bx&&bx["client"+e]||bB}else{if(bA.nodeType===9){return Math.max(bA.documentElement["client"+e],bA.body["scroll"+e],bA.documentElement["scroll"+e],bA.body["offset"+e],bA.documentElement["offset"+e])}else{if(bz===L){var bC=b.css(bA,bw),by=parseFloat(bC);return b.isNumeric(by)?by:bC}else{return this.css(bw,typeof bz==="string"?bz:bz+"px")}}}}});bb.jQuery=bb.$=b;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return b})}})(window);/* + * jQuery UI 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(a,d){a.ui=a.ui||{};if(a.ui.version){return}a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(e,f){return typeof e==="number"?this.each(function(){var g=this;setTimeout(function(){a(g).focus();if(f){f.call(g)}},e)}):this._focus.apply(this,arguments)},scrollParent:function(){var e;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){e=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{e=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!e.length?a(document):e},zIndex:function(h){if(h!==d){return this.css("zIndex",h)}if(this.length){var f=a(this[0]),e,g;while(f.length&&f[0]!==document){e=f.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){g=parseInt(f.css("zIndex"),10);if(!isNaN(g)&&g!==0){return g}}f=f.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(g,e){var f=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),k={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};function j(m,l,i,n){a.each(f,function(){l-=parseFloat(a.curCSS(m,"padding"+this,true))||0;if(i){l-=parseFloat(a.curCSS(m,"border"+this+"Width",true))||0}if(n){l-=parseFloat(a.curCSS(m,"margin"+this,true))||0}});return l}a.fn["inner"+e]=function(i){if(i===d){return k["inner"+e].call(this)}return this.each(function(){a(this).css(h,j(this,i)+"px")})};a.fn["outer"+e]=function(i,l){if(typeof i!=="number"){return k["outer"+e].call(this,i)}return this.each(function(){a(this).css(h,j(this,i,true,l)+"px")})}});function c(g,e){var j=g.nodeName.toLowerCase();if("area"===j){var i=g.parentNode,h=i.name,f;if(!g.href||!h||i.nodeName.toLowerCase()!=="map"){return false}f=a("img[usemap=#"+h+"]")[0];return !!f&&b(f)}return(/input|select|textarea|button|object/.test(j)?!g.disabled:"a"==j?g.href||e:e)&&b(g)}function b(e){return !a(e).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.extend(a.expr[":"],{data:function(g,f,e){return !!a.data(g,e[3])},focusable:function(e){return c(e,!isNaN(a.attr(e,"tabindex")))},tabbable:function(g){var e=a.attr(g,"tabindex"),f=isNaN(e);return(f||e>=0)&&c(g,!f)}});a(function(){var e=document.body,f=e.appendChild(f=document.createElement("div"));f.offsetHeight;a.extend(f.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=f.offsetHeight===100;a.support.selectstart="onselectstart" in f;e.removeChild(f).style.display="none"});a.extend(a.ui,{plugin:{add:function(f,g,j){var h=a.ui[f].prototype;for(var e in j){h.plugins[e]=h.plugins[e]||[];h.plugins[e].push([g,j[e]])}},call:function(e,g,f){var j=e.plugins[g];if(!j||!e.element[0].parentNode){return}for(var h=0;h0){return true}h[e]=1;g=(h[e]>0);h[e]=0;return g},isOverAxis:function(f,e,g){return(f>e)&&(f<(e+g))},isOver:function(j,f,i,h,e,g){return a.ui.isOverAxis(j,i,e)&&a.ui.isOverAxis(f,h,g)}})})(jQuery);/* + * jQuery UI Widget 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */ +(function(b,d){if(b.cleanData){var c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)}}else{var a=b.fn.remove;b.fn.remove=function(e,f){return this.each(function(){if(!f){if(!e||b.filter(e,[this]).length){b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(g){}})}}return a.call(b(this),e,f)})}}b.widget=function(f,h,e){var g=f.split(".")[0],j;f=f.split(".")[1];j=g+"-"+f;if(!e){e=h;h=b.Widget}b.expr[":"][j]=function(k){return !!b.data(k,f)};b[g]=b[g]||{};b[g][f]=function(k,l){if(arguments.length){this._createWidget(k,l)}};var i=new h();i.options=b.extend(true,{},i.options);b[g][f].prototype=b.extend(true,i,{namespace:g,widgetName:f,widgetEventPrefix:b[g][f].prototype.widgetEventPrefix||f,widgetBaseClass:j},e);b.widget.bridge(f,b[g][f])};b.widget.bridge=function(f,e){b.fn[f]=function(i){var g=typeof i==="string",h=Array.prototype.slice.call(arguments,1),j=this;i=!g&&h.length?b.extend.apply(null,[true,i].concat(h)):i;if(g&&i.charAt(0)==="_"){return j}if(g){this.each(function(){var k=b.data(this,f),l=k&&b.isFunction(k[i])?k[i].apply(k,h):k;if(l!==k&&l!==d){j=l;return false}})}else{this.each(function(){var k=b.data(this,f);if(k){k.option(i||{})._init()}else{b.data(this,f,new e(i,this))}})}return j}};b.Widget=function(e,f){if(arguments.length){this._createWidget(e,f)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(f,g){b.data(g,this.widgetName,this);this.element=b(g);this.options=b.extend(true,{},this.options,this._getCreateOptions(),f);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(f,g){var e=f;if(arguments.length===0){return b.extend({},this.options)}if(typeof f==="string"){if(g===d){return this.options[f]}e={};e[f]=g}this._setOptions(e);return this},_setOptions:function(f){var e=this;b.each(f,function(g,h){e._setOption(g,h)});return this},_setOption:function(e,f){this.options[e]=f;if(e==="disabled"){this.widget()[f?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",f)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(e,f,g){var j,i,h=this.options[e];g=g||{};f=b.Event(f);f.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase();f.target=this.element[0];i=f.originalEvent;if(i){for(j in i){if(!(j in f)){f[j]=i[j]}}}this.element.trigger(f,g);return !(b.isFunction(h)&&h.call(this.element[0],f,g)===false||f.isDefaultPrevented())}}})(jQuery);/* + * jQuery UI Mouse 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Mouse + * + * Depends: + * jquery.ui.widget.js + */ +(function(b,c){var a=false;b(document).mouseup(function(d){a=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var d=this;this.element.bind("mousedown."+this.widgetName,function(e){return d._mouseDown(e)}).bind("click."+this.widgetName,function(e){if(true===b.data(e.target,d.widgetName+".preventClickEvent")){b.removeData(e.target,d.widgetName+".preventClickEvent");e.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(f){if(a){return}(this._mouseStarted&&this._mouseUp(f));this._mouseDownEvent=f;var e=this,g=(f.which==1),d=(typeof this.options.cancel=="string"&&f.target.nodeName?b(f.target).closest(this.options.cancel).length:false);if(!g||d||!this._mouseCapture(f)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){e.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=(this._mouseStart(f)!==false);if(!this._mouseStarted){f.preventDefault();return true}}if(true===b.data(f.target,this.widgetName+".preventClickEvent")){b.removeData(f.target,this.widgetName+".preventClickEvent")}this._mouseMoveDelegate=function(h){return e._mouseMove(h)};this._mouseUpDelegate=function(h){return e._mouseUp(h)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);f.preventDefault();a=true;return true},_mouseMove:function(d){if(b.browser.msie&&!(document.documentMode>=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target==this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(c,d){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var f=this,k=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(k.aspectRatio),aspectRatio:k.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:k.helper||k.ghost||k.animate?k.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap(c('
').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var g=0;g
');if(/sw|se|ne|nw/.test(j)){h.css({zIndex:++k.zIndex})}if("se"==j){h.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(h)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!f.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}f.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");f._handles.show()},function(){if(k.disabled){return}if(!f.resizing){c(this).addClass("ui-resizable-autohide");f._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;f.after(this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var h=this.helper,g=this.options,m={},q=this,j=this.originalMousePosition,n=this.axis;var r=(e.pageX-j.left)||0,p=(e.pageY-j.top)||0;var i=this._change[n];if(!i){return false}var l=i.apply(this,[e,r,p]),k=c.browser.msie&&c.browser.version<7,f=this.sizeDiff;this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){l=this._updateRatio(l,e)}l=this._respectSize(l,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(l);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,m=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:m.sizeDiff.height,k=e?0:m.sizeDiff.width;var n={width:(m.helper.width()-k),height:(m.helper.height()-f)},j=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,l=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:l,left:j}))}m.helper.height(m.size.height);m.helper.width(m.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(hl.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f');var e=c.browser.msie&&c.browser.version<7,g=(e?1:0),h=(e?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++i.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8.18"});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,n){var p=c(this).data("resizable"),j=p.options;var h=p._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:p.sizeDiff.height,l=e?0:p.sizeDiff.width;var g={width:(p.size.width-l),height:(p.size.height-f)},k=(parseInt(p.element.css("left"),10)+(p.position.left-p.originalPosition.left))||null,m=(parseInt(p.element.css("top"),10)+(p.position.top-p.originalPosition.top))||null;p.element.animate(c.extend(g,m&&k?{top:m,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(p.element.css("width"),10),height:parseInt(p.element.css("height"),10),top:parseInt(p.element.css("top"),10),left:parseInt(p.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}p._updateCache(o);p._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,r){var t=c(this).data("resizable"),j=t.options,l=t.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}t.containerElement=c(k);if(/document/.test(g)||g==document){t.containerOffset={left:0,top:0};t.containerPosition={left:0,top:0};t.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});t.containerOffset=n.offset();t.containerPosition=n.position();t.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var q=t.containerOffset,e=t.containerSize.height,m=t.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),s=(c.ui.hasScroll(k)?k.scrollHeight:e);t.parentData={element:k,left:q.left,top:q.top,width:h,height:s}}},resize:function(g,q){var t=c(this).data("resizable"),i=t.options,f=t.containerSize,p=t.containerOffset,m=t.size,n=t.position,r=t._aspectRatio||g.shiftKey,e={top:0,left:0},h=t.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=p}if(n.left<(t._helper?p.left:0)){t.size.width=t.size.width+(t._helper?(t.position.left-p.left):(t.position.left-e.left));if(r){t.size.height=t.size.width/i.aspectRatio}t.position.left=i.helper?p.left:0}if(n.top<(t._helper?p.top:0)){t.size.height=t.size.height+(t._helper?(t.position.top-p.top):t.position.top);if(r){t.size.width=t.size.height*i.aspectRatio}t.position.top=t._helper?p.top:0}t.offset.left=t.parentData.left+t.position.left;t.offset.top=t.parentData.top+t.position.top;var l=Math.abs((t._helper?t.offset.left-e.left:(t.offset.left-e.left))+t.sizeDiff.width),s=Math.abs((t._helper?t.offset.top-e.top:(t.offset.top-p.top))+t.sizeDiff.height);var k=t.containerElement.get(0)==t.element.parent().get(0),j=/relative|absolute/.test(t.containerElement.css("position"));if(k&&j){l-=t.parentData.left}if(l+t.size.width>=t.parentData.width){t.size.width=t.parentData.width-l;if(r){t.size.height=t.size.width/t.aspectRatio}}if(s+t.size.height>=t.parentData.height){t.size.height=t.parentData.height-s;if(r){t.size.width=t.size.height*t.aspectRatio}}},stop:function(f,n){var q=c(this).data("resizable"),g=q.options,l=q.position,m=q.containerOffset,e=q.containerPosition,i=q.containerElement;var j=c(q.helper),r=j.offset(),p=j.outerWidth()-q.sizeDiff.width,k=j.outerHeight()-q.sizeDiff.height;if(q._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}if(q._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var e=c(this).data("resizable"),i=e.options,f=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");e.ghost.appendTo(e.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,m){var p=c(this).data("resizable"),h=p.options,k=p.size,i=p.originalSize,j=p.originalPosition,n=p.axis,l=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((k.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((k.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f}else{if(/^(ne)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f}else{if(/^(sw)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.left=j.left-g}else{p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f;p.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);/* + * jQuery hashchange event - v1.3 - 7/21/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('