fuse-2.9.9/0000775000175000017500000000000013413661013007476 500000000000000fuse-2.9.9/configure.ac0000664000175000017500000000734613413660577011734 00000000000000AC_INIT(fuse, 2.9.9) AC_PREREQ(2.59d) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([foreign]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)]) AC_CONFIG_HEADERS(include/config.h) AC_PROG_LIBTOOL AC_PROG_CC AC_PROG_MKDIR_P AM_PROG_CC_C_O case $target_os in *linux*) arch=linux;; *netbsd*) arch=netbsd;; *bsd*) arch=bsd;; *) arch=unknown;; esac if test "$ac_env_CFLAGS_set" != set; then CFLAGS="-Wall -W -Wno-sign-compare -Wstrict-prototypes -Wmissing-declarations -Wwrite-strings -g -O2 -fno-strict-aliasing" fi AC_ARG_ENABLE(lib, [ --enable-lib Compile with library ]) AC_ARG_ENABLE(util, [ --enable-util Compile with util ]) AC_ARG_ENABLE(example, [ --enable-example Compile with examples ]) AC_ARG_ENABLE(mtab, [ --disable-mtab Disable and ignore usage of /etc/mtab ]) AC_ARG_WITH(pkgconfigdir, [ --with-pkgconfigdir=DIR pkgconfig file in DIR @<:@LIBDIR/pkgconfig@:>@], [pkgconfigdir=$withval], [pkgconfigdir='${libdir}/pkgconfig']) AC_SUBST(pkgconfigdir) subdirs2="include" if test "$enable_lib" != "no"; then subdirs2="$subdirs2 lib"; fi if test "$arch" = linux -a "$enable_util" != "no"; then subdirs2="$subdirs2 util"; fi if test "$enable_example" != "no"; then subdirs2="$subdirs2 example"; fi if test "$enable_mtab" = "no"; then AC_DEFINE(IGNORE_MTAB, 1, [Don't update /etc/mtab]) fi AC_CHECK_FUNCS([fork setxattr fdatasync splice vmsplice utimensat]) AC_CHECK_FUNCS([posix_fallocate]) AC_CHECK_MEMBERS([struct stat.st_atim]) AC_CHECK_MEMBERS([struct stat.st_atimespec]) LIBS= AC_SEARCH_LIBS(dlopen, [dl]) AC_SEARCH_LIBS(clock_gettime, [rt]) libfuse_libs=$LIBS LIBS= AC_ARG_WITH([libiconv-prefix], [ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [ for dir in `echo "$withval" | tr : ' '`; do if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi done ]) AM_ICONV libfuse_libs="$libfuse_libs $LTLIBICONV" AM_CONDITIONAL(ICONV, test "$am_cv_func_iconv" = yes) AC_SUBST(libfuse_libs) if test -z "$MOUNT_FUSE_PATH"; then MOUNT_FUSE_PATH=/sbin AC_MSG_NOTICE([MOUNT_FUSE_PATH env var not set, using default $MOUNT_FUSE_PATH]) fi AC_SUBST(MOUNT_FUSE_PATH) if test -z "$UDEV_RULES_PATH"; then UDEV_RULES_PATH=/etc/udev/rules.d AC_MSG_NOTICE([UDEV_RULES_PATH env var not set, using default $UDEV_RULES_PATH]) fi AC_SUBST(UDEV_RULES_PATH) if test -z "$INIT_D_PATH"; then INIT_D_PATH=/etc/init.d AC_MSG_NOTICE([INIT_D_PATH env var not set, using default $INIT_D_PATH]) fi AC_SUBST(INIT_D_PATH) AC_SUBST(subdirs2) AM_CONDITIONAL(LINUX, test "$arch" = linux) AM_CONDITIONAL(NETBSD, test "$arch" = netbsd) AM_CONDITIONAL(BSD, test "$arch" = bsd) util_linux_ok=yes if test "$arch" = linux -a "$cross_compiling" != "yes"; then AC_MSG_CHECKING([if umount supports --fake --no-canonicalize]) # exit code of umount is 1 if option is unrecognised, 2 otherwise umount --fake --no-canonicalize > /dev/null 2>&1 if test $? != 1; then AC_MSG_RESULT([yes]) else firstline=`umount --fake --no-canonicalize 2>&1 | head -1` if test "$firstline" = 'umount: only root can use "--fake" option'; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([$firstline]) util_linux_ok=no fi fi fi AC_CONFIG_FILES([fuse.pc Makefile lib/Makefile util/Makefile example/Makefile include/Makefile doc/Makefile]) AC_OUTPUT if test "$util_linux_ok" = no; then AC_MSG_WARN([ ****************************************************************** * Please install util-linux version 2.18 or later which supports * * --fake and --no-canonicalize options in mount and umount * ******************************************************************]) fi fuse-2.9.9/compile0000755000175000017500000001624513413660776011021 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2014 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program 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 this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: fuse-2.9.9/COPYING0000664000175000017500000004325413413660255010470 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. fuse-2.9.9/NEWS0000664000175000017500000001702413413660255010130 00000000000000What is new in 2.9 - Add "zero copy" support for kernel 2.6.35 or newer - Make maximum background requests tunable on kernel 2.6.32 or newer - Require --no-canonicalize in (u)mount (util-linux version 2.18 or newer) to fix security problems with fusermount - Use dynamically sized hash tables in high level library - Memory use of filesystem daemon can shrink more easily - Add "auto_unmount" option - Add "remember" option - Add man pages for fusermount, mount.fuse and ulockmgr_server - API changes: o Introduce "store" and "retrieve" for accessing kernel buffers on kernel 2.6.36 or newer o Introduce abstract buffer for zero copy operations o Allow path calculation to be omitted on certain operations o Allow batching forget requests o Add "flock" method o Add support for ioctl on directories o Add delete notification o Add fallocate operation (linux kernel 3.5 or newer) - Bug fixes and small improvements ============================================================================ What is new in 2.8 - More scalable directory tree locking - Atomic open(O_TRUNC) support - Support big write requests on kernels 2.6.26 and newer - Out-of-tree fuse module removed - Better NFS exporting support - New ioctl and poll requests - New CUSE (Character Device in Userspace) interface - Allow umask processing in userspace - Added cache invalidation notifications - Bugfixes and small improvements ============================================================================ What is new in 2.7 - Stacking support for the high level API - Add filename charset conversion module - Improved mounting ============================================================================ What is new in 2.6 - Improved read characteristics (asynchronous reads) - Support for aborting filesystem connection - POSIX file locking support - Request interruption support - Building module for Linux kernels earlier than 2.6.9 not supported - Allow block device based filesystems to support swap files - Several bugs fixed, including a rare system hang on SMP ============================================================================ What is new in 2.5 - Merge library part of FreeBSD port - New atomic create+open, access and ftruncate operations - On filesystems implementing the new create+open operation, and running on Linux kernels 2.6.15 or later, the 'cp' operation will work correctly when copying read-only files. - New option parsing interface added to the library - Lots of minor improvements and fixes ============================================================================ What is new in 2.4 - Simplify device opening. Now '/dev/fuse' is a requirement - Allow module auto-loading if user has access to '/dev/fuse' - Allow mounting over a regular file for unprivileged users - Allow mounting of arbitrary FUSE filesystems from /etc/fstab - New mount options: 'umask=M', 'uid=N', 'gid=N' - Check for non-empty mountpoint, and refuse mount by default. New mount option: 'nonempty' - Low level (inode based) API added - Allow 'direct_io' and 'keep_cache' options to be set on a case-by-case basis on open. - Add 'attr_timeout' and 'entry_timeout' mount options to the high-level library. Until now these timeouts were fixed at 1 sec. - Some bugfixes ============================================================================ What is new in 2.3 - Add new directory related operations: opendir(), readdir(), releasedir() and fsyncdir() - Add init() and destroy() operations which are called before the event loop is started and after it has exited - Update kernel ABI so that on dual architectures (e.g. AMD64) 32bit binaries work under a 64bit kernel - Bugfixes ============================================================================ What is new in 2.2 Userspace changes: - Add fuse_file_info structure to file operations, this allows the filesystem to return a file handle in open() which is passed to read(), write(), flush(), fsync() and release(). - Add source compatibility with 2.1 and 1.4 releases - Binary compatibility with 2.1 release is retained Kernel changes: - Make requests interruptible. This prevents the filesystem to go into an unbreakable deadlock with itself. - Make readpages() synchronous. Asynchronous requests are deadlock prone, since they cannot be interrupted (see above) - Remove shared-writeable mapping support, which could deadlock the machine - Remove INVALIDATE userspace initiated request - Update ABI to be independent of sizeof(long), so dual-size archs don't cause problems - Remove /sys/fs/fuse/version. Version checking is now done through the fuse device - Replace directory reading method on the kernel interface. Instead of passing an open file descriptor to the kernel, send data through the FUSE device, like all other operations. ============================================================================ What is new in 2.1 * Bug fixes * Improved support for filesystems implementing a custom event-loop * Add 'pkg-config' support * Kernel module can be compiled separately ============================================================================ What is new in 1.9 * Lots of bugs fixed * Minor modifications to the library API * Improvements to the kernel/userspace interface * Mounting by non-root made more secure * Build shared library in addition to the static one * Consolidated mount options * Optimized reading under 2.6 kernels * Direct I/O support * Support file I/O on deleted files * Extended attributes support ============================================================================ What is new in 1.3 * Thanks to user bugreports and stress testing with LTP and sfx-linux a number of bugs were fixed, some quite serious. * Fix compile problems with recent SuSE kernles ============================================================================ What is new in 1.2 * Fix mount problems on recent 2.6 kernels with SELinux enabled * Fixed writing files lager than 2GBytes * Other bugfixes ============================================================================ What is new in 1.1 * Support for the 2.6 kernels * Support for exporting filesystem over NFS in 2.6 kernels * Read efficiency improvements: read in 64k blocks instead of 4k (Michael Grigoriev). Can be turned on with '-l' option of fusermount * Lazy automatic unmount * Added 'fsync()' VFS call to the FUSE interface * Bugfixes ============================================================================ What is new in 1.0 * Cleanups and bugfixes * Added 'release()' VFS call to the FUSE interface * 64 bit file offsets (handling of > 4 GByte files) * libfuse is now under LGPL * New 'statfs' call (Mark Glines) * Cleaned up mount procedure (mostly by Mark Glines) NOTE: Binaries linked with with a previous version of libavfs may not work with the new version of the fusermount program. In such case recompile the program after installing the new libavfs library. * Fix for problems under linux kernel 2.4.19 ============================================================================ What is new in 0.95 * Optimized read/write operations. Raw throughput has increased to about 60Mbyte/s on a Celeron/360 * Python bindings by Jeff Epler * Perl bindings by Mark Glines * Improved multithreaded operation * Simplified library interface * Bugfixes ============================================================================ What is new in 0.9: * Everything fuse-2.9.9/ChangeLog0000664000175000017500000032525613413660411011206 00000000000000FUSE 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) ======================= * Tarball now includes documentation. * Shared-object version has now been bumped correctly. FUSE 2.9.5 (2016-01-14) ======================= * New maintainer: Nikolaus Rath . Many thanks to Miklos Szeredi for bringing FUSE to where it is now! * fix warning in mount.c:receive_fd(). Reported by Albert Berger * fix possible memory leak. Reported by Jose R. Guzman FUSE 2.9.4 (2015-05-22) ======================= * fix exec environment for mount and umount. Found by Tavis Ormandy (CVE-2015-3202). * fix fuse_remove_signal_handlers() to properly restore the default signal handler. Reported by: Chris Johnson * highlevel API: fix directory file handle passed to ioctl() method. Reported by Eric Biggers * libfuse: document deadlock avoidance for fuse_notify_inval_entry() and fuse_notify_delete() * fusermount, libfuse: send value as unsigned in "user_id=" and "group_id=" options. Uids/gids larger than 2147483647 would result in EINVAL when mounting the filesystem. This also needs a fix in the kernel. * Initilaize stat buffer passed to ->getattr() and ->fgetattr() to zero in all cases. Reported by Daniel Iwan * libfuse: Add missing includes. This allows compiling fuse with musl. Patch by Daniel Thau Older Versions (before 2013-01-01) ================================== 2013-06-20 Miklos Szeredi * libfuse: fix multiple close of device fd. Reported by Dan Greenfield 2013-03-19 Miklos Szeredi * libfuse: fix thread cancel race. Exiting a worker my race with cancelling that same worker. This caused a segmenation fault. Reported and tested by Anatol Pomozov 2013-02-04 Miklos Szeredi * libfuse: fix crash in unlock_path(). Patch by Ratna Manoj * libfuse: fix the 'remember' option. The lru list was not initialized for the "/" path. This resulted in remove_node_lru() crashing on LOOKUP-DOTDOT. Patch by Madan Valluri * libfuse: configure: detect new util-linux * libfuse: Use AC_CONFIG_HEADERS instead of AM_CONFIG_HEADER. Patch by Anatol Pomozov * libfuse: rename ./configure.in to ./configure.ac. Patch by Anatol Pomozov 2012-10-01 Miklos Szeredi * Released 2.9.2 2012-10-01 Miklos Szeredi * Fix deadlock in libfuse. Running "svn update" on a fuse filesystem could deadlock because of a bug in the way the paths are locked. Reported by Kazuaki Anami 2012-08-23 Miklos Szeredi * Fix missing config.h in buffer.c. Reported by Matthew Gabeler-Lee 2012-08-14 Miklos Szeredi * Not unhashing the name in forget (commit on 2011-12-09) broke the forget logic in a subtle way, resulting in "fuse internal error: node NNN not found" and causing the filesystem daemon to abort. Fix by incrementing the node refcount if nlookup goes from zero to one. Reported by Kyle Lippincott 2012-08-13 Miklos Szeredi * Fix linking against GNU libiconv. Patch by Natanael Copa 2012-07-19 Miklos Szeredi * Released 2.9.1 2012-07-19 Miklos Szeredi * Fix crash caused by freeing a stack address. Reported by Itay Perl 2012-07-04 Miklos Szeredi * Fix install of mount.fuse from out-of-tree build. Patch by Olivier Blin * Fix build with automake >= 1.12.1. Patch by Olivier Blin 2012-04-24 Miklos Szeredi * Add fallocate operation. Only works on linux kernels 3.5 or later. Patch by Anatol Pomozov 2012-05-16 Miklos Szeredi * Linking to a library that uses threads requires the application to be linked with -pthreads otherwise some pthread functions will be linked to stubs in glibc. So move -pthread from Libs.private to Libs in fuse.pc. Reported by Werner Fink * Fix the compile command in the examples. Reported by Luciano Dalle Ore 2012-04-20 Miklos Szeredi * Released 2.9.0 2012-04-20 Miklos Szeredi * Add missing fuse_fs_flock to fuse_versionscript 2012-04-10 Miklos Szeredi * Check protocol version before sending notifications and return -ENOSYS if a particular notification is not supported. * Add 'flag_utime_omit_ok' flag to fuse_operations. If the filesystem sets this flag then ->utimens() will receive UTIME_OMIT and UTIME_NOW values as specified in utimensat(2). 2012-01-27 Miklos Szeredi * Interpret octal escape codes in options. Requested by Jan Engelhardt 2012-01-26 Miklos Szeredi * Add man pages for fusermount, mount.fuse and ulockmgr_server. Lifted from the Debian package. The man pages were written by Daniel Baumann and Bastien Roucaries 2012-01-13 Miklos Szeredi * Disable symbol versions on MacOSX. Patch by Anatol Pomozov 2012-01-02 Miklos Szeredi * Remove unnecessary mutex unlock at the end of multithreaded event loop. 2011-12-09 Miklos Szeredi * Fix hang in wait_on_path(). Reported by Ville Silventoinen * Don't unhash name in FORGET. This resulted in ENOENT being returned for unlinked but still open files if the kernel sent a FORGET request for the parent directory. * Free request in fuse_reply_data(). 2011-12-08 Miklos Szeredi * Fix build if FUSE_NODE_SLAB is not defined. Patch by Emmanuel Dreyfus * Check for availability of utimensat() function. Patch by Emmanuel Dreyfus 2011-12-07 Miklos Szeredi * Add fuse_lowlevel_notify_delete() which tells the kernel that a file or directory is deleted. Patch by John Muir 2011-12-06 Miklos Szeredi * Update retrieve_reply() method 2011-12-05 Miklos Szeredi * Low level API: lock argument of fuse_reply_lock should have a 'const' qualifier. Reported by Shachar Sharon * Add support for ioctl on directories. Reported by Antonio SJ Musumeci 2011-10-13 Miklos Szeredi * Reply to request with ENOMEM in case of failure to allocate request structure. Otherwise the task issuing the request will just freeze up until the filesystem daemon is killed. Reported by Stephan Kulow 2011-09-23 Miklos Szeredi * Replace daemon() function with fork(). Patch by Anatol Pomozov 2011-08-26 Miklos Szeredi * If configured with --disable-mtab then don't call mount(8) from libfuse to update the mtab. Reported by: James Sierp 2011-08-24 Miklos Szeredi * Use LRU list for cleaning up the cache if the "remember=T" option was given. Patch by therealneworld@gmail.com 2011-07-06 Miklos Szeredi * Add ->flock() operation to low and high level interfaces. This fixes problems with emulating flock() with POSIX locking. Reported by Sebastian Pipping. As with lock/setlk/getlk most filesystems don't need to implement this, as the kernel takes care of file locking. The only reason to implement locking operations is for network filesystems which want file locking to work between clients. 2011-07-02 Sebastian Pipping * Make xmp_utimens of examples "fusexmp" and "fusexmp_fh" not follow symlinks as other layers do that already. 2011-06-02 Miklos Szeredi * Add "remember" option. This works similar to "noforget" except that eventually the node will be allowed to expire from the cache. Patch by therealneworld@gmail.com 2011-05-27 Miklos Szeredi * Check if splice/vmsplice are supported 2011-05-26 Miklos Szeredi * Remove -lrt -ldl from fuse.pc for dynamic linking since libfuse.so is already linked with these libraries. Reported by: Nikolaus Rath 2011-05-20 Miklos Szeredi * Cleaner build output. Patch by Reuben Hawkins 2011-05-19 Miklos Szeredi * Disable splice by default, add "splice_read", "splice_write" and "splice_move" options. Keep the "no_splice_*" variants, which can disable splice even if the filesystem explicitly enables it. 2011-04-15 Max Krasnyansky * Added support for "auto_unmount" option which unmounts the filesystem automatically on process exit (or crash). 2011-03-30 Miklos Szeredi * Patches by Laszlo Papp fixing various issues found by the Coverity checker 2011-03-11 Miklos Szeredi * In case of failure to add to /etc/mtab don't umount. Reported by Marc Deslauriers 2011-02-02 Miklos Szeredi * libfuse: In fuse_session_loop_mt() don't pause when exiting the worker threads. The pause() was added in 2.2.1 to prevent segfault on pthread_cancel() on an exited, detached thread. Now worker threads are not detached and pthread_cancel() should work fine even after the thread exited. Reported by Boris Protopopov 2011-01-31 Miklos Szeredi * fusermount: chdir to / before performing mount/umount * fusermount: only allow mount and umount if util-linux supports --no-canonicalize 2010-12-16 Miklos Szeredi * Highlevel lib: allow hash tables to shrink * Highlevel lib: add slab allocation for node cache. This will allow the memory used by the filesystem to grow and shrink depending on how many inodes are currently cached. 2010-12-13 Miklos Szeredi * Highlevel lib: use dynamically resized hash table for looking up by name and node ID. 2010-12-07 Miklos Szeredi * Allow batching of forget requests. This allows forget requests to be processed faster and doesn't require a modification to fuse filesystems. Reported by Terje Malmedal * Add ->forget_multi() operation to the lowlevel API. The filesystem may implement this to process multiple forget requests in one call * Fix the ambiguity of ioctl ABI on the kernel/userspace boundary for 32bit vs. 64bit userspace 2010-11-10 Miklos Szeredi * Add new write_buf() method to the highlevel API. Similarly to the lowlevel write_buf() method, this allows implementing zero copy writes. * Add a new read_buf() method to the highlevel API. This allows returning a generic buffer from the read method, which in turn allows zero copy reads. * In fusexmp_fh implement the ->read_buf() and ->write_buf() methods. Leave the ->read() and ->write() implementations for reference, even though they are not necessary. 2010-11-08 Miklos Szeredi * Fix check for read-only fs in mtab update * Open /dev/null for write instead of read for redirecting stdout and stderr * If umount(8) supports --fake and --no-canonicalize (util-linux-ng version 2.18 or later), and umount(2) supports the UMOUNT_NOFOLLOW flag (linux kernel version 2.6.35 or later) then, "fusermount -u" will call the umount(2) system call and use "umount --fake ..." to update /etc/mtab * Added --disable-legacy-umount option to configure. This disables the runtime checking of umount(8) version. When built with this option then "fusermount -u" will fail if umount(8) doesn't support the --fake and --no-canonicalize options. * Fix fuse_buf_copy() if already at the end of the buffers * Add new ->write_buf() method to low level interface. This allows passig a generic buffer, either containing a memory buffer or a file descriptor. This allows implementing zero copy writes. * Add fuse_session_receive_buf() and fuse_session_process_buf() which may be used in event loop implementations to replace fuse_chan_recv() and fuse_session_process() respectively. * Remove unnecessary restoring of current working directory in "fusermount -u" * Add ctx->pid to debug output * Fix st_nlink value in high level lib if file is unlinked but still open * libfuse: add store request. Request data to be stored in the kernel buffers for a given inode. * libfuse: add retrieve request. Retrieve data stored in the kernel buffers for a given inode. 2010-10-14 Miklos Szeredi * Use LTLIBICONV when linking libfuse. This fixes building against uclibc + libiconv. Patch by Natanael Copa 2010-10-05 Miklos Szeredi * Add missing argument check in ulockmgr.c to prevent calling ulockmgr_server with illegal arguments. This would cause an ever growing list of ulockmgr_server processes with an endless list of open files which finally exceeds the open file handle limit. Patch by Markus Ammer 2010-09-28 Miklos Szeredi * Fix ambiguous symbol version for fuse_chan_new. fuse_versionscript included fuse_chan_new in both FUSE_2.4 and FUSE_2.6. Remove the FUSE_2.4, which is invalid. 2010-09-28 Miklos Szeredi * Fix option escaping for fusermount. If the "fsname=" option contained a comma then the option parser in fusermount was confused (Novell bugzilla #641480). Fix by escaping commas when passing them over to fusermount. Reported by Jan Engelhardt 2010-08-27 Miklos Szeredi * Add NetBSD support. Patch from Emmanuel Dreyfus 2010-07-12 Miklos Szeredi * libfuse: add buffer interface. Add a generic buffer interface for use with I/O. Buffer vectors are supplied and each buffer in the vector may be a memory pointer or a file descriptor. * The fuse_reply_fd() interface is converted to using buffers. 2010-06-23 Miklos Szeredi * Make the number of max background requests and congestion threshold tunable. New options are "max_background" and "congestion_threshold". Only effective on linux kernel versions 2.6.32 or greater. Patch by Csaba Henk 2010-06-17 Miklos Szeredi * Add fuse_reply_fd() reply function to the low level interface. On linux version 2.6.35 or greater this will use splice() to move data directly from a file descriptor to the fuse device without needing to go though a userspace buffer. With the FUSE_REPLY_FD_MOVE flag the kernel will attempt to move the data directly into the filesystem's cache. On earlier kernels it will fall back to an intermediate buffer. The options "no_splice_write" and "no_splice_move" can be used to disable splicing and moving respectively. 2010-06-15 Miklos Szeredi * Fix out-of-source build. Patch by Jörg Faschingbauer * Add a "nopath" option and flag, indicating that path argument need not be calculated for the following operations: read, write, flush, release, fsync, readdir, releasedir, fsyncdir, ftruncate, fgetattr, lock, ioctl and poll. 2010-05-10 Miklos Szeredi * Remove "chmod root" from install of fusermount. Reported by Lucas C. Villa Real 2010-04-26 Miklos Szeredi * Released 2.8.4 2010-04-26 Miklos Szeredi * Fix checking for symlinks in umount from /tmp. Reported by Al Viro * Fix umounting if /tmp is a symlink. Reported by Franco Broi 2010-02-18 Miklos Szeredi * Fix definition of FUSE_OPT_END for C++. Reported by Tim Bruylants 2010-02-03 Miklos Szeredi * Fix stack alignment for clone() 2010-02-01 Miklos Szeredi * Released 2.8.3 2010-02-01 Miklos Szeredi * Using "--no-canonicalize" with umount(8) conflicts with the race fix, sinceit assumes the supplied path is absolute, while the race fix relies on the path being relative to the current directory. Reported by Tom Rindborg 2010-01-26 Miklos Szeredi * Released 2.8.2 2010-01-21 Miklos Szeredi * Fix race if two "fusermount -u" instances are run in parallel. Reported by Dan Rosenberg * Make sure that the path to be unmounted doesn't refer to a symlink 2010-01-14 Miklos Szeredi * Fix compile error on FreeBSD. Patch by Jay Sullivan 2009-12-17 Miklos Szeredi * Use '--no-canonicalize' option of mount(8) (available in util-linux-ng version 2.17 or greater) to avoid calling readling(2) on the newly mounted filesystem before the mount procedure is finished. This has caused a deadlock if "audit" was enabled in the kernel. Also use '--no-canonicalize' for umount to avoid touching the mounted filesystem. 2009-09-11 Miklos Szeredi * Released 2.8.1 2009-08-25 Miklos Szeredi * Fix missing versioned symbol fuse_get_context@FUSE_2.2 2009-08-18 Miklos Szeredi * Released 2.8.0 2009-08-18 Miklos Szeredi * Add missing fuse_session_data to versionscript * Make sure all global symbols are prefixed with "fuse_" or "cuse_" 2009-07-16 Miklos Szeredi * Clarify how the protocol version should be negotiated between kernel and userspace. Notably libfuse didn't correctly handle the case when the supported major versions didn't match * Add missing pthread link for libulockmgr. Patch by Petr Salinger 2009-07-02 Miklos Szeredi * The context is extended with a 'umask' field. The umask is sent for mknod, mkdir and create requests by linux kernel version 2.6.31 or later, otherwise the umask is set to zero. Also introduce a new feature flag: FUSE_CAP_DONT_MASK. If the kernel supports this feature, then this flag will be set in conn->capable in the ->init() method. If the filesystem sets this flag in in conn->want, then the create modes will not be masked. * Add low level interfaces for lookup cache and attribute invalidation. This feature is available in linux kernels 2.6.31 or later. Patch by John Muir * Kernel interface version is now 7.12 * fusermount: Do not silently ignore command line arguments. Patch by Sebastian Harl 2009-06-19 Miklos Szeredi * Released 2.8.0-pre3 2009-06-19 Miklos Szeredi * Add fuse_getgroups (high level lib) and fuse_req_getgroups (low level lib) functions to query the supplementary group IDs for the current request. Currently this is implemented on Linux by reading from the /proc filesystem. 2009-06-18 Miklos Szeredi * Add "noforget" option to high level lib to prevent ESTALE errors on NFS exported filesystems. This result in paths being cached forever, resulting in ever growing memory usage. Use with care. * Add "no_remote_lock" option to disable remote file locking even if the filesystem implements it. With this option locking primitives (flock, lockf, fcntl(F_SETLK)) will still work, but will ignore remotely locked files. * CUSE patches from Tejun Heo: * Unrestricted ioctl support left some debris. Clean them up: o No reason to pass around pointer to flags. Pass flags directly. o Clean up comment and prototype parameter names. o fuse_lib_ioctl() didn't reply when get_path() failed. Fix it. o Remove unused variables {in|out}_iov from fuse_lib_ioctl(). * Add fuse_reply_ioctl_iov() * Move fuse_session, fuse_req and fuse_ll definitions to fuse_i.h and make send_reply_iov() and fuse_setup_common() global (also in fuse_i.h). These will be used by CUSE support. * Restructure fuse_ll_process() * Implement libfuse side of CUSE support. CUSE uses subset of FUSE operations as dir operations don't make sense for CUSE where one instance implements single character device. CUSE support comes with its own cuse_lowevel_ops and related initialization and helper functions. Except for initialization, it usage is basically identical to FUSE. This patch also adds example/cusexmp.c which can create a character device with name and device number specified on command line. The created device itself is pretty boring. It's a bit bucket supporting read, write and access via ioctl. 2009-06-16 Miklos Szeredi * Add missing fuse_reply_bmap to versionscript. Debian Bug#531329. Reported by Goswin Brederlow 2009-05-27 Miklos Szeredi * Don't call forget_node() if the lookup was negative and write() for the reply returned ENOENT. Reported by John Haxby 2009-05-25 Miklos Szeredi * Add FUSE_CAP_EXPORT_SUPPORT to fuse_common.h 2009-05-08 Miklos Szeredi * Fix missing newlines in some printfs * Fix 'make install-strip'. Reported by Dominick Layfield 2009-01-05 Miklos Szeredi * Released 2.8.0-pre2 2008-12-08 Miklos Szeredi * Implement poll support. Patch by Tejun Heo * Add missing setattr flags to . * Only pass valid flags to ->setattr(). 2008-12-05 Miklos Szeredi * Implement ioctl support. On high level interface only "restricted" ioctls are supported (which are defined with the _IO(), _IOR(), _IOW() or _IOWR() macros). Unrestricted ioctls will only be allwed to CUSE (Character Device in Userspace) servers. Patch by Tejun Heo 2008-11-28 Miklos Szeredi * If open sets fi->nonseekable, libfuse will tell the kernel that the file is not seekable. Patch by Tejun Heo 2008-11-19 Miklos Szeredi * lowlevel lib: fix deadlock if fuse_reply_* is called from the interrupt handling function. Reported by Tero Marttila 2008-10-16 Miklos Szeredi * Allow commas in options to be escaped with a backslash * Add new function: fuse_opt_add_opt_escaped() * Add missing fuse_reply_bmap() to the version script 2008-10-14 Miklos Szeredi * Pass current file flags to read and write operations 2008-07-24 Miklos Szeredi * Clean up debug output in highlevel lib 2008-07-10 Miklos Szeredi * Released 2.8.0-pre1 2008-06-27 Miklos Szeredi * Fix handling of (no)suid and (no)dev options if filesystem is mounted from /etc/fstab or via mount(8). Reported by Jan Ondrej. * Skip calling mount(8) if /etc/mtab doesn't exist or if it's on a read-only filesystem. This works around issues with certain mount implementations. Reported by Szabolcs Szakacsits. 2008-06-16 Miklos Szeredi * Remove fuse kernel module sources. Linux 2.6.27 will support NFS exporting. 2008-06-10 Miklos Szeredi * Fix theoretical infinite loops in libfuse. Reported by Szabolcs Szakacsits * Fix missing include for PATH_MAX. Reported by Szabolcs Szakacsits 2008-05-23 Miklos Szeredi * Fix mounting over symlink. Reported by Szabolcs Szakacsits 2008-05-09 Miklos Szeredi * Don't allow bigger than 4kB writes by default on 2.6.26 and later kernels, so that filesystems not expecting this are not broken on a kernel upgrade. Provide a 'big_writes' mount option to enable this feature. In future API revisions this may become the default. 2008-04-09 Miklos Szeredi * Update warning message for missing newline at end of fuse.conf * Update debug message for successful operation to not include the string "error:" 2008-04-08 Miklos Szeredi * Update error message for missing mountpoint parameter. Reported by Allen Pulsifer 2008-04-04 Miklos Szeredi * Print library version information to debug output * Highlevel lib: don't limit paths to 4095 characters 2008-03-25 Miklos Szeredi * Fix memory leaks on mount. Patch by Szabolcs Szakacsits 2008-03-19 Miklos Szeredi * Fix missing pthread_mutex_destroy in error path of fuse_lib_opendir(). Patch by Szabolcs Szakacsits 2008-03-07 Miklos Szeredi * Add queuing on contention to per-node lock algorithm, to avoid starvation. * Only enable cancelation when reading a request, otherwise cancellation could happen with a mutex held, which could hang the process on umount 2008-02-08 Miklos Szeredi * Block SIGCHLD when executing mount and umount * fusexmp_fh: avoid unnecessary seeking in readdir * Update kernel interface to 7.9: * Support receiving file handle from kernel in GETATTR request * Allow operations with a NULL path argument, if the filesystem supports it * Add support atomic open(O_TRUNC) * Support the st_blksize field in struct stat * If the "FUSE_THREAD_STACK" environment is set, initialize the stack size of threads by this value. Patch by Florin Malita * Add per-node locking, instead of a global tree lock to protect the path from changing during operations. Original patch by Rodrigo Castro 2008-02-03 Csaba Henk * lib/mount_bsd.c: - string formatting fixes - exit if mounting has failed (in FreeBSD a mount failure is not critical per se, as the daemon still could be mounted externally, but waiting for such an event is more confusing than fruitful) - ditch the kvm(8) stuff and simply use forced unmount which just won't block - prettify option specifications - add "-onosync_unmount" kernel option 2008-01-07 Csaba Henk * lib/mount_bsd.c: - refine device closing in a race-free way - add support for "-osubtype" on FreeBSD * makeconf.sh: make it work under FreeBSD 2008-01-03 Csaba Henk * lib/mount_bsd.c: close device before unmount (cf. lib/mount.c rev. 1.43) and fix some warnings 2007-12-23 Miklos Szeredi * Fix './configure --disable-static'. Patch from Ismail Dönmez 2007-12-17 Miklos Szeredi * Released 2.7.2 2007-12-12 Miklos Szeredi * Fix kernel module compile for 2.6.24 * Invalidate attributes of parent directory after create(), since the modification time changes. Invalidate attributes on rename, since some filesystems may update st_ctime. Reported by Szabolcs Szakacsits * Fix NFS exporting to handle 64bit node IDs * Disable old symbol versions if __UCLIBC__ is defined. If a symbol in a library has multiple versions, the runtime linker in uClibc seems to randomly choose between them. * Remove erroneous 'fuse_opt_insert_arg@FUSE_2_5' from fuse_version_script. fuse_opt_free_args() was added in fuse-2.6. * Close fuse device file descriptor before calling umount(), preventing a deadlock when umount is synchronous. Reported by Szabolcs Szakacsits 2007-11-12 Miklos Szeredi * 'fusermount -u' did not umount the filesystem if /etc/mtab was a symlink. This bug was introduced in 2.7.1 by "Don't call /bin/[u]mount if /etc/mtab is a symlink". Found by robertsong. 2007-10-16 Miklos Szeredi * Released 2.7.1 2007-10-16 Miklos Szeredi * Clarify licence version to be "LGPLv2" for the library * kernel fixes: * After mount set nlink attribute for the root inode to 1 * Fix wake up of task waiting for a reserved request * Fix allowing setattr, listxattr and statfs for other users 2007-09-18 Miklos Szeredi * Add missing context initialization in fuse_fs_chmod(). Bug found by "iohead" * Fix kernel module compilation for 2.6.23. Based on patch by Marian Marinov 2007-09-04 Philippe Elie * lib/fuse_lowlevel.c: fix a fuse_req leak in do_forget() 2007-07-31 Miklos Szeredi * Work around hotplug issue, that it calls filesystem with file descriptors 0, 1 and 2 not open. Tracked down by Leif Johnson 2007-07-25 Miklos Szeredi * Don't call /bin/[u]mount if /etc/mtab is a symlink. Reported by Tomas M * Also don't touch /etc/mtab if it is within the mounted filesystem. Suggested by Jeffrey Law 2007-07-12 Miklos Szeredi * Reset args->argc in fuse_opt_free_args(). Patch by Lucas C. Villa Real 2007-07-02 Miklos Szeredi * Released 2.7.0 2007-07-02 Miklos Szeredi * Accept a NULL "op" for fuse_main(), etc. This is useful if filesystem is only invoking fuse to print a help message, or version. Fixes RedHat bugzilla #217343 2007-06-22 Miklos Szeredi * lib: fix locking when loading a filesystem module 2007-06-21 Miklos Szeredi * Add fs subtype support to mount.fuse 2007-06-20 Miklos Szeredi * Add fs subtype support to libfuse and fusermount 2007-06-19 Miklos Szeredi * kernel: sync with mainline (2.6.22) 2007-06-18 Miklos Szeredi * Send debug output to stderr instead of stdout. Patch by Jan Engelhardt 2007-06-03 Miklos Szeredi * libulockmgr: Work around a kernel bug in recv(), causing it to sometimes return zero even if data was available on the socket. 2007-05-29 Miklos Szeredi * lib: optimization: store parent pointer in node instead of parent id 2007-05-25 Miklos Szeredi * lib: don't create new thread for each FORGET request. FORGET messages sometimes caused so many threads to be created, that process virtual memory space ran out. Reported by Chris AtLee 2007-05-24 Miklos Szeredi * lib: fix memory leak on thread creation failure in multithreaded event loop. Found by Chris AtLee 2007-05-23 Miklos Szeredi * lowlevel lib: add fuse_reply_iov function, which is similar to fuse_reply_buf, but accepts a vector of buffers. Patch by Roger Willcocks 2007-05-21 Miklos Szeredi * Fix Oops or error if a regular file is created with mknod(2) on a fuse filesystem. Kernels 2.6.18 onward are affected. Thanks to J. Cameijo Cerdeira for the report 2007-05-11 Csaba Henk * libfuse: fix return value of fuse_loop()/fuse_loop_mt(). Error reported by Csaba Henk, fix by Miklos Szeredi * libfuse: fix unlock in flush * libfuse: do unlocking on RELEASE+FLUSH 2007-05-03 Miklos Szeredi * Released 2.7.0-rc1 2007-05-02 Miklos Szeredi * kernel: sync with mainline: * Use invalidate_mapping_pages() if available * Fix BUG when invalid file type is supplied in mount. Patch by Timo Savola 2007-04-27 Miklos Szeredi * libfuse: call umount(8) directly instead of fusermount if possible * Clean up init script, make it LSB compliant 2007-04-26 Miklos Szeredi * In multithreaded loop, use a semaphore instead of SIGHUP to wake up the main thread on umount. This is more elegant, and works even if signals are blocked. 2007-04-25 Miklos Szeredi * Improve mounting support in libfuse: - check non-empty mountpoint - only fall back to fusermount when necessary 2007-04-23 Miklos Szeredi * Don't chdir to "/" in foreground mode, it causes more trouble than it's worth 2007-04-18 Miklos Szeredi * Replace utils/mount.fuse "sh" script with a "C" program 2007-04-15 Miklos Szeredi * Add -lulockmgr to compilation comment in fusexmp_fh.c 2007-04-05 Miklos Szeredi * Check for iconv. Patch by Csaba Henk * Add direct umounting * Use "fusectl" as the device for the fusectl filesystem. Debian Bug#417945. Reported by Laurent Bonnaud 2007-04-01 Csaba Henk * Fix some FreeBSD related macros. 2007-03-30 Miklos Szeredi * Add support for direct mounting by libfuse. Fall back on calling fusermount if it doesn't work 2007-03-14 Miklos Szeredi * Released 2.7.0-pre1 2007-03-05 Miklos Szeredi * Correctly handle O_APPEND in direct IO mode. Reported by Greg Bruno * mount.fuse should use /bin/bash. Debian Bug#413403. Reported by Thomas Weinbrenner 2007-02-26 Miklos Szeredi * Fix detection of installed fuse in init script. Reported and fix suggested by Davide Canova 2007-02-05 Miklos Szeredi * Fix 2.6.9 RHEL kernels, which have compatibility mutex.h, but don't define mutex_destroy(), bummer. Patch from Phil Schwan 2007-02-04 Miklos Szeredi * Compile fuseblk for kernels which don't have an option to turn off the block layer (CONFIG_BLOCK). Reported by Szakacsits Szabolcs 2007-02-03 Miklos Szeredi * Add filesystem stacking support to high level API. Filesystem modules can be built into libfuse or loaded from shared object (.so) files * Add 'subdir' and 'iconv' built in modules * lib/fuse.c: Fix locking for the reply code in create and open 2007-02-02 Miklos Szeredi * kernel: make it compile on "strange" kernels which have emulated mutexes via but no i_mutex. Reported by Tomasz Mateja 2007-01-28 Miklos Szeredi * kernel: fix BUG in control filesystem if it is umounted and mounted again, while some fuse filesystems are present. Bugreport from Florent Mertens * kernel: sync with mainline, support 2.6.20 2007-01-22 Miklos Szeredi * lib/Makefile.am: actually link libfuse against libfuse_libs 2007-01-19 Miklos Szeredi * Build fix for 2.6.16 vanila and 2.6.15 FC5 kernels. Patch from Ian Abbott 2007-01-18 Miklos Szeredi * Fix abort in fuse_new() compatibility API for opts == NULL case. Novell bugzilla #233870. Patch from Takashi Iwai. 2007-01-13 Miklos Szeredi * Fix option parsing in mount.fuse. Patch from Jens M. Noedler 2007-01-02 Miklos Szeredi * Fix unaligned access in file desctriptor passing in libfuse, fusermount and ulockmgr. Debian bug ID: 404904. Reported and tested by Sebastian Fontius 2006-12-16 Miklos Szeredi * kernel: don't keep unreferenced inodes in the icache. 2006-12-15 Miklos Szeredi * fusermount: Fix detection of fuseblk. Reported by Szakacsits Szabolcs * lib: Fix use after free in fuse_flush(). Reported by Ron Lindman 2006-12-10 Miklos Szeredi * mount.fuse: add "setuid=USER" option which does a "su - USER" for the filesystem * fusermount: use "/bin/mount -f" to add entry to /etc/mtab, and "/bin/umount" to remove entry from /etc/mtab. This gets rid of the ugly code dealing with mtab, as well as a possible race between fusermount and mount trying to modify /etc/mtab at the same time * Fix "buffer size too small: 4" warning for users of the fuse_loop_mt_proc() function. 2006-12-04 Miklos Szeredi * Fix warnings with gcc-4.1 on 64bit archs. Report from Harshavardhana * Add extra warning options, and fix resulting warnings * Really fix fuse_teardown problem 2006-12-02 Miklos Szeredi * Add -lrt to fuse.pc (if needed) to fix static linking against libfuse. Reported by Szakacsits Szabolcs 2006-12-01 Miklos Szeredi * Released 2.6.1 2006-11-30 Miklos Szeredi * Fix API version 21 and 22 compatibility for fuse_teardown. Reported by Bgs 2006-11-29 Miklos Szeredi * fusermount: Print a more helpful message in case the kernel doesn't support the 'fuseblk' filesystem type. This has been biting ntfs-3g users. Reported by Yura Pakhuchiy * kernel: fix build problem for "make -C ...". Reported by Stephen Bryant 2006-11-19 Miklos Szeredi * Fix bug in certain error paths of lookup routines. The request object was reused for sending FORGET, which is illegal. This bug could cause an Oops in linux-2.6.18 or in fuse-2.6.0, and might silently corrupt memory in earlier versions. Report and test program by Russ Cox 2006-11-11 Miklos Szeredi * Print an error if an incompatible kernel interface version is detected in INIT. This will only show if filesystem is started with -d or -f * Fix order of fuse_destroy()/fuse_unmount() in error cleanup of fuse_setup_common(). Reported by Szakacsits Szabolcs 2006-11-06 Miklos Szeredi * Fix recursive locking in fuse_create(). Thanks to Takuya Ishibashi for the bug report 2006-10-28 Miklos Szeredi * Fix automake problem. Patch from Nix 2006-10-26 Miklos Szeredi * Fix mount.fuse to use /bin/sh instead of /bin/bash, which is not always available on embedded systems. Patch from Paul Smith * Fix util/Makefile.am, so that failure to run update-rc.d or device creation doesn't cause make to fail. Reported by Paul Smith 2006-10-21 Miklos Szeredi * Released 2.6.0 2006-10-18 Miklos Szeredi * fusermount: don't try to create a lock file if /etc/mtab is a symlink. Report and patch from Alexei Sheplyakov (debian bug #393693) 2006-10-17 Miklos Szeredi * Minor changes, sync with mainline tree 2006-10-16 Miklos Szeredi * Released 2.6.0-rc3 2006-10-15 Miklos Szeredi * kernel: cleanups 2006-10-13 Miklos Szeredi * kernel: Fix compilation on patched 2.6.18 (fc6) and 2.6.19. Report from David Shaw * lib: Fix lost error on renaming a file. Report from David Shaw * lib: Fix lost error on hiding open files (renaming to .fuse_hiddenXXXX) * kernel: Fix a rare hang on SMP/32bit on heavy filesystem activity. The cause of the bug was that some calls to i_size_write() were not protected by a lock, and hence i_size_seqcount could become corrupted. This caused subsequent calls to i_size_read() to spin forever. This is a long standing bug was probably introduced in version 2.2, and thought to be related to NFS exporting (it's not). It was reported by various people, but Dana Henriksen has finally helped me to track it down, so big thanks to him * kernel: Protect against truncation of a swapfile 2006-10-10 Miklos Szeredi * kernel: Check for signature of super_operations->umount_begin(). Ubuntu kernel 2.6.17 seems to use the new signature found in 2.6.18. Thanks to Florent Mertens for the report 2006-10-08 Miklos Szeredi * Make sure inode numers wrap around at 2^32. This is needed on dual 64bit/32bit architectures, because 32bit applications using the non-largefile interface would otherwise break (EOVERFLOW error would be returned by the stat() system call family) * ulockmgr: handle the case, when a locking operation fails because no more file desctriptors are available in ulockmgr_server. Also work around a Linux kernel bug (known to exist for all Linux kernel versions <= 2.6.18) which may cause sent file descriptors to be lost in the above case * ulockmgr: optimize file descriptor use * restore needed cpp flags to util/Makefile.am * Install udev rules as 99-fuse.rules instead of 60-fuse.rules * Minor clean up of udev rules * Add a synchronous DESTROY message to kernel interface. This is invoked from umount, when the final instance of the filesystem is released. It is only sent for filesystems mounted with the 'blkdev' option for security reasons. * If the DESTROY message is received, call the filesystem's ->destroy() method. In this case it's not called from session destruction as it would be otherwise. 2006-10-01 Miklos Szeredi * Released 2.6.0-rc2 2006-10-01 Miklos Szeredi * Add support for FLUSH+RELEASE operation for FreeBSD. Original patch by Csaba Henk * Add init script to insert fuse module and mount the control filesystem. The script is installed as /etc/init.d/fuse and on debian based systems (where update-rc.d is available) symlinks from /etc/rc*.d/ are also installed. * Include '#define FUSE_USE_VERSION=XX' into examples so they become more self contained. 2006-09-30 Miklos Szeredi * API changes: * Move lock_owner from a separate argument into fuse_file_info * Add a flag to fuse_file_info indicating (1) a highlevel lock operation (unlock all) was initiated by a flush, (2) a lowlevel release operation should perform a flush as well. * fusermount: revert modprobe change (2006-08-18) since it doesn't work reliably with udev * Add support for block device backed filesystems. This mode is selected with the 'blkdev' option, which is privileged. * Add support for the bmap (FIBMAP ioctl) operation on block device backed filesystems. This allows swapon and lilo to work on such filesystems. * kernel changes: * Drop support for kernels earlier than 2.6.9. Kernel module from previous (2.5.x) release can be used with library from this release * In fuse_dentry_revalidate() use dget_parent() instead of dereferencing d_parent, since there's no protection against parent changing and going away * Protect nlookup from concurrent updates * In lookup if a directory alias exists but is unused, then get rid of it, otherwise return -EBUSY. * In mkdir if a directory alias exists, return success, but leave dentry negative. In reality this could happen if a remote rename immediately followed the mkdir. * Don't BUG in fuse_iget() if multiple retries are needed to get a good inode. This could happen if several lookups are racing for the same inode. 2006-09-29 Miklos Szeredi * Fix compilation on 2.6.9. Report from Troy Ayers 2006-09-27 Miklos Szeredi * Fix Oops in fuse_readpages(). Reported by David Shaw 2006-09-24 Csaba Henk * Add support for nanosec times on FreeBSD * Fix FreeBSD compatibility issues 2006-09-23 Miklos Szeredi * Fix one more compatibility bug. Thanks to Ricardo Correia * Fix utimens compilation with uClibc. Patch from Jamie Guinan 2006-09-22 Miklos Szeredi * Fixed several compatibility bugs in low level interface. Reported by Ricardo Correia * Add workaround for ARM caching bug 2006-09-16 Miklos Szeredi * Rename new utimes() method to more logical utimens() 2006-09-14 Miklos Szeredi * Fuse tried to unlink already unlinked hidden files. Bug reported by Milan Svoboda 2006-09-10 Miklos Szeredi * Released 2.6.0-rc1 2006-09-10 Miklos Szeredi * kernel: Fix unlock on close for kernels < 2.6.18 * Add ulockmgr library & server. This can be used for handling file locking requests either directly from libfuse or over a network, etc. This first version is not optimized and the number of file descriptors it uses may get out of hand 2006-09-07 Miklos Szeredi * lib: Add interrupt support to high level library, which may be enabled with the 'intr' mount option. * When an operation is interrupted the thread handling that operation will receive SIGUSR1 (or other signal specified with the 'intr_signal=N' option). The library installs a no-op signal handler for this signal, unless there's already a handler installed. * The filesystem may query interrupt status (regardless of 'intr') with the fuse_interrupted() function. * mount.fuse: initialize $HOME if not set. Report from Sven Goldt 2006-09-03 Miklos Szeredi * lib: Multithreaded loop now allows unlimited number of threads. This is needed for locking operations which may block indefinitely. Also the kernel now doesn't limit the number of outstanding requests so the library shouldn't do so either. 2006-09-01 Miklos Szeredi * Fix recursive lock bug in interrupt handling * Add utimes() method to highlevel interface, which supports setting times with nanosecond resolution 2006-08-18 Miklos Szeredi * kernel: fix page leak if fuse_readpages() failed in it's initialization. Bug found and original patch from Alexander Zarochentsev * For linux kernels >=2.6.18 (2.6.19 if using the fuse module from the kernel tree) the statfs method will receive the path within the filesystem on which the stat(v)fs syscall was called * fusermount: try to modprobe fuse module if invoked by root and unable to open device. This is needed with udev, since the device node will be created only when the module is inserted, hence module autoloading won't work. Reported by Szakacsits Szabolcs 2006-07-30 Miklos Szeredi * fusermount: if selinux is active, restore the original file's security context in unmount_rename(). Redhat bugzilla id 188561. Patch from Yves Perrenoud * Add POSIX file locking operation to high level library * Initialize context for unlink of hidden files on umount. Bug reported by Tim Stoakes 2006-07-14 Miklos Szeredi * Multiple release() calls can race with each other, resulting in the hidden file being deleted before the last release finishes. Bug found and patch tested by Mark Huijgen 2006-07-05 Miklos Szeredi * fusermount: if /dev/fuse doesn't exist, suggest modprobing fuse; this makes sense on systems using udev. Reported by Szakacsits Szabolcs 2006-06-29 Miklos Szeredi * Released 2.6.0-pre3 2006-06-29 Miklos Szeredi * Support in kernel module for file locking and interruption. The same functionality is available in official kernels >= 2.6.18 2006-06-28 Miklos Szeredi * Add POSIX file locking support * Add request interruption 2006-06-06 Miklos Szeredi * Add missing pthread_rwlock_destroy(). Patch from Remy Blank 2006-06-05 Remy Blank * lib: canonicalize mount point in fuse_helper_opt_proc() so that unmounting succeeds even if mount point was relative. 2006-06-04 Csaba Henk * lib: fix emergency umount in helper.c when malloc fails. (The way it was done would end up in a segfault.) 2006-06-01 Csaba Henk * lib: adjust threading related compiler flags. Switch to "-pthread" from "-lpthread" as that's the preferred one on several platforms. Consulted with Terrence Cole and Miklos Szeredi 2006-05-08 Miklos Szeredi * lib: search fusermount in installation directory (bindir) as well as in PATH. 2006-05-03 Miklos Szeredi * lib: fix compilation if CLOCK_MONOTONIC is not defined. Reported by Christian Magnusson 2006-04-23 Csaba Henk * lib: make FreeBSD mount routine recognize if kernel features backgrounded init and if it does, run the mount util in foreground (similarly to Linux) 2006-04-21 Miklos Szeredi * kernel: fix fput deadlock fix, the lockless solution could lead to "VFS: busy inodes after umount..." * kernel: fix race between checking and setting file->private_data for the device. Found by Al Viro 2006-04-11 Miklos Szeredi * kernel: remove request pool, instead allocate requests on demand. Account the number of background requests, and if they go over a limit, block the allocation of new requests. * kernel: fix deadlock if backgrounded request holds the last reference to the super block * kernel: don't use fuse_reset_request() during direct I/O 2006-04-06 Csaba Henk * lib: Let FreeBSD mount option parsing routine recognize "no" prefixes for FUSE specific options as well 2006-04-01 Miklos Szeredi * lib: Add missing rwlock initialization. Patch by Ryan Bradetich 2006-03-17 Miklos Szeredi * API changes: * fuse_main(), fuse_setup() and fuse_new() have an additionl user_data parameter * fuse_mount() returns a 'struct fuse_chan' pointer instead of a file descriptor * fuse_unmount() receives a 'struct fuse_chan' pointer. It destroys the given channel * fuse_teardown() no longer has a file descriptor parameter * new exported functions: fuse_session_remove_chan(), fuse_get_session(), fuse_daemonize() * fuse_chan_recv() may now return a new channel which will be used to send the reply 2006-03-16 Miklos Szeredi * Released 2.6.0-pre2 2006-03-16 Miklos Szeredi * Don't unmount if already unmounted. This fixes a problem seen in the following situation: Lazy unmount a busy filesystem; Mount a new one in top; When the first finally unmounts, the second also unmounts. Reported by Franco Broi 2006-03-15 Miklos Szeredi * lowlevel lib: use indirect function calls instead of a switch/case construct. Besides increased efficiency it helps maintainability & readability too. Patch from Florin Malita 2006-03-13 Miklos Szeredi * kernel: replace global spinlock with a per-connection spinlock 2006-03-10 Miklos Szeredi * Fix source compatibility breakage for fuse_unmount(). Report from Yura Pakhuchiy 2006-03-02 Miklos Szeredi * Fix O_ASYNC handling in fuse_dev_release(). From Jeff Dike 2006-03-01 Miklos Szeredi * Add O_ASYNC and O_NONBLOCK support to FUSE device. Patch by Jeff Dike * Renamed fuse_chan_receive() to fuse_chan_recv() and changed interface to return -errno in case of error. 2006-03-01 Csaba Henk * libfuse: pass device file descriptor to fuse_unmount(), rewrite FreeBSD implementation so that it uses libc (sysctl backed) instead of an embdedded script (kmem backed). Adjust the control flow of hello_ll so that device doesn't get closed before unmount attempt. 2006-02-25 Miklos Szeredi * Lowlevel lib: return all-zero statvfs data if filesystem doesn't implement method. This is needed on FreeBSD, and nicer on Linux too. Highlevel lib already did this. Reported by Csaba Henk * Fix negative entry handling. There was a bug, that negative lookups with timeouts (nodeid == 0) returned -EIO. 2006-02-23 Miklos Szeredi * Fix race between RELEASE and UNLINK, which might leave .fuse_hidden* files around 2006-02-21 Miklos Szeredi * fusexmp_fh: implement flush() method and call close() on the open file descriptor. This is needed if used on an NFS filesystem, which buffers data until file is closed. Franco Broi spotted the situation when 'cp -p' failed to set the modification time because of this. 2006-02-20 Miklos Szeredi * Released 2.6.0-pre1 2006-02-19 Miklos Szeredi * libfuse: fix use-after-free bug in interruptred reply_entry(). Patch from John Muir * libfuse: fix wrong symbol versioning for fuse_mount. Debian bug ID: 352631. Found by Stéphane Rosi 2006-02-17 Miklos Szeredi * Lowlevel lib: Unify fuse_dirent_size() and fuse_add_dirent() into a single function fuse_add_direntry(). This cleans up the interface and makes it possible to do stacking. 2006-02-16 Miklos Szeredi * Fix rare race betweeen abort and release caused by failed iget() in fuse_create_open(). * Add 'ac_attr_timeout' option e.g. for filesystems which do their own attribute caching. 2006-02-15 Miklos Szeredi * Work around FreeBSD runtime linker "feature" which binds an old version of a symbol to internal references if the symbol has more than one version. This resulted in infinite recursion in fuse_lowlevel_new_compat25(). 2006-02-10 Csaba Henk * Refine clock_gettime() querying so that linker options shall be set as it's appropriate for the target platform. 2006-02-09 Miklos Szeredi * Fix udev rule syntax. Reported by Nix 2006-02-08 Miklos Szeredi * In some cases udev rule seems to be ineffective when installed as 40-fuse.rules but work as 60-fuse.rules. Reported by John Hunt 2006-02-03 Miklos Szeredi * Fix compilation when build directory is different from source directory. Reported by Frédéric L. W. Meunier 2006-02-02 Miklos Szeredi * Fix even bigger bug introduced in fix for request_end() on 2006-01-14. Reported by Gal Rosen 2006-01-30 Miklos Szeredi * highlevel-lib: add 'auto_cache' option. This caches file data based on modification time and size 2006-01-20 Miklos Szeredi * Sanitize storage type and help message in mount_bsd.c. Patch from Csaba Henk * fuse_opt: add new helper constants FUSE_OPT_KEY_KEEP and FUSE_OPT_KEY_DISCARD * Add options 'max_readahead', 'sync_read' and 'async_read' * Kernel ABI version 7.6: * Negotiate the 'max_readahead' value and 'async_read' flags with userspace in the INIT method * Add connection info to ->init() methods to both lowlevel and highlevel API * Fall back to synchronous read() behavior if either library or userspace filesystem is using the old interface version. This is needed so non-updated filesystems won't be confused by the different read() behavior 2006-01-19 Miklos Szeredi * lib: if "fsname=" option was given, pass it to fusermount * fuse_opt: add new fuse_opt_insert_arg() function, which is needed by filesystems to implement some argument manipulations correctly * fuse_opt: fix memory leak in handling "--" option 2006-01-18 Miklos Szeredi * kernel: fix detection of case when fuse is not configured into the kernel either as module or built-in * fuse_opt.h: fix incompatibility with C++ compilers by renaming 'template' structure member to 'templ'. Reported by Takashi Iwai * fuse.h: fix compatibility bugs. Patch by Yura Pakhuchiy * kernel: support version 2.6.16 (i_sem -> i_mutex) 2006-01-16 Miklos Szeredi * Added (again) asynchronous readpages support * Each connection now shows up under /sys/fs/fuse/connections * Connection attributes exported to sysfs: 'waiting' number of waiting requests; 'abort' abort the connection * Connection may be aborted through either the sysfs interface or with 'umount -f mountpoint' 2006-01-14 Miklos Szeredi * Released 2.5.0 2006-01-14 Miklos Szeredi * kernel: fix a couple of bugs * Order of request_end() and fuse_copy_finish() was wrong. Posthumous note: Franco Broi managed to exploit this, though it seemed quite impossible * request_end() used request pointer after decrementing refcount * Clearing ->connected or ->mounted connection flags could race with setting other bitfields not protected with a lock 2006-01-10 Miklos Szeredi * kernel: add necessary compile flags for 2.4.X/x86_64. Report from Sean Ziegeler 2006-01-09 Miklos Szeredi * Released 2.5.0-pre2 2006-01-09 Miklos Szeredi * Applied patch from Csaba Henk, to update mount_bsd to new fuse_mount() semantics * Ignore auto,noauto,... options in mount.fuse. Reported by Frank Steiner and Don Taber * fusermount: add 'dirsync' mount option 2006-01-07 Miklos Szeredi * Improved help reporting and added version reporting to library 2006-01-06 Miklos Szeredi * Change working directory to "/" even if running in the foreground. Patch from Jonathan Brandmeyer * Changed lots of functions to use 'struct fuse_args' instead of separate argc and argv * Added fuse_parse_cmdline(), fuse_set_signal_handlers() and fuse_remove_signal_handlers() functions, so that it's now pretty easy to get all the functionality of fuse_main() with a filesystem using the lowlevel API. 2006-01-02 Miklos Szeredi * mount.fuse: the 'user' option should be ignored. Report and solution from Mattd. * mount.fuse: export PATH in the right place. Report and patch from Hannes Schweizer 2005-12-16 Miklos Szeredi * Clean up the option parsing interface slightly, by creating an "argument list" structure, that contains the argument vector and count 2005-12-15 Miklos Szeredi * fusermount: check if /mnt/mtab is a symlink and don't modify it in that case * kernel: simplify request size limiting. INIT only contains maximum write size, maximum path component size remains fixed at 1024 bytes, and maximum xattr size depends on read buffer. 2005-12-14 Miklos Szeredi * Fix readdir() failure on x86_64, of 32bit programs compiled without largefile support. Bug report and help from Anthony Kolasny * If lookup returns invalid mode, return -EIO instead of creating a regular file * Add current output argument vector to option processing function 2005-12-12 Miklos Szeredi * Fix stale code in ifdef FreeBSD. Patch from Csaba Henk 2005-12-09 Miklos Szeredi * Released 2.5.0-pre1 2005-12-09 Miklos Szeredi * libfuse: added option parsing interface, defined in . 2005-12-07 Miklos Szeredi * Return EIO for file operations (read, write, fsync, flush) on open files whose inode has become "bad". Inodes will be marked "bad" if their type changes. Bug report by Csaba Henk 2005-12-06 Miklos Szeredi * Use bigger request buffer size. write() did not work on archs with > 4k page size, Bug report by Mark Haney * ABI version 7.5: * Extend INIT reply with data size limits 2005-12-02 Miklos Szeredi * Fix memory leak in fuse_read_cmd()/fuse_process_cmd(). Bug reported by Vincenzo Ciancia * Handle exit-by-umount in fuse_read_cmd() 2005-11-29 Miklos Szeredi * Check if '-msoft-float' option is supported by compiler when configuring for a 2.4.x kernel. Bug report by Mark Haney * In multithreaded loop send a TERM signal to the main thread if one of the other threads exit. Needed on FreeBSD for a clean exit on umount. Should not cause any harm on Linux either 2005-11-28 Miklos Szeredi * Fix bug in 32-bit file handle compatibility 2005-11-27 Miklos Szeredi * Block TERM, INT, HUP and QUIT signals in all but the main thread. According to POSIX it's not specified which thread will receive these signals. * Kernel changes: * Check for directory aliasing on mkdir, not just on lookup * Check for special node ID values in create+open operation * Sync with -mm: readv, writev, aio_read and aio_write methods added to file operations * Cleanups: lookup code, page offset calculation * ABI stepped to 7.4, changes: * frsize member added to fuse_kstatfs structure * added support for negative entry caching: on lowlevel API if fuse_entry_param::ino is set to zero in reply to a lookup request, the kernel will cache the dentry for the specified amount of time. * libfuse: added 'negative_timeout' option: specifies how much negative entries should be cached. Default is zero, to be compatible with prior versions 2005-11-22 Miklos Szeredi * Add detection of mainline FUSE code in running kernel 2005-11-21 Miklos Szeredi * Don't use async cancelation in multithreaded loop. This makes it more portable to systems where read() is not async cancel safe. Report from Andriy Gapon 2005-11-20 Miklos Szeredi * Warn if API version 11 compatibility is requested 2005-11-17 Miklos Szeredi * More FreeBSD merge * fusermount: don't allow mountpoints with '\n', '\t', or '\\' in them, because it corrupts /etc/mtab. Found by Thomas Biege CVE-2005-3531 * libfuse: don't use system() to invoke 'fusermount -u ...' because it breaks mountpoints with spaces in them into multiple arguments 2005-11-16 Miklos Szeredi * Merge library part of FreeBSD port. Patch by Csaba Henk 2005-11-11 Miklos Szeredi * Use 64bit type for file handle, so the full range supported by the kernel interface is available to applications 2005-11-10 Miklos Szeredi * Moved mountpoint argument checking from fuse_parse_cmdline() to fuse_mount() in preparation to FreeBSD merge. 2005-11-08 Miklos Szeredi * Remove unneeded close() from fuse_teardown(). Spotted by Csaba Henk. 2005-11-07 Miklos Szeredi * Make the statfs change backwards compatible. 2005-11-06 Miklos Szeredi * Change ->statfs() method to use 'struct statvfs' instead of 'struct statfs'. This makes the API more portable since statvfs() is defined by POSIX. 2005-10-28 Miklos Szeredi * Add fgetattr() method, which currently will only be called after a successful call to a create() method. 2005-10-26 Miklos Szeredi * Change kernel ABI version to 7.3 * Add ACCESS operation. This is called from the access() system call if 'default_permissions' mount option is not given, and is not called on kernels 2.4.* * Add atomic CREATE+OPEN operation. This will only work with 2.6.15 (presumably) or later Linux kernels. * Add ftruncate() method. This will only work with 2.6.15 (presumably) or later Linux kernels. * Fix kernel module compile if kernel source and build directories differ. Report and initial patch by John Eastman 2005-10-18 Miklos Szeredi * lib: optimize buffer reallocation in fill_dir. 2005-10-17 Miklos Szeredi * Released 2.4.1 2005-10-14 Miklos Szeredi * libfuse: add debug for write result (by Shaun Jackman) and warnings for too large read/write result 2005-10-11 Miklos Szeredi * Spelling fixes, thanks to Ioannis Barkas 2005-10-10 Miklos Szeredi * fuse_common.h: use extern "C". Thanks to Valient Gough for the patch 2005-10-07 Miklos Szeredi * highlevel-lib: init() and destroy() methods didn't have an initialized fuse_context. Bug reported by Tim Stoakes 2005-10-04 Miklos Szeredi * Released 2.4.0 2005-10-03 Miklos Szeredi * Add documentation to fuse_lowlevel.h * API cleanups: * Remove definitions of unused FATTR_CTIME / FUSE_SET_ATTR_CTIME * Move fuse_mount() and fuse_unmount() to fuse_common.h * Change the return type of fuse_reply_none() from int to void. 2005-09-30 Miklos Szeredi * kernel: NFS exporting leaked dentries. Bug found and fixed by Akshat Aranya. 2005-09-29 Miklos Szeredi * fusermount: fix error message, when unable to open /dev/fuse. Report by Balázs Pozsár 2005-09-28 Miklos Szeredi * UClibc fixes from Christian Magnusson 2005-09-27 Miklos Szeredi * Added NAME="%k" to util/udev.rules. Fix by Mattias Wadman. 2005-09-26 Miklos Szeredi * Released 2.4.0-rc1 2005-09-26 Miklos Szeredi * fusermount: allow user umount in the case when /etc/mtab is a symlink to /proc/mounts. Reported by Balázs Pozsár. 2005-09-23 Miklos Szeredi * Check for special node ID values in lookup and creation 2005-09-22 Miklos Szeredi * Slight optimization in returning EINVAL error in case of an open with O_DIRECT flag. 2005-09-20 Miklos Szeredi * Remove '--enable-auto-modprobe' configure flag. Module auto-loading is now handled by the kernel. 2005-09-15 Miklos Szeredi * Install UDEV rule file, so /dev/fuse is created with mode 0666. Help from Jens M. Noedler. 2005-09-14 Miklos Szeredi * Add memory cleanup on thread exit 2005-09-13 Miklos Szeredi * Set umask to zero in fusexmp and fusexmp_fh, so that files/directories are created with the requested mode. 2005-09-12 Miklos Szeredi * Don't ignore read error in multithreaded loop 2005-09-08 Miklos Szeredi * Released 2.4.0-pre2 2005-09-08 Miklos Szeredi * Revert lock and access operations. Postpone these until 2.5. 2005-09-02 Miklos Szeredi * Fix compile warning on 2.6.13 and later * Fix compilation on old kernels 2005-08-19 Miklos Szeredi * lib: always refresh directory contents after rewinddir() to conform to SUS. Bug found by John Muir. 2005-08-15 Miklos Szeredi * Released 2.4.0-pre1 2005-08-14 Miklos Szeredi * lib: cleaned up (or messed up, depending on your POV) the low level library API. Hopefully this is close to the final form. 2005-08-05 Miklos Szeredi * fusermount: don't allow empty mountpoint argument, which defeats automatic umounting in fuse_main(). Bugreport by Václav Jůza 2005-08-03 Miklos Szeredi * fix warnings in fuse.h and fuse_lowlevel.h if -Wshadow compiler option is used (Paul Alfille). 2005-08-02 Miklos Szeredi * highlevel-lib: added mount options "attr_timeout" and "entry_timeout". These options control the length of time file attributes and entries (names) are cached. Both default to 1.0 second. * kernel: correctly handle zero timeout for attributes and entries 2005-08-01 Miklos Szeredi * Added missing symbols to versionscript (Joshua J. Berry) * kernel: implement two flags, open can set: 'direct_io' and 'keep_cache'. These correspond exactly to mount options 'direct_io' and 'kernel_cache', but allow a per-open setting. * Move 'direct_io' and 'kernel_cache' mount option handling to userspace. For both mount options, if the option is given, then the respective open flag is set, otherwise the open flag is left unmodified (so the filesystem can set it). * lib (highlevel): make open method optional 2005-07-28 Miklos Szeredi * kernel: invalidate attributes for read/readdir/readlink operations * kernel: detect newer UML kernels 2005-07-26 Miklos Szeredi * Make the installation path of fuse.ko and mount.fuse configurable through INSTALL_MOD_PATH and MOUNT_FUSE_PATH environment variables. Requirement and help from Csaba Henk. 2005-07-22 Miklos Szeredi * Fix bug, that causes filesystem requests to hang when unique request counter becomes negative. This happens after 2,147,483,648 operations, so most people won't care. Thanks to Franco Broi for the report and testing. 2005-07-21 Miklos Szeredi * Don't change mtime/ctime/atime to local time on read/write. Bug reported by Ben Grimm * Install fuse_common.h and fuse_lowlevel.h. Report by Christian Magnusson * fusermount: use getopt_long() for option parsing. It allows the use of '--' to stop argument scanning, so fusermount can now operate on directories whose names begin with a '-'. Patch by Adam Connell 2005-07-15 Miklos Szeredi * fusermount: add '-v', '--version' and '--help' options * add inode based API 2005-07-12 Miklos Szeredi * lib: don't block signals in worker threads. Problem noticed by Usarin Heininga 2005-07-07 Miklos Szeredi * lib: don't allow both 'allow_other' and 'allow_root' options to be given 2005-07-06 Miklos Szeredi * fusermount: check if mountpoint is empty (only '.' and '..' for directories, and size = 0 for regular files). If "nonempty" option is given, omit this check. This is useful, so users don't accidentally hide data (e.g. from backup programs). Thanks to Frank van Maarseveen for pointing this out. * kernel: check if mandatory mount options ('fd', 'rootmode', 'user_id', 'group_id') are all given * lib: simplify 'readdir_ino' handling * lib: add mount options 'umask=M', 'uid=N', 'gid=N' 2005-07-03 Miklos Szeredi * kernel: clean up 'direct_io' code 2005-06-28 Miklos Szeredi * Add 'mount.fuse' written by Petr Klima * '/dev/fuse' is created by 'make install' if does not yet exist 2005-06-20 Miklos Szeredi * Fix UCLIBC compile error. Patch by Christian Magnusson 2005-06-08 Miklos Szeredi * Enable the auto-loading of the module via access to the corresponding device file. Patch by Takashi Iwai. * Allow mounting a regular file (over a regular file) for unprivleged users. * Do not create temporary device file. Require "/dev/fuse" to exist, and be readable/writable by the mounting user. 2005-06-02 Miklos Szeredi * Released 2.3.0 2005-06-02 Miklos Szeredi * Fix serious information leak: if the filesystem returns a short byte count to a read request, and there are non-zero number of pages which are not filled at all, these pages will not be zeroed. Hence the user can read out previous memory contents. Found by Sven Tantau. 2005-05-27 Miklos Szeredi * Add "readdir_ino" mount option, which tries to fill in the d_ino field in struct dirent. This mount option is ignored if "use_ino" is used. It helps some programs (e.g. 'pwd' used over NFS from a non-Linux OS). Patch by David Shaw. 2005-05-12 Miklos Szeredi * Released 2.3-rc1 2005-05-12 Miklos Szeredi * File save in krusader and other editors doesn't work with sshfs, because open() is interrupted by a periodic signal, and open() restarts forever, without any progress. This could just be fixed in open(), but the problem is more generic: if signals are received more often than the filesystem can get the request to userspace, it will never finish. This is probably only a theoretical problem, nevertheless I'm removing the possibility to interrupt requests with anything other than SIGKILL, even before being sent to userspace. Bugreport by Eduard Czimbalmos. 2005-05-09 Miklos Szeredi * libfuse: add "tree_lock" rwlock, that is locked for write in rename, unlink and rmdir, and locked for read in all other operations. This should fix the rename/release race reported by Valient Gough and others. The solution is very coarse, a finer grained locking scheme could be implemented, but it would be much more complex. Let's see whether this is good enough. 2005-05-09 Miklos Szeredi * Released 2.3-pre7 2005-05-08 Miklos Szeredi * Better fix for out of order FORGET messages. Now the LOOKUP/FORGET messages are balanced exactly (one FORGET can balance many lookups), so the order no longer matters. This changes the kernel ABI slightly, but the library remains backward compatible. 2005-05-06 Miklos Szeredi * Fix abort for out of order FORGET messages. Again. Spotted by Franco Broi again. Sorry :) 2005-04-29 Miklos Szeredi * Released 2.3-pre6 2005-04-29 Miklos Szeredi * Make fusermount work with fuse kernel modules not yet supporting the "group_id" option (added for the purpose of stricter permission checking). 2005-04-28 Miklos Szeredi * Check for hard-linked directories in lookup. This could cause problems in the VFS, which assumes that such objects never exist. * Make checking of permission for other users more strict. Now the same privilege is required for the mount owner as for ptrace on the process performing the filesystem operation. 2005-04-23 Miklos Szeredi * Released 2.3-pre5 2005-04-22 Miklos Szeredi * Add -msoft-float to kernel module compile flags for 2.4.X. This is needed on certain architectures. Report from Chris Kirby * Fix buggy behavior of open(..., O_CREAT|O_EXCL) if interrupted. Reported by David Shaw * Remove "allow_root" option from kernel module, and implement it's functionality in the library * Fix Oops caused by premature release of fuse_conn. Clean up related code, to be more readable * Sendfile should not use page cache if "direct_io" mount option is given 2005-04-08 Miklos Szeredi * Fix Oops in case of nfs export. Spotted by David Shaw * Fix another Oops in case of write over nfs with direct_io turned on. Again spotted by David Shaw 2005-04-07 Miklos Szeredi * Released 2.3-pre4 2005-04-07 Miklos Szeredi * lib: finalized new readdir() interface, which now supersedes the getdir() method. 2005-04-03 Miklos Szeredi * Released 2.3-pre3 2005-04-03 Miklos Szeredi * Implement backward compatibility with version 5 kernel ABI 2005-04-01 Miklos Szeredi * Released 2.3-pre2 2005-04-01 Miklos Szeredi * kernel: fix dirent offset handling * lib: add readdir and releasedir methods * lib: use fh field of fuse_file_info in opendir, readdir, releasedir and fsyncdir methods * lib: check kernel API version and bail out of it's old. This will be properly fixed in the next release 2005-03-31 Miklos Szeredi * Released 2.3-pre1 2005-03-31 Miklos Szeredi * kernel API: add padding to structures, so 64bit and 32bit compiler will return the same size * kernel API: add offset field to fuse_dirent. This will allow more sophisticated readdir interface for userspace * kernel API: change major number to 6 * kernel: fix warnings on 64bit archs * kernel: in case of API version mismatch, return ECONNREFUSED 2005-03-24 Miklos Szeredi * kernel: trivial cleanups 2005-03-21 Miklos Szeredi * Add fsyncdir() operation 2005-03-19 Miklos Szeredi * kernel: add locking to background list (fixes previous fix) 2005-03-18 Miklos Szeredi * kernel: fix bug which could cause leave busy inodes after unmount, and Oops. 2005-03-08 Miklos Szeredi * examples: add -lpthread to link flags to work around valgrind quirk * lib: don't exit threads, so cancelation doesn't cause segfault 2005-03-04 Miklos Szeredi * kernel: fix nasty bug which could cause an Oops under certain situations. Found by Magnus Johansson 2005-02-28 Miklos Szeredi * libfuse: added opendir() method. This can be used in case permission checking in getdir() is too late. Thanks to Usarin Heininga for pointing out this deficiency * libfuse: added init() and destroy() methods to fuse_operations * kernel: llseek() method for files and directories made explicit * kernel: fixed inode leak in NFS export in case of nodeid wrapping 2005-02-15 Miklos Szeredi * libfuse: clean up some unitialized memory found with valgrind * Add -lpthread to Libs in fuse.pc. Valgrind seems to need an explicitly linked libpthread for applications 2005-02-10 Miklos Szeredi * fusermount: set umask, otherwise /etc/mtab will have unpredictable permission. Spotted by Jindrich Kolorenc * fusermount: set owner and group of /etc/mtab to original values on unmount * libfuse: add 'use_ino' option to help. Patch by Valient Gough 2005-02-07 Miklos Szeredi * Cleaned up directory reading (temporary file is not used) 2005-02-02 Miklos Szeredi * Released 2.2 2005-02-02 Miklos Szeredi * Fix possible race when operation is interrupted 2005-01-28 Miklos Szeredi * Fix compilation on 2.6.7 2005-01-26 Miklos Szeredi * Released 2.2-pre6 2005-01-26 Miklos Szeredi * Fix bug in link() operation which caused the wrong path to be passed as the first argument. Found by Anton Altaparmakov 2005-01-21 Miklos Szeredi * LIB: fix double reply in readdir operation * fusermount: fix uid checking bug. Patch by Adam Connell * KERNEL: fix compile on various RedHat patched 2.4 kernels. Patch by Keshava Gowda 2005-01-20 Miklos Szeredi * KERNEL: provide correct llseek semantics for fuse device (fixes a bug on Progeny 2.4.20 kernel). Reported by Valient Gough 2005-01-20 Miklos Szeredi * Released 2.2-pre5 (matches kernel 2.6.11-rc1-mm2) 2005-01-18 Miklos Szeredi * KERNEL ABI: remove GETDIR operation, and add OPENDIR, READDIR and RELEASEDIR. This ends the ugly hack of passing a file descriptor to the kernel, and actually makes the code simpler. 2005-01-17 Miklos Szeredi * Released 2.2-pre4 2005-01-17 Miklos Szeredi * fusermount: remove capability setting, which was the cause of problems for some users. It seems that FS related capabilities are removed by setfsuid(), so this isn't even needed. 2005-01-15 Miklos Szeredi * fix compilation on 2.4 kernels (reported by Valient Gough) * fix failure to unmount bug (found by David Shaw) * fusermount: improve parsing of /etc/fuse.conf 2005-01-13 Miklos Szeredi * Remove 'mount_max' and 'user_allow_other' module options. These are now checked by fusermount, and can be set in /etc/fuse.conf * KERNEL: change check for fsid == 0 to capable(CAP_DAC_OVERRIDE) 2005-01-11 Miklos Szeredi * KERNEL: fix possible inode allocation problem, where sizeof(struct inode) is not aligned (found by Mike Waychison) * KERNEL: use new follow_link/put_link methods * KERNEL: cosmetic fixes 2005-01-10 Miklos Szeredi * Released 2.2-pre3 2005-01-10 Miklos Szeredi * Add missing code that was accidently left out 2005-01-09 Miklos Szeredi * Released 2.2-pre2 2005-01-09 Miklos Szeredi * Change "uid" mount option to "user_id" to avoid confusion with a mount option "uid" commonly used by many filesystems 2005-01-09 Miklos Szeredi * Released 2.2-pre1 2005-01-09 Miklos Szeredi * If FUSE is configured in the kernel, don't build it by default 2005-01-07 Miklos Szeredi * Compile fix by Christian Magnusson 2005-01-05 Miklos Szeredi * Fix compilation for 2.6.{0-5} kernels 2005-01-04 Miklos Szeredi * KERNEL: if request is interrupted, still keep reference to used inode(s) and file, so that FORGET and RELEASE are not sent until userspace finishes the request. * remove /{sys,proc}/fs/fuse/version, and instead add an INIT request with the same information, which is more flexible, simpler, works on embedded systems. 2004-12-16 Miklos Szeredi * KERNEL ABI: update interface to make it independent of type sizes. This will help on 64 bit architectures which can run legacy 32 bit applications. * KERNEL ABI: add "len" field to request headers. This will allow sending/receiving requests in multiple chunks. * KERNEL: handle file type change more intelligently * LIB: "-o debug" option should disable backgrounding (fix by Fabien Reygrobellet) 2004-12-13 Miklos Szeredi * KERNEL: invalidate dentry/attributes if interrupted request could leave filesystem in an unknown state. 2004-12-12 Miklos Szeredi * KERNEL: lots of cleanups related to avoiding possible deadlocks. These will cause some regressions, but stability is considered more important. If any of these features turns out to be important, it can be readded with the deadlock problems addressed. * Make all requests interruptible (only with SIGKILL currently). This can be used to break any deadlock produced by the userspace filesystem accessing it's own exported files. The RELEASE request is special, because if it's interrupted before sending it to userspace it is still sent, but the reply is not awaited. * If request is interrupted before being sent to userspace, and if it hasn't yet got any side effects, it is always restarted, regardless of the SA_RESTART flag. This makes these interruptions transparent to the process. * Remove shared-writable mmap support, which was prone to an out-of-memory deadlock situation * Remove INVALIDATE userspace initiated request * Make readpages() synchronous. Asynchronous requests are deadlock prone, since they cannot be interrupted. * Add readv/writev support to fuse device operations * Remove some printks, which userspace FS can use for a DoS against syslog * Remove 'large_read' mount option from 2.6 in kernel, check it in fusermount instead * LIB: improve compatibility with a fuse.h header installed in ${prefix}/include which in turn includes the real header. * LIB: improve compatibility by defining fuse_main() (which is now not used), so old configure scripts find it. 2004-12-10 Miklos Szeredi * When mounting on a subdirectory of / don't duplicate slashes at the beggining of path (spotted by David Shaw) 2004-12-09 Miklos Szeredi * Fix bug causing garbage in mount options (spotted by David Shaw) 2004-12-07 Miklos Szeredi * Add 'writepage' flag to 'fuse_file_info'. * More comments in fuse.h * Get rid of double underscores 2004-12-04 Miklos Szeredi * Add -D_FILE_OFFSET_BITS=64 to cflags provided by pkg-config * helper.c: add -ho option, which only displays the options not the usage header. This can be used by filesystems which have their own options. 2004-12-03 Miklos Szeredi * Add source compatibility to 2.1 and 1.1 APIs. To select betwen versions simply define FUSE_USE_VERSION to 22, 21 or 11 before including the fuse header * Add binary compatibility to 2.1 version of library with symbol versioning 2004-12-03 Miklos Szeredi * Released 2.1 2004-12-01 Miklos Szeredi * kernel: clean up writing functions * kernel: no allocation on write in direct_io mode * move linux/fuse.h to fuse_kernel.h 2004-11-30 Miklos Szeredi * kernel: clean up reading functions 2004-11-29 Miklos Szeredi * kernel: make readpage() uninterruptible * kernel: check readonly filesystem flag in fuse_permission * lib: don't die if version file not found and new style device exists * lib: add '-r' option, which is short for '-o ro' * fusermount: simplify device opening * kernel: when direct_io is turend on, copy data directly to destination without itermediate buffer. More efficient and safer, since no allocation is done. * fusermount: fix warning if fuse module is not loaded * kernel: use /dev/fuse on 2.4 too 2004-11-26 Miklos Szeredi * libfuse API change: open, read, write, flush, fsync and release are passed a 'struct fuse_file_info' pointer containing the open flags (open and release), and the file handle. Verion changed to 3.0. 2004-11-23 Miklos Szeredi * More cleanups in the kernel * The 10,229 charater device number has been assigned for FUSE * Version file checking fix (reported by Christian Magnusson) * fusermount: opening the fuse device now doesn't need /sys. * Optimize reading by controlling the maximum readahead based on the 'max_read' mount option * fixes for UCLIBC (Christian Magnusson) 2004-11-19 Miklos Szeredi * Cleaned up kernel in preparation for merge into mainline: * Use /sys/fs/fuse/version instead of /proc/fs/fuse/version * Use real device (/dev/fuse) instead of /proc/fs/fuse/dev * __user annotations for sparse * allocate individual pages instead of kmalloc in fuse_readdir, fuse_read and fuse_write. * Fix NFS export in case "use_ino" mount option is given * Make libfuse and fusermount compatible with future versions * fusermount: properly add mount options to /etc/mtab 2004-11-15 Miklos Szeredi * fusermount: do not resolve last component of mountpoint on if it is '.' or '..'. This new path resolvation is now done on mount as well as unmount. This enables relative paths to work on unmount. * fusermount: parse common mount options like "ro", "rw", etc... * Allow module params to be changed through sysfs 2004-11-14 Miklos Szeredi * Released 2.1-pre1 2004-11-14 Miklos Szeredi * Fix bug in fuse_readpages() causing Oops in certain situations. Bug found by Vincenzo Ciancia. * Fix compilation with kernels versions > 2.6.9. 2004-11-11 Miklos Szeredi * Check kernel interface version in fusermount to prevent strangeness in case of mismatch. * No need to allocate fuse_conn until actual mount happens * Fix potential race between umount and fuse_invalidate * Check superblock of proc file in addition to inode number * Fix race between request_send_noreply() and fuse_dev_release() 2004-11-10 Miklos Szeredi * Separate configure for the kernel directory * Don't allow write to return more than 'count' * Extend kernel interface for future use 2004-11-09 Miklos Szeredi * Fix 'makeconf.sh' to use autoreconf if available 2004-11-08 Miklos Szeredi * Add ino argument to 'fuse_dirfil_t'. NOTE: This breaks source compatibility with earlier versions. To compile earier versions just add '-DFUSE_DIRFIL_COMPAT' compile flag or fix the source. Do not use the "use_ino" mount flag with filesystems compiled with FUSE_DIRFIL_COMPAT. * Add pkg-config support. To compile a FUSE based filesystem you can do "gcc -Wall `pkg-config --cflags --libs fuse` myfs.c -o myfs" or similar. Note, that the PKG_CONFIG_PATH environment variable usually needs to be set to "/usr/local/lib/pkgconfig". * fuse.h is now installed in ${prefix}/include/fuse/ 2004-11-02 Miklos Szeredi * Added "use_ino" mount option. This enables the filesystems to set the st_ino field on files 2004-11-01 Miklos Szeredi * Fix compile problems with ancient (<=2.4.18) kernels (reported by Jeremy Smith) * Add "allow_root" mount option. Patch by Yaroslav Rastrigin * Clear the 'exited' flag when mail loop is finished 2004-10-28 Miklos Szeredi * Make xattr functions work under 2.6 (bug found by Vincenzo Ciancia) 2004-10-26 Miklos Szeredi * Reset request in fuse_flush() (bugreport by David Shaw) 2004-10-21 Miklos Szeredi * fuse_main() now does not exit on error, rather it returns an error code * Exported __fuse_setup() and __fuse_teardown() functions, which make it easier to implement a custom event loop. * Use daemon() call to background the filesystem after mounting. This function closes the standard input, output and error and changes the current working directory to "/". 2004-10-14 Miklos Szeredi * Released 1.9 2004-10-09 Miklos Szeredi * Don't allow fuse_flush() to be interrupted (bug found by David Shaw) 2004-09-27 Miklos Szeredi * Add PID to fuse_context. Patch by Steven James * Change file handle type to 'unsigned long' in kernel interface 2004-09-22 Miklos Szeredi * A slight API change: fuse_get_context() doesn't need the "fuse" pointer, but the returned context contains it instead. The fuse_get() function is not needed anymore, so it's removed. * Fix mounting and umounting FUSE filesystem under another FUSE filesystem by non-root (bug spotted by Valient Gough) 2004-09-21 Miklos Szeredi * Fix deadlock in case of memory allocation failure. Patch by Christian Magnusson 2004-09-16 Miklos Szeredi * Check memory allocation failures in libfuse 2004-09-14 Miklos Szeredi * Check temporary file creation failure in do_getdir(). Bug spotted by Terje Oseberg 2004-09-13 Miklos Szeredi * Allow "large_read" option for 2.6 kernels but warn of deprecation * Make requests non-interruptible so race with FORGET is avoided. This is only a temporary solution * Support compiling FUSE kernel module on 2.4.x UML kernels 2004-09-09 Miklos Szeredi * Fix bug in case two FORGETs for the same node are executed in the wrong order. Bug spotted and endured for months by Franco Broi, and logfile for solution provided by Terje Oseberg 2004-09-01 Miklos Szeredi * Add -D_REENTRANT to the compile flags * Add documentation of fuse internals by Terje Oseberg 2004-08-16 Miklos Szeredi * Change release method to be non-interruptible. Fixes bug causing missing release() call when program which has opened files is killed (reported by Franco Broi and David Shaw) 2004-07-29 Miklos Szeredi * Add fuse_invalidate() to library API 2004-07-26 Miklos Szeredi * Check permissions in setattr if 'default_permissions' flag is set. Bug spotted by Damjan Lango 2004-07-24 Miklos Szeredi * 'large_read' mount option removed for 2.6 kernels, since the default (dynamic read size) is better * Extend kernel API with file handles. A file handle is returned by open, and passed to read, write, flush, fsync and release. This is currently only used for debug output in the library. * Security changes: * Change the current directory to the mountpoint before checking the permissions and mount filesystem on "." * By default don't modprobe the fuse module for non-root. The old behavior can be restored with the '--enable-auto-modprobe' flag of ./configure * By default don't allow shared writable mappings for non-root. The old behavior can be restored with the 'user_mmap=1' module parameter 2004-07-23 Miklos Szeredi * Clean up mount option passing to fusermount and to fuse_new() BEWARE: this changes the userspace API slightly, and the command line usage of programs using fuse_main() 2004-07-20 Miklos Szeredi * Optimize reading under 2.6 kernels by issuing multiple page asynchronous read requests 2004-07-18 Miklos Szeredi * Only use redirty_page_for_writepage() for kernels >= 2.6.6 2004-07-16 Miklos Szeredi * Separate directory entry and inode attribute validity timer * New write semaphore to stop page writeback during truncate * Fsync now waits for all writes to complete before sending the request * Optimization: if a page is completely written by fuse_commit_write(), clear the dirty flag and set the uptodate flag for that page * Some memory cleanup at exit 2004-07-13 Miklos Szeredi * Add FUSE_HARD_REMOVE flag, and '-i' option to fuse main, which disable the "hide if open" behavior of unlink/rename. * If temporary buffer allocation fails in raw read, fall back to a smaller buffer 2004-07-12 Miklos Szeredi * Fix bug in do_open() in libfuse: open count was incremented after the reply is sent so it could race with unlink/forget and cause an abort. 2004-07-08 Miklos Szeredi * When performing create or remove operation, refresh the parent's attributes on next revalidate, as i_nlink (and maybe size/time) could be inacurate. * Use redirty_page_for_writepage() in fuse_writepage() for skipped pages (2.6 only) * Set set_page_dirty address space operation (2.6 only) 2004-07-06 Miklos Szeredi * Minor fix in read: print debug info even if read size is zero 2004-07-04 Miklos Szeredi * Fix race between truncate and writepage (fsx-linux now runs without error) 2004-07-02 Miklos Szeredi * Fix kernel hang on mkfifo under 2.4 kernels (spotted and patch by Mattias Wadman) * Added option for direct read/write (-r) * Fix revalidate time setting for newly created inodes * Remove uid==0 check for '-x' option in fusermount (kernel checks this) * fuse_main() only installs handlers for signals (out of INT, HUP, TERM, PIPE), for which no handler has yet been installed * Add module option 'user_allow_other' which if set to non-zero will allow non root user to specify the 'allow_other' mount option ('-x' option of fusermount) * Fix deadlock between page writeback completion and truncate (bug found by Valient Gough with the fsx-linux utility) 2004-07-01 Miklos Szeredi * Change passing fuse include dir to 2.6 kernel make system more robust (fixes compile problems seen on SuSE 9.1 with updated 2.6 kernel) 2004-06-30 Miklos Szeredi * Acquire inode->i_sem before open and release methods to prevent concurrent rename or unlink operations. * Make __fuse_read_cmd() read only one command. This allows multiplexing the fuse file descriptor with other event sources using select() or poll() (patch by Jeff Harris) * Export 'exited' flag with __fuse_exited() (patch by Jeff Harris) 2004-06-27 Miklos Szeredi * Fix file offset wrap around at 4G when doing large reads 2004-06-24 Miklos Szeredi * Fix memory leak in open (Valient Gough) 2004-06-24 Miklos Szeredi * Add "close after delete" support to libfuse (patch by Valient Gough) * Cancel all worker threads before exit in multithreaded mode 2004-06-23 Miklos Szeredi * Fix locking bugs * Don't send reply to RELEASE * Work with newer libtool (1.5a) * Check for st_atim member of struct stat 2004-06-22 Miklos Szeredi * No request allocation needed on inode and file release 2004-06-21 Miklos Szeredi * Fix possible inode leak in userspace in case of unfinished lookup/mknod/mkdir/symlink/link operation. 2004-06-20 Miklos Szeredi * Fix some races and cleanups in fuse_read_super() 2004-06-19 Miklos Szeredi * Requests are allocated at open time 2004-06-03 Miklos Szeredi * Build shared library as well as static (using libtool) * Change FUSE_MINOR_VERSION from 1 to 0. I know it's illegal but there has not been a release with the previous minor number, and I hope nobody is using it for anything. * Change fuse_main(), so that default behavior is to go into background if mount is successful. '-f' and '-d' options disable backgrounding. This fixes the "Why does my FUSE daemon hang?" newbie complaint. * Cache ENOSYS (function not implemented) errors on *xattr, flush and fsync * Don't call getdir method from open() only from first readdir(). Open is sometimes just used to store the current directory (e.g. find) 2004-05-18 Miklos Szeredi * Added flush() call 2004-05-04 Miklos Szeredi * Extended attributes support for 2.4 (patch by Cody Pisto) 2004-04-20 Miklos Szeredi * Fixed parser with modversions (Mattias Wadman) 2004-04-19 Miklos Szeredi * Added mount option parser to 2.4 build 2004-04-13 Miklos Szeredi * Replaced binary mount data with text options * Show FUSE specific mount options in /proc/mounts * Check in fuse.h whether _FILE_OFFSET_BITS is set to 64 2004-04-09 Miklos Szeredi * Check some limits so userspace won't get too big requests 2004-04-05 Miklos Szeredi * Kill compile warning * Upgraded user-mount patch for 2.6.5 2004-04-02 Miklos Szeredi * Add detection of user-mode-linux to configure 2004-03-31 Miklos Szeredi * fixed zero size case for getxattr and listxattr 2004-03-30 Miklos Szeredi * new fusermount flag '-z': lazy unmount, default is not lazy * Extended attributes operations added (getxattr, setxattr, listxattr, removexattr) 2004-03-25 Miklos Szeredi * If filesystem doesn't define a statfs operation, then an all-zero default statfs is returned instead of ENOSYS 2004-03-24 Miklos Szeredi * Add FS_BINARY_MOUNTDATA filesystem flag for kernels > 2.6.4 2004-03-09 Miklos Szeredi * Fix for uClinux (Christian Magnusson) 2004-03-02 Miklos Szeredi * fuse_main() adds "-n progname" to the fusermount command line * More kernel interface changes: * Lookup/getattr return cache timeout values 2004-02-25 Miklos Szeredi * Clean up option parsing in fuse_main() * Added fuse_get() function which returns the fuse object created by fuse_main() 2004-02-20 Miklos Szeredi * removed old way of mounting (fusermount mountpoint program) * more kernel interface changes: * added nanosecond precision to file times * removed interface version from mount data * added /proc/fs/fuse/version which contains MAJOR.MINOR 2004-02-19 Miklos Szeredi * statfs library API changed to match other methods. Since this is not backward compatible FUSE_MAJOR_VERSION is changed to 2 * kernel interface changes follow: * statfs changed to 64 bits, added 'bavail' field * add generation number to lookup result * optimized mknod/mkdir/symlink/link (no separate lookup is needed) * rdev size increased to 32 bits for mknod * kernel interface version changed to 3.1 2004-02-18 Miklos Szeredi * user-mount upgraded for 2.6.3 kernel 2004-02-17 Miklos Szeredi * Added user-mount.2.6.2-rc3.patch * Add FS_SAFE flag to fuse filesystem * fusermount should allow (un)mounting for non-root even if not suid-root 2004-02-12 Miklos Szeredi * Remove MS_PERMISSION mount flag (that means something else now) 2004-02-10 Miklos Szeredi * Added check for i_size_read/write functions to configure.in (patch by Valient Gough) 2004-02-06 Miklos Szeredi * Fixed writing >= 2G files * Check file size on open (with generic_file_open()) * Readpage calls flush_dcache_page() after storing data * Use i_size_read/write for accessing inode->i_size * Make loopback mount of a fuse file work 2004-02-04 Miklos Szeredi * Released 1.1 2004-01-29 Miklos Szeredi * Properly check if the inode exists in fuse_invalidate 2004-01-27 Miklos Szeredi * Added -q option for fusermount * fuse_unmount() now uses -q option of fusermount, so no error is printed if the cause of the program exit is that the filesystem has already been unmounted * Fix i_nlink correctness after rmdir/unlink 2004-01-26 Miklos Szeredi * Released 1.1-pre2 2004-01-26 Miklos Szeredi * Fix typo (thanks Marcos Dione) * Compile fixes for 2.4 kernels 2004-01-23 Miklos Szeredi * Fix CONFIG_MODVERSIONS compile on 2.6 2004-01-22 Miklos Szeredi * Write all pending data before a RELEASE operation * Suppress 'Bad file descriptor' warning on exit * Replaced fusermount option '-d xxx' with '-n xxx' so it doesn't get confused with '-d' of fuse_main() (sorry about this change) * New fusermount option '-l' which enables big reads. Big reads are now disabled by default. * fuse_main() can accept fusermount arguments after a '--' 2004-01-19 Miklos Szeredi * Support for exporting filesystem over NFS (see README.NFS) 2004-01-14 Miklos Szeredi * Support non-blocking writepage on 2.6. This makes FUSE behave much more nicely in low-memory situations * Fix 32-bit dev handling in getattr and mknod for 2.6 kernels. (Note: the mknod method does not yet use 32bit device number) 2004-01-13 Miklos Szeredi * Code cleanups 2004-01-07 Miklos Szeredi * Released 1.1-pre1 2004-01-06 Miklos Szeredi * Integrated 2.6 kernel support patch by Michael Grigoriev * Improvements and cleanups for 2.6 kernels 2004-01-05 Miklos Szeredi * Added -d option to fusermount 2003-12-15 Miklos Szeredi * Added major+minor version to library API, and minor version to kernel API 2003-12-13 David McNab * Implemented fsync support in examples/example.py * Implemented 'fsync' and 'statfs' methods in python interface 2003-12-12 Miklos Szeredi * Make it compile on 2.4.19. * Add fsync operation (write file failed on xemacs & vi) 2003-12-12 David McNab * Added distutils support to the python module, as per standard python development practice 2003-12-11 Miklos Szeredi * Add file locking for mount/unmount (based on patch by Valient Gough) 2003-12-11 David McNab * Python filesystem - was broken with python2.3, now fixed: - changed PyTuple_* calls to PySequence_*, because os.lstat is no longer returning a pure tuple - changed PyInt_Check() calls to also call PyLong_Check, to cover for cases (eg os.lstat) where longs are returned - Added support for file 'release' handling, which IMO is essential since this signals to a FS that writes to a file are complete (and therefore the file can now be disposed of meaningfully at the python filesystem's discretion) - Added '__init__' handler to base Fuse class, which allows your Python class to know the mountpoint and mount args, as attributes myfs.mountpoint, myfs.optlist, myfs.optdict * General: - added 'mount.fuse' script (in util/ dir), which is meant to be symlinked from /sbin, and which allows FUSE filesystems to be mounted with the 'mount' command, and listed in fstab; also, mount arguments get passed to your filesystem 2003-11-04 Miklos Szeredi * Fix kernel version detection (again). Bugreport by Peter Levart 2003-11-03 Miklos Szeredi * Applied read combining patch by Michael Grigoriev (tested by Valient Gough and Vincent Wagelaar) 2003-10-22 Miklos Szeredi * Mtab handling fix in fusermount by "Valient Gough" (SF patch #766443) 2003-10-13 Miklos Szeredi * Error code fixes in kernel module 2003-10-04 Miklos Szeredi * kernel version detection fix * fusermount now uses "lazy" umount option * fusermount can use modprobe with module-init-tools 2003-09-08 Miklos Szeredi * Integrated caching patch by Michael Grigoriev * Added "Filesystems" file with descriptions of projects using FUSE * Added patch by Michael Grigoriev to allow compliation of FUSE kernel module for 2.6 kernels 2003-06-02 Miklos Szeredi * And another spec-file fix by Achim Settelmeier 2003-05-26 Miklos Szeredi * Spec-file fix by Achim Settelmeier 2003-03-10 Miklos Szeredi * Fix umount oops (found by Samuli Kärkkäinen) 2003-03-05 Miklos Szeredi * Merge of fuse_redhat.spec and fuse.spec by Achim Settelmeier 2003-03-04 Miklos Szeredi * Updated fuse.spec file (Achim Settelmeier) 2003-02-19 Miklos Szeredi * Version 1.0 released 2003-02-12 Miklos Szeredi * SuSE compilation fix by Juan-Mariano de Goyeneche 2002-12-10 Miklos Szeredi * The release() VFS call is now exported to the FUSE interface 2002-12-05 Miklos Szeredi * 64 bit file offset fixes in the fuse kernel module * Added function 'fuse_exit()' which can be used to exit the main loop 2002-12-03 Miklos Szeredi * Added _FILE_OFFSET_BITS=64 define to fuse.h. Note, that this is an incompatible interface change. 2002-10-28 Miklos Szeredi * Portablility fix (bug reported by C. Chris Erway) 2002-10-25 Miklos Szeredi * Use Mark Glines' fd passing method for default operation instead of old reexec 2002-10-22 Miklos Szeredi * fix "Stale NFS file handle" bug caused by changes in 2.4.19 2002-10-22 Miklos Szeredi * fix incompatiblity with Red Hat kernels, with help from Nathan Thompson-Amato. 2002-04-18 Mark Glines * added an alternative to fuse_mount(), called fuse_mount_ioslave(), which does not need to reexec the FUSE program. * added a small helper util needed by fuse_mount_ioslave(). 2002-03-16 Mark Glines * use struct fuse_statfs everywhere possible to avoid problems with the headerfiles changing struct statfs member sizes 2002-03-01 Miklos Szeredi * Another RPM spec file for RedHat >= 7 by Ian Pilcher 2002-01-14 Miklos Szeredi * RPM support by Achim Settelmeier 2002-01-09 Miklos Szeredi * Version 0.95 released 2002-01-09 Miklos Szeredi * Revaidate all path components not just the last, this means a very small performance penalty for being more up-to-date. 2002-01-08 Miklos Szeredi * Update and fix python interface 2002-01-07 Mark Glines * Added statfs() support to kernel, lib, examples, and perl! 2001-12-26 Miklos Szeredi * Better cross compilation support * Ported to Compaq IPAQ 2001-12-20 Miklos Szeredi * Added function fuse_get_context() to library API (inspired by patch from Matt Ryan) * Added flags to fusermount and to kernel interface to control permission checking * Integrated fuse_set_operations() into fuse_new() 2001-12-08 Miklos Szeredi * Applied header protection + extern "C" patch by Roland Bauerschmidt 2001-12-02 Miklos Szeredi * Added perl bindings by Mark Glines 2001-11-21 Miklos Szeredi * Cleaned up way of mounting simple filesystems. * fuse_main() helper function added 2001-11-18 Miklos Szeredi * Optimized read/write operations, so that minimal copying of data is done 2001-11-14 Miklos Szeredi * Python bindings by Jeff Epler added 2001-11-13 Miklos Szeredi * Fixed vfsmount reference leak in fuse_follow_link * FS blocksize is set to PAGE_CACHE_SIZE, blksize attribute from userspace is ignored 2001-11-09 Miklos Szeredi * Started ChangeLog fuse-2.9.9/config.rpath0000755000175000017500000004421613413660770011744 00000000000000#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2016 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # Known limitations: # - On IRIX 6.5 with CC="cc", the run time search patch must not be longer # than 256 bytes, otherwise the compiler driver will dump core. The only # known workaround is to choose shorter directory names for the build # directory and/or the installation directory. # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a shrext=.so host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` # Code taken from libtool.m4's _LT_CC_BASENAME. for cc_temp in $CC""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` # Code taken from libtool.m4's _LT_COMPILER_PIC. wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix*) wl='-Wl,' ;; mingw* | cygwin* | pw32* | os2* | cegcc*) ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6* | nonstopux*) wl='-Wl,' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in ecc*) wl='-Wl,' ;; icc* | ifort*) wl='-Wl,' ;; lf95*) wl='-Wl,' ;; nagfor*) wl='-Wl,-Wl,,' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) wl='-Wl,' ;; ccc*) wl='-Wl,' ;; xl* | bgxl* | bgf* | mpixl*) wl='-Wl,' ;; como) wl='-lopt=' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ F* | *Sun*Fortran*) wl= ;; *Sun\ C*) wl='-Wl,' ;; esac ;; esac ;; newsos6) ;; *nto* | *qnx*) ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; rdos*) ;; solaris*) case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) wl='-Qoption ld ' ;; *) wl='-Wl,' ;; esac ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3*) wl='-Wl,' ;; sysv4*MP*) ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) wl='-Wl,' ;; unicos*) wl='-Wl,' ;; uts4*) ;; esac fi # Code taken from libtool.m4's _LT_LINKER_SHLIBS. hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32* | cegcc*) # 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 with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # 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. # Unlike libtool, we use -rpath here, not --rpath, since the documented # option of GNU ld is called -rpath, not --rpath. hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' case "$host_os" in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no fi ;; amigaos*) case "$host_cpu" in powerpc) ;; m68k) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then : else ld_shlibs=no fi ;; haiku*) ;; interix[3-9]*) hardcode_direct=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; netbsd*) ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' else ld_shlibs=no fi ;; esac ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then hardcode_libdir_flag_spec= fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else 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. 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 aix_use_runtimelinking=yes break fi done ;; esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac fi # Begin _LT_AC_SYS_LIBPATH_AIX. echo 'int main () { return 0; }' > conftest.c ${CC} ${LDFLAGS} conftest.c -o conftest aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` fi if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib" fi rm -f conftest.c conftest # End _LT_AC_SYS_LIBPATH_AIX. if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" fi fi ;; amigaos*) case "$host_cpu" in powerpc) ;; m68k) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=no if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then : else ld_shlibs=no fi ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; freebsd2.[01]*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd* | dragonfly*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9*) 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 ;; hpux10*) if test "$with_gnu_ld" = no; then 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 fi ;; hpux11*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no ;; *) hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) case $host_vendor in sni) hardcode_direct=yes # is this really true??? ;; siemens) hardcode_direct=no ;; motorola) hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac ;; sysv4.3*) ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) ;; sysv5* | sco3.2v5* | sco5v6*) hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics # Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. # Unlike libtool.m4, here we don't care about _all_ names of the library, but # only about the one the linker finds when passed -lNAME. This is the last # element of library_names_spec in libtool.m4, or possibly two of them if the # linker has special search rules. library_names_spec= # the last element of library_names_spec in libtool.m4 libname_spec='lib$name' case "$host_os" in aix3*) library_names_spec='$libname.a' ;; aix[4-9]*) library_names_spec='$libname$shrext' ;; amigaos*) case "$host_cpu" in powerpc*) library_names_spec='$libname$shrext' ;; m68k) library_names_spec='$libname.a' ;; esac ;; beos*) library_names_spec='$libname$shrext' ;; bsdi[45]*) library_names_spec='$libname$shrext' ;; cygwin* | mingw* | pw32* | cegcc*) shrext=.dll library_names_spec='$libname.dll.a $libname.lib' ;; darwin* | rhapsody*) shrext=.dylib library_names_spec='$libname$shrext' ;; dgux*) library_names_spec='$libname$shrext' ;; freebsd[23].*) library_names_spec='$libname$shrext$versuffix' ;; freebsd* | dragonfly*) library_names_spec='$libname$shrext' ;; gnu*) library_names_spec='$libname$shrext' ;; haiku*) library_names_spec='$libname$shrext' ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) shrext=.so ;; hppa*64*) shrext=.sl ;; *) shrext=.sl ;; esac library_names_spec='$libname$shrext' ;; interix[3-9]*) library_names_spec='$libname$shrext' ;; irix5* | irix6* | nonstopux*) library_names_spec='$libname$shrext' case "$host_os" in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac ;; linux*oldld* | linux*aout* | linux*coff*) ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) library_names_spec='$libname$shrext' ;; knetbsd*-gnu) library_names_spec='$libname$shrext' ;; netbsd*) library_names_spec='$libname$shrext' ;; newsos6) library_names_spec='$libname$shrext' ;; *nto* | *qnx*) library_names_spec='$libname$shrext' ;; openbsd*) library_names_spec='$libname$shrext$versuffix' ;; os2*) libname_spec='$name' shrext=.dll library_names_spec='$libname.a' ;; osf3* | osf4* | osf5*) library_names_spec='$libname$shrext' ;; rdos*) ;; solaris*) library_names_spec='$libname$shrext' ;; sunos4*) library_names_spec='$libname$shrext$versuffix' ;; sysv4 | sysv4.3*) library_names_spec='$libname$shrext' ;; sysv4*MP*) library_names_spec='$libname$shrext' ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) library_names_spec='$libname$shrext' ;; tpf*) library_names_spec='$libname$shrext' ;; uts4*) library_names_spec='$libname$shrext' ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` shlibext=`echo "$shrext" | sed -e 's,^\.,,'` escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) # $RANDOM is not portable (e.g. dash); use it when possible to # lower collision chance tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 # As "mkdir -p" follows symlinks and we work in /tmp possibly; so # create the $tmpdir first (and fail if unsuccessful) to make sure # that nobody tries to guess the $tmpdir name. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: fuse-2.9.9/README.NFS0000664000175000017500000000254613413660255010741 00000000000000NFS exporting is supported in Linux kernels 2.6.27 or later. You need to add an fsid=NNN option to /etc/exports to make exporting a FUSE directory work. Filesystem support ------------------ NFS exporting works to some extent on all fuse filesystems, but not perfectly. This is due to the stateless nature of the protocol, the server has no way of knowing whether the client is keeping a reference to a file or not, and hence that file may be removed from the server's cache. In that case there has to be a way to look up that object using the inode number, otherwise an ESTALE error will be returned. 1) low-level interface Filesystems need to implement special lookups for the names "." and "..". The former may be requested on any inode, including non-directories, while the latter is only requested for directories. Otherwise these special lookups should behave identically to ordinary lookups. 2) high-level interface Because the high-level interface is path based, it is not possible to delegate looking up by inode to the filesystem. To work around this, currently a "noforget" option is provided, which makes the library remember nodes forever. This will make the NFS server happy, but also results in an ever growing memory footprint for the filesystem. For this reason if the filesystem is large (or the memory is small), then this option is not recommended. fuse-2.9.9/Makefile.in0000664000175000017500000006615313413660776011515 00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # 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, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ 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 \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = . 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 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.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 CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = fuse.pc CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkgconfigdir)" DATA = $(pkgconfig_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` 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) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INIT_D_PATH = @INIT_D_PATH@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ 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@ MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UDEV_RULES_PATH = @UDEV_RULES_PATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libfuse_libs = @libfuse_libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs2 = @subdirs2@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = @subdirs2@ doc AUTOMAKE_OPTIONS = subdir-objects EXTRA_DIST = \ fuse.pc.in \ README* pkgconfig_DATA = fuse.pc all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): fuse.pc: $(top_builddir)/config.status $(srcdir)/fuse.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @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 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) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) 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/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-pkgconfigDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-pkgconfigDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ dist-xz dist-zip distcheck distclean distclean-generic \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-pkgconfigDATA install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkgconfigDATA .PRECIOUS: Makefile $(pkgconfig_DATA): config.status # 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. .NOEXPORT: fuse-2.9.9/example/0000775000175000017500000000000013413661013011131 500000000000000fuse-2.9.9/example/fsel.c0000664000175000017500000001365213413660255012164 00000000000000/* FUSE fsel: FUSE select example Copyright (C) 2008 SUSE Linux Products GmbH Copyright (C) 2008 Tejun Heo This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall fsel.c `pkg-config fuse --cflags --libs` -o fsel */ #define FUSE_USE_VERSION 29 #include #include #include #include #include #include #include #include #include #include /* * fsel_open_mask is used to limit the number of opens to 1 per file. * This is to use file index (0-F) as fh as poll support requires * unique fh per open file. Lifting this would require proper open * file management. */ static unsigned fsel_open_mask; static const char fsel_hex_map[] = "0123456789ABCDEF"; static struct fuse *fsel_fuse; /* needed for poll notification */ #define FSEL_CNT_MAX 10 /* each file can store upto 10 chars */ #define FSEL_FILES 16 static pthread_mutex_t fsel_mutex; /* protects notify_mask and cnt array */ static unsigned fsel_poll_notify_mask; /* poll notification scheduled? */ static struct fuse_pollhandle *fsel_poll_handle[FSEL_FILES]; /* poll notify handles */ static unsigned fsel_cnt[FSEL_FILES]; /* nbytes stored in each file */ static int fsel_path_index(const char *path) { char ch = path[1]; if (strlen(path) != 2 || path[0] != '/' || !isxdigit(ch) || islower(ch)) return -1; return ch <= '9' ? ch - '0' : ch - 'A' + 10; } static int fsel_getattr(const char *path, struct stat *stbuf) { int idx; memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0555; stbuf->st_nlink = 2; return 0; } idx = fsel_path_index(path); if (idx < 0) return -ENOENT; stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = fsel_cnt[idx]; return 0; } static int fsel_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { char name[2] = { }; int i; (void) offset; (void) fi; if (strcmp(path, "/") != 0) return -ENOENT; for (i = 0; i < FSEL_FILES; i++) { name[0] = fsel_hex_map[i]; filler(buf, name, NULL, 0); } return 0; } static int fsel_open(const char *path, struct fuse_file_info *fi) { int idx = fsel_path_index(path); if (idx < 0) return -ENOENT; if ((fi->flags & 3) != O_RDONLY) return -EACCES; if (fsel_open_mask & (1 << idx)) return -EBUSY; fsel_open_mask |= (1 << idx); /* * fsel files are nonseekable somewhat pipe-like files which * gets filled up periodically by producer thread and consumed * on read. Tell FUSE as such. */ fi->fh = idx; fi->direct_io = 1; fi->nonseekable = 1; return 0; } static int fsel_release(const char *path, struct fuse_file_info *fi) { int idx = fi->fh; (void) path; fsel_open_mask &= ~(1 << idx); return 0; } static int fsel_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int idx = fi->fh; (void) path; (void) offset; pthread_mutex_lock(&fsel_mutex); if (fsel_cnt[idx] < size) size = fsel_cnt[idx]; printf("READ %X transferred=%zu cnt=%u\n", idx, size, fsel_cnt[idx]); fsel_cnt[idx] -= size; pthread_mutex_unlock(&fsel_mutex); memset(buf, fsel_hex_map[idx], size); return size; } static int fsel_poll(const char *path, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp) { static unsigned polled_zero; int idx = fi->fh; (void) path; /* * Poll notification requires pointer to struct fuse which * can't be obtained when using fuse_main(). As notification * happens only after poll is called, fill it here from * fuse_context. */ if (!fsel_fuse) { struct fuse_context *cxt = fuse_get_context(); if (cxt) fsel_fuse = cxt->fuse; } pthread_mutex_lock(&fsel_mutex); if (ph != NULL) { struct fuse_pollhandle *oldph = fsel_poll_handle[idx]; if (oldph) fuse_pollhandle_destroy(oldph); fsel_poll_notify_mask |= (1 << idx); fsel_poll_handle[idx] = ph; } if (fsel_cnt[idx]) { *reventsp |= POLLIN; printf("POLL %X cnt=%u polled_zero=%u\n", idx, fsel_cnt[idx], polled_zero); polled_zero = 0; } else polled_zero++; pthread_mutex_unlock(&fsel_mutex); return 0; } static struct fuse_operations fsel_oper = { .getattr = fsel_getattr, .readdir = fsel_readdir, .open = fsel_open, .release = fsel_release, .read = fsel_read, .poll = fsel_poll, }; static void *fsel_producer(void *data) { const struct timespec interval = { 0, 250000000 }; unsigned idx = 0, nr = 1; (void) data; while (1) { int i, t; pthread_mutex_lock(&fsel_mutex); /* * This is the main producer loop which is executed * ever 500ms. On each iteration, it fills one byte * to 1, 2 or 4 files and sends poll notification if * requested. */ for (i = 0, t = idx; i < nr; i++, t = (t + FSEL_FILES / nr) % FSEL_FILES) { if (fsel_cnt[t] == FSEL_CNT_MAX) continue; fsel_cnt[t]++; if (fsel_fuse && (fsel_poll_notify_mask & (1 << t))) { struct fuse_pollhandle *ph; printf("NOTIFY %X\n", t); ph = fsel_poll_handle[t]; fuse_notify_poll(ph); fuse_pollhandle_destroy(ph); fsel_poll_notify_mask &= ~(1 << t); fsel_poll_handle[t] = NULL; } } idx = (idx + 1) % FSEL_FILES; if (idx == 0) nr = (nr * 2) % 7; /* cycle through 1, 2 and 4 */ pthread_mutex_unlock(&fsel_mutex); nanosleep(&interval, NULL); } return NULL; } int main(int argc, char *argv[]) { pthread_t producer; pthread_attr_t attr; int ret; errno = pthread_mutex_init(&fsel_mutex, NULL); if (errno) { perror("pthread_mutex_init"); return 1; } errno = pthread_attr_init(&attr); if (errno) { perror("pthread_attr_init"); return 1; } errno = pthread_create(&producer, &attr, fsel_producer, NULL); if (errno) { perror("pthread_create"); return 1; } ret = fuse_main(argc, argv, &fsel_oper, NULL); pthread_cancel(producer); pthread_join(producer, NULL); return ret; } fuse-2.9.9/example/Makefile.in0000664000175000017500000006251413413660777013146 00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # 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, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ 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 \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ noinst_PROGRAMS = fusexmp$(EXEEXT) fusexmp_fh$(EXEEXT) null$(EXEEXT) \ hello$(EXEEXT) hello_ll$(EXEEXT) fioc$(EXEEXT) \ fioclient$(EXEEXT) fsel$(EXEEXT) fselclient$(EXEEXT) \ cusexmp$(EXEEXT) subdir = example 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 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) cusexmp_SOURCES = cusexmp.c cusexmp_OBJECTS = cusexmp.$(OBJEXT) cusexmp_LDADD = $(LDADD) cusexmp_DEPENDENCIES = ../lib/libfuse.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = fioc_SOURCES = fioc.c fioc_OBJECTS = fioc.$(OBJEXT) fioc_LDADD = $(LDADD) fioc_DEPENDENCIES = ../lib/libfuse.la fioclient_SOURCES = fioclient.c fioclient_OBJECTS = fioclient-fioclient.$(OBJEXT) fioclient_DEPENDENCIES = fioclient_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(fioclient_LDFLAGS) $(LDFLAGS) -o $@ fsel_SOURCES = fsel.c fsel_OBJECTS = fsel.$(OBJEXT) fsel_LDADD = $(LDADD) fsel_DEPENDENCIES = ../lib/libfuse.la fselclient_SOURCES = fselclient.c fselclient_OBJECTS = fselclient-fselclient.$(OBJEXT) fselclient_DEPENDENCIES = fselclient_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(fselclient_LDFLAGS) $(LDFLAGS) -o $@ fusexmp_SOURCES = fusexmp.c fusexmp_OBJECTS = fusexmp.$(OBJEXT) fusexmp_LDADD = $(LDADD) fusexmp_DEPENDENCIES = ../lib/libfuse.la fusexmp_fh_SOURCES = fusexmp_fh.c fusexmp_fh_OBJECTS = fusexmp_fh.$(OBJEXT) fusexmp_fh_DEPENDENCIES = ../lib/libfuse.la ../lib/libulockmgr.la hello_SOURCES = hello.c hello_OBJECTS = hello.$(OBJEXT) hello_LDADD = $(LDADD) hello_DEPENDENCIES = ../lib/libfuse.la hello_ll_SOURCES = hello_ll.c hello_ll_OBJECTS = hello_ll.$(OBJEXT) hello_ll_LDADD = $(LDADD) hello_ll_DEPENDENCIES = ../lib/libfuse.la null_SOURCES = null.c null_OBJECTS = null.$(OBJEXT) null_LDADD = $(LDADD) null_DEPENDENCIES = ../lib/libfuse.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = cusexmp.c fioc.c fioclient.c fsel.c fselclient.c fusexmp.c \ fusexmp_fh.c hello.c hello_ll.c null.c DIST_SOURCES = cusexmp.c fioc.c fioclient.c fsel.c fselclient.c \ fusexmp.c fusexmp_fh.c hello.c hello_ll.c null.c am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INIT_D_PATH = @INIT_D_PATH@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ 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@ MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UDEV_RULES_PATH = @UDEV_RULES_PATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libfuse_libs = @libfuse_libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs2 = @subdirs2@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir)/include -D_FILE_OFFSET_BITS=64 -D_REENTRANT noinst_HEADERS = fioc.h LDADD = ../lib/libfuse.la fusexmp_fh_LDADD = ../lib/libfuse.la ../lib/libulockmgr.la fioclient_CPPFLAGS = fioclient_LDFLAGS = fioclient_LDADD = fselclient_CPPFLAGS = fselclient_LDFLAGS = fselclient_LDADD = all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign example/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list cusexmp$(EXEEXT): $(cusexmp_OBJECTS) $(cusexmp_DEPENDENCIES) $(EXTRA_cusexmp_DEPENDENCIES) @rm -f cusexmp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(cusexmp_OBJECTS) $(cusexmp_LDADD) $(LIBS) fioc$(EXEEXT): $(fioc_OBJECTS) $(fioc_DEPENDENCIES) $(EXTRA_fioc_DEPENDENCIES) @rm -f fioc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fioc_OBJECTS) $(fioc_LDADD) $(LIBS) fioclient$(EXEEXT): $(fioclient_OBJECTS) $(fioclient_DEPENDENCIES) $(EXTRA_fioclient_DEPENDENCIES) @rm -f fioclient$(EXEEXT) $(AM_V_CCLD)$(fioclient_LINK) $(fioclient_OBJECTS) $(fioclient_LDADD) $(LIBS) fsel$(EXEEXT): $(fsel_OBJECTS) $(fsel_DEPENDENCIES) $(EXTRA_fsel_DEPENDENCIES) @rm -f fsel$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fsel_OBJECTS) $(fsel_LDADD) $(LIBS) fselclient$(EXEEXT): $(fselclient_OBJECTS) $(fselclient_DEPENDENCIES) $(EXTRA_fselclient_DEPENDENCIES) @rm -f fselclient$(EXEEXT) $(AM_V_CCLD)$(fselclient_LINK) $(fselclient_OBJECTS) $(fselclient_LDADD) $(LIBS) fusexmp$(EXEEXT): $(fusexmp_OBJECTS) $(fusexmp_DEPENDENCIES) $(EXTRA_fusexmp_DEPENDENCIES) @rm -f fusexmp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fusexmp_OBJECTS) $(fusexmp_LDADD) $(LIBS) fusexmp_fh$(EXEEXT): $(fusexmp_fh_OBJECTS) $(fusexmp_fh_DEPENDENCIES) $(EXTRA_fusexmp_fh_DEPENDENCIES) @rm -f fusexmp_fh$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fusexmp_fh_OBJECTS) $(fusexmp_fh_LDADD) $(LIBS) hello$(EXEEXT): $(hello_OBJECTS) $(hello_DEPENDENCIES) $(EXTRA_hello_DEPENDENCIES) @rm -f hello$(EXEEXT) $(AM_V_CCLD)$(LINK) $(hello_OBJECTS) $(hello_LDADD) $(LIBS) hello_ll$(EXEEXT): $(hello_ll_OBJECTS) $(hello_ll_DEPENDENCIES) $(EXTRA_hello_ll_DEPENDENCIES) @rm -f hello_ll$(EXEEXT) $(AM_V_CCLD)$(LINK) $(hello_ll_OBJECTS) $(hello_ll_LDADD) $(LIBS) null$(EXEEXT): $(null_OBJECTS) $(null_DEPENDENCIES) $(EXTRA_null_DEPENDENCIES) @rm -f null$(EXEEXT) $(AM_V_CCLD)$(LINK) $(null_OBJECTS) $(null_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cusexmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fioc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fioclient-fioclient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fselclient-fselclient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fusexmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fusexmp_fh.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hello.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hello_ll.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/null.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< fioclient-fioclient.o: fioclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fioclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fioclient-fioclient.o -MD -MP -MF $(DEPDIR)/fioclient-fioclient.Tpo -c -o fioclient-fioclient.o `test -f 'fioclient.c' || echo '$(srcdir)/'`fioclient.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fioclient-fioclient.Tpo $(DEPDIR)/fioclient-fioclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fioclient.c' object='fioclient-fioclient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fioclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fioclient-fioclient.o `test -f 'fioclient.c' || echo '$(srcdir)/'`fioclient.c fioclient-fioclient.obj: fioclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fioclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fioclient-fioclient.obj -MD -MP -MF $(DEPDIR)/fioclient-fioclient.Tpo -c -o fioclient-fioclient.obj `if test -f 'fioclient.c'; then $(CYGPATH_W) 'fioclient.c'; else $(CYGPATH_W) '$(srcdir)/fioclient.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fioclient-fioclient.Tpo $(DEPDIR)/fioclient-fioclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fioclient.c' object='fioclient-fioclient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fioclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fioclient-fioclient.obj `if test -f 'fioclient.c'; then $(CYGPATH_W) 'fioclient.c'; else $(CYGPATH_W) '$(srcdir)/fioclient.c'; fi` fselclient-fselclient.o: fselclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fselclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fselclient-fselclient.o -MD -MP -MF $(DEPDIR)/fselclient-fselclient.Tpo -c -o fselclient-fselclient.o `test -f 'fselclient.c' || echo '$(srcdir)/'`fselclient.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fselclient-fselclient.Tpo $(DEPDIR)/fselclient-fselclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fselclient.c' object='fselclient-fselclient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fselclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fselclient-fselclient.o `test -f 'fselclient.c' || echo '$(srcdir)/'`fselclient.c fselclient-fselclient.obj: fselclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fselclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fselclient-fselclient.obj -MD -MP -MF $(DEPDIR)/fselclient-fselclient.Tpo -c -o fselclient-fselclient.obj `if test -f 'fselclient.c'; then $(CYGPATH_W) 'fselclient.c'; else $(CYGPATH_W) '$(srcdir)/fselclient.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fselclient-fselclient.Tpo $(DEPDIR)/fselclient-fselclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fselclient.c' object='fselclient-fselclient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fselclient_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fselclient-fselclient.obj `if test -f 'fselclient.c'; then $(CYGPATH_W) 'fselclient.c'; else $(CYGPATH_W) '$(srcdir)/fselclient.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .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. .NOEXPORT: fuse-2.9.9/example/fusexmp_fh.c0000664000175000017500000002342713413660255013400 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Copyright (C) 2011 Sebastian Pipping This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall fusexmp_fh.c `pkg-config fuse --cflags --libs` -lulockmgr -o fusexmp_fh */ #define FUSE_USE_VERSION 26 #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SETXATTR #include #endif #include /* flock(2) */ static int xmp_getattr(const char *path, struct stat *stbuf) { int res; res = lstat(path, stbuf); if (res == -1) return -errno; return 0; } static int xmp_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { int res; (void) path; res = fstat(fi->fh, stbuf); if (res == -1) return -errno; return 0; } static int xmp_access(const char *path, int mask) { int res; res = access(path, mask); if (res == -1) return -errno; return 0; } static int xmp_readlink(const char *path, char *buf, size_t size) { int res; res = readlink(path, buf, size - 1); if (res == -1) return -errno; buf[res] = '\0'; return 0; } struct xmp_dirp { DIR *dp; struct dirent *entry; off_t offset; }; static int xmp_opendir(const char *path, struct fuse_file_info *fi) { int res; struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp)); if (d == NULL) return -ENOMEM; d->dp = opendir(path); if (d->dp == NULL) { res = -errno; free(d); return res; } d->offset = 0; d->entry = NULL; fi->fh = (unsigned long) d; return 0; } static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi) { return (struct xmp_dirp *) (uintptr_t) fi->fh; } static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { struct xmp_dirp *d = get_dirp(fi); (void) path; if (offset != d->offset) { seekdir(d->dp, offset); d->entry = NULL; d->offset = offset; } while (1) { struct stat st; off_t nextoff; if (!d->entry) { d->entry = readdir(d->dp); if (!d->entry) break; } memset(&st, 0, sizeof(st)); st.st_ino = d->entry->d_ino; st.st_mode = d->entry->d_type << 12; nextoff = telldir(d->dp); if (filler(buf, d->entry->d_name, &st, nextoff)) break; d->entry = NULL; d->offset = nextoff; } return 0; } static int xmp_releasedir(const char *path, struct fuse_file_info *fi) { struct xmp_dirp *d = get_dirp(fi); (void) path; closedir(d->dp); free(d); return 0; } static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) { int res; if (S_ISFIFO(mode)) res = mkfifo(path, mode); else res = mknod(path, mode, rdev); if (res == -1) return -errno; return 0; } static int xmp_mkdir(const char *path, mode_t mode) { int res; res = mkdir(path, mode); if (res == -1) return -errno; return 0; } static int xmp_unlink(const char *path) { int res; res = unlink(path); if (res == -1) return -errno; return 0; } static int xmp_rmdir(const char *path) { int res; res = rmdir(path); if (res == -1) return -errno; return 0; } static int xmp_symlink(const char *from, const char *to) { int res; res = symlink(from, to); if (res == -1) return -errno; return 0; } static int xmp_rename(const char *from, const char *to) { int res; res = rename(from, to); if (res == -1) return -errno; return 0; } static int xmp_link(const char *from, const char *to) { int res; res = link(from, to); if (res == -1) return -errno; return 0; } static int xmp_chmod(const char *path, mode_t mode) { int res; res = chmod(path, mode); if (res == -1) return -errno; return 0; } static int xmp_chown(const char *path, uid_t uid, gid_t gid) { int res; res = lchown(path, uid, gid); if (res == -1) return -errno; return 0; } static int xmp_truncate(const char *path, off_t size) { int res; res = truncate(path, size); if (res == -1) return -errno; return 0; } static int xmp_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) { int res; (void) path; res = ftruncate(fi->fh, size); if (res == -1) return -errno; return 0; } #ifdef HAVE_UTIMENSAT static int xmp_utimens(const char *path, const struct timespec ts[2]) { int res; /* don't use utime/utimes since they follow symlinks */ res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); if (res == -1) return -errno; return 0; } #endif static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi) { int fd; fd = open(path, fi->flags, mode); if (fd == -1) return -errno; fi->fh = fd; return 0; } static int xmp_open(const char *path, struct fuse_file_info *fi) { int fd; fd = open(path, fi->flags); if (fd == -1) return -errno; fi->fh = fd; return 0; } static int xmp_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int res; (void) path; res = pread(fi->fh, buf, size, offset); if (res == -1) res = -errno; return res; } static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp, size_t size, off_t offset, struct fuse_file_info *fi) { struct fuse_bufvec *src; (void) path; src = malloc(sizeof(struct fuse_bufvec)); if (src == NULL) return -ENOMEM; *src = FUSE_BUFVEC_INIT(size); src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; src->buf[0].fd = fi->fh; src->buf[0].pos = offset; *bufp = src; return 0; } static int xmp_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int res; (void) path; res = pwrite(fi->fh, buf, size, offset); if (res == -1) res = -errno; return res; } static int xmp_write_buf(const char *path, struct fuse_bufvec *buf, off_t offset, struct fuse_file_info *fi) { struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf)); (void) path; dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; dst.buf[0].fd = fi->fh; dst.buf[0].pos = offset; return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK); } static int xmp_statfs(const char *path, struct statvfs *stbuf) { int res; res = statvfs(path, stbuf); if (res == -1) return -errno; return 0; } static int xmp_flush(const char *path, struct fuse_file_info *fi) { int res; (void) path; /* This is called from every close on an open file, so call the close on the underlying filesystem. But since flush may be called multiple times for an open file, this must not really close the file. This is important if used on a network filesystem like NFS which flush the data/metadata on close() */ res = close(dup(fi->fh)); if (res == -1) return -errno; return 0; } static int xmp_release(const char *path, struct fuse_file_info *fi) { (void) path; close(fi->fh); return 0; } static int xmp_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { int res; (void) path; #ifndef HAVE_FDATASYNC (void) isdatasync; #else if (isdatasync) res = fdatasync(fi->fh); else #endif res = fsync(fi->fh); if (res == -1) return -errno; return 0; } #ifdef HAVE_POSIX_FALLOCATE static int xmp_fallocate(const char *path, int mode, off_t offset, off_t length, struct fuse_file_info *fi) { (void) path; if (mode) return -EOPNOTSUPP; return -posix_fallocate(fi->fh, offset, length); } #endif #ifdef HAVE_SETXATTR /* xattr operations are optional and can safely be left unimplemented */ static int xmp_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { int res = lsetxattr(path, name, value, size, flags); if (res == -1) return -errno; return 0; } static int xmp_getxattr(const char *path, const char *name, char *value, size_t size) { int res = lgetxattr(path, name, value, size); if (res == -1) return -errno; return res; } static int xmp_listxattr(const char *path, char *list, size_t size) { int res = llistxattr(path, list, size); if (res == -1) return -errno; return res; } static int xmp_removexattr(const char *path, const char *name) { int res = lremovexattr(path, name); if (res == -1) return -errno; return 0; } #endif /* HAVE_SETXATTR */ static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock) { (void) path; return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, sizeof(fi->lock_owner)); } static int xmp_flock(const char *path, struct fuse_file_info *fi, int op) { int res; (void) path; res = flock(fi->fh, op); if (res == -1) return -errno; return 0; } static struct fuse_operations xmp_oper = { .getattr = xmp_getattr, .fgetattr = xmp_fgetattr, .access = xmp_access, .readlink = xmp_readlink, .opendir = xmp_opendir, .readdir = xmp_readdir, .releasedir = xmp_releasedir, .mknod = xmp_mknod, .mkdir = xmp_mkdir, .symlink = xmp_symlink, .unlink = xmp_unlink, .rmdir = xmp_rmdir, .rename = xmp_rename, .link = xmp_link, .chmod = xmp_chmod, .chown = xmp_chown, .truncate = xmp_truncate, .ftruncate = xmp_ftruncate, #ifdef HAVE_UTIMENSAT .utimens = xmp_utimens, #endif .create = xmp_create, .open = xmp_open, .read = xmp_read, .read_buf = xmp_read_buf, .write = xmp_write, .write_buf = xmp_write_buf, .statfs = xmp_statfs, .flush = xmp_flush, .release = xmp_release, .fsync = xmp_fsync, #ifdef HAVE_POSIX_FALLOCATE .fallocate = xmp_fallocate, #endif #ifdef HAVE_SETXATTR .setxattr = xmp_setxattr, .getxattr = xmp_getxattr, .listxattr = xmp_listxattr, .removexattr = xmp_removexattr, #endif .lock = xmp_lock, .flock = xmp_flock, .flag_nullpath_ok = 1, #if HAVE_UTIMENSAT .flag_utime_omit_ok = 1, #endif }; int main(int argc, char *argv[]) { umask(0); return fuse_main(argc, argv, &xmp_oper, NULL); } fuse-2.9.9/example/cusexmp.c0000664000175000017500000001463713413660255012723 00000000000000/* CUSE example: Character device in Userspace Copyright (C) 2008-2009 SUSE Linux Products GmbH Copyright (C) 2008-2009 Tejun Heo This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall cusexmp.c `pkg-config fuse --cflags --libs` -o cusexmp */ #define FUSE_USE_VERSION 29 #include #include #include #include #include #include #include #include #include "fioc.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" "\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 + (unsigned long)&(((struct fioc_rw_arg *)0)->prev_size); out_iov[0].iov_len = sizeof(arg->prev_size); out_iov[1].iov_base = addr + (unsigned long)&(((struct fioc_rw_arg *)0)->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; 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), FUSE_OPT_END }; 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, ¶m, 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); } fuse-2.9.9/example/hello_ll.c0000664000175000017500000000770313413660255013025 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall hello_ll.c `pkg-config fuse --cflags --libs` -o hello_ll */ #define FUSE_USE_VERSION 26 #include #include #include #include #include #include #include #include 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, fuse_ino_t ino) { 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_chan *ch; char *mountpoint; int err = -1; if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 && (ch = fuse_mount(mountpoint, &args)) != NULL) { struct fuse_session *se; se = fuse_lowlevel_new(&args, &hello_ll_oper, sizeof(hello_ll_oper), NULL); if (se != NULL) { if (fuse_set_signal_handlers(se) != -1) { fuse_session_add_chan(se, ch); err = fuse_session_loop(se); fuse_remove_signal_handlers(se); fuse_session_remove_chan(ch); } fuse_session_destroy(se); } fuse_unmount(mountpoint, ch); } fuse_opt_free_args(&args); return err ? 1 : 0; } fuse-2.9.9/example/fioc.h0000664000175000017500000000135313413660255012153 00000000000000/* FUSE-ioctl: ioctl support for FUSE Copyright (C) 2008 SUSE Linux Products GmbH Copyright (C) 2008 Tejun Heo This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ #include #include #include 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 */ }; fuse-2.9.9/example/fioclient.c0000664000175000017500000000462613413660255013210 00000000000000/* FUSE fioclient: FUSE ioctl example client Copyright (C) 2008 SUSE Linux Products GmbH Copyright (C) 2008 Tejun Heo This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall fioclient.c -o fioclient */ #include #include #include #include #include #include #include #include #include "fioc.h" const char *usage = "Usage: fioclient 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; } fuse-2.9.9/example/Makefile.am0000664000175000017500000000072413413660255013117 00000000000000## Process this file with automake to produce Makefile.in AM_CPPFLAGS = -I$(top_srcdir)/include -D_FILE_OFFSET_BITS=64 -D_REENTRANT noinst_HEADERS = fioc.h noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll fioc fioclient \ fsel fselclient cusexmp LDADD = ../lib/libfuse.la fusexmp_fh_LDADD = ../lib/libfuse.la ../lib/libulockmgr.la fioclient_CPPFLAGS = fioclient_LDFLAGS = fioclient_LDADD = fselclient_CPPFLAGS = fselclient_LDFLAGS = fselclient_LDADD = fuse-2.9.9/example/fusexmp.c0000664000175000017500000001554713413660255012727 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Copyright (C) 2011 Sebastian Pipping This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall fusexmp.c `pkg-config fuse --cflags --libs` -o fusexmp */ #define FUSE_USE_VERSION 26 #ifdef HAVE_CONFIG_H #include #endif #ifdef linux /* For pread()/pwrite()/utimensat() */ #define _XOPEN_SOURCE 700 #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_SETXATTR #include #endif static int xmp_getattr(const char *path, struct stat *stbuf) { int res; res = lstat(path, stbuf); if (res == -1) return -errno; return 0; } static int xmp_access(const char *path, int mask) { int res; res = access(path, mask); if (res == -1) return -errno; return 0; } static int xmp_readlink(const char *path, char *buf, size_t size) { int res; res = readlink(path, buf, size - 1); if (res == -1) return -errno; buf[res] = '\0'; return 0; } static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { DIR *dp; struct dirent *de; (void) offset; (void) fi; dp = opendir(path); if (dp == NULL) return -errno; while ((de = readdir(dp)) != NULL) { struct stat st; memset(&st, 0, sizeof(st)); st.st_ino = de->d_ino; st.st_mode = de->d_type << 12; if (filler(buf, de->d_name, &st, 0)) break; } closedir(dp); return 0; } static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) { int res; /* On Linux this could just be 'mknod(path, mode, rdev)' but this is more portable */ if (S_ISREG(mode)) { res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode); if (res >= 0) res = close(res); } else if (S_ISFIFO(mode)) res = mkfifo(path, mode); else res = mknod(path, mode, rdev); if (res == -1) return -errno; return 0; } static int xmp_mkdir(const char *path, mode_t mode) { int res; res = mkdir(path, mode); if (res == -1) return -errno; return 0; } static int xmp_unlink(const char *path) { int res; res = unlink(path); if (res == -1) return -errno; return 0; } static int xmp_rmdir(const char *path) { int res; res = rmdir(path); if (res == -1) return -errno; return 0; } static int xmp_symlink(const char *from, const char *to) { int res; res = symlink(from, to); if (res == -1) return -errno; return 0; } static int xmp_rename(const char *from, const char *to) { int res; res = rename(from, to); if (res == -1) return -errno; return 0; } static int xmp_link(const char *from, const char *to) { int res; res = link(from, to); if (res == -1) return -errno; return 0; } static int xmp_chmod(const char *path, mode_t mode) { int res; res = chmod(path, mode); if (res == -1) return -errno; return 0; } static int xmp_chown(const char *path, uid_t uid, gid_t gid) { int res; res = lchown(path, uid, gid); if (res == -1) return -errno; return 0; } static int xmp_truncate(const char *path, off_t size) { int res; res = truncate(path, size); if (res == -1) return -errno; return 0; } #ifdef HAVE_UTIMENSAT static int xmp_utimens(const char *path, const struct timespec ts[2]) { int res; /* don't use utime/utimes since they follow symlinks */ res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); if (res == -1) return -errno; return 0; } #endif static int xmp_open(const char *path, struct fuse_file_info *fi) { int res; res = open(path, fi->flags); if (res == -1) return -errno; close(res); return 0; } static int xmp_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int fd; int res; (void) fi; fd = open(path, O_RDONLY); if (fd == -1) return -errno; res = pread(fd, buf, size, offset); if (res == -1) res = -errno; close(fd); return res; } static int xmp_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int fd; int res; (void) fi; fd = open(path, O_WRONLY); if (fd == -1) return -errno; res = pwrite(fd, buf, size, offset); if (res == -1) res = -errno; close(fd); return res; } static int xmp_statfs(const char *path, struct statvfs *stbuf) { int res; res = statvfs(path, stbuf); if (res == -1) return -errno; return 0; } static int xmp_release(const char *path, struct fuse_file_info *fi) { /* Just a stub. This method is optional and can safely be left unimplemented */ (void) path; (void) fi; return 0; } static int xmp_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { /* Just a stub. This method is optional and can safely be left unimplemented */ (void) path; (void) isdatasync; (void) fi; return 0; } #ifdef HAVE_POSIX_FALLOCATE static int xmp_fallocate(const char *path, int mode, off_t offset, off_t length, struct fuse_file_info *fi) { int fd; int res; (void) fi; if (mode) return -EOPNOTSUPP; fd = open(path, O_WRONLY); if (fd == -1) return -errno; res = -posix_fallocate(fd, offset, length); close(fd); return res; } #endif #ifdef HAVE_SETXATTR /* xattr operations are optional and can safely be left unimplemented */ static int xmp_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { int res = lsetxattr(path, name, value, size, flags); if (res == -1) return -errno; return 0; } static int xmp_getxattr(const char *path, const char *name, char *value, size_t size) { int res = lgetxattr(path, name, value, size); if (res == -1) return -errno; return res; } static int xmp_listxattr(const char *path, char *list, size_t size) { int res = llistxattr(path, list, size); if (res == -1) return -errno; return res; } static int xmp_removexattr(const char *path, const char *name) { int res = lremovexattr(path, name); if (res == -1) return -errno; return 0; } #endif /* HAVE_SETXATTR */ static struct fuse_operations xmp_oper = { .getattr = xmp_getattr, .access = xmp_access, .readlink = xmp_readlink, .readdir = xmp_readdir, .mknod = xmp_mknod, .mkdir = xmp_mkdir, .symlink = xmp_symlink, .unlink = xmp_unlink, .rmdir = xmp_rmdir, .rename = xmp_rename, .link = xmp_link, .chmod = xmp_chmod, .chown = xmp_chown, .truncate = xmp_truncate, #ifdef HAVE_UTIMENSAT .utimens = xmp_utimens, #endif .open = xmp_open, .read = xmp_read, .write = xmp_write, .statfs = xmp_statfs, .release = xmp_release, .fsync = xmp_fsync, #ifdef HAVE_POSIX_FALLOCATE .fallocate = xmp_fallocate, #endif #ifdef HAVE_SETXATTR .setxattr = xmp_setxattr, .getxattr = xmp_getxattr, .listxattr = xmp_listxattr, .removexattr = xmp_removexattr, #endif }; int main(int argc, char *argv[]) { umask(0); return fuse_main(argc, argv, &xmp_oper, NULL); } fuse-2.9.9/example/null.c0000664000175000017500000000334213413660255012200 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall null.c `pkg-config fuse --cflags --libs` -o null */ #define FUSE_USE_VERSION 26 #include #include #include #include #include static int null_getattr(const char *path, struct stat *stbuf) { if(strcmp(path, "/") != 0) return -ENOENT; stbuf->st_mode = S_IFREG | 0644; stbuf->st_nlink = 1; stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); stbuf->st_size = (1ULL << 32); /* 4G */ stbuf->st_blocks = 0; stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL); return 0; } static int null_truncate(const char *path, off_t size) { (void) size; if(strcmp(path, "/") != 0) return -ENOENT; return 0; } static int null_open(const char *path, struct fuse_file_info *fi) { (void) fi; if(strcmp(path, "/") != 0) return -ENOENT; return 0; } static int null_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) buf; (void) offset; (void) fi; if(strcmp(path, "/") != 0) return -ENOENT; if (offset >= (1ULL << 32)) return 0; return size; } static int null_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) buf; (void) offset; (void) fi; if(strcmp(path, "/") != 0) return -ENOENT; return size; } static struct fuse_operations null_oper = { .getattr = null_getattr, .truncate = null_truncate, .open = null_open, .read = null_read, .write = null_write, }; int main(int argc, char *argv[]) { return fuse_main(argc, argv, &null_oper, NULL); } fuse-2.9.9/example/fselclient.c0000664000175000017500000000251713413660255013361 00000000000000/* FUSE fselclient: FUSE select example client Copyright (C) 2008 SUSE Linux Products GmbH Copyright (C) 2008 Tejun Heo This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall fselclient.c -o fselclient */ #include #include #include #include #include #include #include #include #include #include #define FSEL_FILES 16 int main(void) { static const char hex_map[FSEL_FILES] = "0123456789ABCDEF"; int fds[FSEL_FILES]; int i, nfds; for (i = 0; i < FSEL_FILES; i++) { char name[] = { hex_map[i], '\0' }; fds[i] = open(name, O_RDONLY); if (fds[i] < 0) { perror("open"); return 1; } } nfds = fds[FSEL_FILES - 1] + 1; while (1) { static char buf[4096]; fd_set rfds; int rc; FD_ZERO(&rfds); for (i = 0; i < FSEL_FILES; i++) FD_SET(fds[i], &rfds); rc = select(nfds, &rfds, NULL, NULL, NULL); if (rc < 0) { perror("select"); return 1; } for (i = 0; i < FSEL_FILES; i++) { if (!FD_ISSET(fds[i], &rfds)) { printf("_: "); continue; } printf("%X:", i); rc = read(fds[i], buf, sizeof(buf)); if (rc < 0) { perror("read"); return 1; } printf("%02d ", rc); } printf("\n"); } } fuse-2.9.9/example/hello.c0000664000175000017500000000366613413660255012342 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall hello.c `pkg-config fuse --cflags --libs` -o hello */ #define FUSE_USE_VERSION 26 #include #include #include #include #include static const char *hello_str = "Hello World!\n"; static const char *hello_path = "/hello"; static int hello_getattr(const char *path, struct stat *stbuf) { 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, hello_path) == 0) { stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = strlen(hello_str); } 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) { (void) offset; (void) fi; if (strcmp(path, "/") != 0) return -ENOENT; filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); filler(buf, hello_path + 1, NULL, 0); return 0; } static int hello_open(const char *path, struct fuse_file_info *fi) { if (strcmp(path, hello_path) != 0) return -ENOENT; if ((fi->flags & 3) != 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, hello_path) != 0) return -ENOENT; len = strlen(hello_str); if (offset < len) { if (offset + size > len) size = len - offset; memcpy(buf, hello_str + offset, size); } else size = 0; return size; } static struct fuse_operations hello_oper = { .getattr = hello_getattr, .readdir = hello_readdir, .open = hello_open, .read = hello_read, }; int main(int argc, char *argv[]) { return fuse_main(argc, argv, &hello_oper, NULL); } fuse-2.9.9/example/fioc.c0000664000175000017500000000750713413660255012155 00000000000000/* FUSE fioc: FUSE ioctl example Copyright (C) 2008 SUSE Linux Products GmbH Copyright (C) 2008 Tejun Heo This program can be distributed under the terms of the GNU GPL. See the file COPYING. gcc -Wall fioc.c `pkg-config fuse --cflags --libs` -o fioc */ #define FUSE_USE_VERSION 26 #include #include #include #include #include #include #include #include "fioc.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) { 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) { 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) { (void) fi; (void) offset; if (fioc_file_type(path) != FIOC_ROOT) return -ENOENT; filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); filler(buf, FIOC_NAME, NULL, 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); } fuse-2.9.9/util/0000775000175000017500000000000013413661013010453 500000000000000fuse-2.9.9/util/udev.rules0000644000175000017500000000003413355372746012426 00000000000000KERNEL=="fuse", MODE="0666" fuse-2.9.9/util/Makefile.in0000664000175000017500000007163013413660777012467 00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # 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, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ 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 \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = fusermount$(EXEEXT) ulockmgr_server$(EXEEXT) noinst_PROGRAMS = mount.fuse$(EXEEXT) subdir = util 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 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.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 = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_fusermount_OBJECTS = fusermount-fusermount.$(OBJEXT) \ fusermount-mount_util.$(OBJEXT) fusermount_OBJECTS = $(am_fusermount_OBJECTS) fusermount_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_mount_fuse_OBJECTS = mount.fuse.$(OBJEXT) mount_fuse_OBJECTS = $(am_mount_fuse_OBJECTS) mount_fuse_LDADD = $(LDADD) am_ulockmgr_server_OBJECTS = \ ulockmgr_server-ulockmgr_server.$(OBJEXT) ulockmgr_server_OBJECTS = $(am_ulockmgr_server_OBJECTS) ulockmgr_server_LDADD = $(LDADD) ulockmgr_server_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(ulockmgr_server_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(fusermount_SOURCES) $(mount_fuse_SOURCES) \ $(ulockmgr_server_SOURCES) DIST_SOURCES = $(fusermount_SOURCES) $(mount_fuse_SOURCES) \ $(ulockmgr_server_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INIT_D_PATH = @INIT_D_PATH@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ 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@ MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UDEV_RULES_PATH = @UDEV_RULES_PATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libfuse_libs = @libfuse_libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs2 = @subdirs2@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 # we re-use mount_util.c from the library, but do want to keep ourself # as stand-alone as possible. in order to make an out-of-source build # possible, we "generate" the file from its original location by # copying it over. fusermount_SOURCES = fusermount.c mount_util.c fusermount_CPPFLAGS = -I$(top_srcdir)/lib BUILT_SOURCES = mount_util.c mount_fuse_SOURCES = mount.fuse.c ulockmgr_server_SOURCES = ulockmgr_server.c ulockmgr_server_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_REENTRANT ulockmgr_server_LDFLAGS = -pthread EXTRA_DIST = udev.rules init_script all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign util/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign util/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list fusermount$(EXEEXT): $(fusermount_OBJECTS) $(fusermount_DEPENDENCIES) $(EXTRA_fusermount_DEPENDENCIES) @rm -f fusermount$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fusermount_OBJECTS) $(fusermount_LDADD) $(LIBS) mount.fuse$(EXEEXT): $(mount_fuse_OBJECTS) $(mount_fuse_DEPENDENCIES) $(EXTRA_mount_fuse_DEPENDENCIES) @rm -f mount.fuse$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mount_fuse_OBJECTS) $(mount_fuse_LDADD) $(LIBS) ulockmgr_server$(EXEEXT): $(ulockmgr_server_OBJECTS) $(ulockmgr_server_DEPENDENCIES) $(EXTRA_ulockmgr_server_DEPENDENCIES) @rm -f ulockmgr_server$(EXEEXT) $(AM_V_CCLD)$(ulockmgr_server_LINK) $(ulockmgr_server_OBJECTS) $(ulockmgr_server_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fusermount-fusermount.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fusermount-mount_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mount.fuse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ulockmgr_server-ulockmgr_server.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< fusermount-fusermount.o: fusermount.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fusermount-fusermount.o -MD -MP -MF $(DEPDIR)/fusermount-fusermount.Tpo -c -o fusermount-fusermount.o `test -f 'fusermount.c' || echo '$(srcdir)/'`fusermount.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fusermount-fusermount.Tpo $(DEPDIR)/fusermount-fusermount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fusermount.c' object='fusermount-fusermount.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fusermount-fusermount.o `test -f 'fusermount.c' || echo '$(srcdir)/'`fusermount.c fusermount-fusermount.obj: fusermount.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fusermount-fusermount.obj -MD -MP -MF $(DEPDIR)/fusermount-fusermount.Tpo -c -o fusermount-fusermount.obj `if test -f 'fusermount.c'; then $(CYGPATH_W) 'fusermount.c'; else $(CYGPATH_W) '$(srcdir)/fusermount.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fusermount-fusermount.Tpo $(DEPDIR)/fusermount-fusermount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fusermount.c' object='fusermount-fusermount.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fusermount-fusermount.obj `if test -f 'fusermount.c'; then $(CYGPATH_W) 'fusermount.c'; else $(CYGPATH_W) '$(srcdir)/fusermount.c'; fi` fusermount-mount_util.o: mount_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fusermount-mount_util.o -MD -MP -MF $(DEPDIR)/fusermount-mount_util.Tpo -c -o fusermount-mount_util.o `test -f 'mount_util.c' || echo '$(srcdir)/'`mount_util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fusermount-mount_util.Tpo $(DEPDIR)/fusermount-mount_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mount_util.c' object='fusermount-mount_util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fusermount-mount_util.o `test -f 'mount_util.c' || echo '$(srcdir)/'`mount_util.c fusermount-mount_util.obj: mount_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fusermount-mount_util.obj -MD -MP -MF $(DEPDIR)/fusermount-mount_util.Tpo -c -o fusermount-mount_util.obj `if test -f 'mount_util.c'; then $(CYGPATH_W) 'mount_util.c'; else $(CYGPATH_W) '$(srcdir)/mount_util.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fusermount-mount_util.Tpo $(DEPDIR)/fusermount-mount_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mount_util.c' object='fusermount-mount_util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fusermount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fusermount-mount_util.obj `if test -f 'mount_util.c'; then $(CYGPATH_W) 'mount_util.c'; else $(CYGPATH_W) '$(srcdir)/mount_util.c'; fi` ulockmgr_server-ulockmgr_server.o: ulockmgr_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ulockmgr_server_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ulockmgr_server-ulockmgr_server.o -MD -MP -MF $(DEPDIR)/ulockmgr_server-ulockmgr_server.Tpo -c -o ulockmgr_server-ulockmgr_server.o `test -f 'ulockmgr_server.c' || echo '$(srcdir)/'`ulockmgr_server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ulockmgr_server-ulockmgr_server.Tpo $(DEPDIR)/ulockmgr_server-ulockmgr_server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ulockmgr_server.c' object='ulockmgr_server-ulockmgr_server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ulockmgr_server_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ulockmgr_server-ulockmgr_server.o `test -f 'ulockmgr_server.c' || echo '$(srcdir)/'`ulockmgr_server.c ulockmgr_server-ulockmgr_server.obj: ulockmgr_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ulockmgr_server_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ulockmgr_server-ulockmgr_server.obj -MD -MP -MF $(DEPDIR)/ulockmgr_server-ulockmgr_server.Tpo -c -o ulockmgr_server-ulockmgr_server.obj `if test -f 'ulockmgr_server.c'; then $(CYGPATH_W) 'ulockmgr_server.c'; else $(CYGPATH_W) '$(srcdir)/ulockmgr_server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ulockmgr_server-ulockmgr_server.Tpo $(DEPDIR)/ulockmgr_server-ulockmgr_server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ulockmgr_server.c' object='ulockmgr_server-ulockmgr_server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ulockmgr_server_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ulockmgr_server-ulockmgr_server.obj `if test -f 'ulockmgr_server.c'; then $(CYGPATH_W) 'ulockmgr_server.c'; else $(CYGPATH_W) '$(srcdir)/ulockmgr_server.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-data-local install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-exec-local @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-local .MAKE: all check install install-am install-exec-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-data-local install-dvi install-dvi-am \ install-exec install-exec-am install-exec-hook \ install-exec-local install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-local .PRECIOUS: Makefile mount_util.c: $(top_srcdir)/lib/mount_util.c @cp $(top_srcdir)/lib/mount_util.c . install-exec-hook: -chmod u+s $(DESTDIR)$(bindir)/fusermount @if test ! -e $(DESTDIR)/dev/fuse; then \ $(MKDIR_P) $(DESTDIR)/dev; \ echo "mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true"; \ mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true; \ fi install-exec-local: $(MKDIR_P) $(DESTDIR)$(MOUNT_FUSE_PATH) $(INSTALL_PROGRAM) $(builddir)/mount.fuse $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse $(MKDIR_P) $(DESTDIR)$(INIT_D_PATH) $(INSTALL_SCRIPT) $(srcdir)/init_script $(DESTDIR)$(INIT_D_PATH)/fuse @if test -x /usr/sbin/update-rc.d; then \ echo "/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true"; \ /usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true; \ fi install-data-local: $(MKDIR_P) $(DESTDIR)$(UDEV_RULES_PATH) $(INSTALL_DATA) $(srcdir)/udev.rules $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules uninstall-local: rm -f $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse rm -f $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules rm -f $(DESTDIR)$(INIT_D_PATH)/fuse @if test -x /usr/sbin/update-rc.d; then \ echo "/usr/sbin/update-rc.d fuse remove || true"; \ /usr/sbin/update-rc.d fuse remove || true; \ fi # 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. .NOEXPORT: fuse-2.9.9/util/mount.fuse.c0000664000175000017500000001072613413660255012657 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ #include #include #include #include #include static char *progname; static char *xstrdup(const char *s) { char *t = strdup(s); if (!t) { fprintf(stderr, "%s: failed to allocate memory\n", progname); exit(1); } return t; } static void *xrealloc(void *oldptr, size_t size) { void *ptr = realloc(oldptr, size); if (!ptr) { fprintf(stderr, "%s: failed to allocate memory\n", progname); exit(1); } return ptr; } static void add_arg(char **cmdp, const char *opt) { size_t optlen = strlen(opt); size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); char *s; s = cmd + cmdlen; if (*cmdp) *s++ = ' '; *s++ = '\''; for (; *opt; opt++) { if (*opt == '\'') { *s++ = '\''; *s++ = '\\'; *s++ = '\''; *s++ = '\''; } else *s++ = *opt; } *s++ = '\''; *s = '\0'; *cmdp = cmd; } static char *add_option(const char *opt, char *options) { int oldlen = options ? strlen(options) : 0; options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); if (!oldlen) strcpy(options, opt); else { strcat(options, ","); strcat(options, opt); } return options; } int main(int argc, char *argv[]) { char *type = NULL; char *source; const char *mountpoint; char *basename; char *options = NULL; char *command = NULL; char *setuid = NULL; int i; int dev = 1; int suid = 1; progname = argv[0]; basename = strrchr(argv[0], '/'); if (basename) basename++; else basename = argv[0]; if (strncmp(basename, "mount.fuse.", 11) == 0) type = basename + 11; if (strncmp(basename, "mount.fuseblk.", 14) == 0) type = basename + 14; if (type && !type[0]) type = NULL; if (argc < 3) { fprintf(stderr, "usage: %s %s destination [-t type] [-o opt[,opts...]]\n", progname, type ? "source" : "type#[source]"); exit(1); } source = argv[1]; if (!source[0]) source = NULL; mountpoint = argv[2]; for (i = 3; i < argc; i++) { if (strcmp(argv[i], "-v") == 0) { continue; } else if (strcmp(argv[i], "-t") == 0) { i++; if (i == argc) { fprintf(stderr, "%s: missing argument to option '-t'\n", progname); exit(1); } type = argv[i]; if (strncmp(type, "fuse.", 5) == 0) type += 5; else if (strncmp(type, "fuseblk.", 8) == 0) type += 8; if (!type[0]) { fprintf(stderr, "%s: empty type given as argument to option '-t'\n", progname); exit(1); } } else if (strcmp(argv[i], "-o") == 0) { char *opts; char *opt; i++; if (i == argc) break; opts = xstrdup(argv[i]); opt = strtok(opts, ","); while (opt) { int j; int ignore = 0; const char *ignore_opts[] = { "", "user", "nouser", "users", "auto", "noauto", "_netdev", NULL}; if (strncmp(opt, "setuid=", 7) == 0) { setuid = xstrdup(opt + 7); ignore = 1; } for (j = 0; ignore_opts[j]; j++) if (strcmp(opt, ignore_opts[j]) == 0) ignore = 1; if (!ignore) { if (strcmp(opt, "nodev") == 0) dev = 0; else if (strcmp(opt, "nosuid") == 0) suid = 0; options = add_option(opt, options); } opt = strtok(NULL, ","); } } } if (dev) options = add_option("dev", options); if (suid) options = add_option("suid", options); if (!type) { if (source) { type = xstrdup(source); source = strchr(type, '#'); if (source) *source++ = '\0'; if (!type[0]) { fprintf(stderr, "%s: empty filesystem type\n", progname); exit(1); } } else { fprintf(stderr, "%s: empty source\n", progname); exit(1); } } add_arg(&command, type); if (source) add_arg(&command, source); add_arg(&command, mountpoint); if (options) { add_arg(&command, "-o"); add_arg(&command, options); } if (setuid && setuid[0]) { char *sucommand = command; command = NULL; add_arg(&command, "su"); add_arg(&command, "-"); add_arg(&command, setuid); add_arg(&command, "-c"); add_arg(&command, sucommand); } else if (!getenv("HOME")) { /* Hack to make filesystems work in the boot environment */ setenv("HOME", "/root", 0); } execl("/bin/sh", "/bin/sh", "-c", command, NULL); fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, strerror(errno)); return 1; } fuse-2.9.9/util/Makefile.am0000664000175000017500000000401213413660255012433 00000000000000## Process this file with automake to produce Makefile.in AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 bin_PROGRAMS = fusermount ulockmgr_server noinst_PROGRAMS = mount.fuse # we re-use mount_util.c from the library, but do want to keep ourself # as stand-alone as possible. in order to make an out-of-source build # possible, we "generate" the file from its original location by # copying it over. fusermount_SOURCES = fusermount.c mount_util.c fusermount_CPPFLAGS = -I$(top_srcdir)/lib BUILT_SOURCES = mount_util.c mount_util.c: $(top_srcdir)/lib/mount_util.c @cp $(top_srcdir)/lib/mount_util.c . mount_fuse_SOURCES = mount.fuse.c ulockmgr_server_SOURCES = ulockmgr_server.c ulockmgr_server_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_REENTRANT ulockmgr_server_LDFLAGS = -pthread install-exec-hook: -chmod u+s $(DESTDIR)$(bindir)/fusermount @if test ! -e $(DESTDIR)/dev/fuse; then \ $(MKDIR_P) $(DESTDIR)/dev; \ echo "mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true"; \ mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true; \ fi EXTRA_DIST = udev.rules init_script MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@ UDEV_RULES_PATH = @UDEV_RULES_PATH@ INIT_D_PATH = @INIT_D_PATH@ install-exec-local: $(MKDIR_P) $(DESTDIR)$(MOUNT_FUSE_PATH) $(INSTALL_PROGRAM) $(builddir)/mount.fuse $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse $(MKDIR_P) $(DESTDIR)$(INIT_D_PATH) $(INSTALL_SCRIPT) $(srcdir)/init_script $(DESTDIR)$(INIT_D_PATH)/fuse @if test -x /usr/sbin/update-rc.d; then \ echo "/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true"; \ /usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true; \ fi install-data-local: $(MKDIR_P) $(DESTDIR)$(UDEV_RULES_PATH) $(INSTALL_DATA) $(srcdir)/udev.rules $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules uninstall-local: rm -f $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse rm -f $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules rm -f $(DESTDIR)$(INIT_D_PATH)/fuse @if test -x /usr/sbin/update-rc.d; then \ echo "/usr/sbin/update-rc.d fuse remove || true"; \ /usr/sbin/update-rc.d fuse remove || true; \ fi fuse-2.9.9/util/init_script0000775000175000017500000000354513413660255012666 00000000000000#! /bin/sh ### BEGIN INIT INFO # Provides: fuse # Required-Start: # Should-Start: udev # Required-Stop: # Default-Start: S # Default-Stop: # Short-Description: Start and stop fuse. # Description: Load the fuse module and mount the fuse control # filesystem. ### END INIT INFO set -e PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin MOUNTPOINT=/sys/fs/fuse/connections # Gracefully exit if the package has been removed. which fusermount &>/dev/null || exit 5 case "$1" in start|restart|force-reload) if ! grep -qw fuse /proc/filesystems; then echo -n "Loading fuse module" if ! modprobe fuse >/dev/null 2>&1; then echo " failed!" exit 1 else echo "." fi else echo "Fuse filesystem already available." fi if grep -qw fusectl /proc/filesystems && \ ! grep -qw $MOUNTPOINT /proc/mounts; then echo -n "Mounting fuse control filesystem" if ! mount -t fusectl fusectl $MOUNTPOINT >/dev/null 2>&1; then echo " failed!" exit 1 else echo "." fi else echo "Fuse control filesystem already available." fi ;; stop) if ! grep -qw fuse /proc/filesystems; then echo "Fuse filesystem not loaded." exit 7 fi if grep -qw $MOUNTPOINT /proc/mounts; then echo -n "Unmounting fuse control filesystem" if ! umount $MOUNTPOINT >/dev/null 2>&1; then echo " failed!" else echo "." fi else echo "Fuse control filesystem not mounted." fi if grep -qw "^fuse" /proc/modules; then echo -n "Unloading fuse module" if ! rmmod fuse >/dev/null 2>&1; then echo " failed!" else echo "." fi else echo "Fuse module not loaded." fi ;; status) echo -n "Checking fuse filesystem" if ! grep -qw fuse /proc/filesystems; then echo " not available." exit 3 else echo " ok." fi ;; *) echo "Usage: $0 {start|stop|restart|force-reload|status}" exit 1 ;; esac exit 0 fuse-2.9.9/util/mount_util.c0000664000175000017500000001726113413661013012745 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ #include "mount_util.h" #include #include #include #include #include #include #include #include #include #include #ifndef __NetBSD__ #include #endif #include #include #include #include #ifdef __NetBSD__ #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) #define mtab_needs_update(mnt) 0 #else static int mtab_needs_update(const char *mnt) { int res; struct stat stbuf; /* If mtab is within new mount, don't touch it */ if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && _PATH_MOUNTED[strlen(mnt)] == '/') return 0; /* * Skip mtab update if /etc/mtab: * * - doesn't exist, * - is a symlink, * - is on a read-only filesystem. */ res = lstat(_PATH_MOUNTED, &stbuf); if (res == -1) { if (errno == ENOENT) return 0; } else { uid_t ruid; int err; if (S_ISLNK(stbuf.st_mode)) return 0; ruid = getuid(); if (ruid != 0) setreuid(0, -1); res = access(_PATH_MOUNTED, W_OK); err = (res == -1) ? errno : 0; if (ruid != 0) setreuid(ruid, -1); if (err == EROFS) return 0; } return 1; } #endif /* __NetBSD__ */ static int add_mount(const char *progname, const char *fsname, const char *mnt, const char *type, const char *opts) { int res; int status; sigset_t blockmask; sigset_t oldmask; sigemptyset(&blockmask); sigaddset(&blockmask, SIGCHLD); res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); if (res == -1) { fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); return -1; } res = fork(); if (res == -1) { fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); goto out_restore; } if (res == 0) { char *env = NULL; sigprocmask(SIG_SETMASK, &oldmask, NULL); setuid(geteuid()); execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname, strerror(errno)); exit(1); } res = waitpid(res, &status, 0); if (res == -1) fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); if (status != 0) res = -1; out_restore: sigprocmask(SIG_SETMASK, &oldmask, NULL); return res; } int fuse_mnt_add_mount(const char *progname, const char *fsname, const char *mnt, const char *type, const char *opts) { if (!mtab_needs_update(mnt)) return 0; return add_mount(progname, fsname, mnt, type, opts); } static int exec_umount(const char *progname, const char *rel_mnt, int lazy) { int res; int status; sigset_t blockmask; sigset_t oldmask; sigemptyset(&blockmask); sigaddset(&blockmask, SIGCHLD); res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); if (res == -1) { fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); return -1; } res = fork(); if (res == -1) { fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); goto out_restore; } if (res == 0) { char *env = NULL; sigprocmask(SIG_SETMASK, &oldmask, NULL); setuid(geteuid()); if (lazy) { execle("/bin/umount", "/bin/umount", "-i", rel_mnt, "-l", NULL, &env); } else { execle("/bin/umount", "/bin/umount", "-i", rel_mnt, NULL, &env); } fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname, strerror(errno)); exit(1); } res = waitpid(res, &status, 0); if (res == -1) fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); if (status != 0) { res = -1; } out_restore: sigprocmask(SIG_SETMASK, &oldmask, NULL); return res; } int fuse_mnt_umount(const char *progname, const char *abs_mnt, const char *rel_mnt, int lazy) { int res; if (!mtab_needs_update(abs_mnt)) { res = umount2(rel_mnt, lazy ? 2 : 0); if (res == -1) fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, abs_mnt, strerror(errno)); return res; } return exec_umount(progname, rel_mnt, lazy); } static int remove_mount(const char *progname, const char *mnt) { int res; int status; sigset_t blockmask; sigset_t oldmask; sigemptyset(&blockmask); sigaddset(&blockmask, SIGCHLD); res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); if (res == -1) { fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); return -1; } res = fork(); if (res == -1) { fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); goto out_restore; } if (res == 0) { char *env = NULL; sigprocmask(SIG_SETMASK, &oldmask, NULL); setuid(geteuid()); execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", "--fake", mnt, NULL, &env); fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname, strerror(errno)); exit(1); } res = waitpid(res, &status, 0); if (res == -1) fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); if (status != 0) res = -1; out_restore: sigprocmask(SIG_SETMASK, &oldmask, NULL); return res; } int fuse_mnt_remove_mount(const char *progname, const char *mnt) { if (!mtab_needs_update(mnt)) return 0; return remove_mount(progname, mnt); } char *fuse_mnt_resolve_path(const char *progname, const char *orig) { char buf[PATH_MAX]; char *copy; char *dst; char *end; char *lastcomp; const char *toresolv; if (!orig[0]) { fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig); return NULL; } copy = strdup(orig); if (copy == NULL) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return NULL; } toresolv = copy; lastcomp = NULL; for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); if (end[0] != '/') { char *tmp; end[1] = '\0'; tmp = strrchr(copy, '/'); if (tmp == NULL) { lastcomp = copy; toresolv = "."; } else { lastcomp = tmp + 1; if (tmp == copy) toresolv = "/"; } if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { lastcomp = NULL; toresolv = copy; } else if (tmp) tmp[0] = '\0'; } if (realpath(toresolv, buf) == NULL) { fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, strerror(errno)); free(copy); return NULL; } if (lastcomp == NULL) dst = strdup(buf); else { dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); if (dst) { unsigned buflen = strlen(buf); if (buflen && buf[buflen-1] == '/') sprintf(dst, "%s%s", buf, lastcomp); else sprintf(dst, "%s/%s", buf, lastcomp); } } free(copy); if (dst == NULL) fprintf(stderr, "%s: failed to allocate memory\n", progname); return dst; } int fuse_mnt_check_empty(const char *progname, const char *mnt, mode_t rootmode, off_t rootsize) { int isempty = 1; if (S_ISDIR(rootmode)) { struct dirent *ent; DIR *dp = opendir(mnt); if (dp == NULL) { fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n", progname, strerror(errno)); return -1; } while ((ent = readdir(dp)) != NULL) { if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { isempty = 0; break; } } closedir(dp); } else if (rootsize) isempty = 0; if (!isempty) { fprintf(stderr, "%s: mountpoint is not empty\n", progname); fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); return -1; } return 0; } int fuse_mnt_check_fuseblk(void) { char buf[256]; FILE *f = fopen("/proc/filesystems", "r"); if (!f) return 1; while (fgets(buf, sizeof(buf), f)) if (strstr(buf, "fuseblk\n")) { fclose(f); return 1; } fclose(f); return 0; } fuse-2.9.9/util/ulockmgr_server.c0000664000175000017500000001777613413660255014001 00000000000000/* ulockmgr_server: Userspace Lock Manager Server Copyright (C) 2006 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ /* #define DEBUG 1 */ #include #include #include #include #include #include #include #include #include #include #include #include #include struct message { unsigned intr : 1; unsigned nofd : 1; pthread_t thr; int cmd; int fd; struct flock lock; int error; }; struct fd_store { struct fd_store *next; int fd; int origfd; int inuse; }; struct owner { struct fd_store *fds; pthread_mutex_t lock; }; struct req_data { struct owner *o; int cfd; struct fd_store *f; struct message msg; }; #define MAX_SEND_FDS 2 static int receive_message(int sock, void *buf, size_t buflen, int *fdp, int *numfds) { struct msghdr msg; struct iovec iov; size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; struct cmsghdr *cmsg; int res; int i; assert(*numfds <= MAX_SEND_FDS); iov.iov_base = buf; iov.iov_len = buflen; memset(&msg, 0, sizeof(msg)); memset(ccmsg, -1, sizeof(ccmsg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ccmsg; msg.msg_controllen = sizeof(ccmsg); res = recvmsg(sock, &msg, MSG_WAITALL); if (!res) { /* retry on zero return, see do_recv() in ulockmgr.c */ res = recvmsg(sock, &msg, MSG_WAITALL); if (!res) return 0; } if (res == -1) { perror("ulockmgr_server: recvmsg"); return -1; } if ((size_t) res != buflen) { fprintf(stderr, "ulockmgr_server: short message received\n"); return -1; } cmsg = CMSG_FIRSTHDR(&msg); if (cmsg) { if (cmsg->cmsg_type != SCM_RIGHTS) { fprintf(stderr, "ulockmgr_server: unknown control message %d\n", cmsg->cmsg_type); return -1; } memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); if (msg.msg_flags & MSG_CTRUNC) { fprintf(stderr, "ulockmgr_server: control message truncated\n"); for (i = 0; i < *numfds; i++) close(fdp[i]); *numfds = 0; } } else { if (msg.msg_flags & MSG_CTRUNC) { fprintf(stderr, "ulockmgr_server: control message truncated(*)\n"); /* There's a bug in the Linux kernel, that if not all file descriptors were allocated, then the cmsg header is not filled in */ cmsg = (struct cmsghdr *) ccmsg; memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); for (i = 0; i < *numfds; i++) close(fdp[i]); } *numfds = 0; } return res; } static int closefrom(int minfd) { DIR *dir = opendir("/proc/self/fd"); if (dir) { int dfd = dirfd(dir); struct dirent *ent; while ((ent = readdir(dir))) { char *end; int fd = strtol(ent->d_name, &end, 10); if (ent->d_name[0] && !end[0] && fd >= minfd && fd != dfd) close(fd); } closedir(dir); } return 0; } static void send_reply(int cfd, struct message *msg) { int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL); if (res == -1) perror("ulockmgr_server: sending reply"); #ifdef DEBUG fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error); #endif } static void *process_request(void *d_) { struct req_data *d = d_; int res; assert(d->msg.cmd == F_SETLKW); res = fcntl(d->f->fd, F_SETLK, &d->msg.lock); if (res == -1 && errno == EAGAIN) { d->msg.error = EAGAIN; d->msg.thr = pthread_self(); send_reply(d->cfd, &d->msg); res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock); } d->msg.error = (res == -1) ? errno : 0; pthread_mutex_lock(&d->o->lock); d->f->inuse--; pthread_mutex_unlock(&d->o->lock); send_reply(d->cfd, &d->msg); close(d->cfd); free(d); return NULL; } static void process_message(struct owner *o, struct message *msg, int cfd, int fd) { struct fd_store *f = NULL; struct fd_store *newf = NULL; struct fd_store **fp; struct req_data *d; pthread_t tid; int res; #ifdef DEBUG fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n", msg->cmd, msg->lock.l_type, msg->lock.l_whence, msg->lock.l_start, msg->lock.l_len); #endif if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK && msg->lock.l_start == 0 && msg->lock.l_len == 0) { for (fp = &o->fds; *fp;) { f = *fp; if (f->origfd == msg->fd && !f->inuse) { close(f->fd); *fp = f->next; free(f); } else fp = &f->next; } if (!msg->nofd) close(fd); msg->error = 0; send_reply(cfd, msg); close(cfd); return; } if (msg->nofd) { for (fp = &o->fds; *fp; fp = &(*fp)->next) { f = *fp; if (f->origfd == msg->fd) break; } if (!*fp) { fprintf(stderr, "ulockmgr_server: fd %i not found\n", msg->fd); msg->error = EIO; send_reply(cfd, msg); close(cfd); return; } } else { newf = f = malloc(sizeof(struct fd_store)); if (!f) { msg->error = ENOLCK; send_reply(cfd, msg); close(cfd); return; } f->fd = fd; f->origfd = msg->fd; f->inuse = 0; } if (msg->cmd == F_GETLK || msg->cmd == F_SETLK || msg->lock.l_type == F_UNLCK) { res = fcntl(f->fd, msg->cmd, &msg->lock); msg->error = (res == -1) ? errno : 0; send_reply(cfd, msg); close(cfd); if (newf) { newf->next = o->fds; o->fds = newf; } return; } d = malloc(sizeof(struct req_data)); if (!d) { msg->error = ENOLCK; send_reply(cfd, msg); close(cfd); free(newf); return; } f->inuse++; d->o = o; d->cfd = cfd; d->f = f; d->msg = *msg; res = pthread_create(&tid, NULL, process_request, d); if (res) { msg->error = ENOLCK; send_reply(cfd, msg); close(cfd); free(d); f->inuse--; free(newf); return; } if (newf) { newf->next = o->fds; o->fds = newf; } pthread_detach(tid); } static void sigusr1_handler(int sig) { (void) sig; /* Nothing to do */ } static void process_owner(int cfd) { struct owner o; struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigusr1_handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR1, &sa, NULL) == -1) { perror("ulockmgr_server: cannot set sigusr1 signal handler"); exit(1); } memset(&o, 0, sizeof(struct owner)); pthread_mutex_init(&o.lock, NULL); while (1) { struct message msg; int rfds[2]; int res; int numfds = 2; res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds); if (!res) break; if (res == -1) exit(1); if (msg.intr) { if (numfds != 0) fprintf(stderr, "ulockmgr_server: too many fds for intr\n"); pthread_kill(msg.thr, SIGUSR1); } else { if (numfds != 2) continue; pthread_mutex_lock(&o.lock); process_message(&o, &msg, rfds[0], rfds[1]); pthread_mutex_unlock(&o.lock); } } if (o.fds) fprintf(stderr, "ulockmgr_server: open file descriptors on exit\n"); } int main(int argc, char *argv[]) { int nullfd; char *end; int cfd; sigset_t empty; if (argc != 2 || !argv[1][0]) goto out_inval; cfd = strtol(argv[1], &end, 10); if (*end) goto out_inval; /* demonize current process */ switch(fork()) { case -1: perror("ulockmgr_server: fork"); exit(1); case 0: break; default: _exit(0); } if (setsid() == -1) { perror("ulockmgr_server: setsid"); exit(1); } (void) chdir("/"); sigemptyset(&empty); sigprocmask(SIG_SETMASK, &empty, NULL); if (dup2(cfd, 4) == -1) { perror("ulockmgr_server: dup2"); exit(1); } cfd = 4; nullfd = open("/dev/null", O_RDWR); if (nullfd >= 0) { dup2(nullfd, 0); dup2(nullfd, 1); } close(3); closefrom(5); while (1) { char c; int sock; int pid; int numfds = 1; int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds); if (!res) break; if (res == -1) exit(1); assert(numfds == 1); pid = fork(); if (pid == -1) { perror("ulockmgr_server: fork"); close(sock); continue; } if (pid == 0) { close(cfd); pid = fork(); if (pid == -1) { perror("ulockmgr_server: fork"); _exit(1); } if (pid == 0) process_owner(sock); _exit(0); } waitpid(pid, NULL, 0); close(sock); } return 0; out_inval: fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]); return 1; } fuse-2.9.9/util/fusermount.c0000664000175000017500000007553513413660305012770 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ /* This program does the mounting and unmounting of FUSE filesystems */ #define _GNU_SOURCE /* for clone */ #include #include "mount_util.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FUSE_COMMFD_ENV "_FUSE_COMMFD" #define FUSE_DEV_OLD "/proc/fs/fuse/dev" #define FUSE_DEV_NEW "/dev/fuse" #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version" #define FUSE_CONF "/etc/fuse.conf" #ifndef MS_DIRSYNC #define MS_DIRSYNC 128 #endif #ifndef MS_REC #define MS_REC 16384 #endif #ifndef MS_PRIVATE #define MS_PRIVATE (1<<18) #endif #ifndef UMOUNT_DETACH #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */ #endif #ifndef UMOUNT_NOFOLLOW #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */ #endif #ifndef UMOUNT_UNUSED #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */ #endif static const char *progname; static int user_allow_other = 0; static int mount_max = 1000; static int auto_unmount = 0; static const char *get_user_name(void) { struct passwd *pw = getpwuid(getuid()); if (pw != NULL && pw->pw_name != NULL) return pw->pw_name; else { fprintf(stderr, "%s: could not determine username\n", progname); return NULL; } } static uid_t oldfsuid; static gid_t oldfsgid; static void drop_privs(void) { if (getuid() != 0) { oldfsuid = setfsuid(getuid()); oldfsgid = setfsgid(getgid()); } } static void restore_privs(void) { if (getuid() != 0) { setfsuid(oldfsuid); setfsgid(oldfsgid); } } #ifndef IGNORE_MTAB /* * Make sure that /etc/mtab is checked and updated atomically */ static int lock_umount(void) { const char *mtab_lock = _PATH_MOUNTED ".fuselock"; int mtablock; int res; struct stat mtab_stat; /* /etc/mtab could be a symlink to /proc/mounts */ if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode)) return -1; mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600); if (mtablock == -1) { fprintf(stderr, "%s: unable to open fuse lock file: %s\n", progname, strerror(errno)); return -1; } res = lockf(mtablock, F_LOCK, 0); if (res < 0) { fprintf(stderr, "%s: error getting lock: %s\n", progname, strerror(errno)); close(mtablock); return -1; } return mtablock; } static void unlock_umount(int mtablock) { if (mtablock >= 0) { int res; res = lockf(mtablock, F_ULOCK, 0); if (res < 0) { fprintf(stderr, "%s: error releasing lock: %s\n", progname, strerror(errno)); } close(mtablock); } } static int add_mount(const char *source, const char *mnt, const char *type, const char *opts) { return fuse_mnt_add_mount(progname, source, mnt, type, opts); } static int may_unmount(const char *mnt, int quiet) { struct mntent *entp; FILE *fp; const char *user = NULL; char uidstr[32]; unsigned uidlen = 0; int found; const char *mtab = _PATH_MOUNTED; user = get_user_name(); if (user == NULL) return -1; fp = setmntent(mtab, "r"); if (fp == NULL) { fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, strerror(errno)); return -1; } uidlen = sprintf(uidstr, "%u", getuid()); found = 0; while ((entp = getmntent(fp)) != NULL) { if (!found && strcmp(entp->mnt_dir, mnt) == 0 && (strcmp(entp->mnt_type, "fuse") == 0 || strcmp(entp->mnt_type, "fuseblk") == 0 || strncmp(entp->mnt_type, "fuse.", 5) == 0 || strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { char *p = strstr(entp->mnt_opts, "user="); if (p && (p == entp->mnt_opts || *(p-1) == ',') && strcmp(p + 5, user) == 0) { found = 1; break; } /* /etc/mtab is a link pointing to /proc/mounts: */ else if ((p = strstr(entp->mnt_opts, "user_id=")) && (p == entp->mnt_opts || *(p-1) == ',') && strncmp(p + 8, uidstr, uidlen) == 0 && (*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0')) { found = 1; break; } } } endmntent(fp); if (!found) { if (!quiet) fprintf(stderr, "%s: entry for %s not found in %s\n", progname, mnt, mtab); return -1; } return 0; } /* * Check whether the file specified in "fusermount -u" is really a * mountpoint and not a symlink. This is necessary otherwise the user * could move the mountpoint away and replace it with a symlink * pointing to an arbitrary mount, thereby tricking fusermount into * unmounting that (umount(2) will follow symlinks). * * This is the child process running in a separate mount namespace, so * we don't mess with the global namespace and if the process is * killed for any reason, mounts are automatically cleaned up. * * First make sure nothing is propagated back into the parent * namespace by marking all mounts "private". * * Then bind mount parent onto a stable base where the user can't move * it around. * * Finally check /proc/mounts for an entry matching the requested * mountpoint. If it's found then we are OK, and the user can't move * it around within the parent directory as rename() will return * EBUSY. Be careful to ignore any mounts that existed before the * bind. */ static int check_is_mount_child(void *p) { const char **a = p; const char *last = a[0]; const char *mnt = a[1]; int res; const char *procmounts = "/proc/mounts"; int found; FILE *fp; struct mntent *entp; int count; res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL); if (res == -1) { fprintf(stderr, "%s: failed to mark mounts private: %s\n", progname, strerror(errno)); return 1; } fp = setmntent(procmounts, "r"); if (fp == NULL) { fprintf(stderr, "%s: failed to open %s: %s\n", progname, procmounts, strerror(errno)); return 1; } count = 0; while (getmntent(fp) != NULL) count++; endmntent(fp); fp = setmntent(procmounts, "r"); if (fp == NULL) { fprintf(stderr, "%s: failed to open %s: %s\n", progname, procmounts, strerror(errno)); return 1; } res = mount(".", "/", "", MS_BIND | MS_REC, NULL); if (res == -1) { fprintf(stderr, "%s: failed to bind parent to /: %s\n", progname, strerror(errno)); return 1; } found = 0; while ((entp = getmntent(fp)) != NULL) { if (count > 0) { count--; continue; } if (entp->mnt_dir[0] == '/' && strcmp(entp->mnt_dir + 1, last) == 0) { found = 1; break; } } endmntent(fp); if (!found) { fprintf(stderr, "%s: %s not mounted\n", progname, mnt); return 1; } return 0; } static pid_t clone_newns(void *a) { char buf[131072]; char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15)); #ifdef __ia64__ extern int __clone2(int (*fn)(void *), void *child_stack_base, size_t stack_size, int flags, void *arg, pid_t *ptid, void *tls, pid_t *ctid); return __clone2(check_is_mount_child, stack, sizeof(buf) / 2, CLONE_NEWNS, a, NULL, NULL, NULL); #else return clone(check_is_mount_child, stack, CLONE_NEWNS, a); #endif } static int check_is_mount(const char *last, const char *mnt) { pid_t pid, p; int status; const char *a[2] = { last, mnt }; pid = clone_newns((void *) a); if (pid == (pid_t) -1) { fprintf(stderr, "%s: failed to clone namespace: %s\n", progname, strerror(errno)); return -1; } p = waitpid(pid, &status, __WCLONE); if (p == (pid_t) -1) { fprintf(stderr, "%s: waitpid failed: %s\n", progname, strerror(errno)); return -1; } if (!WIFEXITED(status)) { fprintf(stderr, "%s: child terminated abnormally (status %i)\n", progname, status); return -1; } if (WEXITSTATUS(status) != 0) return -1; return 0; } static int chdir_to_parent(char *copy, const char **lastp) { char *tmp; const char *parent; char buf[65536]; int res; tmp = strrchr(copy, '/'); if (tmp == NULL || tmp[1] == '\0') { fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n", progname, copy); return -1; } if (tmp != copy) { *tmp = '\0'; parent = copy; *lastp = tmp + 1; } else if (tmp[1] != '\0') { *lastp = tmp + 1; parent = "/"; } else { *lastp = "."; parent = "/"; } res = chdir(parent); if (res == -1) { fprintf(stderr, "%s: failed to chdir to %s: %s\n", progname, parent, strerror(errno)); return -1; } if (getcwd(buf, sizeof(buf)) == NULL) { fprintf(stderr, "%s: failed to obtain current directory: %s\n", progname, strerror(errno)); return -1; } if (strcmp(buf, parent) != 0) { fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname, parent, buf); return -1; } return 0; } /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */ static int umount_nofollow_support(void) { int res = umount2("", UMOUNT_UNUSED); if (res != -1 || errno != EINVAL) return 0; res = umount2("", UMOUNT_NOFOLLOW); if (res != -1 || errno != ENOENT) return 0; return 1; } static int unmount_fuse_locked(const char *mnt, int quiet, int lazy) { int res; char *copy; const char *last; int umount_flags = lazy ? UMOUNT_DETACH : 0; if (getuid() != 0) { res = may_unmount(mnt, quiet); if (res == -1) return -1; } copy = strdup(mnt); if (copy == NULL) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return -1; } res = chdir_to_parent(copy, &last); if (res == -1) goto out; if (umount_nofollow_support()) { umount_flags |= UMOUNT_NOFOLLOW; } else { res = check_is_mount(last, mnt); if (res == -1) goto out; } res = umount2(last, umount_flags); if (res == -1 && !quiet) { fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt, strerror(errno)); } out: if (res == -1) return -1; res = chdir("/"); if (res == -1) { fprintf(stderr, "%s: failed to chdir to '/'\n", progname); return -1; } return fuse_mnt_remove_mount(progname, mnt); } static int unmount_fuse(const char *mnt, int quiet, int lazy) { int res; int mtablock = lock_umount(); res = unmount_fuse_locked(mnt, quiet, lazy); unlock_umount(mtablock); return res; } static int count_fuse_fs(void) { struct mntent *entp; int count = 0; const char *mtab = _PATH_MOUNTED; FILE *fp = setmntent(mtab, "r"); if (fp == NULL) { fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, strerror(errno)); return -1; } while ((entp = getmntent(fp)) != NULL) { if (strcmp(entp->mnt_type, "fuse") == 0 || strncmp(entp->mnt_type, "fuse.", 5) == 0) count ++; } endmntent(fp); return count; } #else /* IGNORE_MTAB */ static int count_fuse_fs() { return 0; } static int add_mount(const char *source, const char *mnt, const char *type, const char *opts) { (void) source; (void) mnt; (void) type; (void) opts; return 0; } static int unmount_fuse(const char *mnt, int quiet, int lazy) { return fuse_mnt_umount(progname, mnt, mnt, lazy); } #endif /* IGNORE_MTAB */ static void strip_line(char *line) { char *s = strchr(line, '#'); if (s != NULL) s[0] = '\0'; for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--); s[1] = '\0'; for (s = line; isspace((unsigned char) *s); s++); if (s != line) memmove(line, s, strlen(s)+1); } static void parse_line(char *line, int linenum) { int tmp; if (strcmp(line, "user_allow_other") == 0) user_allow_other = 1; else if (sscanf(line, "mount_max = %i", &tmp) == 1) mount_max = tmp; else if(line[0]) fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n", progname, FUSE_CONF, linenum, line); } static void read_conf(void) { FILE *fp = fopen(FUSE_CONF, "r"); if (fp != NULL) { int linenum = 1; char line[256]; int isnewline = 1; while (fgets(line, sizeof(line), fp) != NULL) { if (isnewline) { if (line[strlen(line)-1] == '\n') { strip_line(line); parse_line(line, linenum); } else { isnewline = 0; } } else if(line[strlen(line)-1] == '\n') { fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum); isnewline = 1; } if (isnewline) linenum ++; } if (!isnewline) { fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF); } if (ferror(fp)) { fprintf(stderr, "%s: reading %s: read failed\n", progname, FUSE_CONF); exit(1); } fclose(fp); } else if (errno != ENOENT) { bool fatal = (errno != EACCES && errno != ELOOP && errno != ENAMETOOLONG && errno != ENOTDIR && errno != EOVERFLOW); fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF, strerror(errno)); if (fatal) exit(1); } } static int begins_with(const char *s, const char *beg) { if (strncmp(s, beg, strlen(beg)) == 0) return 1; else return 0; } struct mount_flags { const char *opt; unsigned long flag; int on; int safe; }; static struct mount_flags mount_flags[] = { {"rw", MS_RDONLY, 0, 1}, {"ro", MS_RDONLY, 1, 1}, {"suid", MS_NOSUID, 0, 0}, {"nosuid", MS_NOSUID, 1, 1}, {"dev", MS_NODEV, 0, 0}, {"nodev", MS_NODEV, 1, 1}, {"exec", MS_NOEXEC, 0, 1}, {"noexec", MS_NOEXEC, 1, 1}, {"async", MS_SYNCHRONOUS, 0, 1}, {"sync", MS_SYNCHRONOUS, 1, 1}, {"atime", MS_NOATIME, 0, 1}, {"noatime", MS_NOATIME, 1, 1}, {"dirsync", MS_DIRSYNC, 1, 1}, {NULL, 0, 0, 0} }; static int find_mount_flag(const char *s, unsigned len, int *on, int *flag) { int i; for (i = 0; mount_flags[i].opt != NULL; i++) { const char *opt = mount_flags[i].opt; if (strlen(opt) == len && strncmp(opt, s, len) == 0) { *on = mount_flags[i].on; *flag = mount_flags[i].flag; if (!mount_flags[i].safe && getuid() != 0) { *flag = 0; fprintf(stderr, "%s: unsafe option %s ignored\n", progname, opt); } return 1; } } return 0; } static int add_option(char **optsp, const char *opt, unsigned expand) { char *newopts; if (*optsp == NULL) newopts = strdup(opt); else { unsigned oldsize = strlen(*optsp); unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1; newopts = (char *) realloc(*optsp, newsize); if (newopts) sprintf(newopts + oldsize, ",%s", opt); } if (newopts == NULL) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return -1; } *optsp = newopts; return 0; } static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) { int i; int l; if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) return -1; for (i = 0; mount_flags[i].opt != NULL; i++) { if (mount_flags[i].on && (flags & mount_flags[i].flag) && add_option(mnt_optsp, mount_flags[i].opt, 0) == -1) return -1; } if (add_option(mnt_optsp, opts, 0) == -1) return -1; /* remove comma from end of opts*/ l = strlen(*mnt_optsp); if ((*mnt_optsp)[l-1] == ',') (*mnt_optsp)[l-1] = '\0'; if (getuid() != 0) { const char *user = get_user_name(); if (user == NULL) return -1; if (add_option(mnt_optsp, "user=", strlen(user)) == -1) return -1; strcat(*mnt_optsp, user); } return 0; } static int opt_eq(const char *s, unsigned len, const char *opt) { if(strlen(opt) == len && strncmp(s, opt, len) == 0) return 1; else return 0; } static int get_string_opt(const char *s, unsigned len, const char *opt, char **val) { int i; unsigned opt_len = strlen(opt); char *d; if (*val) free(*val); *val = (char *) malloc(len - opt_len + 1); if (!*val) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return 0; } d = *val; s += opt_len; len -= opt_len; for (i = 0; i < len; i++) { if (s[i] == '\\' && i + 1 < len) i++; *d++ = s[i]; } *d = '\0'; return 1; } static int do_mount(const char *mnt, char **typep, mode_t rootmode, int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp, off_t rootsize) { int res; int flags = MS_NOSUID | MS_NODEV; char *optbuf; char *mnt_opts = NULL; const char *s; char *d; char *fsname = NULL; char *subtype = NULL; char *source = NULL; char *type = NULL; int check_empty = 1; int blkdev = 0; optbuf = (char *) malloc(strlen(opts) + 128); if (!optbuf) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return -1; } for (s = opts, d = optbuf; *s;) { unsigned len; const char *fsname_str = "fsname="; const char *subtype_str = "subtype="; bool escape_ok = begins_with(s, fsname_str) || begins_with(s, subtype_str); for (len = 0; s[len]; len++) { if (escape_ok && s[len] == '\\' && s[len + 1]) len++; else if (s[len] == ',') break; } if (begins_with(s, fsname_str)) { if (!get_string_opt(s, len, fsname_str, &fsname)) goto err; } else if (begins_with(s, subtype_str)) { if (!get_string_opt(s, len, subtype_str, &subtype)) goto err; } else if (opt_eq(s, len, "blkdev")) { if (getuid() != 0) { fprintf(stderr, "%s: option blkdev is privileged\n", progname); goto err; } blkdev = 1; } else if (opt_eq(s, len, "nonempty")) { check_empty = 0; } else if (opt_eq(s, len, "auto_unmount")) { auto_unmount = 1; } else if (!begins_with(s, "fd=") && !begins_with(s, "rootmode=") && !begins_with(s, "user_id=") && !begins_with(s, "group_id=")) { int on; int flag; int skip_option = 0; if (opt_eq(s, len, "large_read")) { struct utsname utsname; unsigned kmaj, kmin; res = uname(&utsname); if (res == 0 && sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 && (kmaj > 2 || (kmaj == 2 && kmin > 4))) { fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); skip_option = 1; } } if (getuid() != 0 && !user_allow_other && (opt_eq(s, len, "allow_other") || opt_eq(s, len, "allow_root"))) { fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); goto err; } if (!skip_option) { if (find_mount_flag(s, len, &on, &flag)) { if (on) flags |= flag; else flags &= ~flag; } else if (opt_eq(s, len, "default_permissions") || opt_eq(s, len, "allow_other") || begins_with(s, "max_read=") || begins_with(s, "blksize=")) { memcpy(d, s, len); d += len; *d++ = ','; } else { fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, s); exit(1); } } } s += len; if (*s) s++; } *d = '\0'; res = get_mnt_opts(flags, optbuf, &mnt_opts); if (res == -1) goto err; sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u", fd, rootmode, getuid(), getgid()); if (check_empty && fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) goto err; source = malloc((fsname ? strlen(fsname) : 0) + (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); type = malloc((subtype ? strlen(subtype) : 0) + 32); if (!type || !source) { fprintf(stderr, "%s: failed to allocate memory\n", progname); goto err; } if (subtype) sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); else strcpy(type, blkdev ? "fuseblk" : "fuse"); if (fsname) strcpy(source, fsname); else strcpy(source, subtype ? subtype : dev); res = mount(source, mnt, type, flags, optbuf); if (res == -1 && errno == ENODEV && subtype) { /* Probably missing subtype support */ strcpy(type, blkdev ? "fuseblk" : "fuse"); if (fsname) { if (!blkdev) sprintf(source, "%s#%s", subtype, fsname); } else { strcpy(source, type); } res = mount(source, mnt, type, flags, optbuf); } if (res == -1 && errno == EINVAL) { /* It could be an old version not supporting group_id */ sprintf(d, "fd=%i,rootmode=%o,user_id=%u", fd, rootmode, getuid()); res = mount(source, mnt, type, flags, optbuf); } if (res == -1) { int errno_save = errno; if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) fprintf(stderr, "%s: 'fuseblk' support missing\n", progname); else fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); goto err; } *sourcep = source; *typep = type; *mnt_optsp = mnt_opts; free(fsname); free(optbuf); return 0; err: free(fsname); free(subtype); free(source); free(type); free(mnt_opts); free(optbuf); return -1; } static int check_version(const char *dev) { int res; int majorver; int minorver; const char *version_file; FILE *vf; if (strcmp(dev, FUSE_DEV_OLD) != 0) return 0; version_file = FUSE_VERSION_FILE_OLD; vf = fopen(version_file, "r"); if (vf == NULL) { fprintf(stderr, "%s: kernel interface too old\n", progname); return -1; } res = fscanf(vf, "%i.%i", &majorver, &minorver); fclose(vf); if (res != 2) { fprintf(stderr, "%s: error reading %s\n", progname, version_file); return -1; } if (majorver < 3) { fprintf(stderr, "%s: kernel interface too old\n", progname); return -1; } return 0; } static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd) { int res; const char *mnt = *mntp; const char *origmnt = mnt; struct statfs fs_buf; size_t i; res = lstat(mnt, stbuf); if (res == -1) { fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", progname, mnt, strerror(errno)); return -1; } /* No permission checking is done for root */ if (getuid() == 0) return 0; if (S_ISDIR(stbuf->st_mode)) { res = chdir(mnt); if (res == -1) { fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n", progname, strerror(errno)); return -1; } mnt = *mntp = "."; res = lstat(mnt, stbuf); if (res == -1) { fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", progname, origmnt, strerror(errno)); return -1; } if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { fprintf(stderr, "%s: mountpoint %s not owned by user\n", progname, origmnt); return -1; } res = access(mnt, W_OK); if (res == -1) { fprintf(stderr, "%s: user has no write access to mountpoint %s\n", progname, origmnt); return -1; } } else if (S_ISREG(stbuf->st_mode)) { static char procfile[256]; *mountpoint_fd = open(mnt, O_WRONLY); if (*mountpoint_fd == -1) { fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt, strerror(errno)); return -1; } res = fstat(*mountpoint_fd, stbuf); if (res == -1) { fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", progname, mnt, strerror(errno)); return -1; } if (!S_ISREG(stbuf->st_mode)) { fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n", progname, mnt); return -1; } sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); *mntp = procfile; } else { fprintf(stderr, "%s: mountpoint %s is not a directory or a regular file\n", progname, mnt); return -1; } /* Do not permit mounting over anything in procfs - it has a couple * places to which we have "write access" without being supposed to be * able to just put anything we want there. * Luckily, without allow_other, we can't get other users to actually * use any fake information we try to put there anyway. * Use a whitelist to be safe. */ if (statfs(*mntp, &fs_buf)) { fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", progname, mnt, strerror(errno)); return -1; } /* Use the same list of permitted filesystems for the mount target as * the ecryptfs mount helper * (https://bazaar.launchpad.net/~ecryptfs/ecryptfs/trunk/view/head:/src/utils/mount.ecryptfs_private.c#L225). */ typeof(fs_buf.f_type) f_type_whitelist[] = { 0x5346414f /* OPENAFS_SUPER_MAGIC */, 0x61756673 /* AUFS_SUPER_MAGIC */, 0x9123683E /* BTRFS_SUPER_MAGIC */, 0x00C36400 /* CEPH_SUPER_MAGIC */, 0xFF534D42 /* CIFS_MAGIC_NUMBER */, 0x0000F15F /* ECRYPTFS_SUPER_MAGIC */, 0x0000EF53 /* EXT[234]_SUPER_MAGIC */, 0xF2F52010 /* F2FS_SUPER_MAGIC */, 0x65735546 /* FUSE_SUPER_MAGIC */, 0x01161970 /* GFS2_MAGIC */, 0x3153464A /* JFS_SUPER_MAGIC */, 0x000072B6 /* JFFS2_SUPER_MAGIC */, 0x0000564C /* NCP_SUPER_MAGIC */, 0x00006969 /* NFS_SUPER_MAGIC */, 0x00003434 /* NILFS_SUPER_MAGIC */, 0x5346544E /* NTFS_SB_MAGIC */, 0x794C7630 /* OVERLAYFS_SUPER_MAGIC */, 0x52654973 /* REISERFS_SUPER_MAGIC */, 0x73717368 /* SQUASHFS_MAGIC */, 0x01021994 /* TMPFS_MAGIC */, 0x24051905 /* UBIFS_SUPER_MAGIC */, 0x58465342 /* XFS_SB_MAGIC */, 0x2FC12FC1 /* ZFS_SUPER_MAGIC */, }; for (i = 0; i < sizeof(f_type_whitelist)/sizeof(f_type_whitelist[0]); i++) { if (f_type_whitelist[i] == fs_buf.f_type) return 0; } fprintf(stderr, "%s: mounting over filesystem type %#010lx is forbidden\n", progname, (unsigned long)fs_buf.f_type); return -1; } static int try_open(const char *dev, char **devp, int silent) { int fd = open(dev, O_RDWR); if (fd != -1) { *devp = strdup(dev); if (*devp == NULL) { fprintf(stderr, "%s: failed to allocate memory\n", progname); close(fd); fd = -1; } } else if (errno == ENODEV || errno == ENOENT)/* check for ENOENT too, for the udev case */ return -2; else if (!silent) { fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, strerror(errno)); } return fd; } static int try_open_fuse_device(char **devp) { int fd; int err; drop_privs(); fd = try_open(FUSE_DEV_NEW, devp, 0); restore_privs(); if (fd >= 0) return fd; err = fd; fd = try_open(FUSE_DEV_OLD, devp, 1); if (fd >= 0) return fd; return err; } static int open_fuse_device(char **devp) { int fd = try_open_fuse_device(devp); if (fd >= -1) return fd; fprintf(stderr, "%s: fuse device not found, try 'modprobe fuse' first\n", progname); return -1; } static int mount_fuse(const char *mnt, const char *opts) { int res; int fd; char *dev; struct stat stbuf; char *type = NULL; char *source = NULL; char *mnt_opts = NULL; const char *real_mnt = mnt; int mountpoint_fd = -1; fd = open_fuse_device(&dev); if (fd == -1) return -1; drop_privs(); read_conf(); if (getuid() != 0 && mount_max != -1) { int mount_count = count_fuse_fs(); if (mount_count >= mount_max) { fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); goto fail_close_fd; } } res = check_version(dev); if (res != -1) { res = check_perm(&real_mnt, &stbuf, &mountpoint_fd); restore_privs(); if (res != -1) res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts, dev, &source, &mnt_opts, stbuf.st_size); } else restore_privs(); if (mountpoint_fd != -1) close(mountpoint_fd); if (res == -1) goto fail_close_fd; res = chdir("/"); if (res == -1) { fprintf(stderr, "%s: failed to chdir to '/'\n", progname); goto fail_close_fd; } if (geteuid() == 0) { res = add_mount(source, mnt, type, mnt_opts); if (res == -1) { /* Can't clean up mount in a non-racy way */ goto fail_close_fd; } } out_free: free(source); free(type); free(mnt_opts); free(dev); return fd; fail_close_fd: close(fd); fd = -1; goto out_free; } static int send_fd(int sock_fd, int fd) { int retval; struct msghdr msg; struct cmsghdr *p_cmsg; struct iovec vec; size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; int *p_fds; char sendchar = 0; msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); p_cmsg = CMSG_FIRSTHDR(&msg); p_cmsg->cmsg_level = SOL_SOCKET; p_cmsg->cmsg_type = SCM_RIGHTS; p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); p_fds = (int *) CMSG_DATA(p_cmsg); *p_fds = fd; msg.msg_controllen = p_cmsg->cmsg_len; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &vec; msg.msg_iovlen = 1; msg.msg_flags = 0; /* "To pass file descriptors or credentials you need to send/read at * least one byte" (man 7 unix) */ vec.iov_base = &sendchar; vec.iov_len = sizeof(sendchar); while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR); if (retval != 1) { perror("sending file descriptor"); return -1; } return 0; } static void usage(void) { fprintf(stderr, "%s: [options] mountpoint\n" "Options:\n" " -h print help\n" " -V print version\n" " -o opt[,opt...] mount options\n" " -u unmount\n" " -q quiet\n" " -z lazy unmount\n", progname); exit(1); } static void show_version(void) { printf("fusermount version: %s\n", PACKAGE_VERSION); exit(0); } int main(int argc, char *argv[]) { sigset_t sigset; int ch; int fd; int res; char *origmnt; char *mnt; static int unmount = 0; static int lazy = 0; static int quiet = 0; char *commfd; int cfd; const char *opts = ""; static const struct option long_opts[] = { {"unmount", no_argument, NULL, 'u'}, {"lazy", no_argument, NULL, 'z'}, {"quiet", no_argument, NULL, 'q'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, {0, 0, 0, 0}}; progname = strdup(argv[0]); if (progname == NULL) { fprintf(stderr, "%s: failed to allocate memory\n", argv[0]); exit(1); } while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, NULL)) != -1) { switch (ch) { case 'h': usage(); break; case 'V': show_version(); break; case 'o': opts = optarg; break; case 'u': unmount = 1; break; case 'z': lazy = 1; break; case 'q': quiet = 1; break; default: exit(1); } } if (lazy && !unmount) { fprintf(stderr, "%s: -z can only be used with -u\n", progname); exit(1); } if (optind >= argc) { fprintf(stderr, "%s: missing mountpoint argument\n", progname); exit(1); } else if (argc > optind + 1) { fprintf(stderr, "%s: extra arguments after the mountpoint\n", progname); exit(1); } origmnt = argv[optind]; drop_privs(); mnt = fuse_mnt_resolve_path(progname, origmnt); if (mnt != NULL) { res = chdir("/"); if (res == -1) { fprintf(stderr, "%s: failed to chdir to '/'\n", progname); exit(1); } } restore_privs(); if (mnt == NULL) exit(1); umask(033); if (unmount) goto do_unmount; commfd = getenv(FUSE_COMMFD_ENV); if (commfd == NULL) { fprintf(stderr, "%s: old style mounting not supported\n", progname); exit(1); } fd = mount_fuse(mnt, opts); if (fd == -1) exit(1); cfd = atoi(commfd); res = send_fd(cfd, fd); if (res == -1) exit(1); close(fd); if (!auto_unmount) return 0; /* Become a daemon and wait for the parent to exit or die. ie For the control socket to get closed. btw We don't want to use daemon() function here because it forks and messes with the file descriptors. */ setsid(); res = chdir("/"); if (res == -1) { fprintf(stderr, "%s: failed to chdir to '/'\n", progname); exit(1); } sigfillset(&sigset); sigprocmask(SIG_BLOCK, &sigset, NULL); lazy = 1; quiet = 1; while (1) { unsigned char buf[16]; int n = recv(cfd, buf, sizeof(buf), 0); if (!n) break; if (n < 0) { if (errno == EINTR) continue; break; } } do_unmount: if (geteuid() == 0) res = unmount_fuse(mnt, quiet, lazy); else { res = umount2(mnt, lazy ? UMOUNT_DETACH : 0); if (res == -1 && !quiet) fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt, strerror(errno)); } if (res == -1) exit(1); return 0; } fuse-2.9.9/config.sub0000755000175000017500000010676313413660776011433 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2016 Free Software Foundation, Inc. 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 # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program 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 this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # 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 # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) 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." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. 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* | netbsd*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | 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 \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | 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[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; 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 ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | 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-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | 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*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) 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 ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) 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 ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -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* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -onefs* | -tirtos* | -phoenix* | -fuchsia*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -ios) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: fuse-2.9.9/depcomp0000755000175000017500000005601613413660776011020 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program 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 this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: fuse-2.9.9/README.md0000664000175000017500000000775613413660255010723 00000000000000libfuse ======= Warning: unresolved security issue ---------------------------------- Be aware that FUSE has an unresolved security bug ([bug #15](https://github.com/libfuse/libfuse/issues/15)): the permission check for accessing a cached directory is only done once when the directory entry is first loaded into the cache. Subsequent accesses will re-use the results of the first check, even if the directory permissions have since changed, and even if the subsequent access is made by a different user. This bug needs to be fixed in the Linux kernel and has been known since 2006 but unfortunately no fix has been applied yet. If you depend on correct permission handling for FUSE file systems, the only workaround is to completely disable caching of directory entries. Alternatively, the severity of the bug can be somewhat reduced by not using the `allow_other` mount option. About ----- FUSE (Filesystem in Userspace) is an interface for userspace programs to export a filesystem to the Linux kernel. The FUSE project consists of two components: the *fuse* kernel module (maintained in the regular kernel repositories) and the *libfuse* userspace library (maintained in this repository). libfuse provides the reference implementation for communicating with the FUSE kernel module. A FUSE file system is typically implemented as a standalone application that links with libfuse. libfuse provides functions to mount the file system, unmount it, read requests from the kernel, and send responses back. libfuse offers two APIs: a "high-level", synchronous API, and a "low-level" asynchronous API. In both cases, incoming requests from the kernel are passed to the main program using callbacks. When using the high-level API, the callbacks may work with file names and paths instead of inodes, and processing of a request finishes when the callback function returns. When using the low-level API, the callbacks must work with inodes and responses must be sent explicitly using a separate set of API functions. Installation ------------ ./configure make -j8 make install You may also need to add `/usr/local/lib` to `/etc/ld.so.conf` and/or run *ldconfig*. If you're building from the git repository (instead of using a release tarball), you also need to run `./makeconf.sh` to create the `configure` script. You'll also need a fuse kernel module (Linux kernels 2.6.14 or later contain FUSE support). For more details see the file `INSTALL` Security implications --------------------- If you run `make install`, the *fusermount* program is installed set-user-id to root. This is done to allow normal users to mount their own filesystem implementations. There must however be some limitations, in order to prevent Bad User from doing nasty things. Currently those limitations are: - The user can only mount on a mountpoint, for which it has write permission - The mountpoint is not a sticky directory which isn't owned by the user (like /tmp usually is) - No other user (including root) can access the contents of the mounted filesystem (though this can be relaxed by allowing the use of the `allow_other` and `allow_root` mount options in `fuse.conf`) Building your own filesystem ------------------------------ FUSE comes with several example file systems in the `examples` directory. For example, the *fusexmp* example mirrors the contents of the root directory under the mountpoint. Start from there and adapt the code! The documentation of the API functions and necessary callbacks is mostly contained in the files `include/fuse.h` (for the high-level API) and `include/fuse_lowlevel.h` (for the low-level API). An autogenerated html version of the API is available in the `doc/html` directory and at http://libfuse.github.io/doxygen. Getting Help ------------ If you need help, please ask on the mailing list (subscribe at https://lists.sourceforge.net/lists/listinfo/fuse-devel). Please report any bugs on the GitHub issue tracker at https://github.com/libfuse/main/issues. fuse-2.9.9/fuse.pc.in0000664000175000017500000000041113413660255011314 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: fuse Description: Filesystem in Userspace Version: @VERSION@ Libs: -L${libdir} -lfuse -pthread Libs.private: @libfuse_libs@ Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64 fuse-2.9.9/Makefile.am0000664000175000017500000000042313413660255011460 00000000000000## Process this file with automake to produce Makefile.in ACLOCAL_AMFLAGS = -I m4 SUBDIRS = @subdirs2@ doc AUTOMAKE_OPTIONS = subdir-objects EXTRA_DIST = \ fuse.pc.in \ README* pkgconfigdir = @pkgconfigdir@ pkgconfig_DATA = fuse.pc $(pkgconfig_DATA): config.status fuse-2.9.9/include/0000775000175000017500000000000013413661013011121 500000000000000fuse-2.9.9/include/fuse_compat.h0000664000175000017500000001746513413660255013543 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ struct fuse_operations_compat25 { int (*getattr) (const char *, struct stat *); int (*readlink) (const char *, char *, size_t); int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); int (*mknod) (const char *, mode_t, dev_t); int (*mkdir) (const char *, mode_t); int (*unlink) (const char *); int (*rmdir) (const char *); int (*symlink) (const char *, const char *); int (*rename) (const char *, const char *); int (*link) (const char *, const char *); int (*chmod) (const char *, mode_t); int (*chown) (const char *, uid_t, gid_t); int (*truncate) (const char *, off_t); int (*utime) (const char *, struct utimbuf *); int (*open) (const char *, struct fuse_file_info *); int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); int (*statfs) (const char *, struct statvfs *); int (*flush) (const char *, struct fuse_file_info *); int (*release) (const char *, struct fuse_file_info *); int (*fsync) (const char *, int, struct fuse_file_info *); int (*setxattr) (const char *, const char *, const char *, size_t, int); int (*getxattr) (const char *, const char *, char *, size_t); int (*listxattr) (const char *, char *, size_t); int (*removexattr) (const char *, const char *); int (*opendir) (const char *, struct fuse_file_info *); int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); int (*releasedir) (const char *, struct fuse_file_info *); int (*fsyncdir) (const char *, int, struct fuse_file_info *); void *(*init) (void); void (*destroy) (void *); int (*access) (const char *, int); int (*create) (const char *, mode_t, struct fuse_file_info *); int (*ftruncate) (const char *, off_t, struct fuse_file_info *); int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); }; struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, const struct fuse_operations_compat25 *op, size_t op_size); int fuse_main_real_compat25(int argc, char *argv[], const struct fuse_operations_compat25 *op, size_t op_size); struct fuse *fuse_setup_compat25(int argc, char *argv[], const struct fuse_operations_compat25 *op, size_t op_size, char **mountpoint, int *multithreaded, int *fd); void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint); #if !defined(__FreeBSD__) && !defined(__NetBSD__) #include struct fuse_operations_compat22 { int (*getattr) (const char *, struct stat *); int (*readlink) (const char *, char *, size_t); int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); int (*mknod) (const char *, mode_t, dev_t); int (*mkdir) (const char *, mode_t); int (*unlink) (const char *); int (*rmdir) (const char *); int (*symlink) (const char *, const char *); int (*rename) (const char *, const char *); int (*link) (const char *, const char *); int (*chmod) (const char *, mode_t); int (*chown) (const char *, uid_t, gid_t); int (*truncate) (const char *, off_t); int (*utime) (const char *, struct utimbuf *); int (*open) (const char *, struct fuse_file_info_compat *); int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info_compat *); int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info_compat *); int (*statfs) (const char *, struct statfs *); int (*flush) (const char *, struct fuse_file_info_compat *); int (*release) (const char *, struct fuse_file_info_compat *); int (*fsync) (const char *, int, struct fuse_file_info_compat *); int (*setxattr) (const char *, const char *, const char *, size_t, int); int (*getxattr) (const char *, const char *, char *, size_t); int (*listxattr) (const char *, char *, size_t); int (*removexattr) (const char *, const char *); int (*opendir) (const char *, struct fuse_file_info_compat *); int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info_compat *); int (*releasedir) (const char *, struct fuse_file_info_compat *); int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *); void *(*init) (void); void (*destroy) (void *); }; struct fuse *fuse_new_compat22(int fd, const char *opts, const struct fuse_operations_compat22 *op, size_t op_size); struct fuse *fuse_setup_compat22(int argc, char *argv[], const struct fuse_operations_compat22 *op, size_t op_size, char **mountpoint, int *multithreaded, int *fd); int fuse_main_real_compat22(int argc, char *argv[], const struct fuse_operations_compat22 *op, size_t op_size); typedef int (*fuse_dirfil_t_compat) (fuse_dirh_t h, const char *name, int type); struct fuse_operations_compat2 { int (*getattr) (const char *, struct stat *); int (*readlink) (const char *, char *, size_t); int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); int (*mknod) (const char *, mode_t, dev_t); int (*mkdir) (const char *, mode_t); int (*unlink) (const char *); int (*rmdir) (const char *); int (*symlink) (const char *, const char *); int (*rename) (const char *, const char *); int (*link) (const char *, const char *); int (*chmod) (const char *, mode_t); int (*chown) (const char *, uid_t, gid_t); int (*truncate) (const char *, off_t); int (*utime) (const char *, struct utimbuf *); int (*open) (const char *, int); int (*read) (const char *, char *, size_t, off_t); int (*write) (const char *, const char *, size_t, off_t); int (*statfs) (const char *, struct statfs *); int (*flush) (const char *); int (*release) (const char *, int); int (*fsync) (const char *, int); int (*setxattr) (const char *, const char *, const char *, size_t, int); int (*getxattr) (const char *, const char *, char *, size_t); int (*listxattr) (const char *, char *, size_t); int (*removexattr) (const char *, const char *); }; int fuse_main_compat2(int argc, char *argv[], const struct fuse_operations_compat2 *op); struct fuse *fuse_new_compat2(int fd, const char *opts, const struct fuse_operations_compat2 *op); struct fuse *fuse_setup_compat2(int argc, char *argv[], const struct fuse_operations_compat2 *op, char **mountpoint, int *multithreaded, int *fd); struct fuse_statfs_compat1 { long block_size; long blocks; long blocks_free; long files; long files_free; long namelen; }; struct fuse_operations_compat1 { int (*getattr) (const char *, struct stat *); int (*readlink) (const char *, char *, size_t); int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); int (*mknod) (const char *, mode_t, dev_t); int (*mkdir) (const char *, mode_t); int (*unlink) (const char *); int (*rmdir) (const char *); int (*symlink) (const char *, const char *); int (*rename) (const char *, const char *); int (*link) (const char *, const char *); int (*chmod) (const char *, mode_t); int (*chown) (const char *, uid_t, gid_t); int (*truncate) (const char *, off_t); int (*utime) (const char *, struct utimbuf *); int (*open) (const char *, int); int (*read) (const char *, char *, size_t, off_t); int (*write) (const char *, const char *, size_t, off_t); int (*statfs) (struct fuse_statfs_compat1 *); int (*release) (const char *, int); int (*fsync) (const char *, int); }; #define FUSE_DEBUG_COMPAT1 (1 << 1) struct fuse *fuse_new_compat1(int fd, int flags, const struct fuse_operations_compat1 *op); void fuse_main_compat1(int argc, char *argv[], const struct fuse_operations_compat1 *op); #endif /* __FreeBSD__ || __NetBSD__ */ fuse-2.9.9/include/cuse_lowlevel.h0000664000175000017500000000502013413660255014066 00000000000000/* CUSE: Character device in Userspace Copyright (C) 2008-2009 SUSE Linux Products GmbH Copyright (C) 2008-2009 Tejun Heo This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. Read example/cusexmp.c for usages. */ #ifndef _CUSE_LOWLEVEL_H_ #define _CUSE_LOWLEVEL_H_ #ifndef FUSE_USE_VERSION #define FUSE_USE_VERSION 29 #endif #include "fuse_lowlevel.h" #include #include #include #ifdef __cplusplus extern "C" { #endif #define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */ struct fuse_session; struct cuse_info { unsigned dev_major; unsigned dev_minor; unsigned dev_info_argc; const char **dev_info_argv; unsigned flags; }; /* * Most ops behave almost identically to the matching fuse_lowlevel * ops except that they don't take @ino. * * init_done : called after initialization is complete * read/write : always direct IO, simultaneous operations allowed * ioctl : might be in unrestricted mode depending on ci->flags */ struct cuse_lowlevel_ops { void (*init) (void *userdata, struct fuse_conn_info *conn); void (*init_done) (void *userdata); void (*destroy) (void *userdata); void (*open) (fuse_req_t req, struct fuse_file_info *fi); void (*read) (fuse_req_t req, size_t size, off_t off, struct fuse_file_info *fi); void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off, struct fuse_file_info *fi); void (*flush) (fuse_req_t req, struct fuse_file_info *fi); void (*release) (fuse_req_t req, struct fuse_file_info *fi); void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi); void (*ioctl) (fuse_req_t req, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz); void (*poll) (fuse_req_t req, struct fuse_file_info *fi, struct fuse_pollhandle *ph); }; struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata); struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, int *multithreaded, void *userdata); void cuse_lowlevel_teardown(struct fuse_session *se); int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata); #ifdef __cplusplus } #endif #endif /* _CUSE_LOWLEVEL_H_ */ fuse-2.9.9/include/Makefile.in0000664000175000017500000004414713413660777013140 00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # 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, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ 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 \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = include 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 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(fuseinclude_HEADERS) \ $(include_HEADERS) $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(fuseincludedir)" \ "$(DESTDIR)$(includedir)" HEADERS = $(fuseinclude_HEADERS) $(include_HEADERS) $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INIT_D_PATH = @INIT_D_PATH@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ 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@ MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UDEV_RULES_PATH = @UDEV_RULES_PATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libfuse_libs = @libfuse_libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs2 = @subdirs2@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ fuseincludedir = $(includedir)/fuse fuseinclude_HEADERS = \ fuse.h \ fuse_compat.h \ fuse_common.h \ fuse_common_compat.h \ fuse_lowlevel.h \ fuse_lowlevel_compat.h \ fuse_opt.h \ cuse_lowlevel.h include_HEADERS = old/fuse.h ulockmgr.h noinst_HEADERS = fuse_kernel.h all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign include/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status include/config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-fuseincludeHEADERS: $(fuseinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(fuseinclude_HEADERS)'; test -n "$(fuseincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(fuseincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(fuseincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(fuseincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(fuseincludedir)" || exit $$?; \ done uninstall-fuseincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(fuseinclude_HEADERS)'; test -n "$(fuseincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(fuseincludedir)'; $(am__uninstall_files_from_dir) install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(HEADERS) config.h installdirs: for dir in "$(DESTDIR)$(fuseincludedir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-fuseincludeHEADERS install-includeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-fuseincludeHEADERS uninstall-includeHEADERS .MAKE: all install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am \ install-fuseincludeHEADERS install-html install-html-am \ install-includeHEADERS install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-fuseincludeHEADERS uninstall-includeHEADERS .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. .NOEXPORT: fuse-2.9.9/include/old/0000775000175000017500000000000013413661013011677 500000000000000fuse-2.9.9/include/old/fuse.h0000664000175000017500000000036613413660255012746 00000000000000/* This header is for compatibility with older software using FUSE. Please use 'pkg-config --cflags fuse' to set include path. The correct usage is still '#include ', not '#include '. */ #include "fuse/fuse.h" fuse-2.9.9/include/fuse_lowlevel.h0000664000175000017500000015003113413660255014074 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ #ifndef _FUSE_LOWLEVEL_H_ #define _FUSE_LOWLEVEL_H_ /** @file * * 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 */ #ifndef FUSE_USE_VERSION #define FUSE_USE_VERSION 24 #endif #include "fuse_common.h" #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* ----------------------------------------------------------- * * Miscellaneous definitions * * ----------------------------------------------------------- */ /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 /** Inode number type */ typedef unsigned long fuse_ino_t; /** Request pointer type */ typedef struct fuse_req *fuse_req_t; /** * Session * * This provides hooks for processing requests, and exiting */ struct fuse_session; /** * Channel * * A communication channel, providing hooks for sending and receiving * messages */ struct fuse_chan; /** Directory entry parameters supplied to fuse_reply_entry() */ struct fuse_entry_param { /** Unique inode number * * In lookup, zero means negative entry (from version 2.5) * Returning ENOENT also means negative entry, but by setting zero * ino the kernel may cache negative entries for entry_timeout * seconds. */ fuse_ino_t ino; /** Generation number for this entry. * * If the file system will be exported over NFS, the * ino/generation pairs need to be unique over the file * system's lifetime (rather than just the mount time). So if * the file system reuses an inode after it has been deleted, * it must assign a new, previously unused generation number * to the inode at the same time. * * The generation must be non-zero, otherwise FUSE will treat * it as an error. * */ unsigned long generation; /** Inode attributes. * * Even if attr_timeout == 0, attr must be correct. For example, * for open(), FUSE uses attr.st_size from lookup() to determine * how many bytes to request. If this value is not correct, * incorrect data will be returned. */ struct stat attr; /** Validity timeout (in seconds) for the attributes */ double attr_timeout; /** Validity timeout (in seconds) for the name */ double entry_timeout; }; /** * Additional context associated with requests. * * Note that the reported client uid, gid and pid may be zero in some * situations. For example, if the FUSE file system is running in a * PID or user namespace but then accessed from outside the namespace, * there is no valid uid/pid/gid that could be reported. */ struct fuse_ctx { /** User ID of the calling process */ uid_t uid; /** Group ID of the calling process */ gid_t gid; /** Thread ID of the calling process */ pid_t pid; /** Umask of the calling process (introduced in version 2.8) */ mode_t umask; }; struct fuse_forget_data { uint64_t ino; uint64_t nlookup; }; /* 'to_set' flags in setattr */ #define FUSE_SET_ATTR_MODE (1 << 0) #define FUSE_SET_ATTR_UID (1 << 1) #define FUSE_SET_ATTR_GID (1 << 2) #define FUSE_SET_ATTR_SIZE (1 << 3) #define FUSE_SET_ATTR_ATIME (1 << 4) #define FUSE_SET_ATTR_MTIME (1 << 5) #define FUSE_SET_ATTR_ATIME_NOW (1 << 7) #define FUSE_SET_ATTR_MTIME_NOW (1 << 8) /* ----------------------------------------------------------- * * Request methods and replies * * ----------------------------------------------------------- */ /** * Low level filesystem operations * * Most of the methods (with the exception of init and destroy) * receive a request handle (fuse_req_t) as their first argument. * This handle must be passed to one of the specified reply functions. * * This may be done inside the method invocation, or after the call * has returned. The request handle is valid until one of the reply * functions is called. * * Other pointer arguments (name, fuse_file_info, etc) are not valid * after the call has returned, so if they are needed later, their * contents have to be copied. * * The filesystem sometimes needs to handle a return value of -ENOENT * from the reply function, which means, that the request was * interrupted, and the reply discarded. For example if * fuse_reply_open() return -ENOENT means, that the release method for * this file will not be called. */ struct fuse_lowlevel_ops { /** * Initialize filesystem * * Called before any other filesystem method * * There's no reply to this function * * @param userdata the user data passed to fuse_lowlevel_new() */ void (*init) (void *userdata, struct fuse_conn_info *conn); /** * Clean up filesystem * * Called on filesystem exit * * There's no reply to this function * * @param userdata the user data passed to fuse_lowlevel_new() */ void (*destroy) (void *userdata); /** * Look up a directory entry by name and get its attributes. * * Valid replies: * fuse_reply_entry * fuse_reply_err * * @param req request handle * @param parent inode number of the parent directory * @param name the name to look up */ void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); /** * Forget about an inode * * This function is called when the kernel removes an inode * from its internal caches. * * The inode's lookup count increases by one for every call to * fuse_reply_entry and fuse_reply_create. The nlookup parameter * indicates by how much the lookup count should be decreased. * * Inodes with a non-zero lookup count may receive request from * the kernel even after calls to unlink, rmdir or (when * overwriting an existing file) rename. Filesystems must handle * such requests properly and it is recommended to defer removal * of the inode until the lookup count reaches zero. Calls to * unlink, remdir or rename will be followed closely by forget * unless the file or directory is open, in which case the * kernel issues forget only after the release or releasedir * calls. * * Note that if a file system will be exported over NFS the * inodes lifetime must extend even beyond forget. See the * generation field in struct fuse_entry_param above. * * On unmount the lookup count for all inodes implicitly drops * to zero. It is not guaranteed that the file system will * receive corresponding forget messages for the affected * inodes. * * Valid replies: * fuse_reply_none * * @param req request handle * @param ino the inode number * @param nlookup the number of lookups to forget */ void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); /** * Get file attributes * * Valid replies: * fuse_reply_attr * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi for future use, currently always NULL */ void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); /** * Set file attributes * * In the 'attr' argument only members indicated by the 'to_set' * bitmask contain valid values. Other members contain undefined * values. * * If the setattr was invoked from the ftruncate() system call * under Linux kernel versions 2.6.15 or later, the fi->fh will * contain the value set by the open method or will be undefined * if the open method didn't set any value. Otherwise (not * ftruncate call, or kernel version earlier than 2.6.15) the fi * parameter will be NULL. * * Valid replies: * fuse_reply_attr * fuse_reply_err * * @param req request handle * @param ino the inode number * @param attr the attributes * @param to_set bit mask of attributes which should be set * @param fi file information, or NULL * * Changed in version 2.5: * file information filled in for ftruncate */ void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi); /** * Read symbolic link * * Valid replies: * fuse_reply_readlink * fuse_reply_err * * @param req request handle * @param ino the inode number */ void (*readlink) (fuse_req_t req, fuse_ino_t ino); /** * Create file node * * Create a regular file, character device, block device, fifo or * socket node. * * Valid replies: * fuse_reply_entry * fuse_reply_err * * @param req request handle * @param parent inode number of the parent directory * @param name to create * @param mode file type and mode with which to create the new file * @param rdev the device number (only valid if created file is a device) */ void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev); /** * Create a directory * * Valid replies: * fuse_reply_entry * fuse_reply_err * * @param req request handle * @param parent inode number of the parent directory * @param name to create * @param mode with which to create the new file */ void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode); /** * Remove a file * * If the file's inode's lookup count is non-zero, the file * system is expected to postpone any removal of the inode * until the lookup count reaches zero (see description of the * forget function). * * Valid replies: * fuse_reply_err * * @param req request handle * @param parent inode number of the parent directory * @param name to remove */ void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); /** * Remove a directory * * If the directory's inode's lookup count is non-zero, the * file system is expected to postpone any removal of the * inode until the lookup count reaches zero (see description * of the forget function). * * Valid replies: * fuse_reply_err * * @param req request handle * @param parent inode number of the parent directory * @param name to remove */ void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); /** * Create a symbolic link * * Valid replies: * fuse_reply_entry * fuse_reply_err * * @param req request handle * @param link the contents of the symbolic link * @param parent inode number of the parent directory * @param name to create */ void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, const char *name); /** Rename a file * * If the target exists it should be atomically replaced. If * the target's inode's lookup count is non-zero, the file * system is expected to postpone any removal of the inode * until the lookup count reaches zero (see description of the * forget function). * * Valid replies: * fuse_reply_err * * @param req request handle * @param parent inode number of the old parent directory * @param name old name * @param newparent inode number of the new parent directory * @param newname new name */ void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname); /** * Create a hard link * * Valid replies: * fuse_reply_entry * fuse_reply_err * * @param req request handle * @param ino the old inode number * @param newparent inode number of the new parent directory * @param newname new name to create */ void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname); /** * Open a file * * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and * O_TRUNC) are available in fi->flags. * * Filesystem may store an arbitrary file handle (pointer, index, * etc) in fi->fh, and use this in other all other file operations * (read, write, flush, release, fsync). * * Filesystem may also implement stateless file I/O and not store * anything in fi->fh. * * There are also some flags (direct_io, keep_cache) which the * filesystem may set in fi, to change the way the file is opened. * See fuse_file_info structure in for more details. * * Valid replies: * fuse_reply_open * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information */ void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); /** * Read data * * Read should send exactly the number of bytes requested except * on EOF or error, otherwise the rest of the data will be * substituted with zeroes. An exception to this is when the file * has been opened in 'direct_io' mode, in which case the return * value of the read system call will reflect the return value of * this operation. * * fi->fh will contain the value set by the open method, or will * be undefined if the open method didn't set any value. * * Valid replies: * fuse_reply_buf * fuse_reply_iov * fuse_reply_data * fuse_reply_err * * @param req request handle * @param ino the inode number * @param size number of bytes to read * @param off offset to read from * @param fi file information */ void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); /** * Write data * * Write should return exactly the number of bytes requested * except on error. An exception to this is when the file has * been opened in 'direct_io' mode, in which case the return value * of the write system call will reflect the return value of this * operation. * * fi->fh will contain the value set by the open method, or will * be undefined if the open method didn't set any value. * * Valid replies: * fuse_reply_write * fuse_reply_err * * @param req request handle * @param ino the inode number * @param buf data to write * @param size number of bytes to write * @param off offset to write to * @param fi file information */ void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi); /** * Flush method * * This is called on each close() of the opened file. * * Since file descriptors can be duplicated (dup, dup2, fork), for * one open call there may be many flush calls. * * Filesystems shouldn't assume that flush will always be called * after some writes, or that if will be called at all. * * fi->fh will contain the value set by the open method, or will * be undefined if the open method didn't set any value. * * NOTE: the name of the method is misleading, since (unlike * fsync) the filesystem is not forced to flush pending writes. * One reason to flush data, is if the filesystem wants to return * write errors. * * If the filesystem supports file locking operations (setlk, * getlk) it should remove all locks belonging to 'fi->owner'. * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information */ void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); /** * Release an open file * * Release is called when there are no more references to an open * file: all file descriptors are closed and all memory mappings * are unmapped. * * For every open call there will be exactly one release call. * * The filesystem may reply with an error, but error values are * not returned to close() or munmap() which triggered the * release. * * fi->fh will contain the value set by the open method, or will * be undefined if the open method didn't set any value. * fi->flags will contain the same flags as for open. * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information */ void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); /** * Synchronize file contents * * If the datasync parameter is non-zero, then only the user data * should be flushed, not the meta data. * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param datasync flag indicating if only data should be flushed * @param fi file information */ void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); /** * Open a directory * * Filesystem may store an arbitrary file handle (pointer, index, * etc) in fi->fh, and use this in other all other directory * stream operations (readdir, releasedir, fsyncdir). * * Filesystem may also implement stateless directory I/O and not * store anything in fi->fh, though that makes it impossible to * implement standard conforming directory stream operations in * case the contents of the directory can change between opendir * and releasedir. * * Valid replies: * fuse_reply_open * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information */ void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); /** * Read directory * * Send a buffer filled using fuse_add_direntry(), with size not * exceeding the requested size. Send an empty buffer on end of * stream. * * fi->fh will contain the value set by the opendir method, or * will be undefined if the opendir method didn't set any value. * * Valid replies: * fuse_reply_buf * fuse_reply_data * fuse_reply_err * * @param req request handle * @param ino the inode number * @param size maximum number of bytes to send * @param off offset to continue reading the directory stream * @param fi file information */ void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); /** * Release an open directory * * For every opendir call there will be exactly one releasedir * call. * * fi->fh will contain the value set by the opendir method, or * will be undefined if the opendir method didn't set any value. * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information */ void (*releasedir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); /** * Synchronize directory contents * * If the datasync parameter is non-zero, then only the directory * contents should be flushed, not the meta data. * * fi->fh will contain the value set by the opendir method, or * will be undefined if the opendir method didn't set any value. * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param datasync flag indicating if only data should be flushed * @param fi file information */ void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); /** * Get file system statistics * * Valid replies: * fuse_reply_statfs * fuse_reply_err * * @param req request handle * @param ino the inode number, zero means "undefined" */ void (*statfs) (fuse_req_t req, fuse_ino_t ino); /** * Set an extended attribute * * Valid replies: * fuse_reply_err */ void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags); /** * Get an extended attribute * * If size is zero, the size of the value should be sent with * fuse_reply_xattr. * * If the size is non-zero, and the value fits in the buffer, the * value should be sent with fuse_reply_buf. * * If the size is too small for the value, the ERANGE error should * be sent. * * Valid replies: * fuse_reply_buf * fuse_reply_data * fuse_reply_xattr * fuse_reply_err * * @param req request handle * @param ino the inode number * @param name of the extended attribute * @param size maximum size of the value to send */ void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size); /** * List extended attribute names * * If size is zero, the total size of the attribute list should be * sent with fuse_reply_xattr. * * If the size is non-zero, and the null character separated * attribute list fits in the buffer, the list should be sent with * fuse_reply_buf. * * If the size is too small for the list, the ERANGE error should * be sent. * * Valid replies: * fuse_reply_buf * fuse_reply_data * fuse_reply_xattr * fuse_reply_err * * @param req request handle * @param ino the inode number * @param size maximum size of the list to send */ void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); /** * Remove an extended attribute * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param name of the extended attribute */ void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); /** * Check file access permissions * * This will be called for the access() system call. If the * 'default_permissions' mount option is given, this method is not * called. * * This method is not called under Linux kernel versions 2.4.x * * Introduced in version 2.5 * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param mask requested access mode */ void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); /** * Create and open a file * * If the file does not exist, first create it with the specified * mode, and then open it. * * Open flags (with the exception of O_NOCTTY) are available in * fi->flags. * * Filesystem may store an arbitrary file handle (pointer, index, * etc) in fi->fh, and use this in other all other file operations * (read, write, flush, release, fsync). * * There are also some flags (direct_io, keep_cache) which the * filesystem may set in fi, to change the way the file is opened. * See fuse_file_info structure in for more details. * * If this method is not implemented or under Linux kernel * versions earlier than 2.6.15, the mknod() and open() methods * will be called instead. * * Introduced in version 2.5 * * Valid replies: * fuse_reply_create * fuse_reply_err * * @param req request handle * @param parent inode number of the parent directory * @param name to create * @param mode file type and mode with which to create the new file * @param fi file information */ void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi); /** * Test for a POSIX file lock * * Introduced in version 2.6 * * Valid replies: * fuse_reply_lock * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information * @param lock the region/type to test */ void (*getlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock); /** * Acquire, modify or release a POSIX file lock * * For POSIX threads (NPTL) there's a 1-1 relation between pid and * owner, but otherwise this is not always the case. For checking * lock ownership, 'fi->owner' must be used. The l_pid field in * 'struct flock' should only be used to fill in this field in * getlk(). * * Note: if the locking methods are not implemented, the kernel * will still allow file locking to work locally. Hence these are * only interesting for network filesystems and similar. * * Introduced in version 2.6 * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information * @param lock the region/type to set * @param sleep locking operation may sleep */ void (*setlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep); /** * Map block index within file to block index within device * * Note: This makes sense only for block device backed filesystems * mounted with the 'blkdev' option * * Introduced in version 2.6 * * Valid replies: * fuse_reply_bmap * fuse_reply_err * * @param req request handle * @param ino the inode number * @param blocksize unit of block index * @param idx block index within file */ void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx); /** * Ioctl * * Note: For unrestricted ioctls (not allowed for FUSE * servers), data in and out areas can be discovered by giving * iovs and setting FUSE_IOCTL_RETRY in @flags. For * restricted ioctls, kernel prepares in/out data area * according to the information encoded in cmd. * * Introduced in version 2.8 * * Valid replies: * fuse_reply_ioctl_retry * fuse_reply_ioctl * fuse_reply_ioctl_iov * fuse_reply_err * * @param req request handle * @param ino the inode number * @param cmd ioctl command * @param arg ioctl argument * @param fi file information * @param flags for FUSE_IOCTL_* flags * @param in_buf data fetched from the caller * @param in_bufsz number of fetched bytes * @param out_bufsz maximum size of output data */ void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz); /** * Poll for IO readiness * * Introduced in version 2.8 * * Note: If ph is non-NULL, the client should notify * when IO readiness events occur by calling * fuse_lowelevel_notify_poll() with the specified ph. * * Regardless of the number of times poll with a non-NULL ph * is received, single notification is enough to clear all. * Notifying more times incurs overhead but doesn't harm * correctness. * * The callee is responsible for destroying ph with * fuse_pollhandle_destroy() when no longer in use. * * Valid replies: * fuse_reply_poll * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information * @param ph poll handle to be used for notification */ void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph); /** * Write data made available in a buffer * * This is a more generic version of the ->write() method. If * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the * kernel supports splicing from the fuse device, then the * data will be made available in pipe for supporting zero * copy data transfer. * * buf->count is guaranteed to be one (and thus buf->idx is * always zero). The write_buf handler must ensure that * bufv->off is correctly updated (reflecting the number of * bytes read from bufv->buf[0]). * * Introduced in version 2.9 * * Valid replies: * fuse_reply_write * fuse_reply_err * * @param req request handle * @param ino the inode number * @param bufv buffer containing the data * @param off offset to write to * @param fi file information */ void (*write_buf) (fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv, off_t off, struct fuse_file_info *fi); /** * Callback function for the retrieve request * * Introduced in version 2.9 * * Valid replies: * fuse_reply_none * * @param req request handle * @param cookie user data supplied to fuse_lowlevel_notify_retrieve() * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve() * @param offset the offset supplied to fuse_lowlevel_notify_retrieve() * @param bufv the buffer containing the returned data */ void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv); /** * Forget about multiple inodes * * See description of the forget function for more * information. * * Introduced in version 2.9 * * Valid replies: * fuse_reply_none * * @param req request handle */ void (*forget_multi) (fuse_req_t req, size_t count, struct fuse_forget_data *forgets); /** * Acquire, modify or release a BSD file lock * * Note: if the locking methods are not implemented, the kernel * will still allow file locking to work locally. Hence these are * only interesting for network filesystems and similar. * * Introduced in version 2.9 * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information * @param op the locking operation, see flock(2) */ void (*flock) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op); /** * Allocate requested space. If this function returns success then * subsequent writes to the specified range shall not fail due to the lack * of free space on the file system storage media. * * Introduced in version 2.9 * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param offset starting point for allocated region * @param length size of allocated region * @param mode determines the operation to be performed on the given range, * see fallocate(2) */ void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi); }; /** * Reply with an error code or success * * Possible requests: * all except forget * * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, * removexattr and setlk may send a zero code * * @param req request handle * @param err the positive error value, or zero for success * @return zero for success, -errno for failure to send reply */ int fuse_reply_err(fuse_req_t req, int err); /** * Don't send reply * * Possible requests: * forget * * @param req request handle */ void fuse_reply_none(fuse_req_t req); /** * Reply with a directory entry * * Possible requests: * lookup, mknod, mkdir, symlink, link * * Side effects: * increments the lookup count on success * * @param req request handle * @param e the entry parameters * @return zero for success, -errno for failure to send reply */ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); /** * Reply with a directory entry and open parameters * * currently the following members of 'fi' are used: * fh, direct_io, keep_cache * * Possible requests: * create * * Side effects: * increments the lookup count on success * * @param req request handle * @param e the entry parameters * @param fi file information * @return zero for success, -errno for failure to send reply */ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi); /** * Reply with attributes * * Possible requests: * getattr, setattr * * @param req request handle * @param attr the attributes * @param attr_timeout validity timeout (in seconds) for the attributes * @return zero for success, -errno for failure to send reply */ int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout); /** * Reply with the contents of a symbolic link * * Possible requests: * readlink * * @param req request handle * @param link symbolic link contents * @return zero for success, -errno for failure to send reply */ int fuse_reply_readlink(fuse_req_t req, const char *link); /** * Reply with open parameters * * currently the following members of 'fi' are used: * fh, direct_io, keep_cache * * Possible requests: * open, opendir * * @param req request handle * @param fi file information * @return zero for success, -errno for failure to send reply */ int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); /** * Reply with number of bytes written * * Possible requests: * write * * @param req request handle * @param count the number of bytes written * @return zero for success, -errno for failure to send reply */ int fuse_reply_write(fuse_req_t req, size_t count); /** * Reply with data * * Possible requests: * read, readdir, getxattr, listxattr * * @param req request handle * @param buf buffer containing data * @param size the size of data in bytes * @return zero for success, -errno for failure to send reply */ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); /** * Reply with data copied/moved from buffer(s) * * Possible requests: * read, readdir, getxattr, listxattr * * @param req request handle * @param bufv buffer vector * @param flags flags controlling the copy * @return zero for success, -errno for failure to send reply */ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags); /** * Reply with data vector * * Possible requests: * read, readdir, getxattr, listxattr * * @param req request handle * @param iov the vector containing the data * @param count the size of vector * @return zero for success, -errno for failure to send reply */ int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); /** * Reply with filesystem statistics * * Possible requests: * statfs * * @param req request handle * @param stbuf filesystem statistics * @return zero for success, -errno for failure to send reply */ int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); /** * Reply with needed buffer size * * Possible requests: * getxattr, listxattr * * @param req request handle * @param count the buffer size needed in bytes * @return zero for success, -errno for failure to send reply */ int fuse_reply_xattr(fuse_req_t req, size_t count); /** * Reply with file lock information * * Possible requests: * getlk * * @param req request handle * @param lock the lock information * @return zero for success, -errno for failure to send reply */ int fuse_reply_lock(fuse_req_t req, const struct flock *lock); /** * Reply with block index * * Possible requests: * bmap * * @param req request handle * @param idx block index within device * @return zero for success, -errno for failure to send reply */ int fuse_reply_bmap(fuse_req_t req, uint64_t idx); /* ----------------------------------------------------------- * * Filling a buffer in readdir * * ----------------------------------------------------------- */ /** * 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. * * @param req request handle * @param buf the point where the new entry will be added to the buffer * @param bufsize remaining size of the buffer * @param name the name of the entry * @param stbuf the file attributes * @param off the offset of the next entry * @return the space needed for the entry */ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off); /** * Reply to ask for data fetch and output buffer preparation. ioctl * will be retried with the specified input data fetched and output * buffer prepared. * * Possible requests: * ioctl * * @param req request handle * @param in_iov iovec specifying data to fetch from the caller * @param in_count number of entries in in_iov * @param out_iov iovec specifying addresses to write output to * @param out_count number of entries in out_iov * @return zero for success, -errno for failure to send reply */ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count); /** * Reply to finish ioctl * * Possible requests: * ioctl * * @param req request handle * @param result result to be passed to the caller * @param buf buffer containing output data * @param size length of output data */ int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size); /** * Reply to finish ioctl with iov buffer * * Possible requests: * ioctl * * @param req request handle * @param result result to be passed to the caller * @param iov the vector containing the data * @param count the size of vector */ int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count); /** * Reply with poll result event mask * * @param req request handle * @param revents poll result event mask */ int fuse_reply_poll(fuse_req_t req, unsigned revents); /* ----------------------------------------------------------- * * Notification * * ----------------------------------------------------------- */ /** * Notify IO readiness event * * For more information, please read comment for poll operation. * * @param ph poll handle to notify IO readiness event for */ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); /** * Notify to invalidate cache for an inode * * @param ch the channel through which to send the invalidation * @param ino the inode number * @param off the offset in the inode where to start invalidating * or negative to invalidate attributes only * @param len the amount of cache to invalidate or 0 for all * @return zero for success, -errno for failure */ int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, off_t off, off_t len); /** * Notify to invalidate parent attributes and the dentry matching * parent/name * * To avoid a deadlock don't call this function from a filesystem operation and * don't call it with a lock held that can also be held by a filesystem * operation. * * @param ch the channel through which to send the invalidation * @param parent inode number * @param name file name * @param namelen strlen() of file name * @return zero for success, -errno for failure */ int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, const char *name, size_t namelen); /** * Notify to invalidate parent attributes and delete the dentry matching * parent/name if the dentry's inode number matches child (otherwise it * will invalidate the matching dentry). * * To avoid a deadlock don't call this function from a filesystem operation and * don't call it with a lock held that can also be held by a filesystem * operation. * * @param ch the channel through which to send the notification * @param parent inode number * @param child inode number * @param name file name * @param namelen strlen() of file name * @return zero for success, -errno for failure */ int fuse_lowlevel_notify_delete(struct fuse_chan *ch, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen); /** * Store data to the kernel buffers * * Synchronously store data in the kernel buffers belonging to the * given inode. The stored data is marked up-to-date (no read will be * performed against it, unless it's invalidated or evicted from the * cache). * * If the stored data overflows the current file size, then the size * is extended, similarly to a write(2) on the filesystem. * * If this function returns an error, then the store wasn't fully * completed, but it may have been partially completed. * * @param ch the channel through which to send the invalidation * @param ino the inode number * @param offset the starting offset into the file to store to * @param bufv buffer vector * @param flags flags controlling the copy * @return zero for success, -errno for failure */ int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags); /** * Retrieve data from the kernel buffers * * Retrieve data in the kernel buffers belonging to the given inode. * If successful then the retrieve_reply() method will be called with * the returned data. * * Only present pages are returned in the retrieve reply. Retrieving * stops when it finds a non-present page and only data prior to that is * returned. * * If this function returns an error, then the retrieve will not be * completed and no reply will be sent. * * This function doesn't change the dirty state of pages in the kernel * buffer. For dirty pages the write() method will be called * regardless of having been retrieved previously. * * @param ch the channel through which to send the invalidation * @param ino the inode number * @param size the number of bytes to retrieve * @param offset the starting offset into the file to retrieve from * @param cookie user data to supply to the reply callback * @return zero for success, -errno for failure */ int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, size_t size, off_t offset, void *cookie); /* ----------------------------------------------------------- * * Utility functions * * ----------------------------------------------------------- */ /** * Get the userdata from the request * * @param req request handle * @return the user data passed to fuse_lowlevel_new() */ void *fuse_req_userdata(fuse_req_t req); /** * Get the context from the request * * The pointer returned by this function will only be valid for the * request's lifetime * * @param req request handle * @return the context structure */ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); /** * Get the current supplementary group IDs for the specified request * * Similar to the getgroups(2) system call, except the return value is * always the total number of group IDs, even if it is larger than the * specified size. * * The current fuse kernel module in linux (as of 2.6.30) doesn't pass * the group list to userspace, hence this function needs to parse * "/proc/$TID/task/$TID/status" to get the group IDs. * * This feature may not be supported on all operating systems. In * such a case this function will return -ENOSYS. * * @param req request handle * @param size size of given array * @param list array of group IDs to be filled in * @return the total number of supplementary group IDs or -errno on failure */ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]); /** * Callback function for an interrupt * * @param req interrupted request * @param data user data */ typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); /** * Register/unregister callback for an interrupt * * If an interrupt has already happened, then the callback function is * called from within this function, hence it's not possible for * interrupts to be lost. * * @param req request handle * @param func the callback function or NULL for unregister * @param data user data passed to the callback function */ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data); /** * Check if a request has already been interrupted * * @param req request handle * @return 1 if the request has been interrupted, 0 otherwise */ int fuse_req_interrupted(fuse_req_t req); /* ----------------------------------------------------------- * * Filesystem setup * * ----------------------------------------------------------- */ /* Deprecated, don't use */ int fuse_lowlevel_is_lib_option(const char *opt); /** * Create a low level session * * @param args argument vector * @param op the low level filesystem operations * @param op_size sizeof(struct fuse_lowlevel_ops) * @param userdata user data * @return the created session object, or NULL on failure */ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); /* ----------------------------------------------------------- * * Session interface * * ----------------------------------------------------------- */ /** * Session operations * * This is used in session creation */ struct fuse_session_ops { /** * Hook to process a request (mandatory) * * @param data user data passed to fuse_session_new() * @param buf buffer containing the raw request * @param len request length * @param ch channel on which the request was received */ void (*process) (void *data, const char *buf, size_t len, struct fuse_chan *ch); /** * Hook for session exit and reset (optional) * * @param data user data passed to fuse_session_new() * @param val exited status (1 - exited, 0 - not exited) */ void (*exit) (void *data, int val); /** * Hook for querying the current exited status (optional) * * @param data user data passed to fuse_session_new() * @return 1 if exited, 0 if not exited */ int (*exited) (void *data); /** * Hook for cleaning up the channel on destroy (optional) * * @param data user data passed to fuse_session_new() */ void (*destroy) (void *data); }; /** * Create a new session * * @param op session operations * @param data user data * @return new session object, or NULL on failure */ struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); /** * Assign a channel to a session * * Note: currently only a single channel may be assigned. This may * change in the future * * If a session is destroyed, the assigned channel is also destroyed * * @param se the session * @param ch the channel */ void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); /** * Remove a channel from a session * * If the channel is not assigned to a session, then this is a no-op * * @param ch the channel to remove */ void fuse_session_remove_chan(struct fuse_chan *ch); /** * Iterate over the channels assigned to a session * * The iterating function needs to start with a NULL channel, and * after that needs to pass the previously returned channel to the * function. * * @param se the session * @param ch the previous channel, or NULL * @return the next channel, or NULL if no more channels exist */ struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, struct fuse_chan *ch); /** * Process a raw request * * @param se the session * @param buf buffer containing the raw request * @param len request length * @param ch channel on which the request was received */ void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, struct fuse_chan *ch); /** * Process a raw request supplied in a generic buffer * * This is a more generic version of fuse_session_process(). The * fuse_buf may contain a memory buffer or a pipe file descriptor. * * @param se the session * @param buf the fuse_buf containing the request * @param ch channel on which the request was received */ void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf, struct fuse_chan *ch); /** * Receive a raw request supplied in a generic buffer * * This is a more generic version of fuse_chan_recv(). The fuse_buf * supplied to this function contains a suitably allocated memory * buffer. This may be overwritten with a file descriptor buffer. * * @param se the session * @param buf the fuse_buf to store the request in * @param chp pointer to the channel * @return the actual size of the raw request, or -errno on error */ int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan **chp); /** * Destroy a session * * @param se the session */ void fuse_session_destroy(struct fuse_session *se); /** * Exit a session * * @param se the session */ void fuse_session_exit(struct fuse_session *se); /** * Reset the exited status of a session * * @param se the session */ void fuse_session_reset(struct fuse_session *se); /** * Query the exited status of a session * * @param se the session * @return 1 if exited, 0 if not exited */ int fuse_session_exited(struct fuse_session *se); /** * Get the user data provided to the session * * @param se the session * @return the user data */ void *fuse_session_data(struct fuse_session *se); /** * Enter a single threaded event loop * * @param se the session * @return 0 on success, -1 on error */ int fuse_session_loop(struct fuse_session *se); /** * Enter a multi-threaded event loop * * @param se the session * @return 0 on success, -1 on error */ int fuse_session_loop_mt(struct fuse_session *se); /* ----------------------------------------------------------- * * Channel interface * * ----------------------------------------------------------- */ /** * Channel operations * * This is used in channel creation */ struct fuse_chan_ops { /** * Hook for receiving a raw request * * @param ch pointer to the channel * @param buf the buffer to store the request in * @param size the size of the buffer * @return the actual size of the raw request, or -1 on error */ int (*receive)(struct fuse_chan **chp, char *buf, size_t size); /** * Hook for sending a raw reply * * A return value of -ENOENT means, that the request was * interrupted, and the reply was discarded * * @param ch the channel * @param iov vector of blocks * @param count the number of blocks in vector * @return zero on success, -errno on failure */ int (*send)(struct fuse_chan *ch, const struct iovec iov[], size_t count); /** * Destroy the channel * * @param ch the channel */ void (*destroy)(struct fuse_chan *ch); }; /** * Create a new channel * * @param op channel operations * @param fd file descriptor of the channel * @param bufsize the minimal receive buffer size * @param data user data * @return the new channel object, or NULL on failure */ struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, size_t bufsize, void *data); /** * Query the file descriptor of the channel * * @param ch the channel * @return the file descriptor passed to fuse_chan_new() */ int fuse_chan_fd(struct fuse_chan *ch); /** * Query the minimal receive buffer size * * @param ch the channel * @return the buffer size passed to fuse_chan_new() */ size_t fuse_chan_bufsize(struct fuse_chan *ch); /** * Query the user data * * @param ch the channel * @return the user data passed to fuse_chan_new() */ void *fuse_chan_data(struct fuse_chan *ch); /** * Query the session to which this channel is assigned * * @param ch the channel * @return the session, or NULL if the channel is not assigned */ struct fuse_session *fuse_chan_session(struct fuse_chan *ch); /** * Receive a raw request * * A return value of -ENODEV means, that the filesystem was unmounted * * @param ch pointer to the channel * @param buf the buffer to store the request in * @param size the size of the buffer * @return the actual size of the raw request, or -errno on error */ int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); /** * Send a raw reply * * A return value of -ENOENT means, that the request was * interrupted, and the reply was discarded * * @param ch the channel * @param iov vector of blocks * @param count the number of blocks in vector * @return zero on success, -errno on failure */ int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count); /** * Destroy a channel * * @param ch the channel */ void fuse_chan_destroy(struct fuse_chan *ch); /* ----------------------------------------------------------- * * Compatibility stuff * * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # include "fuse_lowlevel_compat.h" # define fuse_chan_ops fuse_chan_ops_compat24 # define fuse_chan_new fuse_chan_new_compat24 # if FUSE_USE_VERSION == 25 # define fuse_lowlevel_ops fuse_lowlevel_ops_compat25 # define fuse_lowlevel_new fuse_lowlevel_new_compat25 # elif FUSE_USE_VERSION == 24 # define fuse_lowlevel_ops fuse_lowlevel_ops_compat # define fuse_lowlevel_new fuse_lowlevel_new_compat # define fuse_file_info fuse_file_info_compat # define fuse_reply_statfs fuse_reply_statfs_compat # define fuse_reply_open fuse_reply_open_compat # else # error Compatibility with low-level API version < 24 not supported # endif #endif #ifdef __cplusplus } #endif #endif /* _FUSE_LOWLEVEL_H_ */ fuse-2.9.9/include/Makefile.am0000664000175000017500000000053013413660255013102 00000000000000## Process this file with automake to produce Makefile.in fuseincludedir=$(includedir)/fuse fuseinclude_HEADERS = \ fuse.h \ fuse_compat.h \ fuse_common.h \ fuse_common_compat.h \ fuse_lowlevel.h \ fuse_lowlevel_compat.h \ fuse_opt.h \ cuse_lowlevel.h include_HEADERS = old/fuse.h ulockmgr.h noinst_HEADERS = fuse_kernel.h fuse-2.9.9/include/fuse.h0000664000175000017500000010347413413660255012174 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ #ifndef _FUSE_H_ #define _FUSE_H_ /** @file * * This file defines the library interface of FUSE * * IMPORTANT: you should define FUSE_USE_VERSION before including this * header. To use the newest API define it to 26 (recommended for any * new application), to use the old API define it to 21 (default) 22 * or 25, to use the even older 1.X API define it to 11. */ #ifndef FUSE_USE_VERSION #define FUSE_USE_VERSION 21 #endif #include "fuse_common.h" #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* ----------------------------------------------------------- * * Basic FUSE API * * ----------------------------------------------------------- */ /** Handle for a FUSE filesystem */ struct fuse; /** Structure containing a raw command */ struct fuse_cmd; /** Function to add an entry in a readdir() operation * * @param buf the buffer passed to the readdir() operation * @param name the file name of the directory entry * @param stat file attributes, can be NULL * @param off offset of the next entry or zero * @return 1 if buffer is full, zero otherwise */ typedef int (*fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off); /* Used by deprecated getdir() method */ typedef struct fuse_dirhandle *fuse_dirh_t; typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, ino_t ino); /** * The file system operations: * * Most of these should work very similarly to the well known UNIX * file system operations. A major exception is that instead of * returning an error in 'errno', the operation should return the * negated error value (-errno) directly. * * All methods are optional, but some are essential for a useful * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock, * init and destroy are special purpose methods, without which a full * featured filesystem can still be implemented. * * Almost all operations take a path which can be of any length. * * Changed in fuse 2.8.0 (regardless of API version) * Previously, paths were limited to a length of PATH_MAX. * * See http://fuse.sourceforge.net/wiki/ for more information. There * is also a snapshot of the relevant wiki pages in the doc/ folder. */ struct fuse_operations { /** Get file attributes. * * Similar to stat(). The 'st_dev' and 'st_blksize' fields are * ignored. The 'st_ino' field is ignored except if the 'use_ino' * mount option is given. */ int (*getattr) (const char *, struct stat *); /** Read the target of a symbolic link * * The buffer should be filled with a null terminated string. The * buffer size argument includes the space for the terminating * null character. If the linkname is too long to fit in the * buffer, it should be truncated. The return value should be 0 * for success. */ int (*readlink) (const char *, char *, size_t); /* Deprecated, use readdir() instead */ int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); /** Create a file node * * This is called for creation of all non-directory, non-symlink * nodes. If the filesystem defines a create() method, then for * regular files that will be called instead. */ int (*mknod) (const char *, mode_t, dev_t); /** Create a directory * * Note that the mode argument may not have the type specification * bits set, i.e. S_ISDIR(mode) can be false. To obtain the * correct directory type bits use mode|S_IFDIR * */ int (*mkdir) (const char *, mode_t); /** Remove a file */ int (*unlink) (const char *); /** Remove a directory */ int (*rmdir) (const char *); /** Create a symbolic link */ int (*symlink) (const char *, const char *); /** Rename a file */ int (*rename) (const char *, const char *); /** Create a hard link to a file */ int (*link) (const char *, const char *); /** Change the permission bits of a file */ int (*chmod) (const char *, mode_t); /** Change the owner and group of a file */ int (*chown) (const char *, uid_t, gid_t); /** Change the size of a file */ int (*truncate) (const char *, off_t); /** Change the access and/or modification times of a file * * Deprecated, use utimens() instead. */ int (*utime) (const char *, struct utimbuf *); /** File open operation * * No creation (O_CREAT, O_EXCL) and by default also no * truncation (O_TRUNC) flags will be passed to open(). If an * application specifies O_TRUNC, fuse first calls truncate() * and then open(). Only if 'atomic_o_trunc' has been * specified and kernel version is 2.6.24 or later, O_TRUNC is * passed on to open. * * Unless the 'default_permissions' mount option is given, * open should check if the operation is permitted for the * given flags. Optionally open may also return an arbitrary * filehandle in the fuse_file_info structure, which will be * passed to all file operations. * * Changed in version 2.2 */ int (*open) (const char *, struct fuse_file_info *); /** Read data from an open file * * Read should return exactly the number of bytes requested except * on EOF or error, otherwise the rest of the data will be * substituted with zeroes. An exception to this is when the * 'direct_io' mount option is specified, in which case the return * value of the read system call will reflect the return value of * this operation. * * Changed in version 2.2 */ int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); /** Write data to an open file * * Write should return exactly the number of bytes requested * except on error. An exception to this is when the 'direct_io' * mount option is specified (see read operation). * * Changed in version 2.2 */ int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); /** Get file system statistics * * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored * * Replaced 'struct statfs' parameter with 'struct statvfs' in * version 2.5 */ int (*statfs) (const char *, struct statvfs *); /** Possibly flush cached data * * BIG NOTE: This is not equivalent to fsync(). It's not a * request to sync dirty data. * * Flush is called on each close() of a file descriptor. So if a * filesystem wants to return write errors in close() and the file * has cached dirty data, this is a good place to write back data * and return any errors. Since many applications ignore close() * errors this is not always useful. * * NOTE: The flush() method may be called more than once for each * open(). This happens if more than one file descriptor refers * to an opened file due to dup(), dup2() or fork() calls. It is * not possible to determine if a flush is final, so each flush * should be treated equally. Multiple write-flush sequences are * relatively rare, so this shouldn't be a problem. * * Filesystems shouldn't assume that flush will always be called * after some writes, or that if will be called at all. * * Changed in version 2.2 */ int (*flush) (const char *, struct fuse_file_info *); /** Release an open file * * Release is called when there are no more references to an open * file: all file descriptors are closed and all memory mappings * are unmapped. * * For every open() call there will be exactly one release() call * with the same flags and file descriptor. It is possible to * have a file opened more than once, in which case only the last * release will mean, that no more reads/writes will happen on the * file. The return value of release is ignored. * * Changed in version 2.2 */ int (*release) (const char *, struct fuse_file_info *); /** Synchronize file contents * * If the datasync parameter is non-zero, then only the user data * should be flushed, not the meta data. * * Changed in version 2.2 */ int (*fsync) (const char *, int, struct fuse_file_info *); /** Set extended attributes */ int (*setxattr) (const char *, const char *, const char *, size_t, int); /** Get extended attributes */ int (*getxattr) (const char *, const char *, char *, size_t); /** List extended attributes */ int (*listxattr) (const char *, char *, size_t); /** Remove extended attributes */ int (*removexattr) (const char *, const char *); /** Open directory * * Unless the 'default_permissions' mount option is given, * this method should check if opendir is permitted for this * directory. Optionally opendir may also return an arbitrary * filehandle in the fuse_file_info structure, which will be * passed to readdir, releasedir and fsyncdir. * * Introduced in version 2.3 */ int (*opendir) (const char *, struct fuse_file_info *); /** Read directory * * This supersedes the old getdir() interface. New applications * should use this. * * The filesystem may choose between two modes of operation: * * 1) The readdir implementation ignores the offset parameter, and * passes zero to the filler function's offset. The filler * function will not return '1' (unless an error happens), so the * whole directory is read in a single readdir operation. This * works just like the old getdir() method. * * 2) The readdir implementation keeps track of the offsets of the * directory entries. It uses the offset parameter and always * passes non-zero offset to the filler function. When the buffer * is full (or an error happens) the filler function will return * '1'. * * Introduced in version 2.3 */ int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); /** Release directory * * Introduced in version 2.3 */ int (*releasedir) (const char *, struct fuse_file_info *); /** Synchronize directory contents * * If the datasync parameter is non-zero, then only the user data * should be flushed, not the meta data * * Introduced in version 2.3 */ int (*fsyncdir) (const char *, int, struct fuse_file_info *); /** * Initialize filesystem * * The return value will passed in the private_data field of * fuse_context to all file operations and as a parameter to the * destroy() method. * * Introduced in version 2.3 * Changed in version 2.6 */ void *(*init) (struct fuse_conn_info *conn); /** * Clean up filesystem * * Called on filesystem exit. * * Introduced in version 2.3 */ void (*destroy) (void *); /** * Check file access permissions * * This will be called for the access() system call. If the * 'default_permissions' mount option is given, this method is not * called. * * This method is not called under Linux kernel versions 2.4.x * * Introduced in version 2.5 */ int (*access) (const char *, int); /** * Create and open a file * * If the file does not exist, first create it with the specified * mode, and then open it. * * If this method is not implemented or under Linux kernel * versions earlier than 2.6.15, the mknod() and open() methods * will be called instead. * * Introduced in version 2.5 */ int (*create) (const char *, mode_t, struct fuse_file_info *); /** * Change the size of an open file * * This method is called instead of the truncate() method if the * truncation was invoked from an ftruncate() system call. * * If this method is not implemented or under Linux kernel * versions earlier than 2.6.15, the truncate() method will be * called instead. * * Introduced in version 2.5 */ int (*ftruncate) (const char *, off_t, struct fuse_file_info *); /** * Get attributes from an open file * * This method is called instead of the getattr() method if the * file information is available. * * Currently this is only called after the create() method if that * is implemented (see above). Later it may be called for * invocations of fstat() too. * * Introduced in version 2.5 */ int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); /** * Perform POSIX file locking operation * * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW. * * For the meaning of fields in 'struct flock' see the man page * for fcntl(2). The l_whence field will always be set to * SEEK_SET. * * For checking lock ownership, the 'fuse_file_info->owner' * argument must be used. * * For F_GETLK operation, the library will first check currently * held locks, and if a conflicting lock is found it will return * information without calling this method. This ensures, that * for local locks the l_pid field is correctly filled in. The * results may not be accurate in case of race conditions and in * the presence of hard links, but it's unlikely that an * application would rely on accurate GETLK results in these * cases. If a conflicting lock is not found, this method will be * called, and the filesystem may fill out l_pid by a meaningful * value, or it may leave this field zero. * * For F_SETLK and F_SETLKW the l_pid field will be set to the pid * of the process performing the locking operation. * * Note: if this method is not implemented, the kernel will still * allow file locking to work locally. Hence it is only * interesting for network filesystems and similar. * * Introduced in version 2.6 */ int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); /** * Change the access and modification times of a file with * nanosecond resolution * * This supersedes the old utime() interface. New applications * should use this. * * See the utimensat(2) man page for details. * * Introduced in version 2.6 */ int (*utimens) (const char *, const struct timespec tv[2]); /** * Map block index within file to block index within device * * Note: This makes sense only for block device backed filesystems * mounted with the 'blkdev' option * * Introduced in version 2.6 */ int (*bmap) (const char *, size_t blocksize, uint64_t *idx); /** * Flag indicating that the filesystem can accept a NULL path * as the first argument for the following operations: * * read, write, flush, release, fsync, readdir, releasedir, * fsyncdir, ftruncate, fgetattr, lock, ioctl and poll * * If this flag is set these operations continue to work on * unlinked files even if "-ohard_remove" option was specified. */ unsigned int flag_nullpath_ok:1; /** * Flag indicating that the path need not be calculated for * the following operations: * * read, write, flush, release, fsync, readdir, releasedir, * fsyncdir, ftruncate, fgetattr, lock, ioctl and poll * * Closely related to flag_nullpath_ok, but if this flag is * set then the path will not be calculaged even if the file * wasn't unlinked. However the path can still be non-NULL if * it needs to be calculated for some other reason. */ unsigned int flag_nopath:1; /** * Flag indicating that the filesystem accepts special * UTIME_NOW and UTIME_OMIT values in its utimens operation. */ unsigned int flag_utime_omit_ok:1; /** * Reserved flags, don't set */ unsigned int flag_reserved:29; /** * Ioctl * * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in * 64bit environment. The size and direction of data is * determined by _IOC_*() decoding of cmd. For _IOC_NONE, * data will be NULL, for _IOC_WRITE data is out area, for * _IOC_READ in area and if both are set in/out area. In all * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes. * * If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a * directory file handle. * * Introduced in version 2.8 */ int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); /** * Poll for IO readiness events * * Note: If ph is non-NULL, the client should notify * when IO readiness events occur by calling * fuse_notify_poll() with the specified ph. * * Regardless of the number of times poll with a non-NULL ph * is received, single notification is enough to clear all. * Notifying more times incurs overhead but doesn't harm * correctness. * * The callee is responsible for destroying ph with * fuse_pollhandle_destroy() when no longer in use. * * Introduced in version 2.8 */ int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); /** Write contents of buffer to an open file * * Similar to the write() method, but data is supplied in a * generic buffer. Use fuse_buf_copy() to transfer data to * the destination. * * Introduced in version 2.9 */ int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); /** Store data from an open file in a buffer * * Similar to the read() method, but data is stored and * returned in a generic buffer. * * No actual copying of data has to take place, the source * file descriptor may simply be stored in the buffer for * later data transfer. * * The buffer must be allocated dynamically and stored at the * location pointed to by bufp. If the buffer contains memory * regions, they too must be allocated using malloc(). The * allocated memory will be freed by the caller. * * Introduced in version 2.9 */ int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); /** * Perform BSD file locking operation * * The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN * * Nonblocking requests will be indicated by ORing LOCK_NB to * the above operations * * For more information see the flock(2) manual page. * * Additionally fi->owner will be set to a value unique to * this open file. This same value will be supplied to * ->release() when the file is released. * * Note: if this method is not implemented, the kernel will still * allow file locking to work locally. Hence it is only * interesting for network filesystems and similar. * * Introduced in version 2.9 */ int (*flock) (const char *, struct fuse_file_info *, int op); /** * Allocates space for an open file * * This function ensures that required space is allocated for specified * file. If this function returns success then any subsequent write * request to specified range is guaranteed not to fail because of lack * of space on the file system media. * * Introduced in version 2.9.1 */ int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); }; /** Extra context that may be needed by some filesystems * * The uid, gid and pid fields are not filled in case of a writepage * operation. */ struct fuse_context { /** Pointer to the fuse object */ struct fuse *fuse; /** User ID of the calling process */ uid_t uid; /** Group ID of the calling process */ gid_t gid; /** Thread ID of the calling process */ pid_t pid; /** Private filesystem data */ void *private_data; /** Umask of the calling process (introduced in version 2.8) */ mode_t umask; }; /** * Main function of FUSE. * * This is for the lazy. This is all that has to be called from the * main() function. * * This function does the following: * - parses command line options (-d -s and -h) * - passes relevant mount options to the fuse_mount() * - installs signal handlers for INT, HUP, TERM and PIPE * - registers an exit handler to unmount the filesystem on program exit * - creates a fuse handle * - registers the operations * - calls either the single-threaded or the multi-threaded event loop * * Note: this is currently implemented as a macro. * * @param argc the argument counter passed to the main() function * @param argv the argument vector passed to the main() function * @param op the file system operation * @param user_data user data supplied in the context during the init() method * @return 0 on success, nonzero on failure */ /* int fuse_main(int argc, char *argv[], const struct fuse_operations *op, void *user_data); */ #define fuse_main(argc, argv, op, user_data) \ fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) /* ----------------------------------------------------------- * * More detailed API * * ----------------------------------------------------------- */ /** * Create a new FUSE filesystem. * * @param ch the communication channel * @param args argument vector * @param op the filesystem operations * @param op_size the size of the fuse_operations structure * @param user_data user data supplied in the context during the init() method * @return the created FUSE handle */ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data); /** * Destroy the FUSE handle. * * The communication channel attached to the handle is also destroyed. * * NOTE: This function does not unmount the filesystem. If this is * needed, call fuse_unmount() before calling this function. * * @param f the FUSE handle */ void fuse_destroy(struct fuse *f); /** * FUSE event loop. * * Requests from the kernel are processed, and the appropriate * operations are called. * * @param f the FUSE handle * @return 0 if no error occurred, -1 otherwise */ int fuse_loop(struct fuse *f); /** * Exit from event loop * * @param f the FUSE handle */ void fuse_exit(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. * * @param f the FUSE handle * @return 0 if no error occurred, -1 otherwise */ int fuse_loop_mt(struct fuse *f); /** * Get the current context * * The context is only valid for the duration of a filesystem * operation, and thus must not be stored and used later. * * @return the context */ struct fuse_context *fuse_get_context(void); /** * Get the current supplementary group IDs for the current request * * Similar to the getgroups(2) system call, except the return value is * always the total number of group IDs, even if it is larger than the * specified size. * * The current fuse kernel module in linux (as of 2.6.30) doesn't pass * the group list to userspace, hence this function needs to parse * "/proc/$TID/task/$TID/status" to get the group IDs. * * This feature may not be supported on all operating systems. In * such a case this function will return -ENOSYS. * * @param size size of given array * @param list array of group IDs to be filled in * @return the total number of supplementary group IDs or -errno on failure */ int fuse_getgroups(int size, gid_t list[]); /** * Check if the current request has already been interrupted * * @return 1 if the request has been interrupted, 0 otherwise */ int fuse_interrupted(void); /** * Obsolete, doesn't do anything * * @return -EINVAL */ int fuse_invalidate(struct fuse *f, const char *path); /* Deprecated, don't use */ int fuse_is_lib_option(const char *opt); /** * The real main function * * Do not call this directly, use fuse_main() */ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data); /** * Start the cleanup thread when using option "remember". * * This is done automatically by fuse_loop_mt() * @param fuse struct fuse pointer for fuse instance * @return 0 on success and -1 on error */ int fuse_start_cleanup_thread(struct fuse *fuse); /** * Stop the cleanup thread when using option "remember". * * This is done automatically by fuse_loop_mt() * @param fuse struct fuse pointer for fuse instance */ void fuse_stop_cleanup_thread(struct fuse *fuse); /** * Iterate over cache removing stale entries * use in conjunction with "-oremember" * * NOTE: This is already done for the standard sessions * * @param fuse struct fuse pointer for fuse instance * @return the number of seconds until the next cleanup */ int fuse_clean_cache(struct fuse *fuse); /* * Stacking API */ /** * Fuse filesystem object * * This is opaque object represents a filesystem layer */ struct fuse_fs; /* * These functions call the relevant filesystem operation, and return * the result. * * If the operation is not defined, they return -ENOSYS, with the * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir, * fuse_fs_releasedir and fuse_fs_statfs, which return 0. */ int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf); int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf, struct fuse_file_info *fi); int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, const char *newpath); int fuse_fs_unlink(struct fuse_fs *fs, const char *path); int fuse_fs_rmdir(struct fuse_fs *fs, const char *path); int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path); int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath); int fuse_fs_release(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi); int fuse_fs_open(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi); int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size, off_t off, struct fuse_file_info *fi); int fuse_fs_read_buf(struct fuse_fs *fs, const char *path, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *fi); int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf, size_t size, off_t off, struct fuse_file_info *fi); int fuse_fs_write_buf(struct fuse_fs *fs, const char *path, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *fi); int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, struct fuse_file_info *fi); int fuse_fs_flush(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi); int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf); int fuse_fs_opendir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi); int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, fuse_fill_dir_t filler, off_t off, struct fuse_file_info *fi); int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, struct fuse_file_info *fi); int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi); int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, struct fuse_file_info *fi); int fuse_fs_lock(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock); int fuse_fs_flock(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, int op); int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode); int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid); int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size); int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size, struct fuse_file_info *fi); int fuse_fs_utimens(struct fuse_fs *fs, const char *path, const struct timespec tv[2]); int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask); int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, size_t len); int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, dev_t rdev); int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode); int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, const char *value, size_t size, int flags); int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, char *value, size_t size); int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, size_t size); int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name); int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, uint64_t *idx); int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data); int fuse_fs_poll(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp); int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode, off_t offset, off_t length, struct fuse_file_info *fi); void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn); void fuse_fs_destroy(struct fuse_fs *fs); int fuse_notify_poll(struct fuse_pollhandle *ph); /** * Create a new fuse filesystem object * * This is usually called from the factory of a fuse module to create * a new instance of a filesystem. * * @param op the filesystem operations * @param op_size the size of the fuse_operations structure * @param user_data user data supplied in the context during the init() method * @return a new filesystem object */ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *user_data); /** * Filesystem module * * Filesystem modules are registered with the FUSE_REGISTER_MODULE() * macro. * * If the "-omodules=modname:..." option is present, filesystem * objects are created and pushed onto the stack with the 'factory' * function. */ struct fuse_module { /** * Name of filesystem */ const char *name; /** * Factory for creating filesystem objects * * The function may use and remove options from 'args' that belong * to this module. * * For now the 'fs' vector always contains exactly one filesystem. * This is the filesystem which will be below the newly created * filesystem in the stack. * * @param args the command line arguments * @param fs NULL terminated filesystem object vector * @return the new filesystem object */ struct fuse_fs *(*factory)(struct fuse_args *args, struct fuse_fs *fs[]); struct fuse_module *next; struct fusemod_so *so; int ctr; }; /** * Register a filesystem module * * This function is used by FUSE_REGISTER_MODULE and there's usually * no need to call it directly */ void fuse_register_module(struct fuse_module *mod); /** * Register filesystem module * * For the parameters, see description of the fields in 'struct * fuse_module' */ #define FUSE_REGISTER_MODULE(name_, factory_) \ static __attribute__((constructor)) void name_ ## _register(void) \ { \ static struct fuse_module mod = \ { #name_, factory_, NULL, NULL, 0 }; \ fuse_register_module(&mod); \ } /* ----------------------------------------------------------- * * Advanced API for event handling, don't worry about this... * * ----------------------------------------------------------- */ /* NOTE: the following functions are deprecated, and will be removed from the 3.0 API. Use the lowlevel session functions instead */ /** Function type used to process commands */ typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); /** This is the part of fuse_main() before the event loop */ struct fuse *fuse_setup(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, char **mountpoint, int *multithreaded, void *user_data); /** This is the part of fuse_main() after the event loop */ void fuse_teardown(struct fuse *fuse, char *mountpoint); /** Read a single command. If none are read, return NULL */ struct fuse_cmd *fuse_read_cmd(struct fuse *f); /** Process a single command */ void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd); /** Multi threaded event loop, which calls the custom command processor function */ int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data); /** Return the exited flag, which indicates if fuse_exit() has been called */ int fuse_exited(struct fuse *f); /** This function is obsolete and implemented as a no-op */ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); /** Get session from fuse object */ struct fuse_session *fuse_get_session(struct fuse *f); /* ----------------------------------------------------------- * * Compatibility stuff * * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # include "fuse_compat.h" # undef fuse_main # if FUSE_USE_VERSION == 25 # define fuse_main(argc, argv, op) \ fuse_main_real_compat25(argc, argv, op, sizeof(*(op))) # define fuse_new fuse_new_compat25 # define fuse_setup fuse_setup_compat25 # define fuse_teardown fuse_teardown_compat22 # define fuse_operations fuse_operations_compat25 # elif FUSE_USE_VERSION == 22 # define fuse_main(argc, argv, op) \ fuse_main_real_compat22(argc, argv, op, sizeof(*(op))) # define fuse_new fuse_new_compat22 # define fuse_setup fuse_setup_compat22 # define fuse_teardown fuse_teardown_compat22 # define fuse_operations fuse_operations_compat22 # define fuse_file_info fuse_file_info_compat # elif FUSE_USE_VERSION == 24 # error Compatibility with high-level API version 24 not supported # else # define fuse_dirfil_t fuse_dirfil_t_compat # define __fuse_read_cmd fuse_read_cmd # define __fuse_process_cmd fuse_process_cmd # define __fuse_loop_mt fuse_loop_mt_proc # if FUSE_USE_VERSION == 21 # define fuse_operations fuse_operations_compat2 # define fuse_main fuse_main_compat2 # define fuse_new fuse_new_compat2 # define __fuse_setup fuse_setup_compat2 # define __fuse_teardown fuse_teardown_compat22 # define __fuse_exited fuse_exited # define __fuse_set_getcontext_func fuse_set_getcontext_func # else # define fuse_statfs fuse_statfs_compat1 # define fuse_operations fuse_operations_compat1 # define fuse_main fuse_main_compat1 # define fuse_new fuse_new_compat1 # define FUSE_DEBUG FUSE_DEBUG_COMPAT1 # endif # endif #endif #ifdef __cplusplus } #endif #endif /* _FUSE_H_ */ fuse-2.9.9/include/fuse_common.h0000664000175000017500000003051013413660255013532 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ /** @file */ #if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_) #error "Never include directly; use or instead." #endif #ifndef _FUSE_COMMON_H_ #define _FUSE_COMMON_H_ #include "fuse_opt.h" #include #include /** Major version of FUSE library interface */ #define FUSE_MAJOR_VERSION 2 /** Minor version of FUSE library interface */ #define FUSE_MINOR_VERSION 9 #define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) /* This interface uses 64 bit off_t */ #if _FILE_OFFSET_BITS != 64 #error Please add -D_FILE_OFFSET_BITS=64 to your compile flags! #endif #ifdef __cplusplus extern "C" { #endif /** * Information about open files * * Changed in version 2.5 */ struct fuse_file_info { /** Open flags. Available in open() and release() */ int flags; /** Old file handle, don't use */ unsigned long fh_old; /** In case of a write operation indicates if this was caused by a writepage */ int writepage; /** Can be filled in by open, to use direct I/O on this file. Introduced in version 2.4 */ unsigned int direct_io : 1; /** Can be filled in by open, to indicate, that cached file data need not be invalidated. Introduced in version 2.4 */ unsigned int keep_cache : 1; /** Indicates a flush operation. Set in flush operation, also maybe set in highlevel lock operation and lowlevel release operation. Introduced in version 2.6 */ unsigned int flush : 1; /** Can be filled in by open, to indicate that the file is not seekable. Introduced in version 2.8 */ unsigned int nonseekable : 1; /* Indicates that flock locks for this file should be released. If set, lock_owner shall contain a valid value. May only be set in ->release(). Introduced in version 2.9 */ unsigned int flock_release : 1; /** Padding. Do not use*/ unsigned int padding : 27; /** File handle. May be filled in by filesystem in open(). Available in all other file operations */ uint64_t fh; /** Lock owner id. Available in locking operations and flush */ uint64_t lock_owner; }; /** * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' * * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations * FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device * FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice() * FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device * FUSE_CAP_IOCTL_DIR: ioctl support on directories */ #define FUSE_CAP_ASYNC_READ (1 << 0) #define FUSE_CAP_POSIX_LOCKS (1 << 1) #define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3) #define FUSE_CAP_EXPORT_SUPPORT (1 << 4) #define FUSE_CAP_BIG_WRITES (1 << 5) #define FUSE_CAP_DONT_MASK (1 << 6) #define FUSE_CAP_SPLICE_WRITE (1 << 7) #define FUSE_CAP_SPLICE_MOVE (1 << 8) #define FUSE_CAP_SPLICE_READ (1 << 9) #define FUSE_CAP_FLOCK_LOCKS (1 << 10) #define FUSE_CAP_IOCTL_DIR (1 << 11) /** * Ioctl flags * * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed * FUSE_IOCTL_RETRY: retry with new iovecs * FUSE_IOCTL_DIR: is a directory * * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs */ #define FUSE_IOCTL_COMPAT (1 << 0) #define FUSE_IOCTL_UNRESTRICTED (1 << 1) #define FUSE_IOCTL_RETRY (1 << 2) #define FUSE_IOCTL_DIR (1 << 4) #define FUSE_IOCTL_MAX_IOV 256 /** * Connection information, passed to the ->init() method * * Some of the elements are read-write, these can be changed to * indicate the value requested by the filesystem. The requested * value must usually be smaller than the indicated value. */ struct fuse_conn_info { /** * Major version of the protocol (read-only) */ unsigned proto_major; /** * Minor version of the protocol (read-only) */ unsigned proto_minor; /** * Is asynchronous read supported (read-write) */ unsigned async_read; /** * Maximum size of the write buffer */ unsigned max_write; /** * Maximum readahead */ unsigned max_readahead; /** * Capability flags, that the kernel supports */ unsigned capable; /** * Capability flags, that the filesystem wants to enable */ unsigned want; /** * Maximum number of backgrounded requests */ unsigned max_background; /** * Kernel congestion threshold parameter */ unsigned congestion_threshold; /** * For future use. */ unsigned reserved[23]; }; struct fuse_session; struct fuse_chan; struct fuse_pollhandle; /** * Create a FUSE mountpoint * * Returns a control file descriptor suitable for passing to * fuse_new() * * @param mountpoint the mount point path * @param args argument vector * @return the communication channel on success, NULL on failure */ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args); /** * Umount a FUSE mountpoint * * @param mountpoint the mount point path * @param ch the communication channel */ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); /** * Parse common options * * The following options are parsed: * * '-f' foreground * '-d' '-odebug' foreground, but keep the debug option * '-s' single threaded * '-h' '--help' help * '-ho' help without header * '-ofsname=..' file system name, if not present, then set to the program * name * * All parameters may be NULL * * @param args argument vector * @param mountpoint the returned mountpoint, should be freed after use * @param multithreaded set to 1 unless the '-s' option is present * @param foreground set to 1 if one of the relevant options is present * @return 0 on success, -1 on failure */ int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, int *multithreaded, int *foreground); /** * Go into the background * * @param foreground if true, stay in the foreground * @return 0 on success, -1 on failure */ int fuse_daemonize(int foreground); /** * Get the version of the library * * @return the version */ int fuse_version(void); /** * Destroy poll handle * * @param ph the poll handle */ void fuse_pollhandle_destroy(struct fuse_pollhandle *ph); /* ----------------------------------------------------------- * * Data buffer * * ----------------------------------------------------------- */ /** * Buffer flags */ enum fuse_buf_flags { /** * Buffer contains a file descriptor * * If this flag is set, the .fd field is valid, otherwise the * .mem fields is valid. */ FUSE_BUF_IS_FD = (1 << 1), /** * Seek on the file descriptor * * If this flag is set then the .pos field is valid and is * used to seek to the given offset before performing * operation on file descriptor. */ FUSE_BUF_FD_SEEK = (1 << 2), /** * Retry operation on file descriptor * * If this flag is set then retry operation on file descriptor * until .size bytes have been copied or an error or EOF is * detected. */ FUSE_BUF_FD_RETRY = (1 << 3), }; /** * Buffer copy flags */ enum fuse_buf_copy_flags { /** * Don't use splice(2) * * Always fall back to using read and write instead of * splice(2) to copy data from one file descriptor to another. * * If this flag is not set, then only fall back if splice is * unavailable. */ FUSE_BUF_NO_SPLICE = (1 << 1), /** * Force splice * * Always use splice(2) to copy data from one file descriptor * to another. If splice is not available, return -EINVAL. */ FUSE_BUF_FORCE_SPLICE = (1 << 2), /** * Try to move data with splice. * * If splice is used, try to move pages from the source to the * destination instead of copying. See documentation of * SPLICE_F_MOVE in splice(2) man page. */ FUSE_BUF_SPLICE_MOVE = (1 << 3), /** * Don't block on the pipe when copying data with splice * * Makes the operations on the pipe non-blocking (if the pipe * is full or empty). See SPLICE_F_NONBLOCK in the splice(2) * man page. */ FUSE_BUF_SPLICE_NONBLOCK= (1 << 4), }; /** * Single data buffer * * Generic data buffer for I/O, extended attributes, etc... Data may * be supplied as a memory pointer or as a file descriptor */ struct fuse_buf { /** * Size of data in bytes */ size_t size; /** * Buffer flags */ enum fuse_buf_flags flags; /** * Memory pointer * * Used unless FUSE_BUF_IS_FD flag is set. */ void *mem; /** * File descriptor * * Used if FUSE_BUF_IS_FD flag is set. */ int fd; /** * File position * * Used if FUSE_BUF_FD_SEEK flag is set. */ off_t pos; }; /** * Data buffer vector * * An array of data buffers, each containing a memory pointer or a * file descriptor. * * Allocate dynamically to add more than one buffer. */ struct fuse_bufvec { /** * Number of buffers in the array */ size_t count; /** * Index of current buffer within the array */ size_t idx; /** * Current offset within the current buffer */ size_t off; /** * Array of buffers */ struct fuse_buf buf[1]; }; /* Initialize bufvec with a single buffer of given size */ #define FUSE_BUFVEC_INIT(size__) \ ((struct fuse_bufvec) { \ /* .count= */ 1, \ /* .idx = */ 0, \ /* .off = */ 0, \ /* .buf = */ { /* [0] = */ { \ /* .size = */ (size__), \ /* .flags = */ (enum fuse_buf_flags) 0, \ /* .mem = */ NULL, \ /* .fd = */ -1, \ /* .pos = */ 0, \ } } \ } ) /** * Get total size of data in a fuse buffer vector * * @param bufv buffer vector * @return size of data */ size_t fuse_buf_size(const struct fuse_bufvec *bufv); /** * Copy data from one buffer vector to another * * @param dst destination buffer vector * @param src source buffer vector * @param flags flags controlling the copy * @return actual number of bytes copied or -errno on error */ ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags); /* ----------------------------------------------------------- * * Signal handling * * ----------------------------------------------------------- */ /** * Exit session on HUP, TERM and INT signals and ignore PIPE signal * * Stores session in a global variable. May only be called once per * process until fuse_remove_signal_handlers() is called. * * @param se the session to exit * @return 0 on success, -1 on failure */ int fuse_set_signal_handlers(struct fuse_session *se); /** * Restore default signal handlers * * Resets global session. After this fuse_set_signal_handlers() may * be called again. * * @param se the same session as given in fuse_set_signal_handlers() */ void fuse_remove_signal_handlers(struct fuse_session *se); /* ----------------------------------------------------------- * * Compatibility stuff * * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # ifdef __FreeBSD__ # if FUSE_USE_VERSION < 25 # error On FreeBSD API version 25 or greater must be used # endif # endif # include "fuse_common_compat.h" # undef FUSE_MINOR_VERSION # undef fuse_main # define fuse_unmount fuse_unmount_compat22 # if FUSE_USE_VERSION == 25 # define FUSE_MINOR_VERSION 5 # define fuse_mount fuse_mount_compat25 # elif FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22 # define FUSE_MINOR_VERSION 4 # define fuse_mount fuse_mount_compat22 # elif FUSE_USE_VERSION == 21 # define FUSE_MINOR_VERSION 1 # define fuse_mount fuse_mount_compat22 # elif FUSE_USE_VERSION == 11 # warning Compatibility with API version 11 is deprecated # undef FUSE_MAJOR_VERSION # define FUSE_MAJOR_VERSION 1 # define FUSE_MINOR_VERSION 1 # define fuse_mount fuse_mount_compat1 # else # error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported # endif #endif #ifdef __cplusplus } #endif #endif /* _FUSE_COMMON_H_ */ fuse-2.9.9/include/fuse_lowlevel_compat.h0000664000175000017500000001535513413660255015450 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ struct fuse_lowlevel_ops_compat25 { void (*init) (void *userdata); void (*destroy) (void *userdata); void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi); void (*readlink) (fuse_req_t req, fuse_ino_t ino); void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev); void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode); void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, const char *name); void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname); void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname); void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi); void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); void (*releasedir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); void (*statfs) (fuse_req_t req); void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags); void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size); void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi); }; struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, const struct fuse_lowlevel_ops_compat25 *op, size_t op_size, void *userdata); size_t fuse_dirent_size(size_t namelen); char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, off_t off); #if !defined(__FreeBSD__) && !defined(__NetBSD__) #include struct fuse_lowlevel_ops_compat { void (*init) (void *userdata); void (*destroy) (void *userdata); void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info_compat *fi); void (*readlink) (fuse_req_t req, fuse_ino_t ino); void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev); void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode); void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, const char *name); void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname); void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname); void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info_compat *fi); void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info_compat *fi); void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info_compat *fi); void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info_compat *fi); void (*releasedir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info_compat *fi); void (*statfs) (fuse_req_t req); void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags); void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size); void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info_compat *fi); }; int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf); int fuse_reply_open_compat(fuse_req_t req, const struct fuse_file_info_compat *fi); struct fuse_session *fuse_lowlevel_new_compat(const char *opts, const struct fuse_lowlevel_ops_compat *op, size_t op_size, void *userdata); #endif /* __FreeBSD__ || __NetBSD__ */ struct fuse_chan_ops_compat24 { int (*receive)(struct fuse_chan *ch, char *buf, size_t size); int (*send)(struct fuse_chan *ch, const struct iovec iov[], size_t count); void (*destroy)(struct fuse_chan *ch); }; struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, int fd, size_t bufsize, void *data); int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size); struct fuse_chan *fuse_kern_chan_new(int fd); fuse-2.9.9/include/fuse_kernel.h0000664000175000017500000003276313413660255013536 00000000000000/* This file defines the kernel interface of FUSE Copyright (C) 2001-2008 Miklos Szeredi This program can be distributed under the terms of the GNU GPL. See the file COPYING. This -- and only this -- header file may also be distributed under the terms of the BSD Licence as follows: Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This file defines the kernel interface of FUSE * * Protocol changelog: * * 7.9: * - new fuse_getattr_in input argument of GETATTR * - add lk_flags in fuse_lk_in * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in * - add blksize field to fuse_attr * - add file flags field to fuse_read_in and fuse_write_in * * 7.10 * - add nonseekable open flag * * 7.11 * - add IOCTL message * - add unsolicited notification support * - add POLL message and NOTIFY_POLL notification * * 7.12 * - add umask flag to input argument of open, mknod and mkdir * - add notification messages for invalidation of inodes and * directory entries * * 7.13 * - make max number of background requests and congestion threshold * tunables * * 7.14 * - add splice support to fuse device * * 7.15 * - add store notify * - add retrieve notify * * 7.16 * - add BATCH_FORGET request * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct * fuse_ioctl_iovec' instead of ambiguous 'struct iovec' * - add FUSE_IOCTL_32BIT flag * * 7.17 * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK * * 7.18 * - add FUSE_IOCTL_DIR flag * - add FUSE_NOTIFY_DELETE * * 7.19 * - add FUSE_FALLOCATE */ #ifndef _LINUX_FUSE_H #define _LINUX_FUSE_H #include #define __u64 uint64_t #define __s64 int64_t #define __u32 uint32_t #define __s32 int32_t #define __u16 uint16_t /* * Version negotiation: * * Both the kernel and userspace send the version they support in the * INIT request and reply respectively. * * If the major versions match then both shall use the smallest * of the two minor versions for communication. * * If the kernel supports a larger major version, then userspace shall * reply with the major version it supports, ignore the rest of the * INIT message and expect a new INIT message from the kernel with a * matching major version. * * If the library supports a larger major version, then it shall fall * back to the major protocol version sent by the kernel for * communication and reply with that major version (and an arbitrary * supported minor version). */ /** Version number of this interface */ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ #define FUSE_KERNEL_MINOR_VERSION 19 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 /* Make sure all structures are padded to 64bit boundary, so 32bit userspace works under 64bit kernels */ struct fuse_attr { __u64 ino; __u64 size; __u64 blocks; __u64 atime; __u64 mtime; __u64 ctime; __u32 atimensec; __u32 mtimensec; __u32 ctimensec; __u32 mode; __u32 nlink; __u32 uid; __u32 gid; __u32 rdev; __u32 blksize; __u32 padding; }; struct fuse_kstatfs { __u64 blocks; __u64 bfree; __u64 bavail; __u64 files; __u64 ffree; __u32 bsize; __u32 namelen; __u32 frsize; __u32 padding; __u32 spare[6]; }; struct fuse_file_lock { __u64 start; __u64 end; __u32 type; __u32 pid; /* tgid */ }; /** * Bitmasks for fuse_setattr_in.valid */ #define FATTR_MODE (1 << 0) #define FATTR_UID (1 << 1) #define FATTR_GID (1 << 2) #define FATTR_SIZE (1 << 3) #define FATTR_ATIME (1 << 4) #define FATTR_MTIME (1 << 5) #define FATTR_FH (1 << 6) #define FATTR_ATIME_NOW (1 << 7) #define FATTR_MTIME_NOW (1 << 8) #define FATTR_LOCKOWNER (1 << 9) /** * Flags returned by the OPEN request * * FOPEN_DIRECT_IO: bypass page cache for this open file * FOPEN_KEEP_CACHE: don't invalidate the data cache on open * FOPEN_NONSEEKABLE: the file is not seekable */ #define FOPEN_DIRECT_IO (1 << 0) #define FOPEN_KEEP_CACHE (1 << 1) #define FOPEN_NONSEEKABLE (1 << 2) /** * INIT request/reply flags * * FUSE_POSIX_LOCKS: remote locking for POSIX file locks * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." * FUSE_DONT_MASK: don't apply umask to file mode on create operations * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) #define FUSE_FILE_OPS (1 << 2) #define FUSE_ATOMIC_O_TRUNC (1 << 3) #define FUSE_EXPORT_SUPPORT (1 << 4) #define FUSE_BIG_WRITES (1 << 5) #define FUSE_DONT_MASK (1 << 6) #define FUSE_FLOCK_LOCKS (1 << 10) /** * CUSE INIT request/reply flags * * CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl */ #define CUSE_UNRESTRICTED_IOCTL (1 << 0) /** * Release flags */ #define FUSE_RELEASE_FLUSH (1 << 0) #define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1) /** * Getattr flags */ #define FUSE_GETATTR_FH (1 << 0) /** * Lock flags */ #define FUSE_LK_FLOCK (1 << 0) /** * WRITE flags * * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed * FUSE_WRITE_LOCKOWNER: lock_owner field is valid */ #define FUSE_WRITE_CACHE (1 << 0) #define FUSE_WRITE_LOCKOWNER (1 << 1) /** * Read flags */ #define FUSE_READ_LOCKOWNER (1 << 1) /** * Ioctl flags * * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed * FUSE_IOCTL_RETRY: retry with new iovecs * FUSE_IOCTL_32BIT: 32bit ioctl * FUSE_IOCTL_DIR: is a directory * * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs */ #define FUSE_IOCTL_COMPAT (1 << 0) #define FUSE_IOCTL_UNRESTRICTED (1 << 1) #define FUSE_IOCTL_RETRY (1 << 2) #define FUSE_IOCTL_32BIT (1 << 3) #define FUSE_IOCTL_DIR (1 << 4) #define FUSE_IOCTL_MAX_IOV 256 /** * Poll flags * * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify */ #define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0) enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ FUSE_GETATTR = 3, FUSE_SETATTR = 4, FUSE_READLINK = 5, FUSE_SYMLINK = 6, FUSE_MKNOD = 8, FUSE_MKDIR = 9, FUSE_UNLINK = 10, FUSE_RMDIR = 11, FUSE_RENAME = 12, FUSE_LINK = 13, FUSE_OPEN = 14, FUSE_READ = 15, FUSE_WRITE = 16, FUSE_STATFS = 17, FUSE_RELEASE = 18, FUSE_FSYNC = 20, FUSE_SETXATTR = 21, FUSE_GETXATTR = 22, FUSE_LISTXATTR = 23, FUSE_REMOVEXATTR = 24, FUSE_FLUSH = 25, FUSE_INIT = 26, FUSE_OPENDIR = 27, FUSE_READDIR = 28, FUSE_RELEASEDIR = 29, FUSE_FSYNCDIR = 30, FUSE_GETLK = 31, FUSE_SETLK = 32, FUSE_SETLKW = 33, FUSE_ACCESS = 34, FUSE_CREATE = 35, FUSE_INTERRUPT = 36, FUSE_BMAP = 37, FUSE_DESTROY = 38, FUSE_IOCTL = 39, FUSE_POLL = 40, FUSE_NOTIFY_REPLY = 41, FUSE_BATCH_FORGET = 42, FUSE_FALLOCATE = 43, /* CUSE specific operations */ CUSE_INIT = 4096, }; enum fuse_notify_code { FUSE_NOTIFY_POLL = 1, FUSE_NOTIFY_INVAL_INODE = 2, FUSE_NOTIFY_INVAL_ENTRY = 3, FUSE_NOTIFY_STORE = 4, FUSE_NOTIFY_RETRIEVE = 5, FUSE_NOTIFY_DELETE = 6, FUSE_NOTIFY_CODE_MAX, }; /* The read buffer is required to be at least 8k, but may be much larger */ #define FUSE_MIN_READ_BUFFER 8192 #define FUSE_COMPAT_ENTRY_OUT_SIZE 120 struct fuse_entry_out { __u64 nodeid; /* Inode ID */ __u64 generation; /* Inode generation: nodeid:gen must be unique for the fs's lifetime */ __u64 entry_valid; /* Cache timeout for the name */ __u64 attr_valid; /* Cache timeout for the attributes */ __u32 entry_valid_nsec; __u32 attr_valid_nsec; struct fuse_attr attr; }; struct fuse_forget_in { __u64 nlookup; }; struct fuse_forget_one { __u64 nodeid; __u64 nlookup; }; struct fuse_batch_forget_in { __u32 count; __u32 dummy; }; struct fuse_getattr_in { __u32 getattr_flags; __u32 dummy; __u64 fh; }; #define FUSE_COMPAT_ATTR_OUT_SIZE 96 struct fuse_attr_out { __u64 attr_valid; /* Cache timeout for the attributes */ __u32 attr_valid_nsec; __u32 dummy; struct fuse_attr attr; }; #define FUSE_COMPAT_MKNOD_IN_SIZE 8 struct fuse_mknod_in { __u32 mode; __u32 rdev; __u32 umask; __u32 padding; }; struct fuse_mkdir_in { __u32 mode; __u32 umask; }; struct fuse_rename_in { __u64 newdir; }; struct fuse_link_in { __u64 oldnodeid; }; struct fuse_setattr_in { __u32 valid; __u32 padding; __u64 fh; __u64 size; __u64 lock_owner; __u64 atime; __u64 mtime; __u64 unused2; __u32 atimensec; __u32 mtimensec; __u32 unused3; __u32 mode; __u32 unused4; __u32 uid; __u32 gid; __u32 unused5; }; struct fuse_open_in { __u32 flags; __u32 unused; }; struct fuse_create_in { __u32 flags; __u32 mode; __u32 umask; __u32 padding; }; struct fuse_open_out { __u64 fh; __u32 open_flags; __u32 padding; }; struct fuse_release_in { __u64 fh; __u32 flags; __u32 release_flags; __u64 lock_owner; }; struct fuse_flush_in { __u64 fh; __u32 unused; __u32 padding; __u64 lock_owner; }; struct fuse_read_in { __u64 fh; __u64 offset; __u32 size; __u32 read_flags; __u64 lock_owner; __u32 flags; __u32 padding; }; #define FUSE_COMPAT_WRITE_IN_SIZE 24 struct fuse_write_in { __u64 fh; __u64 offset; __u32 size; __u32 write_flags; __u64 lock_owner; __u32 flags; __u32 padding; }; struct fuse_write_out { __u32 size; __u32 padding; }; #define FUSE_COMPAT_STATFS_SIZE 48 struct fuse_statfs_out { struct fuse_kstatfs st; }; struct fuse_fsync_in { __u64 fh; __u32 fsync_flags; __u32 padding; }; struct fuse_setxattr_in { __u32 size; __u32 flags; }; struct fuse_getxattr_in { __u32 size; __u32 padding; }; struct fuse_getxattr_out { __u32 size; __u32 padding; }; struct fuse_lk_in { __u64 fh; __u64 owner; struct fuse_file_lock lk; __u32 lk_flags; __u32 padding; }; struct fuse_lk_out { struct fuse_file_lock lk; }; struct fuse_access_in { __u32 mask; __u32 padding; }; struct fuse_init_in { __u32 major; __u32 minor; __u32 max_readahead; __u32 flags; }; struct fuse_init_out { __u32 major; __u32 minor; __u32 max_readahead; __u32 flags; __u16 max_background; __u16 congestion_threshold; __u32 max_write; }; #define CUSE_INIT_INFO_MAX 4096 struct cuse_init_in { __u32 major; __u32 minor; __u32 unused; __u32 flags; }; struct cuse_init_out { __u32 major; __u32 minor; __u32 unused; __u32 flags; __u32 max_read; __u32 max_write; __u32 dev_major; /* chardev major */ __u32 dev_minor; /* chardev minor */ __u32 spare[10]; }; struct fuse_interrupt_in { __u64 unique; }; struct fuse_bmap_in { __u64 block; __u32 blocksize; __u32 padding; }; struct fuse_bmap_out { __u64 block; }; struct fuse_ioctl_in { __u64 fh; __u32 flags; __u32 cmd; __u64 arg; __u32 in_size; __u32 out_size; }; struct fuse_ioctl_iovec { __u64 base; __u64 len; }; struct fuse_ioctl_out { __s32 result; __u32 flags; __u32 in_iovs; __u32 out_iovs; }; struct fuse_poll_in { __u64 fh; __u64 kh; __u32 flags; __u32 padding; }; struct fuse_poll_out { __u32 revents; __u32 padding; }; struct fuse_notify_poll_wakeup_out { __u64 kh; }; struct fuse_fallocate_in { __u64 fh; __u64 offset; __u64 length; __u32 mode; __u32 padding; }; struct fuse_in_header { __u32 len; __u32 opcode; __u64 unique; __u64 nodeid; __u32 uid; __u32 gid; __u32 pid; __u32 padding; }; struct fuse_out_header { __u32 len; __s32 error; __u64 unique; }; struct fuse_dirent { __u64 ino; __u64 off; __u32 namelen; __u32 type; char name[]; }; #define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) #define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1)) #define FUSE_DIRENT_SIZE(d) \ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) struct fuse_notify_inval_inode_out { __u64 ino; __s64 off; __s64 len; }; struct fuse_notify_inval_entry_out { __u64 parent; __u32 namelen; __u32 padding; }; struct fuse_notify_delete_out { __u64 parent; __u64 child; __u32 namelen; __u32 padding; }; struct fuse_notify_store_out { __u64 nodeid; __u64 offset; __u32 size; __u32 padding; }; struct fuse_notify_retrieve_out { __u64 notify_unique; __u64 nodeid; __u64 offset; __u32 size; __u32 padding; }; /* Matches the size of fuse_write_in */ struct fuse_notify_retrieve_in { __u64 dummy1; __u64 offset; __u32 size; __u32 dummy2; __u64 dummy3; __u64 dummy4; }; #endif /* _LINUX_FUSE_H */ fuse-2.9.9/include/config.h.in0000664000175000017500000000501713413660776013106 00000000000000/* include/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the `fdatasync' function. */ #undef HAVE_FDATASYNC /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define if you have the iconv() function and it works. */ #undef HAVE_ICONV /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `posix_fallocate' function. */ #undef HAVE_POSIX_FALLOCATE /* Define to 1 if you have the `setxattr' function. */ #undef HAVE_SETXATTR /* Define to 1 if you have the `splice' function. */ #undef HAVE_SPLICE /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if `st_atim' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIM /* Define to 1 if `st_atimespec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIMESPEC /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `utimensat' function. */ #undef HAVE_UTIMENSAT /* Define to 1 if you have the `vmsplice' function. */ #undef HAVE_VMSPLICE /* Define as const if the declaration of iconv() needs const. */ #undef ICONV_CONST /* Don't update /etc/mtab */ #undef IGNORE_MTAB /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION fuse-2.9.9/include/fuse_opt.h0000664000175000017500000001646513413660255013061 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ #ifndef _FUSE_OPT_H_ #define _FUSE_OPT_H_ /** @file * * This file defines the option parsing interface of FUSE */ #ifdef __cplusplus extern "C" { #endif /** * Option description * * This structure describes a single option, and action associated * with it, in case it matches. * * More than one such match may occur, in which case the action for * each match is executed. * * There are three possible actions in case of a match: * * i) An integer (int or unsigned) variable determined by 'offset' is * set to 'value' * * ii) The processing function is called, with 'value' as the key * * iii) An integer (any) or string (char *) variable determined by * 'offset' is set to the value of an option parameter * * 'offset' should normally be either set to * * - 'offsetof(struct foo, member)' actions i) and iii) * * - -1 action ii) * * The 'offsetof()' macro is defined in the header. * * The template determines which options match, and also have an * effect on the action. Normally the action is either i) or ii), but * if a format is present in the template, then action iii) is * performed. * * The types of templates are: * * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only * themselves. Invalid values are "--" and anything beginning * with "-o" * * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or * the relevant option in a comma separated option list * * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) * which have a parameter * * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform * action iii). * * 5) "-x ", etc. Matches either "-xparam" or "-x param" as * two separate arguments * * 6) "-x %s", etc. Combination of 4) and 5) * * If the format is "%s", memory is allocated for the string unlike * with scanf(). */ struct fuse_opt { /** Matching template and optional parameter formatting */ const char *templ; /** * Offset of variable within 'data' parameter of fuse_opt_parse() * or -1 */ unsigned long offset; /** * Value to set the variable to, or to be passed as 'key' to the * processing function. Ignored if template has a format */ int value; }; /** * Key option. In case of a match, the processing function will be * called with the specified key. */ #define FUSE_OPT_KEY(templ, key) { templ, -1U, key } /** * Last option. An array of 'struct fuse_opt' must end with a NULL * template value */ #define FUSE_OPT_END { NULL, 0, 0 } /** * Argument list */ struct fuse_args { /** Argument count */ int argc; /** Argument vector. NULL terminated */ char **argv; /** Is 'argv' allocated? */ int allocated; }; /** * Initializer for 'struct fuse_args' */ #define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 } /** * Key value passed to the processing function if an option did not * match any template */ #define FUSE_OPT_KEY_OPT -1 /** * Key value passed to the processing function for all non-options * * Non-options are the arguments beginning with a character other than * '-' or all arguments after the special '--' option */ #define FUSE_OPT_KEY_NONOPT -2 /** * Special key value for options to keep * * Argument is not passed to processing function, but behave as if the * processing function returned 1 */ #define FUSE_OPT_KEY_KEEP -3 /** * Special key value for options to discard * * Argument is not passed to processing function, but behave as if the * processing function returned zero */ #define FUSE_OPT_KEY_DISCARD -4 /** * Processing function * * This function is called if * - option did not match any 'struct fuse_opt' * - argument is a non-option * - option did match and offset was set to -1 * * The 'arg' parameter will always contain the whole argument or * option including the parameter if exists. A two-argument option * ("-x foo") is always converted to single argument option of the * form "-xfoo" before this function is called. * * Options of the form '-ofoo' are passed to this function without the * '-o' prefix. * * The return value of this function determines whether this argument * is to be inserted into the output argument vector, or discarded. * * @param data is the user data passed to the fuse_opt_parse() function * @param arg is the whole argument or option * @param key determines why the processing function was called * @param outargs the current output argument list * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept */ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs); /** * Option parsing function * * If 'args' was returned from a previous call to fuse_opt_parse() or * it was constructed from * * A NULL 'args' is equivalent to an empty argument vector * * A NULL 'opts' is equivalent to an 'opts' array containing a single * end marker * * A NULL 'proc' is equivalent to a processing function always * returning '1' * * @param args is the input and output argument list * @param data is the user data * @param opts is the option description array * @param proc is the processing function * @return -1 on error, 0 on success */ int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc); /** * Add an option to a comma separated option list * * @param opts is a pointer to an option list, may point to a NULL value * @param opt is the option to add * @return -1 on allocation error, 0 on success */ int fuse_opt_add_opt(char **opts, const char *opt); /** * Add an option, escaping commas, to a comma separated option list * * @param opts is a pointer to an option list, may point to a NULL value * @param opt is the option to add * @return -1 on allocation error, 0 on success */ int fuse_opt_add_opt_escaped(char **opts, const char *opt); /** * Add an argument to a NULL terminated argument vector * * @param args is the structure containing the current argument list * @param arg is the new argument to add * @return -1 on allocation error, 0 on success */ int fuse_opt_add_arg(struct fuse_args *args, const char *arg); /** * Add an argument at the specified position in a NULL terminated * argument vector * * Adds the argument to the N-th position. This is useful for adding * options at the beginning of the array which must not come after the * special '--' option. * * @param args is the structure containing the current argument list * @param pos is the position at which to add the argument * @param arg is the new argument to add * @return -1 on allocation error, 0 on success */ int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); /** * Free the contents of argument list * * The structure itself is not freed * * @param args is the structure containing the argument list */ void fuse_opt_free_args(struct fuse_args *args); /** * Check if an option matches * * @param opts is the option description array * @param opt is the option to match * @return 1 if a match is found, 0 if not */ int fuse_opt_match(const struct fuse_opt opts[], const char *opt); #ifdef __cplusplus } #endif #endif /* _FUSE_OPT_H_ */ fuse-2.9.9/include/fuse_common_compat.h0000664000175000017500000000131213413660255015073 00000000000000/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ struct fuse_file_info_compat { int flags; unsigned long fh; int writepage; unsigned int direct_io : 1; unsigned int keep_cache : 1; }; int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args); int fuse_mount_compat22(const char *mountpoint, const char *opts); int fuse_mount_compat1(const char *mountpoint, const char *args[]); void fuse_unmount_compat22(const char *mountpoint); fuse-2.9.9/include/ulockmgr.h0000664000175000017500000000124713413660255013050 00000000000000/* libulockmgr: Userspace Lock Manager Library Copyright (C) 2006 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ #include #include #include /** * Perform POSIX locking operation * * @param fd the file descriptor * @param cmd the locking command (F_GETFL, F_SETLK or F_SETLKW) * @param lock the lock parameters * @param owner the lock owner ID cookie * @param owner_len length of the lock owner ID cookie * @return 0 on success -errno on error */ int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, size_t owner_len); fuse-2.9.9/doc/0000775000175000017500000000000013413661013010243 500000000000000fuse-2.9.9/doc/fusermount.10000664000175000017500000000211313413660255012460 00000000000000.TH FUSERMOUNT 1 2011\-10\-23 2.8.6 "Filesystem in Userspace (FUSE)" .SH NAME \fBfusermount\fR \- mount and unmount FUSE filesystems .SH SYNOPSIS \fBfusermount\fR [\fIOPTIONS\fR] \fIMOUNTPOINT\fR .SH DESCRIPTION Filesystem in Userspace (FUSE) is a simple interface for userspace programs to export a virtual filesystem to the Linux kernel. It also aims to provide a secure method for non privileged users to create and mount their own filesystem implementations. .PP \fBfusermount\fR is a program to mount and unmount FUSE filesystems. .SH OPTIONS .IP "\-h" 4 print help. .IP "\-V" 4 print version. .IP "-o \fIOPTION\fR[,\fIOPTION\fR...]" 4 mount options. .IP "-u" 4 unmount. .IP "-q" 4 quiet. .IP "-z" 4 lazy unmount. .SH SEE ALSO \fImount\fR(8), \fImount.fuse\fR(8), \fIulockmgr_server\fR(1). .SH HOMEPAGE More information about fusermount and the FUSE project can be found at <\fIhttp://fuse.sourceforge.net/\fR>. .SH AUTHOR FUSE was written by Miklos Szeredi <\fImiklos@szeredi.hu\fR>. .PP This manual page was written by Daniel Baumann <\fIdaniel.baumann@progress\-technologies.net\fR>. fuse-2.9.9/doc/Makefile.in0000664000175000017500000004160313413660776012253 00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # 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, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ 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 \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = doc 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 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.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 = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" 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@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INIT_D_PATH = @INIT_D_PATH@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ 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@ MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ UDEV_RULES_PATH = @UDEV_RULES_PATH@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ libfuse_libs = @libfuse_libs@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs2 = @subdirs2@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ dist_man_MANS = fusermount.1 mount.fuse.8 ulockmgr_server.1 EXTRA_DIST = how-fuse-works kernel.txt Doxyfile html all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(dist_man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(dist_man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man8: $(dist_man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(dist_man_MANS)'; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man1 uninstall-man8 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man1 install-man8 install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ 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. .NOEXPORT: fuse-2.9.9/doc/ulockmgr_server.10000664000175000017500000000170613413660255013471 00000000000000.TH ULOCKMGR_SERVER 1 2011\-10\-23 2.8.6 "Filesystem in Userspace (FUSE)" .SH NAME \fBulockmgr_server\fR \- Lock Manager Server for FUSE filesystems .SH SYNOPSIS \fBulockmgr_server\fR .SH DESCRIPTION Filesystem in Userspace (FUSE) is a simple interface for userspace programs to export a virtual filesystem to the Linux kernel. It also aims to provide a secure method for non privileged users to create and mount their own filesystem implementations. .PP \fBulockmgr_server\fR is the Userspace Lock Manager Server for FUSE filesystems. .SH OPTIONS \fBulockmgr_server\fR has no options. .SH SEE ALSO \fIfusermount\fR(1), \fImount\fR(8), \fImount.fuse\fR(8). .SH HOMEPAGE More information about ulockmgr_server and the FUSE project can be found at <\fIhttp://fuse.sourceforge.net/\fR>. .SH AUTHOR FUSE was written by Miklos Szeredi <\fImiklos@szeredi.hu\fR>. .PP This manual page was written by Daniel Baumann <\fIdaniel.baumann@progress\-technologies.net\fR>. fuse-2.9.9/doc/html/0000775000175000017500000000000013407447020011212 500000000000000fuse-2.9.9/doc/html/stracedecode_8c_source.html0000664000175000017500000010224513407447020016423 00000000000000 libfuse: test/stracedecode.c Source File
libfuse
stracedecode.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "fuse_kernel.h"
4 
5 static struct {
6  const char *name;
7 } fuse_ll_ops[] = {
8  [FUSE_LOOKUP] = { "LOOKUP" },
9  [FUSE_FORGET] = { "FORGET" },
10  [FUSE_GETATTR] = { "GETATTR" },
11  [FUSE_SETATTR] = { "SETATTR" },
12  [FUSE_READLINK] = { "READLINK" },
13  [FUSE_SYMLINK] = { "SYMLINK" },
14  [FUSE_MKNOD] = { "MKNOD" },
15  [FUSE_MKDIR] = { "MKDIR" },
16  [FUSE_UNLINK] = { "UNLINK" },
17  [FUSE_RMDIR] = { "RMDIR" },
18  [FUSE_RENAME] = { "RENAME" },
19  [FUSE_LINK] = { "LINK" },
20  [FUSE_OPEN] = { "OPEN" },
21  [FUSE_READ] = { "READ" },
22  [FUSE_WRITE] = { "WRITE" },
23  [FUSE_STATFS] = { "STATFS" },
24  [FUSE_RELEASE] = { "RELEASE" },
25  [FUSE_FSYNC] = { "FSYNC" },
26  [FUSE_SETXATTR] = { "SETXATTR" },
27  [FUSE_GETXATTR] = { "GETXATTR" },
28  [FUSE_LISTXATTR] = { "LISTXATTR" },
29  [FUSE_REMOVEXATTR] = { "REMOVEXATTR" },
30  [FUSE_FLUSH] = { "FLUSH" },
31  [FUSE_INIT] = { "INIT" },
32  [FUSE_OPENDIR] = { "OPENDIR" },
33  [FUSE_READDIR] = { "READDIR" },
34  [FUSE_RELEASEDIR] = { "RELEASEDIR" },
35  [FUSE_FSYNCDIR] = { "FSYNCDIR" },
36  [FUSE_GETLK] = { "GETLK" },
37  [FUSE_SETLK] = { "SETLK" },
38  [FUSE_SETLKW] = { "SETLKW" },
39  [FUSE_ACCESS] = { "ACCESS" },
40  [FUSE_CREATE] = { "CREATE" },
41  [FUSE_INTERRUPT] = { "INTERRUPT" },
42  [FUSE_BMAP] = { "BMAP" },
43  [FUSE_DESTROY] = { "DESTROY" },
44  [FUSE_READDIRPLUS] = { "READDIRPLUS" },
45 };
46 
47 #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
48 
49 static const char *opname(enum fuse_opcode opcode)
50 {
51  if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
52  return "???";
53  else
54  return fuse_ll_ops[opcode].name;
55 }
56 
57 
58 static void process_buf(int dir, char *buf, int len)
59 {
60  static unsigned long long prevuniq = -1;
61  static int prevopcode;
62 
63  if (!dir) {
64  struct fuse_in_header *in = (struct fuse_in_header *) buf;
65  buf += sizeof(struct fuse_in_header);
66 
67  printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n",
68  (unsigned long long) in->unique,
69  opname((enum fuse_opcode) in->opcode), in->opcode,
70  (unsigned long) in->nodeid, in->len, len);
71 
72  switch (in->opcode) {
73  case FUSE_READ: {
74  struct fuse_read_in *arg = (struct fuse_read_in *) buf;
75  printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n",
76  arg->fh, arg->offset, arg->size, arg->read_flags,
77  arg->lock_owner, arg->flags);
78  break;
79  }
80  case FUSE_WRITE: {
81  struct fuse_write_in *arg = (struct fuse_write_in *) buf;
82  printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n",
83  arg->fh, arg->offset, arg->size, arg->write_flags,
84  arg->lock_owner, arg->flags);
85  break;
86  }
87  }
88  prevuniq = in->unique;
89  prevopcode = in->opcode;
90  } else {
91  struct fuse_out_header *out = (struct fuse_out_header *) buf;
92  buf += sizeof(struct fuse_out_header);
93 
94  printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n",
95  (unsigned long long) out->unique, out->error,
96  strerror(-out->error), out->len, len);
97 
98  if (out->unique == prevuniq) {
99  switch (prevopcode) {
100  case FUSE_GETATTR: {
101  struct fuse_attr_out *arg = (struct fuse_attr_out *) buf;
102  printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n",
103  arg->attr_valid, arg->attr_valid_nsec,
104  arg->attr.ino, arg->attr.size, arg->attr.blocks);
105  break;
106  }
107  case FUSE_LOOKUP: {
108  struct fuse_entry_out *arg = (struct fuse_entry_out *) buf;
109  printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n",
110  arg->nodeid, arg->attr_valid, arg->attr_valid_nsec,
111  arg->attr.ino, arg->attr.size, arg->attr.blocks);
112  break;
113  }
114  }
115  }
116  }
117 
118 }
119 
120 int main(void)
121 {
122  FILE *in = stdin;
123  while (1) {
124  int dir;
125  int res;
126  char buf[1048576];
127  unsigned len = 0;
128 
129  memset(buf, 0, sizeof(buf));
130  while (1) {
131  char str[32];
132 
133  res = fscanf(in, "%30s", str);
134  if (res != 1 && feof(in))
135  return 0;
136 
137  if (res == 0)
138  continue;
139 
140  if (strncmp(str, "read(", 5) == 0) {
141  dir = 0;
142  break;
143  } else if (strncmp(str, "writev(", 7) == 0) {
144  dir = 1;
145  break;
146  }
147  }
148 
149  while (1) {
150  int c = getc(in);
151  if (c == '"') {
152  while (1) {
153  int val;
154 
155  c = getc(in);
156  if (c == EOF) {
157  fprintf(stderr, "eof in string\n");
158  break;
159  }
160  if (c == '\n') {
161  fprintf(stderr, "eol in string\n");
162  break;
163  }
164  if (c == '"')
165  break;
166  if (c != '\\') {
167  val = c;
168  } else {
169  c = getc(in);
170  switch (c) {
171  case 'n': val = '\n'; break;
172  case 'r': val = '\r'; break;
173  case 't': val = '\t'; break;
174  case '"': val = '"'; break;
175  case '\\': val = '\\'; break;
176  case 'x':
177  res = scanf("%x", &val);
178  if (res != 1) {
179  fprintf(stderr, "parse error\n");
180  continue;
181  }
182  break;
183  default:
184  fprintf(stderr, "unknown sequence: '\\%c'\n", c);
185  continue;
186  }
187  }
188  buf[len++] = val;
189  }
190  }
191  if (c == '\n')
192  break;
193  }
194  process_buf(dir, buf, len);
195  memset(buf, 0, len);
196  len = 0;
197  }
198 }
fuse-2.9.9/doc/html/fuse__lowlevel_8h_source.html0000664000175000017500000031006213407447020017013 00000000000000 libfuse: include/fuse_lowlevel.h Source File
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)
fuse-2.9.9/doc/html/passthrough__ll_8c.html0000664000175000017500000035344013407447020015620 00000000000000 libfuse: example/passthrough_ll.c File Reference
libfuse
passthrough_ll.c File Reference
#include "config.h"
#include <fuse_lowlevel.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
#include <dirent.h>
#include <assert.h>
#include <errno.h>
#include <err.h>
#include <inttypes.h>
#include <pthread.h>
#include <sys/file.h>
#include <sys/xattr.h>

Go to the source code of this file.

Detailed Description

This file system mirrors the existing file system hierarchy of the system, starting at the root file system. This is implemented by just "passing through" all requests to the corresponding user-space libc functions. In contrast to passthrough.c and passthrough_fh.c, this implementation uses the low-level API. Its performance should be the least bad among the three, but many operations are not implemented. In particular, it is not possible to remove files (or directories) because the code necessary to defer actual removal until the file is not opened anymore would make the example much more complicated.

When writeback caching is enabled (-o writeback mount option), it is only possible to write to files for which the mounting user has read permissions. This is because the writeback cache requires the kernel to be able to issue read requests for all files (which the passthrough filesystem cannot satisfy if it can't read the file in the underlying filesystem).

Compile with:

gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_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 _GNU_SOURCE
#define FUSE_USE_VERSION 31
#include "config.h"
#include <fuse_lowlevel.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
#include <dirent.h>
#include <assert.h>
#include <errno.h>
#include <err.h>
#include <inttypes.h>
#include <pthread.h>
#include <sys/file.h>
#include <sys/xattr.h>
/* We are re-using pointers to our `struct lo_inode` and `struct
lo_dirp` elements as inodes. This means that we must be able to
store uintptr_t values in a fuse_ino_t variable. The following
incantation checks this condition at compile time. */
#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
"fuse_ino_t too small to hold uintptr_t values!");
#else
struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
{ unsigned _uintptr_to_must_hold_fuse_ino_t:
((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
#endif
struct lo_inode {
struct lo_inode *next; /* protected by lo->mutex */
struct lo_inode *prev; /* protected by lo->mutex */
int fd;
bool is_symlink;
ino_t ino;
dev_t dev;
uint64_t refcount; /* protected by lo->mutex */
};
enum {
CACHE_NEVER,
CACHE_NORMAL,
CACHE_ALWAYS,
};
struct lo_data {
pthread_mutex_t mutex;
int debug;
int writeback;
int flock;
int xattr;
const char *source;
double timeout;
int cache;
int timeout_set;
struct lo_inode root; /* protected by lo->mutex */
};
static const struct fuse_opt lo_opts[] = {
{ "writeback",
offsetof(struct lo_data, writeback), 1 },
{ "no_writeback",
offsetof(struct lo_data, writeback), 0 },
{ "source=%s",
offsetof(struct lo_data, source), 0 },
{ "flock",
offsetof(struct lo_data, flock), 1 },
{ "no_flock",
offsetof(struct lo_data, flock), 0 },
{ "xattr",
offsetof(struct lo_data, xattr), 1 },
{ "no_xattr",
offsetof(struct lo_data, xattr), 0 },
{ "timeout=%lf",
offsetof(struct lo_data, timeout), 0 },
{ "timeout=",
offsetof(struct lo_data, timeout_set), 1 },
{ "cache=never",
offsetof(struct lo_data, cache), CACHE_NEVER },
{ "cache=auto",
offsetof(struct lo_data, cache), CACHE_NORMAL },
{ "cache=always",
offsetof(struct lo_data, cache), CACHE_ALWAYS },
};
static struct lo_data *lo_data(fuse_req_t req)
{
return (struct lo_data *) fuse_req_userdata(req);
}
static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
{
if (ino == FUSE_ROOT_ID)
return &lo_data(req)->root;
else
return (struct lo_inode *) (uintptr_t) ino;
}
static int lo_fd(fuse_req_t req, fuse_ino_t ino)
{
return lo_inode(req, ino)->fd;
}
static bool lo_debug(fuse_req_t req)
{
return lo_data(req)->debug != 0;
}
static void lo_init(void *userdata,
struct fuse_conn_info *conn)
{
struct lo_data *lo = (struct lo_data*) userdata;
if (lo->writeback &&
if (lo->debug)
fprintf(stderr, "lo_init: activating writeback\n");
}
if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
if (lo->debug)
fprintf(stderr, "lo_init: activating flock locks\n");
}
}
static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
int res;
struct stat buf;
struct lo_data *lo = lo_data(req);
(void) fi;
res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1)
return (void) fuse_reply_err(req, errno);
fuse_reply_attr(req, &buf, lo->timeout);
}
static int utimensat_empty_nofollow(struct lo_inode *inode,
const struct timespec *tv)
{
int res;
char procname[64];
if (inode->is_symlink) {
res = utimensat(inode->fd, "", tv,
AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1 && errno == EINVAL) {
/* Sorry, no race free way to set times on symlink. */
errno = EPERM;
}
return res;
}
sprintf(procname, "/proc/self/fd/%i", inode->fd);
return utimensat(AT_FDCWD, procname, tv, 0);
}
static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int valid, struct fuse_file_info *fi)
{
int saverr;
char procname[64];
struct lo_inode *inode = lo_inode(req, ino);
int ifd = inode->fd;
int res;
if (valid & FUSE_SET_ATTR_MODE) {
if (fi) {
res = fchmod(fi->fh, attr->st_mode);
} else {
sprintf(procname, "/proc/self/fd/%i", ifd);
res = chmod(procname, attr->st_mode);
}
if (res == -1)
goto out_err;
}
if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
attr->st_uid : (uid_t) -1;
gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
attr->st_gid : (gid_t) -1;
res = fchownat(ifd, "", uid, gid,
AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1)
goto out_err;
}
if (valid & FUSE_SET_ATTR_SIZE) {
if (fi) {
res = ftruncate(fi->fh, attr->st_size);
} else {
sprintf(procname, "/proc/self/fd/%i", ifd);
res = truncate(procname, attr->st_size);
}
if (res == -1)
goto out_err;
}
if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
struct timespec tv[2];
tv[0].tv_sec = 0;
tv[1].tv_sec = 0;
tv[0].tv_nsec = UTIME_OMIT;
tv[1].tv_nsec = UTIME_OMIT;
if (valid & FUSE_SET_ATTR_ATIME_NOW)
tv[0].tv_nsec = UTIME_NOW;
else if (valid & FUSE_SET_ATTR_ATIME)
tv[0] = attr->st_atim;
if (valid & FUSE_SET_ATTR_MTIME_NOW)
tv[1].tv_nsec = UTIME_NOW;
else if (valid & FUSE_SET_ATTR_MTIME)
tv[1] = attr->st_mtim;
if (fi)
res = futimens(fi->fh, tv);
else
res = utimensat_empty_nofollow(inode, tv);
if (res == -1)
goto out_err;
}
return lo_getattr(req, ino, fi);
out_err:
saverr = errno;
fuse_reply_err(req, saverr);
}
static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
{
struct lo_inode *p;
struct lo_inode *ret = NULL;
pthread_mutex_lock(&lo->mutex);
for (p = lo->root.next; p != &lo->root; p = p->next) {
if (p->ino == st->st_ino && p->dev == st->st_dev) {
assert(p->refcount > 0);
ret = p;
ret->refcount++;
break;
}
}
pthread_mutex_unlock(&lo->mutex);
return ret;
}
static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
struct fuse_entry_param *e)
{
int newfd;
int res;
int saverr;
struct lo_data *lo = lo_data(req);
struct lo_inode *inode;
memset(e, 0, sizeof(*e));
e->attr_timeout = lo->timeout;
e->entry_timeout = lo->timeout;
newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
if (newfd == -1)
goto out_err;
res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1)
goto out_err;
inode = lo_find(lo_data(req), &e->attr);
if (inode) {
close(newfd);
newfd = -1;
} else {
struct lo_inode *prev, *next;
saverr = ENOMEM;
inode = calloc(1, sizeof(struct lo_inode));
if (!inode)
goto out_err;
inode->is_symlink = S_ISLNK(e->attr.st_mode);
inode->refcount = 1;
inode->fd = newfd;
inode->ino = e->attr.st_ino;
inode->dev = e->attr.st_dev;
pthread_mutex_lock(&lo->mutex);
prev = &lo->root;
next = prev->next;
next->prev = inode;
inode->next = next;
inode->prev = prev;
prev->next = inode;
pthread_mutex_unlock(&lo->mutex);
}
e->ino = (uintptr_t) inode;
if (lo_debug(req))
fprintf(stderr, " %lli/%s -> %lli\n",
(unsigned long long) parent, name, (unsigned long long) e->ino);
return 0;
out_err:
saverr = errno;
if (newfd != -1)
close(newfd);
return saverr;
}
static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
struct fuse_entry_param e;
int err;
if (lo_debug(req))
fprintf(stderr, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
parent, name);
err = lo_do_lookup(req, parent, name, &e);
if (err)
fuse_reply_err(req, err);
else
fuse_reply_entry(req, &e);
}
static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode, dev_t rdev,
const char *link)
{
int newfd = -1;
int res;
int saverr;
struct lo_inode *inode;
struct lo_inode *dir = lo_inode(req, parent);
struct fuse_entry_param e;
saverr = ENOMEM;
inode = calloc(1, sizeof(struct lo_inode));
if (!inode)
goto out;
if (S_ISDIR(mode))
res = mkdirat(dir->fd, name, mode);
else if (S_ISLNK(mode))
res = symlinkat(link, dir->fd, name);
else
res = mknodat(dir->fd, name, mode, rdev);
saverr = errno;
if (res == -1)
goto out;
saverr = lo_do_lookup(req, parent, name, &e);
if (saverr)
goto out;
if (lo_debug(req))
fprintf(stderr, " %lli/%s -> %lli\n",
(unsigned long long) parent, name, (unsigned long long) e.ino);
fuse_reply_entry(req, &e);
return;
out:
if (newfd != -1)
close(newfd);
free(inode);
fuse_reply_err(req, saverr);
}
static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode, dev_t rdev)
{
lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
}
static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode)
{
lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
}
static void lo_symlink(fuse_req_t req, const char *link,
fuse_ino_t parent, const char *name)
{
lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
}
static int linkat_empty_nofollow(struct lo_inode *inode, int dfd,
const char *name)
{
int res;
char procname[64];
if (inode->is_symlink) {
res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
/* Sorry, no race free way to hard-link a symlink. */
errno = EPERM;
}
return res;
}
sprintf(procname, "/proc/self/fd/%i", inode->fd);
return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
}
static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
const char *name)
{
int res;
struct lo_data *lo = lo_data(req);
struct lo_inode *inode = lo_inode(req, ino);
struct fuse_entry_param e;
int saverr;
memset(&e, 0, sizeof(struct fuse_entry_param));
e.attr_timeout = lo->timeout;
e.entry_timeout = lo->timeout;
res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
if (res == -1)
goto out_err;
res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1)
goto out_err;
pthread_mutex_lock(&lo->mutex);
inode->refcount++;
pthread_mutex_unlock(&lo->mutex);
e.ino = (uintptr_t) inode;
if (lo_debug(req))
fprintf(stderr, " %lli/%s -> %lli\n",
(unsigned long long) parent, name,
(unsigned long long) e.ino);
fuse_reply_entry(req, &e);
return;
out_err:
saverr = errno;
fuse_reply_err(req, saverr);
}
static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
{
int res;
res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname,
unsigned int flags)
{
int res;
if (flags) {
fuse_reply_err(req, EINVAL);
return;
}
res = renameat(lo_fd(req, parent), name,
lo_fd(req, newparent), newname);
fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
{
int res;
res = unlinkat(lo_fd(req, parent), name, 0);
fuse_reply_err(req, res == -1 ? errno : 0);
}
static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
{
if (!inode)
return;
pthread_mutex_lock(&lo->mutex);
assert(inode->refcount >= n);
inode->refcount -= n;
if (!inode->refcount) {
struct lo_inode *prev, *next;
prev = inode->prev;
next = inode->next;
next->prev = prev;
prev->next = next;
pthread_mutex_unlock(&lo->mutex);
close(inode->fd);
free(inode);
} else {
pthread_mutex_unlock(&lo->mutex);
}
}
static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
{
struct lo_data *lo = lo_data(req);
struct lo_inode *inode = lo_inode(req, ino);
if (lo_debug(req)) {
fprintf(stderr, " forget %lli %lli -%lli\n",
(unsigned long long) ino,
(unsigned long long) inode->refcount,
(unsigned long long) nlookup);
}
unref_inode(lo, inode, nlookup);
}
static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
{
lo_forget_one(req, ino, nlookup);
}
static void lo_forget_multi(fuse_req_t req, size_t count,
struct fuse_forget_data *forgets)
{
int i;
for (i = 0; i < count; i++)
lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
}
static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
{
char buf[PATH_MAX + 1];
int res;
res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
if (res == -1)
return (void) fuse_reply_err(req, errno);
if (res == sizeof(buf))
return (void) fuse_reply_err(req, ENAMETOOLONG);
buf[res] = '\0';
}
struct lo_dirp {
int fd;
DIR *dp;
struct dirent *entry;
off_t offset;
};
static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
{
return (struct lo_dirp *) (uintptr_t) fi->fh;
}
static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
int error = ENOMEM;
struct lo_data *lo = lo_data(req);
struct lo_dirp *d = calloc(1, sizeof(struct lo_dirp));
if (d == NULL)
goto out_err;
d->fd = openat(lo_fd(req, ino), ".", O_RDONLY);
if (d->fd == -1)
goto out_errno;
d->dp = fdopendir(d->fd);
if (d->dp == NULL)
goto out_errno;
d->offset = 0;
d->entry = NULL;
fi->fh = (uintptr_t) d;
if (lo->cache == CACHE_ALWAYS)
fi->keep_cache = 1;
fuse_reply_open(req, fi);
return;
out_errno:
error = errno;
out_err:
if (d) {
if (d->fd != -1)
close(d->fd);
free(d);
}
fuse_reply_err(req, error);
}
static int is_dot_or_dotdot(const char *name)
{
return name[0] == '.' && (name[1] == '\0' ||
(name[1] == '.' && name[2] == '\0'));
}
static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t offset, struct fuse_file_info *fi, int plus)
{
struct lo_dirp *d = lo_dirp(fi);
char *buf;
char *p;
size_t rem = size;
int err;
(void) ino;
buf = calloc(1, size);
if (!buf) {
err = ENOMEM;
goto error;
}
p = buf;
if (offset != d->offset) {
seekdir(d->dp, offset);
d->entry = NULL;
d->offset = offset;
}
while (1) {
size_t entsize;
off_t nextoff;
const char *name;
if (!d->entry) {
errno = 0;
d->entry = readdir(d->dp);
if (!d->entry) {
if (errno) { // Error
err = errno;
goto error;
} else { // End of stream
break;
}
}
}
nextoff = d->entry->d_off;
name = d->entry->d_name;
fuse_ino_t entry_ino = 0;
if (plus) {
struct fuse_entry_param e;
if (is_dot_or_dotdot(name)) {
e = (struct fuse_entry_param) {
.attr.st_ino = d->entry->d_ino,
.attr.st_mode = d->entry->d_type << 12,
};
} else {
err = lo_do_lookup(req, ino, name, &e);
if (err)
goto error;
entry_ino = e.ino;
}
entsize = fuse_add_direntry_plus(req, p, rem, name,
&e, nextoff);
} else {
struct stat st = {
.st_ino = d->entry->d_ino,
.st_mode = d->entry->d_type << 12,
};
entsize = fuse_add_direntry(req, p, rem, name,
&st, nextoff);
}
if (entsize > rem) {
if (entry_ino != 0)
lo_forget_one(req, entry_ino, 1);
break;
}
p += entsize;
rem -= entsize;
d->entry = NULL;
d->offset = nextoff;
}
err = 0;
error:
// If there's an error, we can only signal it if we haven't stored
// any entries yet - otherwise we'd end up with wrong lookup
// counts for the entries that are already in the buffer. So we
// return what we've collected until that point.
if (err && rem == size)
fuse_reply_err(req, err);
else
fuse_reply_buf(req, buf, size - rem);
free(buf);
}
static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t offset, struct fuse_file_info *fi)
{
lo_do_readdir(req, ino, size, offset, fi, 0);
}
static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t offset, struct fuse_file_info *fi)
{
lo_do_readdir(req, ino, size, offset, fi, 1);
}
static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
struct lo_dirp *d = lo_dirp(fi);
(void) ino;
closedir(d->dp);
free(d);
fuse_reply_err(req, 0);
}
static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, struct fuse_file_info *fi)
{
int fd;
struct fuse_entry_param e;
int err;
if (lo_debug(req))
fprintf(stderr, "lo_create(parent=%" PRIu64 ", name=%s)\n",
parent, name);
fd = openat(lo_fd(req, parent), name,
(fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
if (fd == -1)
return (void) fuse_reply_err(req, errno);
fi->fh = fd;
err = lo_do_lookup(req, parent, name, &e);
if (err)
fuse_reply_err(req, err);
else
fuse_reply_create(req, &e, fi);
}
static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi)
{
int res;
int fd = dirfd(lo_dirp(fi)->dp);
(void) ino;
if (datasync)
res = fdatasync(fd);
else
res = fsync(fd);
fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
int fd;
char buf[64];
struct lo_data *lo = lo_data(req);
if (lo_debug(req))
fprintf(stderr, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
ino, fi->flags);
/* With writeback cache, kernel may send read requests even
when userspace opened write-only */
if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
fi->flags &= ~O_ACCMODE;
fi->flags |= O_RDWR;
}
/* With writeback cache, O_APPEND is handled by the kernel.
This breaks atomicity (since the file may change in the
underlying filesystem, so that the kernel's idea of the
end of the file isn't accurate anymore). In this example,
we just accept that. A more rigorous filesystem may want
to return an error here */
if (lo->writeback && (fi->flags & O_APPEND))
fi->flags &= ~O_APPEND;
sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
fd = open(buf, fi->flags & ~O_NOFOLLOW);
if (fd == -1)
return (void) fuse_reply_err(req, errno);
fi->fh = fd;
if (lo->cache == CACHE_NEVER)
fi->direct_io = 1;
else if (lo->cache == CACHE_ALWAYS)
fi->keep_cache = 1;
fuse_reply_open(req, fi);
}
static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
(void) ino;
close(fi->fh);
fuse_reply_err(req, 0);
}
static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
int res;
(void) ino;
res = close(dup(fi->fh));
fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi)
{
int res;
(void) ino;
if (datasync)
res = fdatasync(fi->fh);
else
res = fsync(fi->fh);
fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t offset, struct fuse_file_info *fi)
{
struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
if (lo_debug(req))
fprintf(stderr, "lo_read(ino=%" PRIu64 ", size=%zd, "
"off=%lu)\n", ino, size, (unsigned long) offset);
buf.buf[0].fd = fi->fh;
buf.buf[0].pos = offset;
}
static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
struct fuse_bufvec *in_buf, off_t off,
struct fuse_file_info *fi)
{
(void) ino;
ssize_t res;
struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
out_buf.buf[0].fd = fi->fh;
out_buf.buf[0].pos = off;
if (lo_debug(req))
fprintf(stderr, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
ino, out_buf.buf[0].size, (unsigned long) off);
res = fuse_buf_copy(&out_buf, in_buf, 0);
if(res < 0)
fuse_reply_err(req, -res);
else
fuse_reply_write(req, (size_t) res);
}
static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
{
int res;
struct statvfs stbuf;
res = fstatvfs(lo_fd(req, ino), &stbuf);
if (res == -1)
fuse_reply_err(req, errno);
else
fuse_reply_statfs(req, &stbuf);
}
static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
off_t offset, off_t length, struct fuse_file_info *fi)
{
int err;
(void) ino;
if (mode) {
fuse_reply_err(req, EOPNOTSUPP);
return;
}
err = posix_fallocate(fi->fh, offset, length);
fuse_reply_err(req, err);
}
static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
int op)
{
int res;
(void) ino;
res = flock(fi->fh, op);
fuse_reply_err(req, res == -1 ? errno : 0);
}
static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size)
{
char *value = NULL;
char procname[64];
struct lo_inode *inode = lo_inode(req, ino);
ssize_t ret;
int saverr;
saverr = ENOSYS;
if (!lo_data(req)->xattr)
goto out;
if (lo_debug(req)) {
fprintf(stderr, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
ino, name, size);
}
if (inode->is_symlink) {
/* Sorry, no race free way to getxattr on symlink. */
saverr = EPERM;
goto out;
}
sprintf(procname, "/proc/self/fd/%i", inode->fd);
if (size) {
value = malloc(size);
if (!value)
goto out_err;
ret = getxattr(procname, name, value, size);
if (ret == -1)
goto out_err;
saverr = 0;
if (ret == 0)
goto out;
fuse_reply_buf(req, value, ret);
} else {
ret = getxattr(procname, name, NULL, 0);
if (ret == -1)
goto out_err;
fuse_reply_xattr(req, ret);
}
out_free:
free(value);
return;
out_err:
saverr = errno;
out:
fuse_reply_err(req, saverr);
goto out_free;
}
static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
{
char *value = NULL;
char procname[64];
struct lo_inode *inode = lo_inode(req, ino);
ssize_t ret;
int saverr;
saverr = ENOSYS;
if (!lo_data(req)->xattr)
goto out;
if (lo_debug(req)) {
fprintf(stderr, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
ino, size);
}
if (inode->is_symlink) {
/* Sorry, no race free way to listxattr on symlink. */
saverr = EPERM;
goto out;
}
sprintf(procname, "/proc/self/fd/%i", inode->fd);
if (size) {
value = malloc(size);
if (!value)
goto out_err;
ret = listxattr(procname, value, size);
if (ret == -1)
goto out_err;
saverr = 0;
if (ret == 0)
goto out;
fuse_reply_buf(req, value, ret);
} else {
ret = listxattr(procname, NULL, 0);
if (ret == -1)
goto out_err;
fuse_reply_xattr(req, ret);
}
out_free:
free(value);
return;
out_err:
saverr = errno;
out:
fuse_reply_err(req, saverr);
goto out_free;
}
static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags)
{
char procname[64];
struct lo_inode *inode = lo_inode(req, ino);
ssize_t ret;
int saverr;
saverr = ENOSYS;
if (!lo_data(req)->xattr)
goto out;
if (lo_debug(req)) {
fprintf(stderr, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
ino, name, value, size);
}
if (inode->is_symlink) {
/* Sorry, no race free way to setxattr on symlink. */
saverr = EPERM;
goto out;
}
sprintf(procname, "/proc/self/fd/%i", inode->fd);
ret = setxattr(procname, name, value, size, flags);
saverr = ret == -1 ? errno : 0;
out:
fuse_reply_err(req, saverr);
}
static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
{
char procname[64];
struct lo_inode *inode = lo_inode(req, ino);
ssize_t ret;
int saverr;
saverr = ENOSYS;
if (!lo_data(req)->xattr)
goto out;
if (lo_debug(req)) {
fprintf(stderr, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
ino, name);
}
if (inode->is_symlink) {
/* Sorry, no race free way to setxattr on symlink. */
saverr = EPERM;
goto out;
}
sprintf(procname, "/proc/self/fd/%i", inode->fd);
ret = removexattr(procname, name);
saverr = ret == -1 ? errno : 0;
out:
fuse_reply_err(req, saverr);
}
#ifdef HAVE_COPY_FILE_RANGE
static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
struct fuse_file_info *fi_in,
fuse_ino_t ino_out, off_t off_out,
struct fuse_file_info *fi_out, size_t len,
int flags)
{
ssize_t res;
if (lo_debug(req))
fprintf(stderr, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
"off=%lu, ino=%" PRIu64 "/fd=%lu, "
"off=%lu, size=%zd, flags=0x%x)\n",
ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
len, flags);
res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
flags);
if (res < 0)
fuse_reply_err(req, -errno);
else
fuse_reply_write(req, res);
}
#endif
static struct fuse_lowlevel_ops lo_oper = {
.init = lo_init,
.lookup = lo_lookup,
.mkdir = lo_mkdir,
.mknod = lo_mknod,
.symlink = lo_symlink,
.link = lo_link,
.unlink = lo_unlink,
.rmdir = lo_rmdir,
.rename = lo_rename,
.forget = lo_forget,
.forget_multi = lo_forget_multi,
.getattr = lo_getattr,
.setattr = lo_setattr,
.readlink = lo_readlink,
.opendir = lo_opendir,
.readdir = lo_readdir,
.readdirplus = lo_readdirplus,
.releasedir = lo_releasedir,
.fsyncdir = lo_fsyncdir,
.create = lo_create,
.open = lo_open,
.release = lo_release,
.flush = lo_flush,
.fsync = lo_fsync,
.read = lo_read,
.write_buf = lo_write_buf,
.statfs = lo_statfs,
.fallocate = lo_fallocate,
.flock = lo_flock,
.getxattr = lo_getxattr,
.listxattr = lo_listxattr,
.setxattr = lo_setxattr,
.removexattr = lo_removexattr,
#ifdef HAVE_COPY_FILE_RANGE
.copy_file_range = lo_copy_file_range,
#endif
};
int main(int argc, char *argv[])
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_session *se;
struct fuse_cmdline_opts opts;
struct lo_data lo = { .debug = 0,
.writeback = 0 };
int ret = -1;
/* Don't mask creation mode, kernel already did that */
umask(0);
pthread_mutex_init(&lo.mutex, NULL);
lo.root.next = lo.root.prev = &lo.root;
lo.root.fd = -1;
lo.cache = CACHE_NORMAL;
if (fuse_parse_cmdline(&args, &opts) != 0)
return 1;
if (opts.show_help) {
printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
ret = 0;
goto err_out1;
} else if (opts.show_version) {
printf("FUSE library version %s\n", fuse_pkgversion());
ret = 0;
goto err_out1;
}
if(opts.mountpoint == NULL) {
printf("usage: %s [options] <mountpoint>\n", argv[0]);
printf(" %s --help\n", argv[0]);
ret = 1;
goto err_out1;
}
if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
return 1;
lo.debug = opts.debug;
lo.root.refcount = 2;
if (lo.source) {
struct stat stat;
int res;
res = lstat(lo.source, &stat);
if (res == -1)
err(1, "failed to stat source (\"%s\")", lo.source);
if (!S_ISDIR(stat.st_mode))
errx(1, "source is not a directory");
} else {
lo.source = "/";
}
lo.root.is_symlink = false;
if (!lo.timeout_set) {
switch (lo.cache) {
case CACHE_NEVER:
lo.timeout = 0.0;
break;
case CACHE_NORMAL:
lo.timeout = 1.0;
break;
case CACHE_ALWAYS:
lo.timeout = 86400.0;
break;
}
} else if (lo.timeout < 0) {
errx(1, "timeout is negative (%lf)", lo.timeout);
}
lo.root.fd = open(lo.source, O_PATH);
if (lo.root.fd == -1)
err(1, "open(\"%s\", O_PATH)", lo.source);
se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
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);
if (lo.root.fd >= 0)
close(lo.root.fd);
return ret ? 1 : 0;
}

Definition in file passthrough_ll.c.

fuse-2.9.9/doc/html/fuse__opt_8h_source.html0000664000175000017500000004647013407447020015775 00000000000000 libfuse: include/fuse_opt.h Source File
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
fuse-2.9.9/doc/html/open.png0000664000175000017500000000017313407447020012602 00000000000000PNG  IHDR BIDATx 0 ׬ՙ\39b!9{|I>$#ߴ8/z/>2[giU,/~\ 9ٸIENDB`fuse-2.9.9/doc/html/globals_func.html0000664000175000017500000002765313407447020014473 00000000000000 libfuse: Globals
libfuse
 

- f -

fuse-2.9.9/doc/html/ioctl_8c_source.html0000664000175000017500000010144113407447020015105 00000000000000 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
fuse-2.9.9/doc/html/dir_e1dbc8ba94a86723d4c32227b7c46099.html0000664000175000017500000000376313407447020017173 00000000000000 libfuse: lib/modules Directory Reference
libfuse
modules Directory Reference
fuse-2.9.9/doc/html/tabs.css0000664000175000017500000002174013407447020012601 00000000000000.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sm-dox{background-image:url("tab_b.png")}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:"Lucida Grande","Geneva","Helvetica",Arial,sans-serif;font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,0.9);color:#283a5d;outline:0}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace!important;text-align:center;text-shadow:none;background:rgba(255,255,255,0.5);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:rgba(162,162,162,0.1)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:white;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:url("tab_b.png");line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:#283a5d transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:url("tab_s.png");background-repeat:no-repeat;background-position:right;-moz-border-radius:0!important;-webkit-border-radius:0;border-radius:0!important}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a:hover span.sub-arrow{border-color:white transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent #fff transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:#fff;-moz-border-radius:5px!important;-webkit-border-radius:5px;border-radius:5px!important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent #555;border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:#555;background-image:none;border:0!important;color:#555;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent white}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:#fff;height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent #555 transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:#555 transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px!important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:url("tab_b.png")}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:#fff}}fuse-2.9.9/doc/html/mount_8fuse_8c_source.html0000664000175000017500000017026413407447020016260 00000000000000 libfuse: util/mount.fuse.c Source File
libfuse
mount.fuse.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 
9 #include <config.h>
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <stdint.h>
17 #include <fcntl.h>
18 #include <pwd.h>
19 #include <sys/wait.h>
20 
21 #ifdef linux
22 #include <sys/prctl.h>
23 #include <sys/syscall.h>
24 #include <linux/capability.h>
25 #include <linux/securebits.h>
26 #endif
27 
28 #include "fuse.h"
29 
30 static char *progname;
31 
32 static char *xstrdup(const char *s)
33 {
34  char *t = strdup(s);
35  if (!t) {
36  fprintf(stderr, "%s: failed to allocate memory\n", progname);
37  exit(1);
38  }
39  return t;
40 }
41 
42 static void *xrealloc(void *oldptr, size_t size)
43 {
44  void *ptr = realloc(oldptr, size);
45  if (!ptr) {
46  fprintf(stderr, "%s: failed to allocate memory\n", progname);
47  exit(1);
48  }
49  return ptr;
50 }
51 
52 static void add_arg(char **cmdp, const char *opt)
53 {
54  size_t optlen = strlen(opt);
55  size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
56  if (optlen >= (SIZE_MAX - cmdlen - 4)/4) {
57  fprintf(stderr, "%s: argument too long\n", progname);
58  exit(1);
59  }
60  char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
61  char *s;
62  s = cmd + cmdlen;
63  if (*cmdp)
64  *s++ = ' ';
65 
66  *s++ = '\'';
67  for (; *opt; opt++) {
68  if (*opt == '\'') {
69  *s++ = '\'';
70  *s++ = '\\';
71  *s++ = '\'';
72  *s++ = '\'';
73  } else
74  *s++ = *opt;
75  }
76  *s++ = '\'';
77  *s = '\0';
78  *cmdp = cmd;
79 }
80 
81 static char *add_option(const char *opt, char *options)
82 {
83  int oldlen = options ? strlen(options) : 0;
84 
85  options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
86  if (!oldlen)
87  strcpy(options, opt);
88  else {
89  strcat(options, ",");
90  strcat(options, opt);
91  }
92  return options;
93 }
94 
95 static int prepare_fuse_fd(const char *mountpoint, const char* subtype,
96  const char *options)
97 {
98  int fuse_fd = -1;
99  int flags = -1;
100  int subtype_len = strlen(subtype) + 9;
101  char* options_copy = xrealloc(NULL, subtype_len);
102 
103  snprintf(options_copy, subtype_len, "subtype=%s", subtype);
104  options_copy = add_option(options, options_copy);
105  fuse_fd = fuse_open_channel(mountpoint, options_copy);
106  if (fuse_fd == -1) {
107  exit(1);
108  }
109 
110  flags = fcntl(fuse_fd, F_GETFD);
111  if (flags == -1 || fcntl(fuse_fd, F_SETFD, flags & ~FD_CLOEXEC) == 1) {
112  fprintf(stderr, "%s: Failed to clear CLOEXEC: %s\n",
113  progname, strerror(errno));
114  exit(1);
115  }
116 
117  return fuse_fd;
118 }
119 
120 #ifdef linux
121 static uint64_t get_capabilities(void)
122 {
123  /*
124  * This invokes the capset syscall directly to avoid the libcap
125  * dependency, which isn't really justified just for this.
126  */
127  struct __user_cap_header_struct header = {
128  .version = _LINUX_CAPABILITY_VERSION_3,
129  .pid = 0,
130  };
131  struct __user_cap_data_struct data[2];
132  memset(data, 0, sizeof(data));
133  if (syscall(SYS_capget, &header, data) == -1) {
134  fprintf(stderr, "%s: Failed to get capabilities: %s\n",
135  progname, strerror(errno));
136  exit(1);
137  }
138 
139  return data[0].effective | ((uint64_t) data[1].effective << 32);
140 }
141 
142 static void set_capabilities(uint64_t caps)
143 {
144  /*
145  * This invokes the capset syscall directly to avoid the libcap
146  * dependency, which isn't really justified just for this.
147  */
148  struct __user_cap_header_struct header = {
149  .version = _LINUX_CAPABILITY_VERSION_3,
150  .pid = 0,
151  };
152  struct __user_cap_data_struct data[2];
153  memset(data, 0, sizeof(data));
154  data[0].effective = data[0].permitted = caps;
155  data[1].effective = data[1].permitted = caps >> 32;
156  if (syscall(SYS_capset, &header, data) == -1) {
157  fprintf(stderr, "%s: Failed to set capabilities: %s\n",
158  progname, strerror(errno));
159  exit(1);
160  }
161 }
162 
163 static void drop_and_lock_capabilities(void)
164 {
165  /* Set and lock securebits. */
166  if (prctl(PR_SET_SECUREBITS,
167  SECBIT_KEEP_CAPS_LOCKED |
168  SECBIT_NO_SETUID_FIXUP |
169  SECBIT_NO_SETUID_FIXUP_LOCKED |
170  SECBIT_NOROOT |
171  SECBIT_NOROOT_LOCKED) == -1) {
172  fprintf(stderr, "%s: Failed to set securebits %s\n",
173  progname, strerror(errno));
174  exit(1);
175  }
176 
177  /* Clear the capability bounding set. */
178  int cap;
179  for (cap = 0; ; cap++) {
180  int cap_status = prctl(PR_CAPBSET_READ, cap);
181  if (cap_status == 0) {
182  continue;
183  }
184  if (cap_status == -1 && errno == EINVAL) {
185  break;
186  }
187 
188  if (cap_status != 1) {
189  fprintf(stderr,
190  "%s: Failed to get capability %u: %s\n",
191  progname, cap, strerror(errno));
192  exit(1);
193  }
194  if (prctl(PR_CAPBSET_DROP, cap) == -1) {
195  fprintf(stderr,
196  "%s: Failed to drop capability %u: %s\n",
197  progname, cap, strerror(errno));
198  }
199  }
200 
201  /* Drop capabilities. */
202  set_capabilities(0);
203 
204  /* Prevent re-acquisition of privileges. */
205  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
206  fprintf(stderr, "%s: Failed to set no_new_privs: %s\n",
207  progname, strerror(errno));
208  exit(1);
209  }
210 }
211 #endif
212 
213 int main(int argc, char *argv[])
214 {
215  char *type = NULL;
216  char *source;
217  const char *mountpoint;
218  char *basename;
219  char *options = NULL;
220  char *command = NULL;
221  char *setuid_name = NULL;
222  int i;
223  int dev = 1;
224  int suid = 1;
225  int pass_fuse_fd = 0;
226  int drop_privileges = 0;
227 
228  progname = argv[0];
229  basename = strrchr(argv[0], '/');
230  if (basename)
231  basename++;
232  else
233  basename = argv[0];
234 
235  if (strncmp(basename, "mount.fuse.", 11) == 0)
236  type = basename + 11;
237  if (strncmp(basename, "mount.fuseblk.", 14) == 0)
238  type = basename + 14;
239 
240  if (type && !type[0])
241  type = NULL;
242 
243  if (argc < 3) {
244  fprintf(stderr,
245  "usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
246  progname, type ? "source" : "type#[source]");
247  exit(1);
248  }
249 
250  source = argv[1];
251  if (!source[0])
252  source = NULL;
253 
254  mountpoint = argv[2];
255 
256  for (i = 3; i < argc; i++) {
257  if (strcmp(argv[i], "-v") == 0) {
258  continue;
259  } else if (strcmp(argv[i], "-t") == 0) {
260  i++;
261 
262  if (i == argc) {
263  fprintf(stderr,
264  "%s: missing argument to option '-t'\n",
265  progname);
266  exit(1);
267  }
268  type = argv[i];
269  if (strncmp(type, "fuse.", 5) == 0)
270  type += 5;
271  else if (strncmp(type, "fuseblk.", 8) == 0)
272  type += 8;
273 
274  if (!type[0]) {
275  fprintf(stderr,
276  "%s: empty type given as argument to option '-t'\n",
277  progname);
278  exit(1);
279  }
280  } else if (strcmp(argv[i], "-o") == 0) {
281  char *opts;
282  char *opt;
283  i++;
284  if (i == argc)
285  break;
286 
287  opts = xstrdup(argv[i]);
288  opt = strtok(opts, ",");
289  while (opt) {
290  int j;
291  int ignore = 0;
292  const char *ignore_opts[] = { "",
293  "user",
294  "nofail",
295  "nouser",
296  "users",
297  "auto",
298  "noauto",
299  "_netdev",
300  NULL};
301  if (strncmp(opt, "setuid=", 7) == 0) {
302  setuid_name = xstrdup(opt + 7);
303  ignore = 1;
304  } else if (strcmp(opt,
305  "drop_privileges") == 0) {
306  pass_fuse_fd = 1;
307  drop_privileges = 1;
308  ignore = 1;
309  }
310  for (j = 0; ignore_opts[j]; j++)
311  if (strcmp(opt, ignore_opts[j]) == 0)
312  ignore = 1;
313 
314  if (!ignore) {
315  if (strcmp(opt, "nodev") == 0)
316  dev = 0;
317  else if (strcmp(opt, "nosuid") == 0)
318  suid = 0;
319 
320  options = add_option(opt, options);
321  }
322  opt = strtok(NULL, ",");
323  }
324  }
325  }
326 
327  if (drop_privileges) {
328  uint64_t required_caps = CAP_TO_MASK(CAP_SETPCAP) |
329  CAP_TO_MASK(CAP_SYS_ADMIN);
330  if ((get_capabilities() & required_caps) != required_caps) {
331  fprintf(stderr, "%s: drop_privileges was requested, which launches the FUSE file system fully unprivileged. In order to do so %s must be run with privileges, please invoke with CAP_SYS_ADMIN and CAP_SETPCAP (e.g. as root).\n",
332  progname, progname);
333  exit(1);
334  }
335  }
336 
337  if (dev)
338  options = add_option("dev", options);
339  if (suid)
340  options = add_option("suid", options);
341 
342  if (!type) {
343  if (source) {
344  type = xstrdup(source);
345  source = strchr(type, '#');
346  if (source)
347  *source++ = '\0';
348  if (!type[0]) {
349  fprintf(stderr, "%s: empty filesystem type\n",
350  progname);
351  exit(1);
352  }
353  } else {
354  fprintf(stderr, "%s: empty source\n", progname);
355  exit(1);
356  }
357  }
358 
359  if (setuid_name && setuid_name[0]) {
360 #ifdef linux
361  if (drop_privileges) {
362  /*
363  * Make securebits more permissive before calling
364  * setuid(). Specifically, if SECBIT_KEEP_CAPS and
365  * SECBIT_NO_SETUID_FIXUP weren't set, setuid() would
366  * have the side effect of dropping all capabilities,
367  * and we need to retain CAP_SETPCAP in order to drop
368  * all privileges before exec().
369  */
370  if (prctl(PR_SET_SECUREBITS,
371  SECBIT_KEEP_CAPS |
372  SECBIT_NO_SETUID_FIXUP) == -1) {
373  fprintf(stderr,
374  "%s: Failed to set securebits %s\n",
375  progname, strerror(errno));
376  exit(1);
377  }
378  }
379 #endif
380 
381  struct passwd *pwd = getpwnam(setuid_name);
382  if (setgid(pwd->pw_gid) == -1 || setuid(pwd->pw_uid) == -1) {
383  fprintf(stderr, "%s: Failed to setuid to %s: %s\n",
384  progname, setuid_name, strerror(errno));
385  exit(1);
386  }
387  } else if (!getenv("HOME")) {
388  /* Hack to make filesystems work in the boot environment */
389  setenv("HOME", "/root", 0);
390  }
391 
392  if (pass_fuse_fd) {
393  int fuse_fd = prepare_fuse_fd(mountpoint, type, options);
394  char *dev_fd_mountpoint = xrealloc(NULL, 20);
395  snprintf(dev_fd_mountpoint, 20, "/dev/fd/%u", fuse_fd);
396  mountpoint = dev_fd_mountpoint;
397  }
398 
399 #ifdef linux
400  if (drop_privileges) {
401  drop_and_lock_capabilities();
402  }
403 #endif
404  add_arg(&command, type);
405  if (source)
406  add_arg(&command, source);
407  add_arg(&command, mountpoint);
408  if (options) {
409  add_arg(&command, "-o");
410  add_arg(&command, options);
411  }
412 
413  execl("/bin/sh", "/bin/sh", "-c", command, NULL);
414  fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
415  strerror(errno));
416  return 1;
417 }
int fuse_open_channel(const char *mountpoint, const char *options)
Definition: helper.c:424
fuse-2.9.9/doc/html/fast17-vangoor.pdf0000664000175000017500000222216513407447020014415 00000000000000%PDF-1.5 % 2 0 obj <>stream xctem&vvlv*m۬۶m;Nvӧ}~1=qM\{/2"e:!{#Sq{;:&zFn,+ௐ LNŔnj5503`"N.JU%u*c0_OgKs;7S{[S;׎ʦ S)@D^ASJN@)! 03u2(Xd-MMfNv&LK`pv05fal`dk` 0w2s{? +!'u],\*;O Cb;[UZSҿtaj] -..22X:;z_i:[ڙg'SsC'Sg0 ߪ7tpW.Φ6f0LcmniϠHٙ-7quӿDPM`bj g7$e>(o!7r+G%ZF{ng,cc17?8WCu'#bBv agYD`fhSڙ:Xڙe_11?g7M/IJ.7Y{uYXM cd{\l,@bC'Kj:S|_`MeC;tKGWS)ѿ33r12Kj&,zŠpu2xP[Ҫ-qVeS/yy筙LeKvn+WFy%7 Ͷvܖ<ш0q*&  q7r~1'y_Wb6EhӮ{2'#UtLʋw֦.f%*xm$ 1m"l:[,MFUZ3608Iyc t('QPXKsZ>Q+8D󲣹QP$suv8xrJ$P$f-{9\ b#ia c@`=-p\ʋA4/s k|ꅾ :DXPp}cCЍ.} 4 WnL.ѭR{uN0aT^Qf:]JJm_Kra&4WXT;f1Q5y&RFQ'TwG#wj%b(10/A"L48/<ґx;1 ᎋXfmX;fZZU u=$J6Xx!pbwwi|J5N!-gQVd٘ubiS,`zxBb9F d ^쫯|, 2pmn[i,x( )C[6onD.v`w•ǯM{n3:.`>aV+A5{oya!bJsqGv}78'doh(sc>F[ZdH|==r/g}[0%tܸ,@$#e-ay e=]yCi&<)İ>*Z1mZm=%_[L]Bx`\ G1+qì$!`Vkd"@ٕ>Զ,DJ^C +E=̩`9p@( rvJ Fg3+wS0)Mg2K Ιt=By`)MuyU:t gԖDy 63g4-?mCb'1h3Hv !ut *ǛN,9Utlqp]: @z\\M'g@L$]UGu<}O;!ni7.yYTUla'2XD *1a\wUhM0Mt"Ұ@OOmLBła=LVHɢ So'E; F ]:^K SJx|"伽b A$MeJ y&>ɶQ9.;fsj @P띆é#AybUZ4hr\atI,}i|I% Djuha+߲,w:hwx wEGBHt$,'|S"\>EAnޔF nD{".ۮ}#cfg^W\I} (S~1Ld2R#К  aL:uڴ  =yT3*{ݸjp뵶l~?oz&yZqvQ0gB5 v@pJDCPqNu\uW(̬%}Zo(:T b6hb(M).c<.Ohh裗bp) A!`E]\-Km;z#OU#rg|9ĩ*gc)BWֳs|O72 U[-PvVާsm[].{&ߗLEe]1p e) 3sQ;wϣPWBCIIpE+ !tIE%!0sXDP[{LRGWл) %M}픂yyޤ͵9)UOˏaT>T E?\ǖ.οIcD1>$\x|2U.z:7-pp?JTKcLbEˠX_T4%َQ2[Tg V㒾,q ɳi0 )<ւֿ'"rL \ 7^m9?]&zT/@.fp#dV 9v:( ˔x`2UY:j]'ԿA1e&uX>zWKPUnZ])5ךiV[#kM>?[4g">M0qF~Ytb:wU|-9ZpAQ~' i Q EȲz9o[B}[R-OC+N05zs֝E$0 7AgܞI1xB`Κя i:F_,\ta ޱK@ Z$c9]Rh 2w-ll06xr y9 ɉ,E}e}NafoðI=EҞo8?:鞀~8OOK\G }ڟy8#޶ ~yz{J猖[FBFuɏI loW+֮Mܚu'ׁJ 1R>`*Fv۩䛨?$Kk[˵L{ r.S81w 9T.z@Ĭz[}68ek-i8oD}w1-ւ-1 B8sY|q_ "=H/3fyșaKNĺ[TK6)ڧ,5pDW{K=nU3!.|8K?z,j-ah:̡ wQ Ʉ[I9GZadᾸ̳cX~/@q.IWF#aǤXa.#!rn9_9,İI6_SCHV8s"ů Ճ *wԄ[zI]p&؅y|xD$CV_5͜ C%#˔d\샒pnMKJ(SOu.&zŃ|g)`waFte!UhZ K԰[; ?w%{b`a@'7Dgv洴FP'iD}LLSiERAƎ+ptZHMJ(Gs*ă!8𹤘([qTܱ;9Xaˁ u(w ѲR|L;Z/v'g#q,V] ̃PzK%/ɹ^װYx  U;_!T&f*SvZz0_޿}-zbL_ w]₌ 0fikT;lqU65qK>a>fuPxcJѡĂbnN 9Vގ yXpdAvפ'52Qby^1KʟNh3BvL3דWf(E%9ۍ蜆t s.t}GVp&b4;_A dA^ؔAmd?]ثC vDyH;TRArL%ቀנZPUY[:UW@ʠ%MÑgHSqq MJ4kkU~IBY4 kR'@hQk>eK- ۅx33죕>Нa6?m^N fH;JTE~?7e_ޏiK*~ X4gv]#~Q691tG4I;ٍshz=A旅$'G$`23uNt!3ιkM8<&M֤JzRp^O ~EEI jZ2O*zq1̳sudy;e1дO O[G<[344}O-! |͚"Zk`B7vJH={k9h gt;oK0wFIY ~(p2 Vp Ϡ$jS?bAYGy_#|qM $݌7]*7?yÂ./321ym>87"i=[ =whi)?iiWjt+VjܝY,AWę^whcM9իa2td/۞!V|PMV]-g{NPڛr@I).+шC$;!RpTD6'LKwY6X@Z-6d? p ~T`d .٦⍔~,uXMӯjUlnq5vk>~[bX֋ <%8! k&%1g…ysH5mQy++,lS (<0+d@I8U2 ؒ)02.՛@Tя aKa$y P91gٚ0!g뵒bD;Zl9+;O.9+,i_:Wnb0PFM^x`twLGXyiS!h% އJL7u)-ҼkhJF'5dL9,Mlꬨy}@t_4d(^~ܬ7d?х8;(H6fgZ@G_ $IjD!rIվov8}k`>ݾgՉ]3)<:7lugELAh -C3 )qhtǂ;na]1c}o#1:;Fs!>݉->4CBB9C"l0pSK9{lPuiOY2.uZH]{o6 ]}.!Շ\X?>DR@dGרΝj0` (B#ѕhMYj"$"<: ]‚] yN81{LmyaIv ݡYy=Ҡc@>߈xk/Φ. gK8+D"PQH~}{ǎ&l FT1 [T2.W^ /A4W$ ڨD~V\7V!ϙ'y!ě7&gKe-Bn4FY _;'Ŝ{^TCF׊BZ\af0Ȝǁd'J5ǵd2S6[@n 51i}* BTC\%OR½ZL/)`6SIt;v"U'M$R^/x8J#*(5aqeT/Q 8ooi@]q Z_KC1docTVfͰ@O OQ1vc`BMPȉL hlR1)yɳyF~4z^!ghD˶Lb#]}]g: ށ5o39!jAE7) ;}& XjY9+|lެihtz(rF38IM _ -}c;^>X.ܑ$?T\ZYyYya{?jA_pbx Cj*=P"ʄC1+WsJv6[e}Gj1z?ęjD7M'G+;5ʴI3s&FJ_րR*¹mG:0A7jgZP0T0Nӯ*R,d}B/X1v"}4w 9En"lz?i:5 ]x@6=cPY2jKmtџqx "U#i ,<%ϒF\/|_+#>7QynDžh ŸXf"єO +4:ZgŪפr?!usa, 4/Oud%r} ń^܁I5M`Q+esOg4܈|Q'>$Qwe8|,k慌k>`B>x r0{s&"@:-M%A~'~t c9lF4[K' '#1oxlHa,1|(GiHHU~Z'Y/ |C}0` ƫZ w_uSoVߩ BUB~armJ-9ƴ-;VZlS0 U:.aL ֪ZDJ\ZM|1HCDDMJGo{W|LMHܼ4 pl䂆v[wB.(IeِA}#d4Q脻N$`j1Nǀ Kp;yL`W+c^yV4 w m"yć/Jx׳%C,dg dm+yVA^]iZ[YSc.zb?{)y\LoO[ux; Mg[Ҹ/QJ hDJc>4 MʭKcf;N/hA` TcОJX LwO~h bIa)N3viE ^\7%E6}兴=nSRR4Pדt?tE²4J FX*&)k*qþ?H:q3x}/cTHCZR$|cc(U{pvJw,{v)ONTqʿa?Cj~F}gYR E+/R7ɣtjE]Bnedo_1?n8".v 3ؒY45M3i~wiνf'PL z'bSTWD/M_70_@kJE0Pl(0f$[Apƿ8 an4wceJJT@&!i0ZR[S @2)vZ\b/5>=q6ކbqz$ Kƶu CE? k#O=MVU2̬Q_ -^'2˲Pf*oV!hYc.N4 S#>Dמ+ ZrA-?o@5bT|XW#j/.K#Hd&P{Ɲgya3WRpqŢ9"I/ u̼f$C4G#CZY-&u£AՑ. gM%&vj҇_$rU-Q&Ěs%Պ\!#u9fΑ&9Ձ`F`J*u9ߚ8T&H8h.\ )y-|l!4[ Kiw0ى@)kҷhHE\֚USD0 9uvd$E< %1m8 eUx1iݻd%(]Lr4a'l&WJ!#Wf"x#{HKDiZ(U)I :,4A\Kr c*°w+TVK093s`0g*0PBed tH.y|k9Rw.r3&AT+s)%"n\#FMݸލWTܐP=@"~Z/0?9 *0\«/PQ=!I*I AbxY>''j'je4{<moU3#"Gzwnjc;˴Kt{3I S<`>(Q5Y& (y2ūh mk /=nZ(+d7(})L1 l#|e0b(uah>PN^s~[>SkQ6;R!v!XbQF+4&ɭ2`= {m*-&PV7Z~ ;|Z zm`zbJHKsdRK57%'s?p 7-o,h&Ơb8q>Id4۟ y=:3d!0% 瓶EN7Z;,=\"c$Gpx*{Em"f97fZ Pq*};g|, 口O+NHBPmK)&|i%?.nxNQ 3B."^кsZ{3m3<^zlb Y TX?g]Z0oVeOp ˺rn7–t˱p)%nm`nso%.Ea #DYoou滒cƐ2dsZa3v~"?rZ ;9i~4-u Éaa-*nksEE#пLwO2/D.Vss'53qqɖY&UID1n`z(y曨%bEEЦ3[ViB,͎"Sh{\=CDu kyid Q?8R9Fte˭X]Lg 獟*wG64A \mU`ad>D\]ElS#@aQ|*n#(hgƘ톾K/Gp ]bz25K8Ht5r Չ|z"2zC%Uyӱl.Ui}ʡcNF@R)ΙjƧ1/8(4g̑nڐepsYvf[;CZnؾ)| 3gJXc? ̃NM eU#T0w bL۬9kS&DJvnr:!<‡ &-Ъ"4HxElJ@? ~Ɏ?E|4X|jfsfִxKhryj Afm}m3Ռߖbc7 06õ߮.1aD,GE[`T dҰtmd\EzHw=> A] ;C%x5_mjD 6Ĉ 2K^N.Tw_:* $n x# σ?=/s0OMi)E5!%Wۛ*.pXXd1F?Y5C}w&RvwLv~f!1p\h8:n[S@3Nv"Mvxhky;U~?ʰ|uꭶu})d_rRivr=e"*AݬDF! sE;;<&r2xrlRmEOȃE)bȓ[MA)b@F}"avCy&/09uL7H bҍo .49 ud Ψ27M/-]G7+e^6p<+٬Գb00clTUuFZBNw=%DS$Ag-c:l׊]xl~͂Oo&Ee0yk"8O}"LG+ >pcʿEIW&BԶU:3?W'L$ D?;Q$¢CN}hU `p 52$}# ޛQ6]ago$ ?"@/Y(e>.wPx+!` ' ҦmY c&b|G(S׶̘#auⴑVaD%6  Ejqah#/dւLb|f r k7n0G.R/+$EF?7[ WJT<ŋ$>LSԛ@ZC PgZ>A0V2%,mf #!#l`kf ,6ٸiD= jo:{<F9"E[}4LcrmdN ۖKWL>zz{!Tz= !aH|t7,T#pb LVKmHًDtu^Y?+1q#Q =?#' u]V}YHPy`@+Ɵnщ{pכ0i] Lq)_qVj?QxMQdm}D1W輲dJhl,C[Cb,yI`iVRAM$V[q #iU wxJE AqhꝘ9`?P~(܏d7)QYˏč2#2 .?Y!]Ӈ Xf)`Nu:{& KlFRTlmJ&>`ɋ֙A6WF7џ_G쌦:Il;!y^Ui 41(-PPj~rQ?^a|cxT!g[MgP 0VWrWqˠJM,q?mY?/T[ǽJU2A] S讨,< 2K@ѭ =6U1pFLgUkaYFl;nݞ W+k+dAfu T0f*0jؤ4HusV1>pŻ0GZ e|2\1sLG(B1WEyl * +J τYv3EtMbeU*O691N\P+V1YO1ieKHM?4`ǘY /SX^#go wzzHyp7Wڼ$R75?"3nXQBވ-E yYh`=H D>BؼKL_qhKvu-f-59ezf _ղ &vыuPCփ#)'NzlSTEYgrqbgw݅Rv mjgQ +Ἆ) mmi/2% a}$Pa1fa[<zA]?GVlCnY$O#g`>#75!Chsׂ5Sn?f)PmTMF4V[ @) sc!{XxBeCw=T;I+p I  YX5p`v/L@0Wm"zB.;Wxu)TT{G}c~ 8%)ɓ,KY]k̴q86}i ǁSS)%\?wIFnuzcX.S׮#9>I1p$wWe6[_e̼.$23M}L$SӮ"6b >ɦYw7H᥎|QdNS.r`Jw\Eix !۲ZfA).L3DaPc:)Q km+.ʮ阉&gZb.~3=^Di Zʄ"0tro++S}wc cWlvܻϤV/e‰ A=Kn7+@!!RB'Fm:!CB=lZZƒt0:f @c,90-];~<*& H? UI'OSv Aff`2U*jߨ]Fx(F#'F8 A; 0S3ȱ@'7?s|&TN\RfU mȯ+,,UT []a,Dv棺<ƈ3M(UfC߸Jl IkѨX]Rap|Պ-۠3y;rC\:@W͔lpWNM#M#[_K#+F%i{/&كEUAB>T^yv4eyBO~&Mr:EI[Q-3Y,ؾo /pN nh ?늺T?oj9}!j,Q29k^'vsQ^[Ӌ.dJzoUı>Z l:΀eT=~ny.xL\6 (.y??='A욾. â43S]Cxۙ.{{)ow*}eSG=vkd/Ʈ{ӔD}zԿ(šW{[\q*?Ň4a6+B>SLJizpQ< T9)vr-# $MZH%;zaa%yj?+]4(.&<岯 (~Dq>Hduij|%T+QGvLew[mQ:uy][]@aŰ n i(% .3( -1ZGm.+XP3mKg?zR-z"V|_f\v*Bf69 ;{k覊1v+p',m4ߺ`M f)o0^0A' zU-岙{IӮb(ԅ\mR9Tz({\eޯ>W3XsV~g*[EʈzP}ũNH>*x4̚\2tuRX:\-b5 %׼"Оze}q6g3nEDqIM {yPB=lF2Ƒ_~GICVn8Y[;"zDdoaAq˭$g~`=fZ"HH;4k4cL t8LfYc@G/t;w&ib).gUXJ1!~2Q`^y EZd=뭵cQmj(,W 3w}QpTmLY۟2e-05t,bm+{S(RA9t^1&Ng.`Gcη7Mӽ,j"g46}?ɸx~_CPtNK݌H뱄K]mXn7{2NniУHUc%ry0(?=XR5nN9 _$LxqS횒A-I84K6N[r^X!9Q|赚ʃR3@ ȇT2Va'(+?Lu.r7/(CPԏ=o_[]dOS3>o mA KR#9TPf7]-^TMߙ_*v;u.Z03E MƧ4}ڧ)~>v<ؗF3]AZ*m\6L1]]⮾tT7a"x4劌73b.d7ΏU/͵tؘl 8W'OVDgdнV9@B^C!yt):Vc-®&~d˺IzP\v14(D8`=u2Yi0ѫ2jX#=̄q Aq%yE9@\6餋犅̠Tȫ{_dЌPm bft2-Ma!SKH76 Ĭ-4,TK& 2Z_΋ CDL??M!7;o\o0Ldd Ny f )M8_2[Ȼ짐 34L1o! Pg{GD4L2>Ol1Oр?dTiGk2%SLX7P-hchB=F:bƓCeh8|cPwQD7 WC^޻x@`TQt}ЄKY!;jrKod0R.`4|JK5Oeikm{,;BU, Yl j|i h:xln8O3_Q Uʋv "^>O :7]=]S\5繍נp`,;vy[TZbU'Ӑ,+#1&6;- VTv^4HaQB1jzF˩rD { bM+TO|?AݗpZLJE* G&6t4UnbfjtYOuQ6ٹp';\2ikm(C?7d`T&  Nf9e{>X4xpxt-VHH`Il8  QJf'vc9YdpUE@YGa/,m:W% (5O|rkxb6E1OdЬa(Lǣ4Rʛ<͞s1c;Z$3i[Aޢ 7*΁Mς?k'0:_m"0@ڧM]N(̣Jџ[\7T|:C|n+uFgC"6swW0.ϹrR  q wBd;b­*~+D7*Z/C,'^' +[xaQn;|*S(3 dWVZB+ T2M=g"uت1NXVkƩN/ź\1HYҦB0mAcTzM D|n KH!E_<_"!RTe3xbtݸ V=x.)A6Ow(Û?/<&$ d/Ȯ[Y;oqy`K 1&=`NS {MC~1KF*^!\P^AkA ၴ,7{vRN*WݾVVUœ+ }npj1ts>3|v_6Ft-9V\{R#z7Rs5?@sTUI;7&WPs*E$7syvs0o}<gHmI3G%ʼB t5|;#)*!{ﮛSnSXz < K\~_h*2xdd`2.ل*WGw :" :ϏJBb`?{šuvZqS&\`ӻkfXbK,Xrׁ-RY~Z}-hGd*S4^;7ap|Cۓf.d;dkjkE}`a:ၮ I3PCmeU*Ovj_ ~;u0)cnKr9wxWOx(<~}a րRE贆.{T b1s%OR#J7~0{5m?">O# U|0R#8krw+z qfPR!i6-B!n|)׻zyG)km3 {뼞qra^8h⹿@nKWopUEU'Pj2:vB {U{XfYqs&Uĩf{v(/cMݒt w*MQۻbܶYC4ϔ6@L윰)DئPÔUYcͅmg~ȧxsygBȔ. Q̵<n0j{Y0a?:ƕ'J9 .KTxuOq[tؐYգ'G2aHKl"${yzF_۸]~DdsWOJn+g EA7{yU#, >+'&Յp¹}oUlMhwU}C*svR8>MY6ζpo8g6qx 6feһLmz'\_z1$XB,<`N?⸣1:VO:M;ʼnǼ~=ɗ[<6əoF%Sc>€V砄g/0"lwx> {BwCkԣ>S$Vh0)[r 6)Io;'wz6%` P}V`mֹZuMj򚺺/U%ôFWF=>?e}P3In9ZG s.]1)M\я%>+TEw/gF%cDTL Dj>_SqW!%-thsN`|FĿr{ Tg|U!`5=mQΚko;^D3V'^70<W^GfFVGڑp5Gs$R:1*t%ʐVu.qC|%+E|qLU :d,O[Kof̣=CP,!#FXqxz\<3B/͉3vqRٶ-D@w0TR miBRW0x6/#YX! %yrR/-ִh`T-DB",G6V~{­0ݺŵ^%(,}W;~W*GjY [4Q&MSHB d)m4_>Vgs` ):q|x詮D[L~ ê}A==|kelХߎ/fؼ;hm'D?R.hP/ZJ-+ C1.jad/S͡V)pQ\V&@@c2$ᚠVc\7^غMjd]ڱV(,Ukug# X1f?w}F3N)7J2Q0$ VV7͝C1V'P@KzEE˅8rUBʁ %w _QHw/Y!<_ܡڑ//.)ZxX]}ئ7c 9?'hD/] lV[R\EQ3 ǁ>υ<¾ݤ.a%,nf K1䮏Bu=u*:>$w8.,gؓ2.D^a?ˎx^8&GÝ[~871hHv@"\6A=r|UIp/^k)y8S- Ȝo{$C>]l }i3NYJށ|01b:Ɲ=?{捴8_W>$.leGqlE-]_(+#ĐFC mpa[Y~I2F;8)tKތ9c 4:_ ZfY9:?g\" ^8<7YJf*l|ZyGaS/dZU_4^G3? GҦI-֐:E~<,]ZUnM}I*e2E0fg[MuosS40b (Ѝ,iÈ0-C&ԝ(@ q` FU\jtNMĦrcQ]2 z0S:/߆0UXiB<7(Z=vĎYmP R( V=` GQDv.Kfq=A0?ׅVVO1Τ5E9u5.2tu\3LpM1c+˩:'o4l=.@d5`]ZZc7dmԷ7nbJi,+{ٵLq+~ϫkZYߴ6KN-ʞW~ɆC~ j2Ɉi)E! wԍ CiVȺ?sr_uw$n3L;@VE `r~jIn|w: ` iK{%Jø0E}1:5^{bTUv:C}VRYJlÿ́sJQ OEjz{Zx"lj58PE93vZhi:l=B2ceO2P0%M^nRc!&np]h\Evg uw/F##C[eE$dPVRJ4UD &KTt3˲IRj!u踯 = d?i@bDB'8?*UͰNPvYX8jMb.P܆&wJL), LKϙ݅Py5yQEr׆ijر) CT)nױzY۵754f?lDB7z4)龻BpF<쵻[r Fr j# C75&U |=z4 )NKCM/c<~Q8eZS`[8 BWj`hfK^ďz¡a DLou JPA-UJ`+aEȵKln@3ָ,kH` [Ԡf"AoeytExxFz_G{xQr?/b1lloJwf ihkYiCOG̾˭pn#6Q! Z/~j,ĶB`WwzM>k̰@EdpV崙Xk*Zw6DH0Cw A^ zd$/_9SL]9!ifP(/Ɖ\(ƺbf@qO6TzVXX:ÊPNPm }(ʢQ,aIX^P9 ٢63n$Pwz>#B$nd3*]|rB64ъ(A=i>`DzvWc<,A̩cɰײwOigKp70P}6% ,k_c`ڽwֈxc4mmiH(VPL ^8gmy]J5tr qi$}2ućzZ csϭZ^XԦ;Tat|Ddx/5cA#zw5 #ɮstytsvmLf5}|xűfǹ.\$ 7א: )"uugxpfb(:kN/IXhL5Gf1-z9Y Vs mpCUOlzg{Q9SN8;u|Y/*@όgJ!3v-#c Eʖi:e%X9dm?%#(18xtWm&)ڿSq{Ue{ZF冰Lz`߉mw½"[T>{! /MZ[.$roS5I\dH>'î/c{NUt?%8&!ݼޓrMcܼY(h@:|ߐ's韉ZT-xCޟ)eqozBi.cynu:c1Wn_  ; hûmD,T[:S$;VK2J01Aewt6|MASHHn[eLh~;6LpDO60%'@ <`G/eIg^%NdmF=.Hw,yQ8+q/;4P)ABt„]ڪhhADh][`b-Vϳ^ݏLdԹHP )P k^r{_FQ"nyStĞ_` FhnWAD31S XGQwn#]R5hqTmB(ڑv|Q@9͋D9\:yV[-,K .2ӁaȱUPOU$8|aæ񮔉*/P:!nI0CxY3J!^m(7Q׀ N&= #LX"%qUi MctiR{'NuQ&ŽyV)§xge/nnwMI``r+"l 7nKiJS#Q:Ej,.}ѧ*5HL 2{jMgsirHvaq[y!nnkslLtV6494ZZىFKR+rĥf.e:R|>K^h^>ѫ=9pv#5ԟq=Kg}%HWbb)'*!r W1+Ja]Sa"ȼ!C ~ 7+a p;xݴ#/#]^Ax݇We*J!OG;B @scħs6><| uig%/d܊{1kݡ ( a#K^ҜF%jx(lG+CH#ɑ%7.νw&~w+ )w"Ww:'5cc c'_G&5$E # $q;5=ψ?g;r{eLɹv_r vD,g Kxyq[+T`~EF?8=jq.ofh@wKx 7UI-12-} !CiSъW3Q"_"Z:D#~zܔ:FfO(ՏHI>ǽ0ĭmd42T)` Uv,hSZF``]8MQҟ V,reopl`}ėYs,5L*c6! huW\ ?'N'?LVXRW tQ4n8enϡaf8AcP AY5<0ON6c >]Y8 4Ԡ8B Um,0fP1 aYi;:A_2 ٮFӕXmZ6iR؅p?AO_2ŜLflڀëbI>AE,S̏0)юs'ZDaz肹ygͽ!dr*Z<ݥ !Ջ`qWnZ B5\|l5$9)2\ 6d9J?$i^(:UnPđ;l-L92  =&=aOeDa\6R} N"but4VPI\w'"DV6ԽOaWY*sb"jVP}$dQ3$Qa-EÆf#J9<}T4|e ?gxkN. rqʩKa2K?JЯv*1hS.:^wAܑ"[T¦Xː#dUyȏn9^sA#lk,Q\iRb7^/h36ƴX}6Cci{(0"^ɄfɊ`f"4/!F԰D1#fO;-^yF5k)ūfW;s a%+P#@$yݤ=Qs:jU `B8vݭ U;(U0%1ɀA2D74Rx ZA"#'HA kByeYV 41-TIG -s<q'狼ygWjA9+xZ fW2kHJ砙{\Bb\qHOδS%aݗ[!fD-"93=s(Zy % "Nn$DI}FOi'opGf;~MUDte5&(p_+aY]%v$Z0yވ%>BR2TpeS0j'g2 o\4-sX^MR[D̬yÓs\8gFҔo_u=S}c FfI6wZiXLMz)>Y9K&{NO"sݹۮ уJ0+`p/P<"@u֝7Ǜb[ dۦ-F1חMh/85HWbPc#c&MuM)6 LũC\iH)Hq+֧YcUT1M5>; vh/5i1 b{KE<\c{>zWcQ<}  dp&9Pig=ܭ-EN=ìJS:|!X:pǨ^suڏ^bu}Ѹ1̫6Bv-!2I:Fz?){@)ƋDZ[C7Ues`̣b[z `s6nfr/y9R,&%3=phdyA%uufOG<"[\?5/U ?$ =]?zĉQHh:#+Un!+VcMO| L)[*&i){C CCy$oYqGQ0L2\j$#"m1ј9A bw"`pe!h=par;95O3E<ʟOrQSo  sH}f6Og'JDL>%}DkG}fM?SfD. /"K=bP,%.V;+.8Zoz!']=KDԣR(' }\|^~Z9ut*p\'=<,*{x{ I(#!QfZ -=qxs͡ѡG,? gkĆŷKRGAXok.5|QlV.1ݿAd lΩ#;Ja E&:@شu G0䧖ek]챲;f&t#6B TIAiu)`Ŗ\]*hVYOB\W8<· EĄ8&:^b0u8ָJƀO80MtyuMg}& 8#Ǿ+X+ XIѽHBȀkx x!YJu Ѝލ˚!sFmp>L88%nW Dғ,@XULQbͪ4->)OY1gm?4Ԏd]\[A{ +bd0(m_~EgibK%9Ag@i[RS1hTJYHnx4O]ߚ,mpI_Dc=M˟8Q/&#N5H߿QsT6UWYV<;Sb]UEOL,g(ȋ8 ~)(Hmնp&)e5 jH޹dV%$sciDm@R2Vl˾>ܠ˙"GaƞeZBmIiPc7aΥ7b?Vi ARb$cQr6њi䥑q Θ;0u%x&`[01> p r[YyK?Xj178ߑ泦BߖzLwAL5jf5"mC:!)> 6!FJ'q@M¦Ϙo$Y$) v4#%eq"u08[H\OgeɐRe_}Oxf5M~Llu./)]Ek\h)Vo uOLOɔBTVvJ$'HOÕ:3Qm "m=7+.Q=S08ȓ{w˒幨q}.؞,o;F̾4eN&TՖ!ifv; _pN6@"dre 7->_+hnZz22WJB0_=l5)6j&3]+ m soEHb-R9}2lLt~ssR~RYy"h^io^QXLkȂv|nuNv|s%t"ijU=`3:< Jhn<1Z=8Adt!gbA#_Jpݰ8Eb[ADW ؀Y7MϪY:.1dRnm|YF ILK|׎V_JenJحIԏ/YPg &+&G܏ ><W0>śl?2Dkl1: ? q1&4!c{fDY)G\斅r\GI̚[!9RDX6DFλy~/Qmm"55ڻmU&7Ȋ&a$.OwXvUAOS!A\KR@LgG(xiʽmϋ8{!mݶX_/%´NY {БSB55MКgMO2 UhˀN ?i{Dw^47M"࠱qR: ~+"Z6 |"0&ҙ;L 鳋g Z1 ?y7ʋƅpuO1Q~ЎcZU_Lnw}wNBYVqCgW6GfŢHYԉ9;2Cgq.`%{H9,[fTM@eSt@ڲht9ZMi?'V/7;Ӳ_L^R|P[EỏP*3('w';8mq"aU|D3U~뙂Jl^W#L,'|^n5_,k_'AP@[YOV>c3;s jC֫L ̂'|3]h>wb[Re/RT|T]A;*>-涷s-Q9@W"OXBfH'3qEvGcf!Xtc,s yE:QJ}Z 4ɍ;Qx֗&YnB,W >c~jɊ3hho.ERk$r\n `";bX7 2fSnuu ԂU+jQ_ )Z1뎨yGJ jG~z=ed֞ˡId]ŵm!547^qy+8v]8K]LJ'^Bܢ|Dăr.Ā Shf5kctH2 +,2wCoduab1*}Z zTMhF4Q>kګQn ya] ١{`Q ƅ{]]ѭ1:a6߁ݫksH{9]KB iN[r;_^L%r%ZgU>5omGPqQ/OLC!!MN~:|'2_ljV Jïsgg. agoi+^ԯm#$x!?F/E,I%϶ac/$P*F@5sWZN ")N:>%Ƴ՝02SS9GUIVyWHeeC@7d{h2̆<Ȟ{Ij$7N4Y~hN(;qxY©0KK4׷ @|zJ+Qb#x `Ɇܼ`c_<ҿ}\ƧCyбtԟk;L̘?7}"B|"HBBJC endstream endobj 3 0 obj <> endobj 1 0 obj <> endobj 4 0 obj <> endobj 5 0 obj <>stream x+| endstream endobj 6 0 obj <>stream xe @DSjyl*l҆xĽE,ga jz4ňc A(Z]rn^z-FZߩTv2ڤ?Ζ ؁۞!'33:{CF~2h#(OPћF 'uLCHkz4: endstream endobj 7 0 obj <>stream x+| endstream endobj 8 0 obj <>stream xm @D)\SDBNH^roC,fyQC IB"`nڠf<uy978w 8YB3 wQzܩ4TrtOt=ŏT`1i4 endstream endobj 9 0 obj <>stream x+| endstream endobj 10 0 obj <>stream xeA @W̱.ʚy0x{V?-ѡh8|3C IB"`m]jGʖצ[[{x "$ymTgto_γ[/>yaxRkK!0٘4U endstream endobj 11 0 obj <>stream x+| endstream endobj 12 0 obj <>stream xeA @W̱.- ^OKt(93ߠgAS!ڶV66ܢgmXqk}JSۍse(]F|F {v=CNvbtf d򌠴B7N& }Ʉ%47 endstream endobj 13 0 obj <>stream x+| endstream endobj 14 0 obj <>stream xe @})ܙR%rB7IKP)oP3`H! V4tmc5 V׺Y:.Vܩ4Tvumv_%ˈQ\Ϟ]^ķp7:d<#(U_q83!844 endstream endobj 15 0 obj <>stream x+| endstream endobj 16 0 obj <>stream xeA @W̱.y0x{V?-ѡh8|3C):C>stream x+| endstream endobj 18 0 obj <>stream xe @})$T`#6$P)o3(FHdPvD5֗s`zoĮ՝jEo7)ͮǙ9ٱbq237^\,BEoN)Ҽ P44F endstream endobj 19 0 obj <>stream x+| endstream endobj 20 0 obj <>stream xeA @W̱.j- ^OKt(9̠gAS(8F ImU (Nצ[z8 "$yTigTo_γ[/>z~pR)l< iM/Q4C endstream endobj 21 0 obj <>stream x+| endstream endobj 22 0 obj <>stream xeA @W̱.ʪy0x{V?-ѡh8|3C IB"`mB ci'R2Tsxˁ}Y$tp?zdp<͝*CΊMYO},'Op(:ŦdcZ %4= endstream endobj 23 0 obj <>stream x+| endstream endobj 24 0 obj <>stream xm @})ѻR%rB7IKPpfAE! Em V׺Y:.Vܩ4T\mvٟ,#>+Gq={vCNvbz d򌠴b7n14Tԇk4 endstream endobj 25 0 obj <>stream x+| endstream endobj 26 0 obj <>stream xeO @S̱.Xa%7*\7l~ZCq jz4ňc mk3Mu9ϳ[S&EX-#>#Gq{v=CNvbtf~t2<#(S_4EꙆP4@ endstream endobj 27 0 obj <>stream x+| endstream endobj 28 0 obj <>stream xm1 0+nE:TpJ#t->stream x+| endstream endobj 30 0 obj <>stream xeA @W̱.y0x{V?-ѡh8|3C)ELyu'o8X'w)0 1}4I endstream endobj 31 0 obj <>stream x+| endstream endobj 32 0 obj <>stream xmA @W̱. K nUV?-ѡ0 *zF,)$ &E>h82 T(cMP/ځaL28Nꗣ3P̳t]śZCq*01fe4 endstream endobj 33 0 obj <>/ProcSet[/PDF/Text]>> endobj 39 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 40 0 obj <>stream xڍ:vFw/݆1[שU^=Kyuj'1U5{f6}}deCcyhME<7>ps?qaZ(Z:?nLlNkitz?nRA{ & 4R8UvGSʻ05f]ݮV&ɢ6? \gQ-@<- PfFQqawz,s*qb\" 1KvX>E{|P%aT m 4ra)a|…s nk5/khBfUZcNbO2^} Ԩr )yIa įImDy<0Px {BJÍ1ij.? `QAĠ$$h\sn}<\OE4  `|pxztȽt(&.U&X@ĞY]Bj*Và Teq>4?`_}I B we7XFyXe}_!͂1ͦXRfX@ ܑd/ܼP97?\Y5yV4-Pߥo;[i? r=bʡ.FqvbPڕ= *"v gV,gTn/"+=((UN=Q@bZS~D!6:똑} 7N tcp{*ƑɡQ.G7s}[K/jXUGI V<aNC;呿dx>肪Aeʮ( S߱u܀7,q#T2Hl4\ x7LWZ-$(*O%+.kvI>ClE$/i|t[@׮)dWNwdEjygG]39 WX'+,\ JI~1@>˜b>3l<ve!"FaƍbOCHFItL⬯9#S^{SȉxjeRT%?5pqV`SX:wm3z#za;[d}{q%k+u1'`"q;a{@G~.&<^VΩKʦa1* di|1#JC/#-⊵MӊSjpE&DtKr&83SE'b~~\3d4?{e ҒٸpDPl%C#<4y%ŅđD-7IbW`x]&G hvE+'x¨:U>T›ɂ)X2vǭƎt fQՙKc8A0f| {MsboafukUFY?O8S$cjA֘aSnې+a7`#G s>#\bRсs:F-b ,r>)X89uaΉfο}%8o3)XAϜG 89`D&%sH/['->޴Fڒ-Bw :LE*UxjUdP"oR䚐MN@WƘ8ˌa`K莅gJK*;!y3MWۥM,$;n%$Ғ* @L |-,^}ͰVvF:*(4Pem𳤄o%S's:vLFkEoi'3tl1.jӌ]<17 YlOEƮ|'XH6bg nX=+P)sZD"\Bq@ ŹFְ0"(Rs)O:\[^:oBe@c.E=tmB]ws@ M퇦/YIkޗ>/d^ %V6>~TJ3M_Íٽ˲8/ffוQ{?g?.v(7~vϒ.R#_WN endstream endobj 34 0 obj <> endobj 35 0 obj <> endobj 36 0 obj <> endobj 37 0 obj <> endobj 38 0 obj <> endobj 41 0 obj <> endobj 59 0 obj <>/Font<>>>/Length 1096/Filter/FlateDecode>>stream xWKo9 ϯm3qlv@=8$vkg;i$H]ɏDQ`r\}pFzT6U;~4d>95DQ8Μ5AsV8kgX0&5hk gۨMmuc!HmgU0FF-YRz2_t#ɘѠq"oyr_W>\#" L͚kX]^:+J饦k,+KM6%P $:[pPb룘yJ(уn>&D\N)#] IqC魂*5 _}~T8$|8E #$'|H1h_߾ia`[CsYhg6OikhƂR BRIޏ(wVtJR(nFYSNCYSqWKL׿uع/>:tJC:u1\]slw <8<γur竤@Qp:!ƙ3@l%ǜ !o߶q= M8{n7۾=<<;Zف H sqtًN{&[ID3W=Ͽ*ÓJXŖZ߯nq++*SsCqʪ~93ҪTY&eug_f~tpJ endstream endobj 64 0 obj <>/XObject<>/ProcSet[/PDF/Text]>> endobj 54 0 obj <>/XObject<>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 66 0 obj <>stream xڭ%7"! kmןrHQKU0wv~zW~8YLgW73-gZDarGpR?ug8uQի{(<nJnfUrwoa6g" >W˲Y?\0O^qU=ND|9MɩWMm55?lU}MUoFWu_uZў(V_U}m.諦Fx,ؔMӮzQrRxԦl[gAy&Xmil7XvS`ss{ <#N,IW Uw \q; |\)V]åYvp_T+3csO?Sh\o*J/%?" ltVצ9EW-pW`4b/YsǢlD@*KQEk-:r;BɡZG:B @oew 쌠AW%UEUob- I _8tmڲXr϶+aq2R}F 8X4K*;4E-e[!=tffZ}8N xd t)B>! G#=w)6[5ɝe|d6B`\SdX/d(AQ]E{͋f9,@l3/|a*s2<fhjOj;* `uS􋻲ʗjqg%? 3,Vۥof %)"푲o8X^/Ra-dz4 0GFN "ZD@Q۪'2f#Q9 ٰGj\F7enAF1, /e[bY3ɎJ3,uC,2@TtB:*, ׂ%Ff|`F @Pw CEQ3j%bM3hD6v g LgYtX?ϳ02NH]Ûjv;奢YWP尸V4G;?C-:0 c*p<=rA,m86 c %eVat@YB$Uzl?\QMf8dE|4&&VQQOxU [cH \`:rK.rs4,5H3#q/Ԝ` !.6p*ؤa@tG:h(H?,?D*vY|yE4jvh*<{ɐ#m2L?O(k3xC6}쿔Pp6:x, aDs38e,DLNNb۲F39{wўCsRhw\4_p϶$Ad0J8yfG>G/~v7Q(1HA\BÆ26V D= n|;W34~wH+Ԩ(pGu:q"ø! 4G>n:2FbXLD:g:aY fk`K0AB; ZAsm({-01q!H'g5RkWM[`|7Dq- K{.1@tTTam4ٶq_i{w4 ^PհڲVRccsw0fkl'9n쵐C4t2mv* s_4ETgR˽W Je :٤b$psid0žQQi`iRavs;1ÈͬI`)BEIE4 m9G+hĀ{& 5'y9{D)X&CaX|2'' G"u<ڋmXCT;Dq'cEqsuo(jW0ȱow3J2 M^A"c|03d̯ 8!t͹yI,1vn`5\ՠqhd>0JƷD 6OGֻYlHlcfBzlBпQ!8Q%sN}gxnx753u@Ǡ+|8(]WdhdG$W9IjL,>}$VDCCcy1o@*D{cP`nףB/^lj†( ܁h5ӱT7  R^퇮]&; pUt.ȢȆ0$ve1 0v^ N}yEݦ-M| Q)EHbiq_p_lm 偰]m.m(k  6)k&fa|e>*n]0q-xM"Y/Dzw-ZJسMN4L+L: :4WB\4x`Y4覥` w|ӗO`$Cm4]C ǀY?vd<|BUe3&ҮFy>:YDinse"=,Pb쏿`0qgRh]>qϒHM#8Bnљ1ʤSh(~XPәgi.J&Ct+6ruUpay$D CLV߂'飡{<( Yhff4hIs=_?n qrro&zLߣ~(=sZfY >P_wp R["(wt*8}2H ŗE_&ĭx7/a蝏(01?bpL&i ?q~h!#Ջ8&K}`\B @(cH\ (IsgPRA@&vYgqFR_H> %a;0/r)Z`م#~|"O>y+zily{,1 xv9 ǟB!mS5AK^,3͸I@37~Vǘ L(}@pțpiV8ɎFX5imaXw-YQ;ҷF(9Y3|p V' ${yD>ZiTAAPH}7جs䫉6('£L] rQ6>~4&;Go1P-P.A%ƍmer:m?y?AWIyy(;.)>!G|`$;eQF 9Ȉ@y/kuO^ڃyw)V/ O!'912,kj[K?U1HѠ`鈎P*<yNOݎv\i$@DB.o?c@c'`|S-Fw* Ka zUwO.ӝ6~w,]XI$d1@xq~x<vi"1B}q*Ld7z8A7=&jE`~(Q[y\^9&Q}_<Μ21uDΦv]w;{ݾKM0JbW+ uˌ1v1t@<‘rq@<$̐$O|c;Cy }cx>0ƿ| Sq> 0g8ǽ$=u2ܘX@g G rX&PkA3a{g"F4Ԡp ۿ e&E':e`fJ)69^|~??yJ.oYqB$8qU5-"|+7!IޏarTNN_wtӱj9 Kgz?` LcSP05P4fRnG0>p!c}l#N3]0O$"&zRDs8d$%tcIǢユ?LMf)h|1c~x8X8w1"lmlnfԖ]ڬiҧ#w&nXkƤF={Ljd,E0V+Gw?WKp*tdzrj:7Љ4e^U-r]}΃n5M.j_cI+f&w| D=$P3Nc4tC8|ƌ_jͣzu$⹋Ҳlu|q~("^"QC:T Rs>fϵf `.]X췀Q;FNjs`aBMu"t*T]+,$^ݕh&ݔ}Ia1_mf|?"L#6LRL1{ZK ;ٮJC'KyF7`/c?y"*cx IrzPmMJ1jHGq͹0 ÷TX҂2,]s^X2]F@_nL AK ?3'fjw&%ouWÛZRnО xvJa>~K);;fah{M_||ld0^## 8"@)䓻&[.{}L@Tug0JϘ&y|^ܱ<:ZxKjnۢޮ`؁:VKW]"]oxk%R {y#LHz_m(P"9GoXLxm;lx! $q@e5mA*Uᩤsa@Mleqi.<-Xښ)7ANq92dA-'Jq2 YQؘ)4CUMlKf.'O7B endstream endobj 65 0 obj <> endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <>stream x}WyTS׺?1pV(y؄j:lNjq" (!s S28V^kK]۷am;뮻zk$$g~P (PPS>8K 00/p͵DA\p~y(> ή⨒Қ|qˉqɿ[vݿlٴykDv?W"vT"V_rJJsDٕO78PWYUW(%*)SB\Y]sxC'oA*:D5TH%Q;:*JvS{&jz^SۨT/,š^dBP9} NU fр6 ܀Qsᖅ8zoYܳx6h[A̒g`s\.Eg.a8gVMhZ%K%8W]V^ږR[RQ.%+Ð3pŻgKqN5Z`򽮖3^.zWHr*YZ#nfU.B\~ȼH4z!7d|)h2;N4!1CZ 5}̖>Nw +_('+ ^i60oVUk$r1z]ڦd.K8PQm=t#^8'Z(8 QJET0A0~Rbk]M2:ĕ;zɮ8mrnɾ3U,QeT?ΔTvc =vY>YQ|B2 ߔ*"YȫB6/ 4:Vsg:e_-5*jWpgL jZ[k!-ҘVqZqQcߤ U@E%){󇞈29,&6'jwn. qIG{' nArq [!ЛuCۊ DRuV"i4z!Lo8zPYY&D\yGB<3{ i,_4S}a)آA*)"U1OdL] c:$V) gwQx7=Kr 5 IK*l׺]GN93t94/ r!̤5כwYgjͨ Zx&NmR7̈́u\9GT׻ƅ8)]w#bݧ<`fd {El/;SY(@,[17GNM&Y۫GϢS-%k*֩TҺ*KΎ -xc|/O/d2ލT* )dy5 g}Q %Ω2><޶ӧk;.A|P֋ :F*Fc߈psAOy2?|:sot,yia%_T(MF !8\%oEp˚SIÓ[ԹEAML<݉f,%~Yje mcOnҺ\XҳtIuRj4X5}mHd"yyD[E`DR^8X>vg ^uEȶu^.yeVM=yqn\쑯U6U6ڥTG=R󲅩%n. ]}ןzo}Ǹ-4OiТBcmK56llBkd:!HHVgb!Ya445Sd Wi2 _gpř/.8IS,b0[v^h { I{}GN%Tt&pvn 8sS'|xwD%[Uqby\v'J޻rp:ǿe= /g/'˜Oֲ)@5#*V'זK$te L0=$y߬bgq0d}naV]V֢9E{{/Ҍ2aYF] y+ ߩQ~DNtOp0`#{_q"#;9qaC߳ J6d/ D^ gy?L^VD#lwsӼ14!9Wt9ݻ@hձ#2Oz'O"cG&.j߆9fVG27/Ѯ>8}926tUy]_/Mь5Ο`VWW[uN=-89फ़=Bkq:|֐m|ev-7< dcBUnhG+]}00W*:+:;ŝ"V*|xB>?/ ]ijꩢCjiI-fzƕ\2,wOɱ+UzT thLw C#u~?JM W\GW pŲ[7x8_rmKMWl/=1GYgn7kZZ@""7i.Ia9&G`l@JT[T(/8L9*Q!Ft|0$56V?-qp:ΝK{G]mz .ȊKӣv(t[}=`p|ic]'q$(9t']R,Rv1fp2?p9ljNcX^,ˀ!Q-a~YJc Y}熑™N#5Yjd!vHEvJۂ an3g:Mz$lx?ܶMeNdjvl=]c'!8ޙ4x )lcIn<Ҳ7AUF| 7ގM-;(VЛ2Pr[4ϞR$y@ΞZi,]H>^HM|CӃUIfs XOdA_N .zh׋{, Y=j8PI endstream endobj 73 0 obj <>stream xeR]LSg>e|ߴ%M$f&H76 ]QdU TN[)?вwzZʿH7:݈L3f[̖xt;lYv}'y_RP4Mo4[L\6f}GJK m%j3!>&>.L)iOb[nwh߫:rlgA&ޫ=4q:v\X[du-9hՖ>M5f2UUN*]T SPvAeQv]B* 1u,05U1[qRuA ?1Ϫ}Xnh<$zy#$ `kAw>B3&1i#^uzd9Hځ8\VˢB[7ӽQ_{fițDp691wzykD_u3˟c;9ihzsS_5 :]nGޠ+ƚC{J.zi̻c#XN^~ޢi$ٱHEЅ)J$ܺ=bBn10=!΍w&4>2Q1(3AQg\`=>zI= E2ÁǾp␫DzL[  3mWVvyt$k q%/:^ԙ>/Font<>>>/Length 2744/Filter/FlateDecode>>stream xZKsWɕqrJ$]9|PQkJ H9)|=]`eGK|hs|P{^\~P#!w7 1GƏ2qJH[VZ[\1 )`Ka,3Rb9 A'$N> o*v`͙%[BzAES3z_a^lX\&$)V0p\nKgmNyrz᱒B1'L1"K QۘtDI*hR*Tmڐւ(ʈ +<"/>("`PDR9Ʃʱ^`QkY’ c|:G/K*o<$Q6ZW"Q>h[!ST^82k'4Ȁ*i%[$bAT,Y,`J3?%u^O_s9{ԇaG C*3=rpT=qE!я8YYrd(a*Z"SO'M&jRUA*APTTM"Su?!_9$nӒ]O5aMa1Q&i"< bm|"fmEHp U BL1ZۋY"T? 7.\r6u!󙘾Bl@x&rWmuαI א:BmܫpSet[`ѣƞ?g󁆹 EtD JTM/ )D=QA:"*P#b'V phzLLJNo. UbSU^-=jT̫`ЎWAx5*B՜Tj mTE*5Vy|Ty]8y3{tŘΌsz2125$|S!Aٜlʓ졬(Z?w"dNؖH'w\E_K˪{\L]=1Ū"ԑ3zRX [1Hm^\z x b6e`^^ƥ.̊u+kv,xL/Cv-,c2Fx >tp ,h4=Ie{<`񽡐(a;ܡ/.-(q-٥2DqcNt_cz&݇oSI{Fj wK Ew}. 6|{VL3㻏{" lKμ5=;7~xy?>$8'%˗k+%#(//Y6Jǎh}=M8ڻ@6C#QˬϽqzSq>`G"Ga|LOA҈mh;YGu7!z93&fw,ϱ~}]17uR#uX٤ono;%*w}{߾;t=f?X)x~0g>ݗ~|]´ U_de}u9̠\@wߦ/ۯQK|if%>FE6ȇ(>O-%D->/XObject<>/ProcSet[/PDF/Text]>> endobj 55 0 obj <>/XObject<>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 81 0 obj <>stream x[IsFW0bS`A KIfݶEl@B؜_?oKlLR#RHd&r}⫿L~GyT_*b^~ޕMU]]]JwK5=M=$=ĥXqo*U}[5׿,eT;sw^kKC5 uKr7R~Υ$laF2Tuu{w6ޠv1L6^ ?2np(S'=ǎյr#=EY_:qWb`ri4Xі(IDNvo#D5Sm`NEv~D`>YqrO^(,3Įh$`JǺ |PIMgjW buڇ:K*znBxfr+sw%]ӕvg+1Y+?q~CoȨCtUv00]uۢ<_Zy~/9#2櫲RT<|<0C e;rR9%Nx`/:+Ǭv+>Xi䙵vAɍtW2W` D''u(,IȃdUkHM @8e&=BPEYM] /#ZC-/ˮ>DQZEdm*}e~:@/оRN#IEI]ݎ$[I$r"=XLQW^tƣJAmxq!LtebtbSfIciC`8 VpJ(NgX%<Q9ʣ)*GHB+'/]HgӉ8T>ܯ5^XgPݥԝv6%ur^.a5*}ցEAv]ZMB{ӇXac<Є**#\,.hcWRA"/90f[O`C瀣259%<ă$*#tpD,Kx0kmMXR ^) sf-9MLXѬ1 U.-&DvU~X `v+sB%*;2*N+;ƮL+u> -w= Ӎq/..:qVٟ u ~ʾ>E4X5a㙖玗PŠ0A E?rMxȎygRLwc1>Jiji$-BF(.J5,|l:x@Wrg`dru! *Tz ȥrr_5]?H-687ЖqF)ޟl b'ҸQ@Lg87/Y Y*L}nW>1U*TSDXӖ[ O*p1\XMb.f`%ǞZ tH17z| XK}M*,;"\Pýш y[M$pZPɷ|xUuՠGxl𢙠F=w/- ,Mm|!{sjIj5b,xx/P5Tzm3fo55z9l(Ґ3Zb)˽i~܋waAP,P ٰ# OL;GR̸o܈t* NkGf&ɃqK3/Ue`׃2oQ'45rG !Lb!"l4,LZC_">fκ p^Xu?:i3ZN| _ra`פ Sv48g 6=\zS؁70 Bz\c}xas7bxhp }-]5>VX*I QPǛŷQ&`qQLW=bgyQ&T~Wt <~ *Sq˭c҆\W/:p6[58uZaj EP@KswBXQ*ن͝1x߂*-( {^a !-,8U#K^+~ajjM< dؿ=Je`hI أ>-e)/Qn̈́6Ю%53B֗GІSs$QMҤ{LM&`y[7o.l6oySw.$3{u5bxc)Tg4$B,AυxAmOAy2؍h}b8. yU%N Cj$K/_ .Y{#s2B,|n|\[tq }ԳQǘ<)'7åv-f` ,f`S̓<09@:JfxIpg3ҽ0qg|Vxx=|Ei1Wh}y\qdl3Ղq{WaJX.`eB GbJ+Fo{Rr`АU|ÎwJQZ~J6a:Ox7o.k dPl7ҁj,i TZCv`t<2SyCi" YdJ Pl$Z^#U,o*Wv80OPc>y| XD$,HA[,j6?F8ݪu"g*{ '(1 6&2\lKl"ab]EYlmR2}-hpN]/l}Oy;B}JBI.f ֨U d0i~q B_|c=%J܄)& Ùc["SQ?•-A{0alŵLRۤs)`Mt"> endobj 76 0 obj <> endobj 77 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> endobj 82 0 obj <> endobj 83 0 obj <> endobj 84 0 obj <> endobj 85 0 obj <>stream xuWyTS׺?1sTL(Mx8:80 `&B 0(" (uXmުKk}>]wVI} < cAa@a`(s=AϛBC7x/&^7ރA3 &h[f nǐ9$K䧸RvQ7гg~oV]Fx芘uQa&2ȲHz%$a G?9a;ǧj8ot-_JlTb.`r:f-] 0} ܫMRYd~E-y]p+ss$GQQ&df({8mx@4lPRh @ 幕Ǫ EEh Fp> )Hf^f< ooߧ <ժd~7 1„"U O(F)^.69\!v̖^~ 71-LE cn7) QԄ1҃z ܖ꾇v"북u`죴ԨQ՞㻵ࢿf`-f{slRTDdbvK3S2y ĢZy$&((#{k+G B4G&ntVF;%V8vrLph@WU5ek[~\jWTdxq3*!ר O(P`-ɦ!3Ο7O揑5M꟝j;u %GBbLԝo ]treQ c##D߉%v1͉LMw  } a UKEMXaT*djAeRf)0T4ƂhAkw20C/8A9L_ |:+ɯ"/z$0E|l{KOWXUjn;㼾ښDSSɒsbӥ 7sʐ}S^Ցf0\YWY"K"]wZ'6i j, rՊ:-&ҙ0 'Jt""Gs1yGPtk'zV?BdD9h|ZU:zϓǧn&+uL$%$0y'ڄ7]7|]R[nPNeҙJLS ҋ/>%[?I^~DQH|V & ʁ؅Q}iWz:v5&\0}%I0"V1B;ɸh<38ߓ?uFPm:.VO:-kT\F58 z])Nuwz̎' qp' 'kkQ$Nv \UIts6WV=M O;?_RsmYk j"U2 -?uhryi.PnEwƴ. }E~1!9'mĹh)5"gߑӤ}(G@BҲ™p݋ぁ#/İΠ0v_Tck1pP?ݽMdVhD(RۉԨC9KD +j:eeᦤ+)ǏOzxךZk[;lg9Lh=)Tj 2ϝ*mU#WHl7{(D ,u&ތgq B<~v~j=Y8 #\}.CUZMzKS',-PEr^ r|=7N(J<58(s(gdv_NY' davN]Ɣ+K[Ȃݰ\;  ,X̖Z/$2OSUVa+.u>n_Ùctт?u 7{˒O`jLm0I:YPb.-/5y } (XBv&*"wSV9(K SЃlqF> bj,ʝdؤA[nZ);\  2/41bGN1-<M]{ 3E]SrZFHqzsw >(x4|VgQIvG_&7$M%I'ǟEawr 2sLxRnH$/㦰%>jf3P\v Ӽxj'V6n[lz[EKo6J`R*ۻf[Smfhnץ*e{dCS]Wzpb?C۹𜺟0v4-(:)0[1̭jՂԄ>Ff:j:`oX80[Dy;M&SdY,Uf  [ endstream endobj 86 0 obj <>stream xeTiP[}BۢQ,ՎҴ$&񸩱.b1HbI.}z-# $a}!ıcq?$G_Nt~sΜs>q8rU;KU 2~/>Ã,.dY˲{H}i u:ɚ/W׭{#ySmkb6JӬ7ԵzTii^씔V 24ͭZ~äX1Varۅ`X!Ųұ0W$MppN==k@=h}Y SZ)(+Z@H :G^C`*hlǎ"fğUamsDCNh;xN߱Ay|.|rfOX ]N|l.ڠ[?$00b5IOrF>Gsgtd݋3 !^GcWo:Jlw Ύ֕7TTZx[9u;䩫g4|&qsok~^>D%`yI[0Y,j/aBhFwG#0e~6.TOo^%1(@>. 4ԱH8>OE K :7A/mM^Czݽacؕb,>81ё4fM YSSSd9졶Zޭ]"cF*H6Xv5-;ۣ59(>;®`ts2}W.49%vu$! 8Du.<$/:FթwQwGo:y+YO4# cl>lI/EdItpG"O[5=ñ`oà;"*'፹{'U]%Ӧq%#_B/̸6 pK'ձbgɓ{uDTTgиusnM{,~Qpwr`o9`%w30&] n>izwo-}; FlP?@1!KߧrVEa͖ $?%9Y0U9E{4>=TE:D}}^O `wv˙ ` ;vL1 ?T ǧ =bZ|q_8X}(Ư|1!c¯hW!nֱ hs6@\VĆT1u9FE6x$:ˬf60.ݿpb &4pYءPIy~)>stream xcd`ab`dd M- MU~H3a!3k7s7ˆrB{w``fdtu/,L(Q A($Ud\R3ԀԜԼܤb ~ > A9E2 ! ,,减}=gľ0~zeIg2kjmʰCe~\:$yWUh;adL{7[O#be݌+?&dѹjoFlX`kmǺmwsrehrv>jg=n&F{K' 'M|6( endstream endobj 88 0 obj <>/ProcSet[/PDF/Text]>> endobj 56 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 91 0 obj <>stream xڥ[IȑWgsB.@#y4=Vyx6Vk~ĖXXYu!\c""vϯy;S슸t{89ĉqc4}<|z껩={2USǻ=|}SNE ÿ JEP^gE4vw:_K$Cy5Ϫ-MG pzC$i˱M1/hMCsѵ0e_!W粨<Ԕcu䂺'/k$_sQJsQ^KDUb% x<5p憛9* SIT~ߊK+?ǎ$˱/Lܥp YuSmo)),1e'7,{o:uE K{8]MA'Ǖ}6CDx7s8iA/LсOc+XA kI͏B5,ud0 ԗǩl@dçFi黺V% YGM}qHS/H*mKj8t;cV-:쫡9R W| گJNhZ{hЂD!c / 7lë_^)(Mvj"ֶإEgy;\^}9M>SNE5UV2kSW6^ު L,ײ//H*VS*TzBW rDb (:dj4O՝Nte nj"#+Bƚ]+e0"1c]VοPX?.ݝJ_'c N<~'Y~.GNJc5_ 痦j/@D۵HF k<׳_+|C\$gL|j{HxUde[Œ^uхr㕾V{:`s `a!vr:ܾ48/h&cckFl\?eY'fgs'y}]+r6ùkB)()UԓKRgڮ6'N@7f*9IT%'Z( 4T22??_F]^M6OQ 콅y4/D[y.]\O>"ÒGߑp(4- 1nHH!Kg_ÉX: fF勺 "{nV8;Ts=; \X.RdT?T]4O $_)&ʆ=0x*2Xp,u2e@]o7YF2ͽd,T7)*+:R),g^4RtЯKa-N>0ڳ42mۊ HṰ ±J&J'45eu{ٟ`L@/Ý#Ҋe Ckv\WW,w@"bzi>Af?\\AY pZ NW$d*S=rsoP9&C__G&NΣ'$3p~d 6.WT)1 0plG >ʁ;8ukqU=\N_8FvF`#4,S/H0qV HIHrƍ񡼛jX%Ki,dz3QΐW1^ˬgMJgk\-o3$~e)r[Hl51u+p̣AY^WJ@|a {JtB`TROGq1gcxg@0U!F-h,R{BG*@ɜ*Ar`ͮ$g^y)ԁfA\V(1*4?x\_%h#p ;3Ch1iL:2ob `lO[MH +Y,\Ip=^㔗6#8{oq |JıIQ b{k$`5IYc-Hj8ġ:2;PNlBP_s, ؕёaۯwuX ȺETNcw) AOs;pf$pW^dJaӍK*ۗ r\) dMā4=!)b"6LAB߀\>I(SA/]L(>:)DLze+>vpW*qжX0؊#424nҒʙVzd!`>G`Gk}AV9g4e.ǰH!3ސ`QS?%IF 2zr B%xR6kx'/{mZº`]y|"ܵ, &o"/eYTqƱQSc8.sЁ8f+$0&1or.yHc-h3I!F/a}nyҷي4VjPMԼD?3 ~?C]D@T'ZZ*7ET=@X/yq%8&#y | )wDPV(CC_ fhRa9GmNioqI?dOރ t!ZtvN].WMP"i#)8tJ' B'l0Ԋu~PEEkwٞ Ƞ5ݮ-Hjg`/8Dԡ:r)bG t>$MG8Ik|"NJ :tTUO·H(Ҽߨ*cN5ST,YhHA,R@| q2qv^]or)ֿw{ds2;N'BJ]7NbbK,k;+AHX3KyŌcn- O PZB`pe/l/4}O_V]6եK[AS9U= 8Y}Y!<6gl`׀9k:Xz|s(x1 endstream endobj 89 0 obj <> endobj 90 0 obj <> endobj 96 0 obj <>/ProcSet[/PDF/Text]>> endobj 57 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 99 0 obj <>stream xڭ[K䶑WmS|{o)O+|t`Y]TWe>4j/3GZGlD /31CW~oԦOLJ>d& ({x~=ǽ-ݵOjdW/6NzkJktڪoM"?=kߗ hY{c"Id,(`&i(>_Y6f 4{9Hs'(X^<̋D76hhCiQ4{6euEIf[O=&Nݙ!&a,=A>dO)ܷ 9 ĺthޚ$b{S}xÍ]sį)#EjpfQ$wo~fIñ )6OW|XGikyhڮԷ)S95}]$4rl:'ݍ>g}zՇftv;q*˺}<۵H\,ǥz;:P0kb`^K3q= }|ևrI tNA~_/۱ff73+]N"֐"O'H"'Χ;ȰDGvx= ̃Igzl>VldH!,V%A$QjFKlY,g1gn2bBb^H=JLX Y;~:m {\VLZt{*ܴ&SD}ŝGڇFlh$|fc*:&ma6Z; Sj$@'vj b/^wI?7mf=J|b{{5FkE2&j96Yj%i{ @AHNM)k9 !2@hΐ3=u99`h̴Z^9+#g*p±u-D'zP 9?忟;,Kt[ D1J]s_G᮪gVM@*(<2d(|G.mQ.: 0hV}wu/w[w>dnA7 1N`GjZ.:aP {df!߭63wJmUa/i!MV!]%5y/!hwsxoX_`Xxlw[AZD6'^ܨn h|Krr\̝d~8ud>ܼ̌4dWalaEb9H 3 ~GV1RXj逕ʪƗk/V\!Y8 F^:~phQB~h:BK Ð=l4) h{z]_\hC6!iQoIZM wqI:bbׇfFtkj8"l!E>{lpCH9B AȢ9+vZv)Fz2[oY&La(d!+ngbWjkhZ8c!¥?JR bS9 MYL@57ɕ= ˗Zg'CŸ}sir72KʪyJ+F2]n%\1c^Ҹ"SefAd쐶R.O=(#Ypь'mm4( L6i0CJ.129$i!"Vc&3^b s_L9U[}&K6i˖\f)&ςn nӘĉڇN{A'j"T!ƨg-X-R⮑T5bIԧ / hi)D2Rm7͊sV9HivEq!̀Zkfp✍~tv^c̞S4yd_9nbUĂ{368 "6-}X :>jhWcҗY&)t6]{Al/[ 0[A|D$WX}]olzx!ژP:Xj3Zģ4sMplӍ9;34P#" c7jj0f7aǥOH qN߸l~W]Da#/+jlnCo$)ڶchr~W%RE&(rhb$)[;f:EPb%:$dv7*H"R\ RR~t0̭+X$=4c# NF1Im  0/uDRޣVIV0m]L,t8ɥY۸K0ECjN oZĥWxb,dGxrLeu u$([F{NL7#=˃ӕJ,Q_Ak‹V1W/M`(_IrM&&,n*5ٲE5"ӥ?O1Jz3F>>'?q#mĄeq$y9!2< P''<(ꓥZ̲ݚ7ճl 1uӸwDR>zH:ot õgb9B$Z?~Psih9 tOϵjh\kUPyF?ǜ97f|88ԝ3 yVa|G)ծ4t>> VkGÌX9`P9yy f0cVa+ggm:DǾHTٯnR'dxfHޟWJp>[[##+b0[Q{7rz6/ѣ̅#>Lys8Z8"u& RNR]&23 D0)d jx; U+{F <  Z% ,.u9L=}U(u$*RW^L^H =et & |/@`;Y㯯 ?wӸf %,2JF$C5q0 /,) B;WYI^l}(S\PxpJ|/lDpY~ReèQ~ @"2!Rdh*EΌñjvs zI ȵI>T~f3'#Ĩ: +*8% NEHB2yop~@_ch~? 3 Hyb4Zߤ7ib2F-ktpm3wM;p*|6T_FRӄ;f&IvKXkJzA< gx!q)aQ#]dp!jCw]3p3ĉׯB!8̎3h[z,)6Uu#Q1TR1@T$uٷ:Rђ֥t*B\$,ty\+**2, h\V N8%zF"KT^_ ~6H\DA.. QR$=0)83,eZ.MDjkkuRMos2 ]zÅA_qn1ǃ3܊cXWeF Fx{ R+pĎ%qʋwF~N-b܆GvLn Dnp*wn 0|SWoRT͔)_4v+e6ȭ Z~UhRq.omR1W,ksXn"%ܓ=ya`hx$*~į rCgNSisRT{Ds=u^\ &SrUwS\^f$tmqu Gz& *:M:N~/ψpN|,+[w%[ួ7>r=eIFmslCuvB&lMn+E$9;Mdi~A\I1@L֍s %ޜ^&BDAbR_nKN$%o d)!UKSyԁ;ރ(FI'duBIWb$Y><2f3/ ejwZ({Kks.pWL[Y#ބ\uHzf]n,KJǮ1W٘`Ş endstream endobj 97 0 obj <> endobj 98 0 obj <> endobj 104 0 obj <>/ProcSet[/PDF/Text]>> endobj 58 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 107 0 obj <>stream xڭ;ۖ۸ Yvbq 8n;dֳn${<~(t73T_WAv/"Xq)ԽJnm|6{& Unia#,͠UmnooPQhdc[78ٰc!~'#:w>ੳ-=45SmN7[!yGq[nNU_n{wfoaI Z2vK:UYW"PvI^0m^.34G}]]DI$&ތ$$i*\H4(ܛTa&Fz~h`^"ؽ%Ym, sle$-2/^Gq\*ͯX/̻֒̓<&LrFqxBJ_4m-&Jaee~JP?@:'|\+=b `N}C,ɭ"ywrl"3@RooWFMKq#:# \JomadHy{xdsˠvC~0R"&jmNw y2@Q=\AI}AuDp,[قd =7T|kP628EpSa wA>j ʺuĤЁiT^uoM?j K*x,hC`ok÷oyTW~Kj7偓QV۪W-]W@m H*UH|HhQ@@6{cgOvk&Y61vw%OFM,t}T8jnFH4n{noHQ֘:z?:((c 6 z,I[BߡF=]@cUF:}f;Zq)2R"7>J%HQ E4eys*_FJE܂J l%u[diz;w +?(9 /M%e ƈV~$,=bQ6vD{q - KhV1VLN۷0 TvdHjH؄<' xR/d$ׅ6aGɝk֘Tӕ2;%ٗ˭LOh&F\5A0[Wm :>[.#Ws?u&$#K&e s@0lX`/YZƐD$)iuSjgUK$>ߕ6h rZRc$ R g%y5 { 2'ڈf@3sm*4k9BM-r$on^u[j=9FO{7]c?s^ud7y"zFt>uwX/W% nmx$J>~;^':o2t H5c^݁tN!BE2Xӡ*goc|wWM9NGw&1~rѢ}͑J`) G#>GKHqϢTqUO58o~<>[/9?0]YC x:~d`'V-aʂP[W,UK8nf jXu27/(@"BxӑXh Y3l4&KrH3:D2 c<4'C[G^tk] ڙ@>C @ohVU1L!_Qi8 أBѫ[C %>!>bK%\>8'n(4QԕNB %9u/!9?+!`''ܕwd3u_a9_9=GVa9E ҮD0IJ7v4XrEl\@C޳}a%#FйYDx1PaLfA%֥fmL!,Re) |s5IfiS g6;ztSo{ox;}ʺۡYbƅHǐc?-Q-TM󠋺~d,\2T[z4HU`3z{2qgbb-w7` "ضoEPE*DQ&QmMX5\(Y6_6Fb)wl`}$ [ޮ@\R$<3+4DFubZ;_ o,kiex%v kOH[9?-Ɇq}T܁z;çe@"I`7ӑc,Q&yTݸF -9-`2dD$*RN_cZrEp`K$Ga$&z 955D9 0x5)ѣ@ja?4ccXE_fDxgC8\ J eHATqYN`c8zc2a[^8i&bEV6WYWC3XY,S`Rb`eyx0v̝hk$ Y{>Ն vEUvߤ̻SQ! $J%$o/ݷ-n9Դ3쀗F(6(-V%0ϋ_n;s>|瞳tT* Y1?(c9ڌidK.d,yp8/D.HKYT/B N C A୰e 5Ǿ<`8:(L^QƳ޷)L 6P[t{4pBvV S3wf$/L8 du[r-B(RF^t^Ov_(Y9W*`Lk%ЦoGGEyU9Q9{PY ]XcO-Cg=ΎI.`<7-+K+))~]ĉݾkZb?`c>h;נ@tMXY#`l6r|U>668J޴Ww_8uy^\搷caas$af@ͮV='uXv6j:DY9c[C :!ϣѭCWo\.HUbsh"w9!cRaȓ.91g ;'T W軁TSQ !f`qRS~[_% Se$ˠsQ [pFѝt]GNT䓣.=}fm".y~42Lѓ|`FgFTMu(8eSKhaH G%N`nt#kރt.Kބ¿%E2 ')yՖ7,X O=6.B&[,͢l ǹ/j_`)g: 0"xun#nڧA=l:V ͩֈñE!_*Ε{sM7XY0m>SE֘03t({'(u%)C\3!T|Q~AzF_8Ul2q_3@g)|'/(4ZW.O.N2eak* &sX 5] .X5U'5j8zOhAvH-`X2OT`)[:mlGfL_BnMxSk&BZc9\.UITF}MXrBu k:ix.46S*S[CCM}D w൲sM]=}!4UVv˕u5C~6r׾b<5΋};.M̆?3 ݗW8WXigR$I(TqGC[Zf> endobj 106 0 obj <> endobj 112 0 obj <>/Font<>>>/Length 8953/Filter/FlateDecode>>stream x\Mdqݿ_Kдc),K F` L(}ɺ6oGeeeՇܻc;0n]Kn_īj!}j|ޡIOB?}?az?h}nO z c{ů|Z_o`Tÿ>~ cBr>‡ Ǘ%RX/?ˏeKW[[/?[yů>S-9{yЉ_t3G31|˘^.v h 潷2 lv߾ӛo_}o+wZO!77}g^nt^ooxzabm2 3^_|sdoE3vijҽo/_{9RĔtI񗼪WѯRۗF!:k"s+֣ٽO볯Ooxols)d+fn_y3G<Z[g_j9ʾ}sbHR\0L!u.λ{y _ jlJX*VDc\Ec ,iߛU,>4:-8zx 1p*Wǩ/8fм>5AS$BoŻ'{R~3uc2O8sM>lGJ0(yce+'ǽ=jZKuL|FDwjOXK BL9:^Iw=[l#M0Ƭo?ŘM1]vVpA\lW;C()0$5B0S1j."# K}P7 iRZ{VX'NRud%;=* mI47]P!{ri91F'ݦ⪁,سڬ@{ P}Cbǻ(WzGN T6 1cVܞ6Lt MƷ ,CiGC9W `?L0\*C7GM.qqQgښyT2@ ft˴YI l9mjJaAbŚլ2+1:% \D1@ޘs13;or\GDIn;07X9 vo0ݙ][!c(| orIPn{enS379Pe<™>yenJk)mm ԿM_M&3cueHq6%_*;cW:ml* b|7öM.'{emb36PW 6a;k9;#>l5do[ Q kAHjC4#M|SWl>BOg4hVqSIԖl1B#`u?bAf5ԧJ'wmGLMOg?ANBoL@hko4`"#:AJL"ZBt8@+}wPݥ" -UCr/ych(T<{J RU,^*Zsv_ R T/U*_X\LxR0O fRը-CwTfRF*{ _*O<ss1&ŽwÙ< cLl8M0, kϘL%8fbj,&n^Ϳ@hLeh ]14$6#fQE6/D;5f0UX! d3T 樰5Ņ@1b3c$|R a#̑a[ iw ;2ՆTE&[DvW!/ L0Q3  L[Nl@**6$E7v,¥˄P^"s|0qᶱh1oaR6F[hRzNhꈱX Y!]Fw9ɳ:cJQz3MywH]\pzڌ vlS ގM(^2L ϱͱ}9& toK MkW@׀DJ K MۉP ͏ CW܀7#'@1ZVo T6k @K;, ^pv(V]h/n ` /Lj9B`T ;LT2G@DuQ57qņhĬEN ڗŷ9׾kZ8# F =o0|N*Mq77x>mk߀%}&}:.Wc1Li5־yG +洯C-{N:7ViJi_k_~*^:{J xA}>i_}0N2:vGOyy' 3 ipPZq&W5|Q6ݒQ |= vӯ"aK ߲jĞ$-aC/!U$@o`Fأ5r>eEQbT8[2jGMؕZ27288 +kb7r\!#/[t4BɱcUtNAvJ-̤CWy^l's\ -UE:3iV86lxFH!ϩS6u'L]6pd[?3rasd 9_X+#%-[[Y;XoO_$nmsX/@s_=UB[Qi)T͜)(dFL,'PJ2 ABS^!䟆3=k"Vi"WHjJi2A+ 59WAw .*9 4Y ut8j?%9Y= Ή_ Ϊ/ ,\aw4Xi~དྷj 6N{@ qU/PX-/Ќ/P`5 Dʊe/~I}H16~f lHY5_RӍ_ꝣ/ C6~AK/ M_"B@,ˉ_3?Kj'~ @/?񋸄~I5v`y܉_h7~%!K`6~Id8D &n4~16;K*E `c{E+ O=4/b%_}Hi/)DJE'~I̫r'~?Kʥk'~ NȚ_&_RTF_:b/[DJ SOO)/}ٮ%Rb 1lU_"$/0-E7~ApH _cM/Cpm!MS?K _:)0$X4_"* u%R`'~A?5d#%2HD54_lSV|6~C_69)-=n(_"qc *O" AֿǗء}[5xK#4 SlM, oiĝ)H0~LVSa0Ů݄i"a23Y0M$L'Li":<]89MZ)8>69y^XXx010UASt=L&L!yor0USs),7aHwO't}bawt=ПՄ)& SOEOCg gagh_UPk+V໵Apt}*I!>Bխ}o+A־O, ^{=>h9zѾ\;#WQ<]}Gt}b]tz$N*}zL>՗\$Q⴯&A}NH,UOö\<])kst=h$}MXJ_ #Yjgz0 }tfRח8@gV(uWTuo&98 G{LF{̙ .` mge^Q`;+:*cO|˕M]lHp*UT⿪םZh]v.^[)][ε5К5xmM澸&מZٹxmM&smMfҚ.̥!i?[l/,&MmYlȊYu[ ,2O Mr#ZisvU!jsZK eR7,%#7dIy2" /TYa6\=l a{td# Jl-ʲf2|t抻 i(F[x(lV/ci[?.P&n/giҶ+dS.P ϻ 2sO?hj $鵼lNۃ h2oQʶ0CA&s@;HY5rǫKvwRfW/{rk=9EA-9l]9IA:{e%R͌U.ثyT53ڟEU탣֗v[~R#'etmI]-?}[~4zеޛ-?mY=-?I K[>)vi/q-X kƴb--V^Y.|[~6̵|rҖ_.mzҖiڥ-_i-U%zEO|ª|i˧ի|zi˧-Xq\Yc.mܤ-8+_ ˥--yi!|tiI#-NEs'1~ig8.DҘS.(o),|&o̷\.LZNߘBm-nmW3--?1|{-Un÷+ -_w+m CX wx>AA0s ݊yk*^o%\`6IRW/o]ݳV%񸩬*ڵ1 7Dhݬ~N>0o&JD&#QnA)5LUiuxjB:F}Sga[kߕx;3/;@#Ld!/H!_rB[\^Ax3P%gy(%%YsI =<_s*(pB^OlCûpI]џpDy4uJ33|E8S>gs}9#]I f?Z爕uɏ+LUyQ9D<0J;VK;}%VL ]N;}%VM6΋zkO0۰ϋR뵠yQoQ }`[#~|a*Cx֘1}D*r>΋RϋzkOiuvpӋKsGoM?΢;{h>/?9qf4YW}^jE>qD;,KF|!|G?ga rQ8v}^T#8DL>1J!\'r}b늂SW #9>1cr<ΝTlaM_'FJ+WNdQʮpK8*˲>/c~JK-|D͏;N2wC]2.d/zB枺 .dKېeݚulck[]ԦYVW{}(@1L0p-/˶ұOH}& u +tօ}_grq endstream endobj 116 0 obj <>stream x+2T0B˥kJU endstream endobj 118 0 obj <>/XObject<>/ProcSet[/PDF/Text]>> endobj 119 0 obj <>/XObject<>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 120 0 obj <>stream x\[sF~`U*Pfgm!$V_gΖ`.==__gh6ٻWl'Y*f)b_l X޴ZTb!WyRʼnY72eq$jvy=KX0$ǹ].gD>Kui>6l.4~,ٯң'I4? <0 xSM?JX''[e ylݟW+3)1q]=O4vl?cNyڿHZq3մZ%̔ka<7,a2ndGXS˖?Ʃ lؖuW`'*]75 ۸oV%jY]i'k72><͍;| >~i6gBG _dҜtcw%/~\d~Rtx # ݀)`;xA^P E(4t@gsXXsPcoGr'sd r #r8 S < r4@4Q"TgFg7EܬL}=@3hO]KD`Ǡ~*!衷L_&'A=69 ϛ~\[`kS(/ؕv<5G]m KDC$ 9u 'SB3^EA@Q+@yѧx=G1TD96m0 P w2;&gpQ>d*CBDU,Vi|^%\s~yy I2dvL½Ϡ=Y&~2!_0DRJX6_"_eSG8}O{T豮V+̹Q5p3)۩ՊϲjEi*4%`2g&IϫHQ2 MIOAO= 05RGHD|D<$>dXuT`9P6^γ4< O6jL84D<Dž_iP>f6 ̳Isq(ĺ\d*CB/%)CY,uy[6a"ƹnvFgz ;_ֆʵޅ`16rz2C< sgtW29ycM} 4'Bh(߷qt3f#˳\Dŕ@I0QC]8f"VTMgePqi3Fe{U}CնnhLhsO*5!,b^]YgK[?5R8P}y&X]T&a못Gq1s`5ˈ/ӪryOäA$w%H'CEeu =ۢWC,-J׭Ò"zSχq R514U-[KL IC,6ڊ\lu[:whٮv|;9 @r  .iY_),.Sid^ aé\v-㩏]tL먥aMכbR&һ^گmuSW&6@&ZZu_x*&oTez0Ks\ZQiM|N{vw/ %}Zuh;{08MԸN!c4*y(4&VJD?SH(`zo9iheMLU!(ݶ5Zz6/d@Gh-k-Cr_(MXO8C渲54sr&AQ'crzRΤk]Gcʢ5%zŦFm %`, y[VJZHTi4# :1b^yG"v)KQ;1=1ߑN-V4favd`𾩌l<|rϳ@\x7V#PNiGL k0 XTvժÛ"]ġYr=zdyMH3v\F``۴nnMjYء A|{XHA/x[\Y"ܭ[4·˯Wc56R[UY90od~)?,Dꮴ z罾ijv+WUktN|&s [Uiuϒ8a ݣ1:%jh Ǹ6Ђ45BL%T|U~U'6 Yz6~YuM0Ҙey '!ƃa!1˓#N2p.‚e߅&)u_"\T+0ߤ) 4lv̆Q\hWQmDa^\}28Cd{.0$9t̋lUЀ*Kxj)'dttW56I:@TYv텢!nMKB=$kܬ~hB)d!݁ )Tmw3o ;%gN!v4@rĶǀX$%8Dn2!^cUJ25ߜU-Ean,¸ }m#`J۷SptƍЧ`ތI iqyhlPPCnIdRD.uݱaLڏ5%(I76!9 ~0ss #hmQ8*3F"WÄEoyv04<i0-eL)J~`*\,5 5 6A~q9d{IMAce&z+ߟMO#.5zoGG14OfXWZH63DQpݨmw VMI`~kW?r.wFh?|p^\Nczua7G'}_ UfSo(Z"g8%a(+u WM ̮QixL}GO!Ý*0bGbT wb)aI"Ic4hs#D:'#ǚt4|& ի0jYWnmeՎŶ\Z]QYq`) E L wul_Yc^n| endstream endobj 121 0 obj <> endobj 117 0 obj <>/ProcSet[/PDF]>> endobj 113 0 obj <> endobj 114 0 obj <> endobj 115 0 obj <> endobj 127 0 obj <> endobj 128 0 obj <>stream xmWPg^YHn$FHIpq .M3S :B"Q?(H4ӻq&qlI0r-7Hշoyy^fcXK<#bD1A Jj Pl3g5R^ U6ep}cXy'q\ZBDXxܽZ~ÿٲk.?;#bRDQln{'saiqA!!o^AѢ(#qq7޲e#DDLpr|'Ļ]EaA a[Ɗ'IUrlB OL: x8Tohc{B$BbO+`icǏ ڂi*t>Dja5bB*DqXh7k Pm7 brzq=؛"_I< x B154no<Ӷ2j5YeS΅[r$xk0 睭+*܂wD6Z7ે|# Tp,8Ȗǣا8ql0 2J]ͯ3lyB Y/ZpH'yy}DU,i'[+JG\<;շ E;=sʲ6|U~4N)[ Q{IsLY} l>B43רpOw* &Y <՜r|LC&c8˺1cK{I1a5@qOb.0Mgt$, Ζ XssLZJJ 9^V8́q,\^Y)9:r!:zg Յ[i{MSl*,|YzW=A5G px%sIYBP-ȬDҞbMr>-;UpH N%tNWNC } }ߡƁ}E*𐀱 SP#ӿKXS|uDm2)m.O]6{. WqT m^^6guՔ&'ůvp<#&D>ѕA "9TruEtux.e*fBMŜ]rO.%"#q<0{[-7Z"60R = 'Qiw G2J@ N9 `pt|QIOX: adn$M 0Mw_zZ2s=.. `n+Nj kتB-iY/a)E<0SЪE~JZrs s wgK+EEJT 2B؃^̝4]F3pl E +*&uJIm 8uZk?P c]\) g⸻zF^e` s/Y\UŰ~v)>W_)q ΒUq@D]jsV_̩{.<6GR{Yqϐ8kedAg&rg%#0 <QUT% 2Kg5媾>N5ڌ}Ԗ7DʕY2@$iJV13 O$RLEyy:anY^)Qs) m@ %#@$q =Ww嶀W]\ҷwtӗfzVEge(@/ hu¥|{uMm%y5 $'xh NK?+lÈeOMu\5grVT@Η;C{wK06jS0 68*i(N:^_t-U/#_@_naS^V=#W]ڋ. 5{Qq')ɓd4G@Rt%Hc9bNZ$ٖ|n6TU7=8ͬlj t % rraIr6 cGvI =M=[)07-7 W@52O)6AMuW8xZ^.D&~pq)?//*S .j8G,|5hpXi8"+*ժu, =_W gӫg4,U 65HmdCHʻUUE ٔ;*ېa>GR/*Mb^K3i)Q6 jΫN̍p*އmdQ#?08pͱ7Һ xnNhL(Lp3E M 3xv6 ŕ;d]a:=6knq/C/\?b_zٹ.0N댺vu#@HwF4!))@TJ'ƵV聧OxZ}/ĸf`:Y8H65gZ@㭶c/k>7ݲFE WCKSS4?TOh*ʬәʉ3Ty~AҼySlaY>f Ȟ}x*K頓YqP&̊U-EKu׳s~4i(7Is@f׌ k~IX5*ڕRAς:Zu9wT*GFh/W2_z \PրL3wq`Vcst4>,_rp.^rr0 hw 삜~0dJDc ܀hcez5|<1\7UD.5@9'"ȁ&C.W{gt~ Aju 3*c:.ՊcGtcHZ{GLڣ"tYO:ˆb865(Vih+Kg<N.YtTܥHYԷtRo=kk kz 0/^+ K,OJ3dy ܫ@Vz؁r|@M  *;$/,[kq6Q^q7 x|ALa0vJv#| хxB>zw1i֦=# n" V;Z8p9q\5׻.%`+ēSCx(~ǎa iZĂl81WjhՕɢs8$g29AL rp~`<xJ5犸|%Nо.?)R"V[zKNhZrS͗K-&1 5&cujmruEj4j+>sppaXf-6cO?OiNjG?G|tkb{}co/+9芷d_I01~EN>n gϾgoF'ɭa`@wYw +DP=@YYX-gL&Uu_ކ6ÅDE+w!v Dl{!7, R3TPE =oTߪk֘W4oC;!f_7.LH3_L|uLu}~MWv?w=Iz ~U~fLt>'ufw-M] \ömt.pˁc:1%&ɍiU)Wc >t". OL$%/@@ҒLM8T:Dy۲%K^.Ya<. endstream endobj 129 0 obj <>/ProcSet[/PDF/Text]>> endobj 122 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 130 0 obj <>stream xŝoݸϧSS<1}7N6r3UIj/dʣFwjslhM؝FnyCo?l`.hͿ[<4v~<|z} Fͥt#T2B_L¸ҘQ:Dg!]b ۴Q6ŖM&5뽡"nؾLEKњ2N"5ݥE_ 1*RGQ4%5PES OHb0)q'a2[o\&o}2^KOe%oÇ/*/_XMJ(QR5̚Qj Xu.?~ꝛ.S7Ck~|~uͫ?>>|?@׻䠪Ȣls*k 37#>oCK -_tT@ym* @F趂)n˗1w~|@SXXÔ4[4jejpa?2wo͕tϝy{̅ї!_՗~BKD(^kv x:nOko7/ e}\/ Oe=??vQlۗ=F7f1tuRT_jn_߾߾}~܊WC:k 1fH0葉0W6Dj;tu^_Ezbp۪뵹:Sb Ztvqx(F #=#_jF"_F"_nFӢ@\F"_+F@F"_F@FJWw~Wx/Heۿ6ǽdzH\fa6C%#OYy JzMQ<ڊ&f( ̊ U=İgY*&P#VhEkak9/ՠGÇvC{ g@dS|wz>ΐ] )_I)PH(#O-TyOi{w|Twt[x$]\ו.n6&\L޽&p?:#ك叀W$UUO AR@ꯔ *2pdPT)PJ?wJUU*˝J TSTɗqÁX|*W6屽~+>e}}<, (qDzl'4w0%v3t/Wި%/ n=Fh+3abWF2 e51,S(9=ư|SNĪڋ.w1g7MrFX$gU,L h 32FEˠ8S?JgU,?%PSɗ1sPǙ 59M󰅙?c*y\@֯"RL<95c׵~\;`^yu]ā6nba1llv̳/N87lNIr_^?w/#51ŗCP|)Qz,K ܤ(_JTϝ/*pNIK TSR #xg://TK_a=oâGvZ9nL ġ ;,=h]zȊ=>ZWQCV 036r`e&LwnQGVlX;|{)nM\N ^gփ9 .oc v.G ΖGKNJ׀V&L|MZPﱢ/5 oe_@hOiE| J|8'VeP3J-V:5Cc'+)Pj@VHCLkG2lX-Z*d0`hZaWX(^.v^?\vRGXZ:9Z|K% aK-2(Ο\|KO @@T'ver2V/]޴66K-^quKM4TXu]39Y+JHWt vS.Z^pajㆷe h:)h+*W§v{E>Rh lc3U-Xw)$pW⨱v]aeI] LEvc[ vG . l!H@mRAb_) *PNI. \DS%wJ2vu"v-_P: 55B XDCUŮhfrg+IpWj]¡C.Z^p vb:)h+*bW';_ TBvEuq&]Ղe`Bv%.u]aeI]Ivc; F o, o-@mJo.= o/@ o0EJo1@Jo2&tص|Auj})˱&v+]\]\7kmt Pcr\4t$@..X~.[E^p 5u zʩɎܷ; PศN9+r0.qmro;ïTR$T.mc-kq]1ǵ>{^tF:F@RX$NU,I 辴 '2FˠpR JNU,Ŝ?%P#S8ɗp\Ք|52V)/Y#(EJ뿢 Hf(q+GnpرrL e0P5Ph qx);1jsjO=h4ZbAϫ*ڡu#bvȱ 짚0в/ :Yr(AV ؗ,ڍWݕlTX(_)&8nb3WE;wp& QwUb*PTŗ; %B- TSPPj dĝ@-ZMi{Z˗TGQ7sBf@8:**v.jʝYSBi]‘d3kU VAWe- ǗC,"j% rEȑj@VH (]6GZ] DPH`g~,Zuy+u7lPcv*f,qӋGd, M!H@RA2_n! *PNI`, \@S%wJ2f&m.c/X+Sx b,0gZYtR^P 5UU!+5\ZB:蚐] Y~Qd rdYZFȊ]A#_c. Xy4_4&U#,*EQDWt%a] T,m+ k 2A JJ5JfXJ'J]Id@uOI+@W7jt5m͂&]*AWgЌ9oa>}~uw@lD]X& TNK /w0Jmp$#_.)|@Ց;%|{&tw9tL Ip/{°j!&tzvM 0 U 8Э@pnؾ|4wVAoU=Uo3WϣG]X9t5!Ms-݊SMh \=4;([`I-@vlm,͐]Eox`8k}[YSzlG17VGOC4W(1ISQ*HAє@*) 4WK'wJ2P]N _F)TE.M-_P~MR 1TbR U:V]dՊ8Һ8#uMS&VAW)ty/<ézʣ89d cZ!U'5 M,$PHT8ƞjcL!qI}>nbZp& 7Rb*PgTHŗ%B* TSOR dĝ@*T>ݰj,Xm LU7^L߇;xn8MȢMrP6kvE3;UV5d7a!sb [KL ʰ g]&W1]+c_[K~̈́^$}Zj2vBZC-ie'#k_. SK1`;C,G'mi1U@~pKΏ@b_ꇄ"p!DP׀J9s25*ʜ 7TdmЅw/$8zxZwpKqh.=Is3l~3leb؝$)J^WF`B6$W]$*W.\9Z  9_Ǧ`MK-u%L9xﰼr_F<ẁrd&ra:뇁g`??N#Ї*D_ WrJ|-R2(@-;%*pN @@) ˸,ouEA,rV,rfU,5Y|PhtbXj-Y|PS5bY)Yj_,,5-cYҚE QPjSY%5,bUjf1eE(Y\fq, \SkWY)5)#7b(+f[prּWL9q_5`'8h;pm?j W]PW S|0yrcgh^<<2 Vj?Gf'7e~دbe?%P2ϓ42?-`ͤa=\t}[znbk6`YP#Lְgj5HcX: )9(,ְRdE@QbOp[DZ u ?6avB XEQj.Ǫ>wL) $,Sq]zeYj3ZUU;7} ԋE Uz`@ʯO嗆}[9Rh e19:ҀՂB*r%.[:3u]a]IYخ?RWYΈ^wtb*p% aKu?J[|P2(@%;%*pN @@N)˘˯/ }Amj3_)u]z!ܵ wUz*wE3{B0 *xšnW)-u5+:WUz^kW-XtR͞е5'W=MlFX2hRaNk^hdRȮz[트q$\pG'K7[b$*PTP%{ %. TS2s@.) %wJw d}-&EZ:wpb]j!CθK7t旧׶yz}Pc#jI\k]bE^oJ QntUA/{h] [U" N5m` 6qQ,?r.C6"} w]aBp !q!諰tE6r(:( *>|chw\XɠJp>fRF <, qD.]GE3 ήs"ڮmT1|ne ZSԋoNģQOFvXszXBB9!kST6ɗ,z37y15.cO#>rJ '}ܤmcL]'䏀$LUO A@j *2pdP`)P?wJ\UJ˝L TSɗ0ztf._}>3 ?`f~}<, qDzg4s$8q&vS*00sfbg3fFhRGw2O`@k}'@6rBdֵ s1d^$9(/;!HL f)$de6Eɠ SU;%Pq /#@ĉx9Y]\P2;ߖ o݄_2 }d͞<h5zY A+g(;ً)d}lT̄<[ 'd6ݓ/%X(g$`fbp>rJgbK73 8s1g$LxA Ar&_n$g TFK 9/7*Jřs$p&_)@;%|3Hntr򅪜z̙&g~8|!gnlt^gܩ\ۤ2ɟ<h`zyfNXו1jxwl# V6*kbƢw|Ջr>Feד$XQ)'$kZ=-lÊP9!]mcKΤ#R">WP$U% 1h@ /[Jq$08_)@;%ࢺucp_lkg%-_~17Rvi =8{>FLfX!xc`!*0y cg`=.dalT䄉<V|c}O`@@I|Jg+y-Ԕs8ۦh{ v0:}]xA A2%_n$S TK /(JŔs$0%_)@;%|)_n$L|wk0-SϟSơ'+bC G|nf2s0U!z*c؁RSI=R Sbc=Mדm1 L0dʂ=VL Lc3HyL\K6[oU1K4$LaKdq0?'`?^jC0W=1 R*HA@*) 0W+wJ&2PN $_ vrgڠD_Aibl10 1 Fm2T4@m2ݴI:ɵ1Z;14IPmckuv(S&Vء<.B;M2O9:J  4cNq^i'd t]cyrX^?~-K|X TO ADj ,2pd`)Q?wJf;%,%2PNIKc{1pX._ c\5!CW;ujx^&cǪȞ7Ո=X VUq+_X<Ű`daQ V.bX=,aQI7=B%rBJta I[11z;LPMiтӢdfeBA2@{Z|KeP,PM?%*ϟ`f )f<{bBUn@&5|(qd j}.‡&GKmUqA+_(wM|ڮ{6D%}aLr&Li3{e\M W}gE}O>ͽ'>NGk b'*p' yR5VJɓ|5Q2(@5;%'*p}N @S)<  <|iQz4] n( ?e~>Hh<ۧFs:Mکȁ~ό \uj42F?ʓm潲Qhdb)lPNG KlXgZ|%G9!-yj`TSIX>5S,#1 |C`)Pz+K ܛ(X Tϝ|rR U*Xe<4nTvӥYM<,qw* }N%F;Y]#q+_6+/n\G'{n%+*EXa("@%FM'_GQF`ʗWRÿ)v1,ڔ2UӚdQs9n6tٹԈ-#, r.*OAҥ@XZI|KePt)P?%.*:˟K (T)tٶ.ߧʖpi&߄ˣlu|خGY#HV?Azи"`;;??UcWPRZpg&2 6QT9;kCX!jTR{I7S8q38dO7R-|GncHvΈCPGF#|xC A2_^rC,PZ .3TX'D 02at\nl"atU"A"lmO31A3H):E"Lhx0 rws-b~ ~9<ȡΩ- Nq^ΰ2C!؍m<.ЕV=wOhq`/ZOhľ,Υpz\hktʈ} ha%\ac2^? k" @|?K0uEpwt|su^?ޏ"-`݂Hkb w*ʂ^ ) dH W+Pk]>hV 4L?B7m+ $ĺ{TB!q-1MК N#e#vmG1^o˵[b C t 鐯ub*PTtȗ%C 3S萯Wp dȝC@A|꾨 af >(xmQ| ѣ.-x͚G) _oWoLu*0Ec_vEHm&)m&l3M᡽ܮQK~ YKºH7rPk 7ֿ@EЛpO'r^b|ٌCPK@/_Ų! ɗbYZC+PVA/_i T@OI _W %J|2:K0H/Sԙz&x(qj̻D= zX] ލ%|/)q+_Ԁ_[GSwU2wW) ՗/&a]]y-ҕwxS9Uw3xsyŸ?m#иW4$U1S*H]A@j7) W+L~Mޱ%A )9WL.LG?dG1#^ȶ0!(FG/ !HFݝdD g)$#eEɠQ F;%}dF}Fj& h%ԵC IXWOD Dj<0r ^<$ M̃Y&by)M|hUC@%_^hCDW$Q TL /\پ_?}yo?՗o_>/ǧ_~~<"vehUO-K1w>ϒԸO}mW_>ޟ;q^3 \* VtmZW}{=_z;9Zۏ{xck _-?Wo?_oW~yOqӏ?u^}:)a?#}u~I/pگx:׉Q_"N_??_{ȷmyK|0׏_>?Ywl>/Font<>>>/Length 9243/Filter/FlateDecode>>stream x\M$q_1G)7dْe#,$jEGJ {gfgfy;nUʪ_n=7|n}Tn}J~哾}v[R}~gOy y߾;͟V 5ۛݎ?x?ιDz?<u?+r?{ E/4r_%=<_})E?(E-^BQq.%ZkD'ޏF_9c *9~z{2'0 amկ7QZXӰ?~i4~ћym1&w7]ӈ9 }#lEIH~It/$~6rB~ ~| Ra9?~Yuׇ?G?M).'yFŻMC* |u ?n?M;a|o~__G#98i06^ϗc~ǧ FVqZoo>gu;gX=$@>7SOeܳ d>\bӠ{+❉{s_c<~7!}tm֏O󳯾?ްo.3t)=z z 1̉{+hx ;q{lJ8!6N&y;AC1%U ؈FxbU~Z+'=e.mhڑޅ=fs __H=u o5(p  nQ5rSw d}mk] GST!-Q{5X.P!~߽aXZL!펍A#k>ۨXcPNcq?+ QtpXxCË @1ީ$3SGCRӘ8zp$~ ~G; |5;4n5*V'eK+?uPڝ]9lVށ=CstH>PmL ' ЦSi1JӪk)sl8BB$S9:Tq+t,`2!y:1*ġu ˓UPf43ђhU.4IECzEOE-$bIX)gcxx8h(Þ`&ɔ'vEI̐L !?R^,+A2 uqr&c ѥ-Ǜ*Th He'lQ 5=$&h5g4@R5GESI0D1ZRFKYBTb3m `#1 ?76`q"#7ZY1Ue,ԅ~rLx&}4 k `15 ])rp9j63h\Y(&qӘ^d{D7#Zo 89BZ؉pW> jaCgY98 <Պi0:4ZўiB pV+a;fΚт :9߳3ZSvF+$ $g2@-20 Y9P ohj!Bfu,§*ajvf lQ47fBI2EB\]r٢iB ZS[-x7 )n|048}YV 젙V-Gg]yjQGV ,jQIZXY]Vb/fق6{fclAi(we Gufby8 \fX2f f(xSle!Hg(h/bq8eV sĂ1#",ڋ8K_{e"glk C5s,f_G8Y<Х\0{Ì,R;)@a肳D3c] ,Ǎf{ ,'=!D E"IdEN`#G7L'`"jrZsDh0P@sʡ缸3Iyw2013wXI^ܙssgzkg2^v L:wv/v=0w( 0e9whtLG>w0.;żrIwi H803{_߿8qwx<b=/88πqFpR-e{0@*(xn~#a biU!8"T<[#ΆA0Ld3F24m38b-t18Z &%CPZ ۅD8` '[JӀhẀL{sXσs5 lg.0 5!aN?{z] *FνyQ:pcKT0&KTѶ҉(ED)Eu VUh/*E&\:b|U/Q=!xQ f/QAkw29Q jKTa Ë hsxQ\ Mfmx_ g}}ѐYƁ+6Jm&< N2ȓ'!3Wb~H&~< p"D{Q#f:Ar at6TxCŹR9֐AXܔf`%*a`8P|s_}OC$f24SÀ`*$ϰ`+4*qO1PB1PaJfTJ`/j n#8E` _>l L] .0|Ҁ@2T93o3$*Gs鍱eb?)>`/}{a>pK8ؼ>0R>pB,}H8xx^N; >$f>@>#P"N3- v=fڊ';}8h*="qE0Cd^qӰy}a?®K_꾧 y-F>;e^5õ~8ӻ8mb|n_B\ƒLWe JQq g݇& n44nL@lKHp 0m x[a@޲:ؔR}!4FS~a*A@_m+&0b(x7‰ }fӕa|'(I[!*Q\y9Ai&+1Z1B9X*[qNAak 'q*^ã.E/(Dhb9}tCCiK0diKzSzcC$^1L3>LE4)>jNI^({}~]CٲP>NxР8}TKUe \Np2 ʥޫ;} aiʭsMx rN6}y.o|&W~*xJNC*C+\Ehҡ[S5P} /Y2%%Aу8 > <VE 9c􍧏`6[cJHcRgHF0; Es}fh G s p8+*%"\yd<1}Xuϕg`VިzUT^`EPC"U}XE^Aq?1),/b1AKz0ZVb {\`,/LabO͆%giՊE3PT9CI0rƃ-_}'F*XH[fa$`D<1ST}aR뤒N[YR#$˲0rҾ0R4P # BnH%;F'FF26{a0Hn_ GC a$iR"1cT[ 0h #H^pJ2Iua$` Ma4FPa]FJZH ֓H0tֽ0Rc #%ТH{)Ƴsa<FW"a`F“V0 H4|a5za H օkhiH Kh #ŬH54H1n0H/.,2bF,a} #%20RdaFɮj %AsNPBIM] PR YJ$xlԩ%<,7yP^UJ-:Q* %.-BI1J*-`*pҀp'Ner8i@KD:qR&94%\ș8UNN"hI' pп,I#D.^lLre_eD<Ү2 NmJ v5~3U˸Үb t=XZ|͕w?xJsiW+ #FJ .kT4Mv7tam9i+*(\HC;z]ͻZQ.6 ]yWyiE@+ g/dyn3 .McYԄDmKb5 7MF 1>ȥ r TKLx r HgVAN!xMH"]7_Spe =&$ =&$I0MH̕¸ 2 " ,M "CǦ M^Ud® UUWW&c29b |2zT(z\kEf3V.U.J)|!T9C!!"V>{+\/a"r+"\HE)ˇy^>_|+"I{mˇm/Uˇ^>D(~֞|r[0o|?^Ї<Ӈ^>L ^>L ڶZabSy/&|n|nClĀv+BaӇ4>({+B^>L ӷa [01ʇjĜV>LnV>;[017'@2 (D,ְ|ouwe^=vx$VcZ1E={eO7L̴wo({6a޽Zy&ݺmv{6)+{6ֽ]B}ƎX'> v紑s_ḟj#l4M' Sd] ,#)VaAy2Qf%7# I֚؂}"xZ#8́dQ<#CAr[{ ijCڔ0 $)L +ͥp >,hF+x1lRXe<`<44l./NX_wxMfpV1ىtq6a4$L4E2\,-zJڲIycbux(ڱɬe6tSM6Qy6i87Q%,gi3 _EMTO Eʱ_w{l"{DqE?&w.XStv9m_jMʅKM[][Wd%WWt5+/]qEKZۿ1f؂^5~53.k>\zzدnlW75_H ܮn0 bmW7tHدn [oدn oapu] \vuCW7 zsut>\0uW7c`__݀8?\w|!]݀0?<\puC`@n`j!3`W7`Gn3ѷn?=\gFq]~uCuuH[W70دnHuW70zدnHuW704دnHg^W7W7dgغ_ݐ-un b߮nȖwW7Vnzbwu+ t ,JW7jW7Tܬ%}|H Z_5~`3gVC-٣j=B4y:B`tj&IQ5B#dކr0Fhvu(]#4Ab <]#t Mu#`zt/\sr^u]?fʆ]+v )Ɏm:H2VUF]2#WT]-iHDIEB+뼩8FIZ&ϩxePfe^zpa e67d ,_mI^3$17_߿}R{bpjO>l/.գgCh /׬M궳؂tkoĮ[A:7YM3Hj5mє"g5]z(Jge#5lzGA|A_}]?|+ ?=-tO9';\KeƫuN7L{7Rv9kBfrO59V2ԑLs uKF6ߡH֒.U9!>,֑B9s#?Z 4|^ "]Ej珬?;/8] ښz&֧K7X9lSfҀF˚! bntjo]Y9٦&bk ?QSw=_0d|>-x =ʿwsB.lf@~Y`u1Efx`Y]3jк׬.qʙ/K\a.񄢻K7yj]]"uեDyW祳]]"$ `~//Ο=qXbg>b_obKdb]l麄]la'=bwqb|[lK ^l ?b8 endstream endobj 135 0 obj <>stream x+2T0B˥kJ\ endstream endobj 137 0 obj <>/XObject<>/ProcSet[/PDF/Text]>> endobj 123 0 obj <>/XObject<>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 138 0 obj <>stream xڥْ}U)*ΓeI$Ju`K$J$6_wVJU=}(YV껛Doo^3LgSIݭ~>T.U3i1F?V!]90Rg8vkG2Fm#$ѧ*^vGX-,숖=V2_;0|"My\s9Uzc8 (ֺ8͕&[o~؊vSo:<}?p,ta(벯P5UWՎXzݥci3U <ۓZ@pێ]_4W ?~HK/TT6x5`\M%k?g8QUٗJF5*@+nP?c\ٔǾUx٫D ܏<檦_wնU@Vﻟ>jQng^ 5VF+>DͨI܁0*T^弹TSV}ҿ´U 3 Q<6qLcW$x-bkΏp|]lhŪ!`"i8 VboP! #731n5ڄoPǎ~g0Ό"ڕCW m l\KOJ#;ȉhNqW"yfDzX٨CWnBZx'G;6e`۞j;nKPÙIz=;Odէ δ(u_S]Yoj ֱI20&]JM;0pnft6^GqN7@ve /&9XUK׸újUni&ù+x@Dн#W>XC(O0[,j ikV_?As#Iu~zCFJԔ]DNժ(K+EUxߗ6x %X魛-va?sM ɈRI6 id)m-#kZ?Ta<:О)/ySO7wHttyK"?m!౾]{BnN߲]v57jتsK Aʀ;gh)Ms˨\AlLs:j>3Mq{RJ#.n %3uR85q1äpgIa_'q^Gڝ8hSʘFx!K gb;JA%` vIqJ' A D*]@<2qLs/9U ˰/OdxHyyR)blH5Hw( 1\B&Gq1$"VUX.xc:]u09KLP}O[>B3p1Ǵ3 B͆2Pnr/\-,`R2Ɉ({m6ݢ/d}ڄSF/}bq] k%-va? X)F #1f|ͣ&]oRx'ќ~ҸR͸DаRt%9ŹUKʂ ŽBX!0~ DP&?_p  #|01C{Bu nkvpbѓ K6rӮscugn{l*UT~_7MAlZE*…^/[މO XYz 9 3I E^֥A n.2`|06d[rɉ-Nz+4!j>Os+;f+y6casyN-FWXYY!u fU%XnAVyRa۱etX>i4`JޝM{76~lJ_A2G0 @GdV.8Jopwax_I@5GߴaQMsQB dC0F|/&5OE5f|gɏh?ČG7?JLl1+Ր6~UN?M̗>w$}xw381G`3ċ@Ț,^Q u6_K_?U@,TcB^z)C]HP­`bK\QR*,-Ίa=NuO\Bz*69;͵e7ŏo :JK)CAxD2 YGr ܿz`J`ӿď=u>Ĭ›k7Dr[ڑ7l;KP:&ݩ@IҀvr_%38Op *u"K*mV̗}}eVbu?\UiByǣf{4EQ F~z&ʷ, [߆wX}܎7 X^'lqoiW =Ɂ!aEc6ocsycU*v:[M/L7)(// ;+kz~7AFϊSt)#[|Ȼm< Yqxvms+\sw| %Fp0p[~Y}C~[4%S6 ޡ鿍p>/ProcSet[/PDF]>> endobj 132 0 obj <> endobj 133 0 obj <> endobj 134 0 obj <> endobj 139 0 obj <> endobj 140 0 obj <>stream xmX Tڞ23nTSڄZ+nj] "E$$$k $,Bd_qj܊q'x{=99|.f5cX3<£+EQAі,z6@8;s\3 6aUvȆ^<~ jfalK=$ą%}pe˖?Jb,[̼IFb 휘##ÏمFJb킂yE #vGĈ>pn̟ã&MFn_hb. M W0 [-[#ng݉="9/x@k{ACQ^׬]# |b0G[ab >abRl;sV`3ہvb.l51#lsfc6Q\bbYaB1+54e͔rvV|N3>Wd 94uԢyN{8yz ٌfް>d[5f5jFeszNs7~y{ҷ,`=&ָ:҅=DyMdOESSybk$B`N@޳,F <'U{bXLL(4C9t0.BQv*\"\+ޙ Yh'IV@E~*@B(> oaj"xpit.SB+ Wz&S2BibBv$R8ote>P&Cqk9ֈ.YU:[ZnFw&HHA-0Nt ]oU8$E 9 1E2]0 p1sF)L1_a>H!>bhm'ùCs 5zezqRם$K ^Ƿ_%f1Ufc'8IxzRJj2H|YoOa"y'\ iY{ 4p9)iเNȯdoTsIǺ-qd*Uj<r3Jw\-(I`"^Jk:],H5WQ >#jxp7 grC"=PRCʃKRMmA$bnu:ğ\^ ݯ6fW0et.W'MCTI0 e -B6y=|tDArPYNxA/I$/(PS#A$%"nϙ?|ynt6?&Я&J ,0j٥$^B@BY9)SR0Jp>FVwAؒТHl.$AcQޖ\"y"H}t"VqLAz\+cu)ٵ + UGn =z] n6\n _S+DMj8m{Nb ޗUU6%@}DDqB@m?t6]MZ\ C9xX"O*/1a*y^rNF\)ְYubhEr'Q!i] >u)>cj/=[γ8nedAɐ, lUnzێ)dLgˌ2%@Uu}\)zT!d_e4\%\[Wm)) Krlhj>O@ab<'.{]s^UI=O겶NZhUdFZRj\0>Av8drTY25H QhZo KK1 v'e '[?Hl$<@WsA<QNPY7l$r:BwzfEB&BOug& Wo2d1 ^B- K҂DϠ߃omyd[o2Ӫkܓ35bu:R{?zEFbp;%dҰ` wEm:˟2r TUW1F-^EL,Z ͗-i)9YRԈX^>?tSp@iJdkcvmk pUaԗ :-NY噆4$#WE9h>W. zz?ew`t $Yr@m A`ceI5 ꛪƸvj/Kᇏ8G﯇w@T铓5P'ү0ZNuC!ΆwA18+Z/ ] ;|h~qUrgC2V`@qy@ӁbgWZ4.!!,#Ua^a<3;Hv \Y2mn[66wVeJ@jCs6/-lW:Y|<"-hMq5L2~)5 ~>2<t}uW[گA3X: 8aZsU[4o`I̢H:ɪAm^ܼI}5'B3|4qږL$39YXl)mN. Ϗ 4=x"ӤԞdg |ݣ'͕-\?ܻ-QEyq%ZKr9)j631VB"D}IYΐaΈ3yRE6}m !@8T[` se: ֪@^qPn&͋ST.$Boݔ,D#jt-O?p`Te wEӪ'cX'_iUnpu k|:._g,̬WA>9"4BA\ Wד(^qb(0%x^Ug&W'M,C wEK*}Fw[M/ylsPt133aMP?oNW ǻ[~0]>9p#`$|,xՅ#GlۍAf8t\"O|v/`舻@fDPG[YM߰$RJx{Y'*8Qhh>1.VE-%8N4e(>D -~W۩cXf/*6y]ؒI&s;>=~"*l7~&jyK ~ӿhn~!n ֎=[Ւb̥!̼nwp/r ur*ݔh5zzJ :VGԊۋE|n`EQȡu4A43^V͘aA~` endstream endobj 141 0 obj <>/ProcSet[/PDF/Text]>> endobj 124 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 144 0 obj <>stream xڽ\YsƖ~`Քk* h ybfd<@$$bL Fsn,d,y8Ys`1ٷ/_/$Y523!g͋%9γ̔ұzMގeif fJƹ\_ݼZg,nf6Ma2Lnߣ]q_Wsh{w??vNcd75hC$In=Aq.o(kz\,.ʶ{|"a.Je8d78|)qda.E'9rx)fMg_B&q(ߦ{rV_feVOZʓXI=}Z?6uj/1_Y4=͍HG_un۔\}KW2r5u_߾һ+)K<XelN%u8TQ4{&>/1 Q{}vo(N)%b]+Osxg\`L1Xa:TǙ|fMT&"$q.oW:5pD${TH#bCZ'$Ybߖ ]8'J.aFWiĠcƃByS?2"J˘8J XV]eQnyH`zv ;2g> v.kS&NO%F|4:N ^>m~٣T yHvG.>>d{YXfKd<*OrAyBLz4WѶ+֧S1d$=c\dT%QLݧ;9i|==iF zd|tDajJo`2xsuѕ"(*;Usq+! t@ݵ_maKI-?4dnj.\qmn-T,+Dvj29Ge_wՎϨ6CՓUy̹v曘C)9Jqq466q.ͩ3NyC\)r h+[|N{,(QcŶvo8sT3 +ӯ_k+(I8m *zKu h+Z=H8bt<&XF˴#V[dI3)[7 *Vt/onICghg6ci7[@H,n{*7^UʽU^7]U+^u( 宬ҍP3խmi 7;[7L{hX6 I"vK0ZtrwxK%\$Nm620êݞi,}p"lY}dXY,V\%Tʮ$h&ܩ_}&Q[aᇪ޿Ǣdi^-ɡǞ ތ97n׎UIp^wC@Mxi|C$ƝdeVվF=7tA I_'U`#R-oe*ꭣn۸v;H)nQq_V/KG؉ `ݪ^,zWlY{ >C_NOhoMRvܙ9|}d1~ 8K\&\~8-A]ؒLE1LG{v*ҭ(V%C2&K~d[#LNTGnVn Xfz4/X:aQ䱵'z b VEǃUD 矃 -,=,3b/jSH 4?rUd}\hm<8iYrQi H4 Xb K5uk[Wc`rl +XQ4m;[,YfW$FA&4-US`?3i"}S,ˠ|©I.AnRs/%N*Ip7 6(pNEQflmc[^EQwxG[&7ϙo,kKKl )ՎF E?Ğ|F"aV+byhIЮϏ (]_(QfE2Z=AO1#DShrH\V0{sN rUWXԬC #,lP0y!ł$Ɂpv_N3Sh p7# 4QZsчcA"[W5gLX9 = p܈Z4(e[Z Mɥ]eJ3;ݡE \}:Ď7sn? qk< |[߶v"Ać0C(uC@weCKR c9vF*,*> 6lYuJ#&|")b{cC9l?7*vEeX(LRG 9vnAX[r]$Z.=q=&]phNݣJB(mEXUS*jw̬7ON42Wб}с&rs)*οi1BbǧSv̹)Ȳ 󩍪 .:qpA1'κ;] 'o)}ħPm%L@WcEQ5o؀lGqfpni8%͠s`j7raU}F @_2ʷ>c0aoιM9TTu gY[- gա$y"n2l6ctK<K.tZH k^1TєQ.r[lVb=.lhsE#yl 8ݶy~=5 tT"Z&u){iHM#?;ө,,@0Hp@H}|"G넗E'?5o?HHSpޜνH$ذ`ߠuSO)5yS1jx)X:N|A% M$~ 3s}dЂc4fOv9aZd2gP0.#X a#r\Dv4knNzW vÈ=ae{ lkB)dp+Cm4zR31 _ kx][Wdk?kE@PA 1(Ub 2\rK2EL9K/(t|ʦm׭_C9]T<n9vP0\챽0$/W*}k4 @x]խi] $:$pұ5\TT_xK8?vY3M0%#$} sݔ'ޙwmrtsBJHa-<9H]'V;^g lVb߀’'cPZ3ۢrPN [#&&U+52m)!IL"cX*$LOBll"XGjF8jHdOxK@bJǰ(k4@{%n R9RMx,2r`֧j%id*KP>pO`V.jQ'O0H{졬d*qeC>BV'n Ae4c=hU\dKBGK+C/=̠v 󆦲їb/7]%b5lK2vv]/3i:PLi:'b[WG7za%+gxE "-2RX˓ӻ $]$? (_q嗑34\Pρ:4>}!X֪ TI񂩚SSzQpC 繘12"< B.t X9.}: Ԙ$:i';m, 2i Dops@ʮ'bd#HH0,1$`aTi^uWR8?dLS/"NtnYI0"X?;%<m=BV>1L%" 'z߮lf,@#Gߗ-ԃ{eF]z[ ]r1 a{7tQ31NmEOY~uպ썁DZ xQ`es|b;U 1"xm5 w"[G ؎0o;]P w$5c܎Ex~޹/k']Sx?U>ʼnБ=LKKSX B[Ȳ!Y4!GO%L6ҳ9s6I?2ŐoI>LЩysx+>לtf9>-ckz?\ } 8فi_+ǎUfJe$; F>)}xPp<8\E = V,8) @a9kՂX,L  4|ޅ5GKJUح|ր˽?81g#͹-݀`xe?+bLQA8=3A0Q'-V%Meݭ8,Tuᛩ0F4RP]XolVIlm0 I.@o;J{X- w: %s\Mҧw*W\ |iWH{Vko)g) 'u;c v Yf/F I"BT3qeQg+f˚0?QdRHa.q/a>`)IW1A],3p x SzIJʫ%a.W~P )q,~mx>행-~؜VG !2TK!f:}ߴzꓻsjm*SR:;BaָI+=hϒuxCG@tۣ7/k2 endstream endobj 142 0 obj <> endobj 143 0 obj <> endobj 149 0 obj <>/Font<>>>/Length 12549/Filter/FlateDecode>>stream x}]lmTJnRDzdT![$<%FBZX;sgGW/ |g~$ۧw_>|'~_RuۧOo|Wdȏ&ϩ||=ҿ}Ocp=~?s~%/$Qasovn[Q(kJУ9LSW>jz}ضvO"SI_9u|cB])99u|c\rW?_ "͏|"^_?h$$:N~/9Uu|cR^oϾ_PdN\o~()NjE{OSܛRs˲ON'+?=_/Ko{w;|MfǏ~wo>2SM§HwcØןH/W\(Ls֭İ~:I}[Cv# tL+Ozɿ?OmG,O_-OQj-/⿡*la~=G_=T%zJ>`%ꘜ4<d,zK Ǭ,8H_3T8_Zj35c>RkС:AC3 !PrE(LO59ѵƙu]m(CuyI/{/{&f_Fw.{$,wْx/{]K{ VNeK&lL&J姑 UZUjEglijϷ퍤\OY+:1S0.3:? CRZф?ou:_ʹZRkww=ԩSY;Hì9H:}|iM ojk6gN}Fco`jjY=/) r"57Zlc*~33쬛L[W m!FRӬit3Q!C:#0DWn:䂮2sV7(he4Y"e4UQfi i696SW q6e8+Vg2M! 0V36l^kNg2mg2 L+2dd:؟3:c2]DޙLN1 Ut&p;=63֏Qͨ7ҙP;K܌.QύWe3Y|ی.FM\=EQPR< 7Agqc^^؇7 ϙ6q,Ra7)-zK C=.6\< @sjj4jMx{# {%`&5QQ.r`qiw5{%]pJZ!gwtR2ިWڌ3P/P2ިW`QcMߙ8+JK`Dߙ2QۤMo+:a78ȕ=?2Aoq.ިWz57B]6y`yvW`mMbm A6@c0.!y{9w 14g/.{!ɱyȉ/{9w o@e/lwˁ^ym8{9w !Lg07m{!Iqr6 ^Z`]k^wCQ~@őuOso'o{=wyl}߮@<ʱƗ9v0%9zzv@69;.PONc㇚W1bx@p!S$9_$R6jxAjl@mLǛ%B¢<F`S7zٗ}IPn=' 1aX/o#'6ƘB3Ʒ^iq8ӤdA1MRH#LSUzia3)~"rӴa5iRTiZp4Ӵ2M6i%#7Mj/4'5M{4isnJ d>ܖk;t<[=q^|z?>n}kݯQ{nO^q_ <|t9tukN<l÷\(GzQ0_Ҟ x:p^Ofg='?'3w8'3NPrNF:=t'h@W4`t"ʟҙ(go!\o(F %É 8x7N:S+l|{ϑk0}㈓h!NzV5P' Z!V!"oE2ܪ[m$=#P 05 [ Fh-e.F>BU*H Lee j@Yћ7@McQfMkAVSqaT,>1z.`Ō*@-^Xr+`iѽc< Um)dG;!+zf.EYqာaK($my"&㋰T&!z#݇ƈˇ3t*fpKnw q>,3[fZYvźpLDفYjs#.z; a 1tpyA3\x}_8\r#cFqM6FOnƤ"D, l d-WN!N#D(^:AY"tj#"",сHDT@r "jn"}:" 3:(`Y!b,aePq  Qt_C"JeB@FlAEgw2ژeA,nai~4莾3h>bQκwu }VFњD}Ht>%pZƨ@3,@C2ځP1KY%sl^vV9!06DÐ.^MݤhwT"6j&[-fWvDz3ٱwvALeGbKPQDMW6q, gP8@0*bTЮk*겫 !]aSlYػN]5p6c ?BbBTAVoZ HCJM* M JTᨂޫT5Љ*(9*9U`fm9 `iyQ䩂,DT! M*?TAP!M -uSATU'QA-ZvT!/U~Sַ S;TA݋F 0vki8 #3Lwn6y+т>0E26UQPM, U݊npUUW}S+cz>A" eAbz>fj`t} ^b|>c!A4 GԎ+DA,zP Aw`ӗ`8:3A7z"(Xp+XBwPG `QKlQ~4Q"h.,M)f+?u.,u1`ނ`QHQNP(``Q`-2EeE! [^Q`Q|Qh[P>A`]`Q"^[V  YQ"`Ah 4E,n#*X^ ݩ%*X}`945(X A"{KA?(XHİ4g,E@,kT%KTW$ˠ`)) CAR . ,] ;x CARІ.(Xm =`,W A1(XB , ] N )rwhC* |gȎ~7wCTv)*xC.ϰRJ4T| B( icQ%3+h QN1|0KSXf$3, VCeнrMXIHH;aLṉ+)զi) U`$v2,|0kdWWe_=FvHv"J;eN-n4֧&NRRI7ܥbr۩h]JY2*5 컔dVU>5SuBݖw/a!FwZxd Nf}4xc!ÆLyT@0!X0ٱ/)RE}9]6dm?AjE- 8k9xM*,=QJe^+VUeu9U>Xm "'gKwJO];ܲNYV>gYA%se/YVlϲx,+`\$/[V>(eљ/+P|ULle ϲRD&98 5fe gY!FWò,+P}`gY!d$-+?aY!o 峬J"_V`*)[.yP>*)[=8 Ujme,YVPe.YV~Y!J BsUm ,+nPnYVZ[7½er-+,ᗕnL*QmT-9#BQЫˠ-)9eZ/5|9;>Y(5\560.pӊ8\֌ ]=ZY-2|֌\==Z.h͌V{f|V+=Z3bG!{Z ѪE?=ZYT]V%Tӣ|VjXGI,|V=ZM{ZjףjB}VӧVzhe1g=Z)IGUjggU+nǢ?s} 6d4˞Wr(W\iSNi !jz/ÐONii:s\}5Z2|yJ0Zeq)aWz*K @r` uoٚΈ1Lظ:5i`;T6Eik7=dX-;Ǥ9̑vs5i>]D&!0v#o!:l1cP!ऐwz/,@o:lRxp9c" 5l5 )(+8РԽ'`aw9ŮlQtaJ.Z+޶y$LVrv ؏xeʹc&UhM.!)Jdj^$4R*LeFm^9$+t%P4F俵 };w<%YAT.QI0D8 xۺ$օ•Rxk]mQ{X_E ׿䭺R~/~N/5Ygjļi3!,)ԁ;aR"l^bPcL: )p(Y^XJ >=ڍuo%1qGbM0- DdN z '6(yEi ,\Xx@=L˻T#_x@- &` zii:W$ hyDij6<4]Gx`d#<b 2C"L$4!+N4c>ͼs}sۢ[4c=.ϗ-QAo`ь?F&Hhl-,-~,[Rh,EfWp= ò׳0v`?¸! w`\pp=pe';3p?63C Ђda1Wc 2Z}~$1@}z7WƝc֓=\{\k{\/m%GH6gؒ̓zgiC4V\Ϛ*O<ա|NM/w/?_Zgk"ZNh̎I1;[ٺbTl6E 2ZNnONPQNldO)LY,W ;!5GaCxt{ϧq/5`YK  AR;:!+;:-k Z0ִ7kІNLVq,!#,Y9UhoJ!7!UPGy: u%_[DWAkH}|?y܁აм}3G;ZXr? 7B["&Rd2d4| L%V]8o֨ac" YjAc Un^Bd߻5< y{Ac%\U$< ASiTt? c, i̮d+ҺjàI֕.MlffpZ([; H޳|ASrm ӗ"js΂GJ}: z| W:]B6u_d>\uG}/ DF#cSid7ҕ*m, =.Kw;GƲ1頫>2Mk,):?ʱTfoLNӏ@g`Ј5ָո*\K[d5!B{G U,R7y c{l endstream endobj 153 0 obj <>stream x+2T0B˥kJc endstream endobj 155 0 obj <>/Font<>>>/Length 23133/Filter/FlateDecode>>stream x]mq~y$#^k=R6(Ӣ@ aA3o$`ޕVϝAۻOϪ^7O7ݟ>ŷ[O*? ݧ_{joHx\s}^_?>O=c|?S_;WoetKK?o[]/i^v/ % ^~O_<%?o?CocZ~Q҇SE%GBo#O(ߩ!o}(NEk(ۿPkoqX/r*ҧ<߰+hcyv {Z_ˣ_|VF~w#$;&3:È!u O @3n/y_5_F2ƨoO|^ʼo9!W[oBj۷|_: o$on=}t-#.`ݢ_,` aoO];% ^??{=@ tqo?3ϯORW5=5J}oú`fi@X1<+ؿtk6HoXƍ$^lnX ߢ}.13ɁXBKMIxwvW_쮌Y`c~3aG}WZUzοeaef{|]fahu|wK <>~mg"xX`'6,HO(1oGm ?9 {zcmC2:\i{$Ro]{ BǞD6x0Om"0~m_djwsz^aowpSi|wt4_ͬXmc[ ?2 (axOTm%3;!3ߎyD)O`>`Q G k22{vɹ;wUjā6~*Ͼ=zGt"=yU엙0Op/>}F ̦C@Td7h0̞!=hf)Ucq& :ДOٰܪ> jU`=|%C|]LAJk ;?Ij<&w029>7;S >l}(v|Eb-{%{Zf#l د,[0 lBꍜ°4]l! 6e.c(c 9ۯNc0Sqz1f;BH{CA#P1+O8<JDl1<1b+1! Ҽ1B[@Ǝ`?zɚP`6 L[Wi !61T;74g f.- d !CC1XOchf =$g HNH{yNkFJԆa謡 5k>ag CcK9c0H=c0jyg v AEt3/k| W2f=0qo6dƟk "x͠^3"l<3xq_NxƇƻJH\OA'|vqM'4{뙇5= <p@dj#ʙgmЖ)bGyyM%RV8j Z# "nM=) xTn`]{RxIڅ]^Rh)4ac]:b =9Ck5 %50)`yO5|o&4<"jؘqMe`^g\ pE 9X{]@Pa6;CEdyI8uy!gz%3x .iVcJ~02v pʘ:;/VaC?fRɮ(z'$oRPo=EgSygS 3 3){<Ǥ24),9pI1ՙTȤ,jI;f':*vzΤ%oR>a2)c3靏Ef--gQS,YlLv6mlB[F3+:92*3iT>3 Q16]ڟw6ŀxr6ewǦ}dIΨАL ReT hEQ {DiSYeS>RM!eePewA;wΟP hp2笺ҿ|+)~Cy硱nN $IA@l<4;4x;4<CcCc֡sx(i;4<=C3A<ZO?44B%֡vwhh:4a?Б}MUl{)QhCC#.`*e[}UWx~s\×n|~f~=+x50FJ H1ەXdH{`H>Б~05xٮ`<\{GgAG:d0fT}gwݼ!e JCEn;'P ^cWg('f J^"M7k!}kH@' )A'`A#z533 0r%*I@Y`P9Aҟ恎^d욤6N/fK!3QJ"W.Z̫Vvϼd_ud 2y`Nȫ{HqՁHp=ldU"\ R/3kf! YE@~QI%zA!:xz 8-+.ֳ}Upw7 2 2÷D ~,djQCPT#x@o o+qyqHɤɽ;%1g2Iv, _gw*`/5%t-vYeW>aGȍ2m#0|õ((>OdY,m#Q œpeYIUt7Tkcͳ%9*2C>v5, "+dz)-+age](BL8yfOo*X0#N# DnTeup* }4D*R͘[H A6Rc Uۙ[Hea(G [TeHQ(!* Eb;5&P5KسTT(Gw@eN3[4NXGX8B{TC qʀ*p Evd%NdS{ S띩S(:0eс9LT@Ɛ킩Zi ZU2 jTR}FRm_/)KPb)6Sv |TJUm 1an*>5:23*(,BITIU1RأlS, vpm)te`)|*@RT!B hB XiNUFHHb1 UM i͓:'D'oA4`'ZuR=S"l,1w^ľWfJC4 ]2POBxOs5E fKX!0iW%BT`uV vKٚus0&!  6^7p< KńR쓵i :JPgŜ}<|,UU%5Htl2rɡ7XYxeZn~O4X17[b_6HC)n/xaa *B, 0÷cg e95cd zavH'ĭ]&8Lšn1,tzX r?ن}@&3 J.@6/tzX1kLKз" 0~ C2KXmvLd¡ YS6M|,d ,:a[ ;A*=na'D5B!S`Y M[KȄ3cLK*sz&0Y17xm!^d "Dзp-y4z?K8PO kX%ЉK8PO J_e',<9v6V2JxRd ]WH0,E4/P,kRd `e?1(ty|eGI+|yXy+\GJ0c"?._]~4۷t\ɻ|%sp+|旛whjѹ|/Ϧ\|( Y+Ügû|cb|o.>ù|_sWzG=x| sRԝ7'h-㣢`w~* y|㳼U7ƷGI</-j{|;_ly|bYr 1a{8_ 3qߣP> /;ϢR~A y;>}F_uv1A/=qlsn a{{IgDa%ϡU/Ok7}Fm4}2 h,O{h FZtnTp= r~u&çr > ~2 v~B Np ;|ޜ'q%4Kc ?* 9׿+IH:uFO3V?9؋f_+F}{$FPu#HkvWifH F]] D--e"z 4eΠAl3HT'e i/O"r;O3k cl5=3EAW^qfb;h qfQCbĉyEKbm2K\H@2EЃRiw(C,1a):CV$ Z S@®-*bSBL_0EBV;%,݆-C<,v9 vq9yIlޟVGϣΙMsylVu1pds.\qϙޟSbs&@熈۟3?LyO~y@s&u!s憼?A$ǟ3T?{?g*z.FW?GvϟF4ϙ5Kޟ#/n'-sf.$9l`pnޝ?gV:"LNFQ')ڝ?-O:S88qȸƷC(c̭we6rБΡ?86@plN! Pu7ラ +4y=LM+nڞX0U;,E6Cyf*D;,EN (j|/<U#EYn-nTC J#+{)3TH,Ddz?+"EhlROEōh|F[2Hzw(spFu=ʼi 7|WDSLDc,VHq"ͶlԊIQx-%a+&-,װ:a+&qB>ԙ:IQyBQʼnWTgHji2Rg6`>?.~4!:OS,k(0So6 HX35͆7^)OYCš9xԛ >Қxߑl^lg D{g!\a" mU(=%n;5e鿦\+o;5%VyM~DL5}jV5kVvrHIzQ8'wwgw(s@" xt5%,A$q< H 9V! JxP@q9 xP҂ؠO1Hj,PP(zP@<(0 EA10< J4%(0)r@#;HmPPrTXY$] 2AkjZTQݠaҪA@(t XPP 3{P­oPP&ԃBSYܠl(@.P(=4q@!_w}\կAA8p[LFZdYL ?*9׿ϜV7AR6L% 2:e$|hRahUg+sL^tnjDif"_2}_vQNQBE (/R.@9Ccc\i)}U\R6p,@&K9/O:BrieP#rTb)$,S,PMQOVY( (bglv,> IEx&ijCf"<@_6)/Or?a'ԝy-D`7zX#Y@|ڂʂ*4e FsrMX0}Hh&,D1a N3 ,,X ekB̄Ra$:` y,,XG"d]㚰@(ҙ \=*a,X0Dg,D(Ȱ`W3 r`,) |3 rYY`o!Y3ځRX1Eљ =0!aU3*{,юtu,=lB"7;@6 %>ؤ%k\]>SKl~#yYSM6N{g*\VT68֙  3:Ʋuq'̿);eNeH-1on+7RR`D߈2i5ro$Hgz#_uo2;M=# }g_ίPo}h$A-Of)x)Pf"z@C E70j UC EO1'{ۘc{.euB n?ӛ {hxy’R4NR1@*[HzXP8RpVyh['dc(lLӊ]svN!aLP kʏ)ń3ARRCy)hR4ʦ"؝Z3AyR4rZyd^5DWH'* p׺h-ugkp⭸&j&OHkLPN]cm®ETZ]IU `q&pMHR;/ I%o [tK?Fq9Cqthuy BD3gjA`&~gKm\"v.I]k~j[g/,`be:!%7j8aR!ŀ1!U%Ik SHܠEȅwi0Mr\1` )-@HǴyYQ6Ws𕠁"w|^ۆf/szMTH'Ҽ\` W8/$qDmi\iIKYk\n[gq4뽀diGi]qqMԼ\arFr;;V)؎K f0Xj|N@Uxu%]sqώ8sIw?;S. u,(-t&2?>q k$Ƈ^ӨIF5 ld)R8Ȓ D,EjYV_` KA{NYͪY$R$'p%A"_ʌG!źY3BȒ%'p%qFȒ%'pPd%KN Kp${U7$GV,YjY#٫%KM Kx${Ud dI #KAHvnda19dITEY(8PYB:G*,zd[ zq# ˷! eGA<P.{da19yd GYw! P/8da# GdPh>B䑅e dQ{d`avȢW(Cpf7P>:da),_Bx%+"xdcsf;BU%K#zdapٍ,5=ݙ),'Y(YD{dftP;dhA u@Cȶ-!K@wf7P# %Gj,F! QCR+ǒ5#?¬2ﳺWuìtgV=>XY}3+fV;xf|ͬwbbVQvP.f5 3,7R3+̊IYwsIYQbVL:\ Y)JL9\̊BΎY%*ަIYQ3ĬŬ0w1ĬfV⹘Uͬ(왕 fVYRxͬUŬ0s1YQ3Ya6bV 7$ŬofEgǬ/f9Y̊*ΞY% ^fV_=Ŭп|3+8̋YaxfVtͬ:ͬ7JYL.fYnfY.fY#/fYjofY/fYof@\*Y!ofpbV_ì01+DV7%!Wz1+/fTͬ_Mnf<Ŭ?0+/ftŬP57bbVKU>g v3+B.fYr145g.s1Y.fͬT9̊Y)ȳKVS0+<]J%4ϬT:̊Ŭ̊<Ϭ#=YJŃ,)LìTs“So#ʎ |F}KGܐW!x,g^sFLP Liq;[l>VY īh\Z`\`zvpխGgS|5(кףxխPgr6ʁɪYR>z`܃V3^-~:˴u=೩hqY۳>ֳŻù3rr`)Ruob~r`;\eΒճ:j`)RUj`h3ZuK= #PݦRV}n-E{csNʟ:xs!p.=AWcs<\zT?.]:~\:=DKMǥ3OssL7\zl\[\:ǡΡ']rr|kΡ3ˡ&YЙ0r"wЙ^7“cv qr/Cg)xt5Cg Zˡ*Y.Qd:ۡ3m֢s&Й~+^e,hYCgy"ۡ3Y1Ρ3C8v$n|;tܱk;K^u{_ǡ3SڒW9t&\r"wsfِnP;zp1x^Ysr3OzfR"2 c^e|=A,]KR.h!b׹60o ){f!0;/- {0zJ{ӛ=`^fp 07{@qf 7{&=tJ8E {|`/=k.0$M0aHY=`  {= 8= 8A= sL]}`XrX,=0Qu,g^{n=0ov_=@:b|{0\?lg؃Ys,gIؠbXr8o,{`f[/8c[/8c؃Aqf=`A {܉&J,h7{SOPqynə=p  ]s8{HAoݱRp{`[PJh]i7{ؙvh]쁝i7{Rau졶|uU7{.mi{4ؖvLE\A ӳPQ=\ֳ݋=LJ\:7]b|;PjpaxH/0=0Yp&.vɋ= UБك$Ρ3rf[.ΌgL\쁉=t}Ρ3At9t&.\sZ{P˱fƼCgbM9t&.d7Ρ3w&.0=0qx\t[/0S=4Бta&CCo{9UЕvu쁩ً=p؀gFzwͧ7)/?w?wO߽ۿ|7>y}G!^K?P^?{Zd(ftkT8žLXV@syG9,I V01ZpPй@PaGBs*auSNv+'>7A'lCIS53KMTs9.pm~HPqED/,HTm{5:=bE{-:2A硗nR@&bK*,\]ImYMZ9in)E? y ̈#OI&M$)ڥH\lj҃F/mSLjZbv\)>'Q*u/!s}-4O+(#L%]TrQ(*k7mvQkpԜMs .=TT\%4xp)ʆʾyE]e8:HVܦhCiG!>RJ?(#*k1@u$$dи`I!{ ޸뒒K 0BX'H1Hv)^w%>9*M9$6NC|i{{CZ;s\}Ҏpa*(FE8^Gm]Ym z\QJ\eEMkڒ@Y5WcDk{rX]ň5tn0tsКԲuQMY5%'jsR.qV{»T'?etS 깔޻L-.%Ny.؋Y.bV6[ȯcU~; v Lꎭ{?H:hĕV~A䆑[k v{ wDNHK3SϹ.Ղcn?XU/_5u^YeW\Alxp*:ǝ%Z gP "gZ+=VG )~:ƙugh@`eg[16ntڞٌQS t!h+RvKeuGʞoY 8kZǸ"[Agy*bK-%q"[Y%LXpX 931[ zq9쉃rAHʕ'yYQr-TC2Z&!P4NbgU[L8m /ͩshٕ G)Z1:ƾSԘc-S/i'3=@@`0U]W߭i ge 4gv}.:E-Xvz3Fe"B' \P \1 \jBݨ* ,FM ‹UbN\PQ/07{'ԷoTDLp*/orìLi/q9+q{`vOl .E}5?[`sf FavgqBEȤ|q3p@һL>2ߍ(3&<ېDDklv;?Qga+i'&E]g/1`o^nMPP- \)IMI[!|%V'4X&xۣ`cxx E+H<2  씁/kf~Aq2"̺0kEr,b ,' 8q3sWZ-r`xYw~1d?kgl C=n*'kLzK⻶Pkj,u9.| Vū֨b ȳ!%--axn[fWׂ$>&) ŵ-{]6v\1%^٣۹O2ָVb!ÜZ7ֶ񰷶c4UvurOm\p8aV`Aќ`ܝ\x v6.nTҌ\-ЙBBSme 9y Cu R!rh&;O(չO;OQ\ԓ8]S+]?sy$Z2ZNk5^#9ZDΜfWBYZcC;C,ORJ5:\)̉52Gҳy)k|Lu#a4D8vF)ReȫyDhK6a)Rhpq?r9e^#1P_"ȍjy!#.ŋE~_uCwZۊU^b›&?ߥx /T*}V*i2Գ.A\Ĉ m5 %M!̓QTgc_"ŖbPOQL,kJ?q&3ĸĴ>@"#$K:RB"~I"TB3E=9:;-$ɇy tZW^ԱC$yt.E4=A}]Wt_8(_kg@E/hjתL;} .3"ijw4̲EX"9vawG}:ӇަyL't:+^L6}z[M?K>oLjeMu>En]OS6}7} ]O(wO\mhL ܦ msnG2}J#o|>C1|>CQ@M!m(DݦmȪߦ6}.Gd{>k?4}o~˺~B#ckvBN6 _WP< {E:AWB q*t^FvBS v%:'2Ҝ.J`*8Af֠R&h,lX {hɳJ1u!xJ1]p۩RhP'*Nt0ѩRp 虲9U]`;NGܨ6RЪR\0!]Hp2:HSVe 5E 2,SHJhk.ShMU ]Y:E ν_cIk."g8}jħEU2Y:UHR=[~W)r[ /MO&?Wm\?57{Ԅ;M=K3ˉDE_N+'Kre|91ArcGM(?_NdeD rb\_N/'&_N~/'O5r}9=ŗ9|91!3}9Q꓾>ˉtD6g_N/'&uDwrb6PKzYCiz?]{>6NLI'>&QbfӘllRy?lҬllRy?lZ"_,Fx.Ox.x6zXLJ7lsE FhC0jc/Xk@F cGK/?^5umxd!T}ФEPР u: vIG$TA>p`Z`6~a ICM $s pt(SD%Q@A6ZR3muцUF7l`:%8Ā4=,4.5%9k[Jdc]I*^!2p9739Ka Vp2I*OV*a q7 **bP%RmtQc J=1BE8\d$; OpÆ*"b~n'w}m *FU3% ڬ-_h rVIи>D:ٱs7{~G?/ӵz:~A߸OOFQQˬ8A?sci(nCރBGGFKllk; N|?`Sov'h퇸AJ=N%mE@KmEt;?Ͼ"?QPG_c+FK^#+%qkV>@gSS| G_C)FG_l*Fq5W 81 dfƹ裾#2~;_T5-6v :zlWvrpt5%0U&-n.5lw?Xmc7//OPg3cEG{_̩tI33F棲q~իPii9\nj԰tq*F͇:ҵj9Eub"kBi *&t^K}6^ U>Ԉt\:Bu=TkSc*ѧ,9>eHG''V+;y}STA lꈮ\:P5s]+~:%QmBGUQBmP;Sٙi ~-{_ܽ f6$Sr LFB(zLp\T."7$Ӡ@aeRmdtTwNAuviJ WO2gl%KR~z<0hMlgNgiY=4>'Öl ~`9WVxbմ%]YM4<Ӌsݰ<ԜP 4jvixuU WjX-#;ufմY iu9Ă8h^l\n5pО8u6Q;߈;}Qg|M:.ޤzgo⚧k.C?>EW\^u/Gw-jlڻo݋vŶ5}FD}fVfL|gd9~YǦ=nRw_$_J["zi4M{ڶg 5XIh[µ[K+_qvQqe>rk8t-r;8tmw one>or~_4G +#Mg5X}ir[},ɡ'3WZC<6xqdnk g2xt<<r>stream x+2T0B˥kJj endstream endobj 161 0 obj <>/Font<>>>/Length 26324/Filter/FlateDecode>>stream x}]mqhGHͮ| [u<<l OYUY}{.`pL}>2W~\O/kzy??/C}:^RxO ~݇kϯ?G㥿|עVӏ/>~|"/c6^ө]zgi|5֟I N^y%ϞErE?E>igU޼JbR>T/~߼NK%}GL}(״^湧>k|!y5 6~VS0l+U׮/?_}Ery)چ~W˧&뛟M֑7yyO6roƿ?W}Zo~Q|>W8oվ߂$[_70r'cʛ7o ?-?ȏ:|04> OF;_Ðλo~wQx.˿8AϛwF˟ /_Ͼ9B5߃<z˿_r?ۿF_x_9ţ>}җ#t_9E͟>kאt= /_=:z_HYq}OO>;\?Okq{vm?/gO_^4k$|?׻zY^q见 8;g+7 +dloopARo5kF??kTָLkfƸ>4>3u>suC^Q^×I :7}Bֿ\ÎR}_?}gџj=|~XũGbo_߿3÷^wq|iN8?Ոj}H+͉ Of_}gϽ׻^r/h@ԁZFSF~h"Z-·47DIUdoU?Tϯ$^"GdM/0C'5i&ր1[Mx.pL_5=dom^{n;mw=^O=o+I=x۽ߜ昩\j۞Jn[smim7&QO7F|pB֡|_;rIIe*N9ԃ ǔX Y#/OR~L/)EaeWJxB!նY51SU3Izoy CRmO(#®<5zpn S(͟z__`8eFzҪòQڙ\yFs%NyUo  \Az敓4c_G iGOSg4Mf q8z$qqi/M=U3BTV )Dƛ¯OZ^xF7;5z3X{͏=B  1[FE><YDD)!M6QwQ?ӄFGhiDa*%}ϖK*OiE=JV5k -fV'E;zlqd,Imzg&nN,OlJ#)Tz&lJp F$8nnUiPQ}ޏMG?1M}O6*z"Ѧ-ʱ/{l*ĩ>6U%qMKUXDZ'tl*Qnm*e 62"l*!#TSg86aJ F%Q%QQQu}fFcU]_q*ufvnU] 7* zۦR`x׻LJTX9PSL*UIlRcX$>fm*U==4NѠ845sc!*ECN}Uy+~oƿٸWF#J>Èx>%h#EC@ь'X/y"f 󑀢O0](S#f E Z"f|BWP4kP EQh(# (FUP"N}W#bz4E U( HJ,wЩ̓Y@-#4JP)P5'_ʣ^=u{:) AeQAݢ6.:jttS@P˞=]) AeOAݞ.{ ttS@P˞=] 2fPAAu:,* [FePAݞҞ~=m\2fN?99E\tseOۘ6~1tgDAG?_zKܭjWwM5dN?:=.i :KZ}^YKOx~_vHBU_?c2 L\ƬȤ?=jgeigGbؽN(T0(ַq:3xai.vqQT(;ɰ8-=8pA_*T-ﮘަ; W-~L6_ 1Tsz^Ds\_*F*y_U+7z"$Z8.Բ R3AJ4eW.2JmVb5}m^*GkD48ZEE]4aT$3,nCMSMհYe?]K'\(w:jIGR+*qTQ9P.Rzl@ZԲ:p.W6-gpTm3,CEn ZKfsn:Ժ4uvpMM,MubCf'2k?x)NcΎ!kӐC1М3]BuXf$`/S۱; mnvlӫ fvYєLff0eev*LEl7;0+9+0sFS җ0G;Ov@ NÉ ñ4vӄ} >ׁ4o~nx]Ӟhx9NCln8G0;Eevifٺv f7zN,X\[f\prmM8MnuIIvQbա$X]zү#Y MMJO CIY|M{ "ؿS?aGwzIh?:E;:y ~ y{:LEЭI)JV Z=V O{=+fbv@Ֆ*GZVN@w>&di~۫W1űeW6Rlk[{]g tXRȯd{u܁JA_<,yXhc:cRG <=Z3>&.>F<&$D3>!{PcñZ!Ǥ^}BwcPJ4oԗȪgz2w5?YPߨw`WLckA ц>l?yp S-6FӋ17'-eN_ gQ\(`6FEϳdG;!-/SV< Wi=80%in8 iik#Tyt22H5yMjv nX[0% +N3=vènt~VP`\'3[B TAE ˢHCC8 8x LlcW.N[G?t 2HJ]$mQa /33;uv,< MP K*YtTI\ нSMAXo*gQ\0`gѡR.֥`̥Co#F(x.-ͺ.Ӡa"B76f&\ 9ؽTMT}z([j )~DǗ'3a,xg΋f0xzp%1d9aǓa5P5aY4N֙N\K1}HAHa2`)>)E9B OҪ1>JD\ OBNa E+G?6TchG?τ.`skiEㄢD-""5$q'.aait +c(k=TޱWᡐ:d SB1t)R%TdN<8<)VE /'I}v!jd<a0VsJzfλf>f 3$`m/0zqv%t X@,qˆx²>#m,j0f2|YGf 5j%R0렀9>`l0,K)X+C/ |(kЕ,`cYgD8X>AP7rF2}oHA nmo$k@L?6Rl$k(iL?}!bCYo@"h ʪ~$ezlThCYہ2=T$l$TtLf}o(%n(nHei:|;sfD>lXW@*Y2$^EVEɍ w&${lIm85(r!NCyX.0%+JQ*֨%]m}ڐ9{Y5XG717t$Y[4+zd83\BѱxL1/Aļk`CP ۮU!x7pgp $Ugeޞ9p zq3hVRCP$xҗjrm@x݇ќ$;wf4D7t \*vk`0G hpϰ aIBu~qj,LPďBt9'# wތ (5ć-޲;dB%ңq#gUX5BsXr!~Bq%]CH@(15d̃P#KAJ݁iF8$B:YJSQ2| c3R"F=0*r#D=@VO 70#D%28 IvD_QBt *5kc@ZÂƆ<Q :,Ho T2:aC & hJ䈌P9zTnQyH>%HfBLؔOoӃOi0':9@i\: ЁG6TA6@Y n}Tӆ^ +j 4TDB[*?QwBmuQRBQQ $w/j#EBSS &R(qj0<8B,":҃S(袷rۃS w`( ŔM667< 8j)n]sz[,҄Qz';=r6 Kb5Xf,&b@ 9jIWa#Q3AFv$I;.7AB,jcDˁBZi2,;jr21|txMeIH"&@)-Lh%ߋ~=(zW9q橫(z5f Nz=* 2*)M*=K\j@.@4<%PxxznHef68ށ]<~XY' @SVaLPQ3=FDE%c|hL#UCT)Kۼ.@3Q`F lo-PJF'#2;ig Pp0rgn ",5n[Ю0-`WqҒaB VUlo搊l^*D_0b_h4Mfl6r_Q*24(7N7U9-)6oU@oopg2z!q=~Pބ{G}VAD:uiy[R% HcJD*0l]<THS>xjn6_- F@Svhk('y#/;DfܯH|F*#(\xޏ AD̰_;k҃mhHg̭ć )~vIQ xfp҅(yL~ArPH`tKFZԕ1DeQd18ƉqĎ(G 7j}gD] 3>} Bn@(#Jg@(_x@(g;J$@`o!;giPFF!|-PF>!>B9y;r B9YO [<"w Br@(#aAFiPF>!W zϴ@6edplm#s F*I'A~!Q > n) B-ӌ Bt2Rd6 #B6Ls!r;rBӻȝDc0 4kDc6Bq@^4!wdO6G# o;lG&AOaӊ`<u  B 윥B$|,qXа B<Џ; IMB!ڎw>@OfD`Ll}Lb!1ͯR0˜Y`Y47i3/*d=8=MjpB#N2x3o)[za8>b$K@@o[8iE(닓2RS.椈Vչ rYJ)Y]-@caY5]ә y0;w9Q!wtŐ3\/}`4G4).͘PŌ!*L"3qގ)4W4d1 -rB}1 WSCH^JD4üԜ~zG īY S(uLyyՉ #` :,jTȈ2k+y 鑾ОyZb&hg#cE wu(f*1yVXeQ->ʕQll݇̍"ිQ8.a|Ă%dZQ69?<{O (P+9KA (=KB~Pl3ah0 y0,. 39؃aS@,`0)`XJN^P-.^F"N#G(_05%F=D4K.SqX\?_ `sL 3g4asflYҭ6sOi.x?ZFG@13&@z1*& TJPV(B`qB4ǔMCˆX'W'>:Cyx8MZfmΛ@Hel`W:ĺ 64&/F}ؐ}1.KaO&ܨ׬)*Y!І3DQM#$i'v_A>ŇjA|L( a2ka |6J!;%2Eb>1~|~DOcT:{(CK%K,"$4*㸄+G8 C퐜ka̺,$L]EM󗤣p*Oh@]]ii8qt : J%~b7Z2&a.[U'K,:kFvK309f@x䝆B&Ɣ QGՙAV#CQ:,& *=aL(yD #+ 0Cah1Q F?i0n@#eS'O tk#AӐҦ4Αkq,>fzɠ^[c]2qk$dK-5~&r15l-AT1w"03 >~^S/y s⺜H@eog C@0wo#a(QZݳI31?}kt0mg2Ȭ3k&h #FahUdڝ<,31//#N)޾ N8|.Ok::i톀wT:x-u]F嗚\ l:ΈwɍwyX+6bqm]礈wPb;=ՃrNs1m1H;cm٤:xLxjp;xJ{0ީR|;cm㝞1,x̰mSG6 7ACl!9x<;x3]|sNsN=8q]n-h.S$ S0_.ٽw97).wӄD٪yN.S[?xtZxX[ܲN;j+Nmͅwd]>xG&r5;]n; g8kys~N+w( wH(.{;0-KxG&Aذ;nU lK==]8x5\;n4f)qUL&2lXx'6qF" C٠Z'6erRDiN[Cd>|RHB ;vIUHSMJfSd."+ TnB)u1*L`IS/B+"u@ ʩ-2J@g$n"o|i>B) A;մ#6GPX\I$ HB<`Ѻ2 ]yCrym$|Gj X \R .mASGI㝹bay~jtgneVT^DAӀ"^Hֻ+t; ?m}F#օ@HZ@  KƹHP@ b) X? 7#B"G0!< ?z7 = BV'T.A(Ea?܉tĠl'cB(ldԌFJQdq$eB)dSJğlIBѹB8H 6I? ")<'E6 \g}StefO$!/ƒ?}&_hD_Jl8Sh y:gh9O/3n3:< hn; 4a&  }E3P l U.IF5А}}7GAK_uy禒{z`a@vqIQ7CNxi%) @}5%EO.z-uIY L*L""?H&EI=Y(dRT8ArIg֪%eB 7{Rڍ@ jSIYMKz\aoYi];ҳu9N+9×g[YU Ie -J} ,NtFKsO5޴He((EՕgKoP_ZǙ;Hcoig a"?9guBM +,cc 8]l/ b -bé7nuÌJម rFU~:\md3:{^u+ŐL+6'@sBsꭲ,Ϧ,@ٙ2`s̐ݗuFE~V*~ũ\%]&,H#o\BBF=Uebn=P8TK^ekfQg1pQe3iE-Mxh<@ VT ۦ+q^V7OukE:F#lX߲ %\,w6JSLVLVlc0|UzI?nH ]qkQ<뜶6oLapybZ ;:fj1ܩEq}.,X$;D6 {Ʉ~ٵ3W(̽ $v!fJ K(%. ਟܢ&0\RX޴2($=q&ǎ((Խ- b~B}\\Hk6K KUDbzj9|)W(pbXCI`J 1\#ynؾ!RR MnrA)2o1 xPʙHA)2"JzQR(|R@-B))A](圌R+70 xPʹ4K6 Q9"4Zd@)P["c"6ErA&<(RQ8 Py82V`<3TFi (Qa(F)c"7GrF)o9 QʘN2`0Tw2pA)c^bS6_2VSWkiϾ|6YL A=u󤃢s\k,bUM=s&˃XyNU E:gm6X3m7sO{.. 1(j_dyPjr2EE@챿+mdmo%r {|^W\1T<ϳ*ˍ9Z sg 0c*̜!Mk sgQ0CbcFJ,f^ D ڗ4EY854 rg`Բ=?8*ȝ,%SG38jU!yngq1K^FX> A$F5N9ϳoOHF+9^Ãu 'C\φd/O=$Pcz5 mN>O[@%={ӲWnSQ7,tYȥlΈÃ[k;]d{Ƞ^Lp3@OQG;ad{HgK?[@*pG>J={pG,~l1݃;p^H3= =g4q?O_Cp*OD/J jU ˉdl*Avr%ɌÁ  ˛ pJ̫,9 .'9\݁*Av"WUrP%M<=eZm>pAeI9{*a~2b‡5ft']b5f\P%OfLƬUD TT XO P%NRUP%LPFhz{۞|H3@0C1߃RP%PJ &.d(bGŧJ0 vR|ܞT#@0E1僐Ir{>bU %|ՊP%OHJ|U%&3 $ՇVGɱaP嵍' )U h=@ DQF";g}b|tH $'TAN(17T SS>HՍUs28! |cȞ2ā*^JLf 9! (7"TM/["@մbH(yj>ue|ٸW)$9 xJ!RbJoR埽~uN 丏f.[ӂysh`}*]T=# :-GQuԃ괞4ɿ4RF@%7KsZr(m$9-șK\F'֜֜$5.#Wq iqO\F HGԜ&2e¤9.# R2AҜ2/KԜfq'j\F țK\Fh<[sZ7׸ Ceyei/@5渌K ӂ9e^9-L2Ը@7@#l oQs:Cayei/@5渌^I iNq[Is$k\F HK\F@W2A\tIsԜ2A<2G¬9.# 希@7xV2Aޜ2bys D5e:Y 8-HG\E!EiA<*9"$)"`R*vRmH|ĶZ]@h{q@tE%[$@Ee]qA6 )B S c؈kKE`=!B YkVHVl2V帆@-!Rᢸ #{s2zF\C .@BOkHȐq  2D%! !cH[w !#2Oq b @  M#!)ͧnH[w !wrݐ 11@B6+{ AѸr|5n\C~Uz$f3}hp\C@@k,JP"$ERnH ̸Ԇ$FR$ Aj5! cCc B踆ď!c9l! { ԭ[B!! ~Aqm)V10-0iU"$4y];bBf K&1kI̹~f%1vIb:ޓĀrlj$F̡$D;;QNbNbF$wȅX)$$,;`Āx%1t'1 )I I wS,$I Hwi;INb0M~'1`)I 5I XwS^I Xw yw`CޝĀ|'1ؐ$w`Nb@TLI wSg$ bC`?ޕiIb/&1d*^I fɯ$L;0Đx%1 $Y D;r+!QNbJb?$$L;4Đx'1ֈXPƻ_I wӑ |`EޕĠu%1Xw'1I VILf]o'1%$wJߝ`NbP1 ?';;;.8} $fߺa$1Q;ӕ×@$1[w[W#Xu'1X;4͕oI pJb8Xw'1̺I $uw +ߺߺy, I p]I $yT{ uw9+|]Lb v%1I̴6$1mI oI o]I voI F$swÝ$`Nb0[w%1PnI W9+a/Jb{'1I_I u$;İA~AF-$+jİa%16$"wC@ NbHD*I 0{%1Ί Ib] ARch\I Ԧ$D+h8_$BB$1!!yh2w淯??_|~%Zhjo{?|oP~|=e-1n qO]䊿Ȼ>PG#qSmJxQAsj0L! y@̴I`0Inx[X1Uo=/b4wɮUo-9ޒ3A(TqDeɢykTve`OҦ}*e/Q| {8٩p培jr-lH  ya^k{Y S"<’nŘz*>9:|O>EWa )SX/C|Ͱ}1Am\? :sb0U=M]u yl>!D6}݂mA A`hA*ĎZ͇̉qgmpm)|nMPT5"1SLd 9cVB?I*{1(0].1L $~!Pl I@ƅJ8­bo IP DۉG3ĥyP fIsäE!ԖCzTksރwd[,ʃ:F@fYK4ć݇gL 0BQnΏ %R m&A-m[ ؓe{/k~`]]#{Rm dFu-,yXjѵ`:tz &jXPuײqsN+5Za*=a${r=ڏ9ap i 8A8Pn2QAw/A~ﶭts}.O\o59k1> L9;RȦȣ,nm`ofU{!bl;(4jY+vqs'XR6-t(M+rE܂G0 䮀[\vQXĤdҗ&"OA+p9KQu"az.ĴAsWoͤCMM}c.ҽWD-𐭱O2yZi *Um ^ڗ4@ p`7ZwB[\nXM%.&H^(B1im``DXo}vntm֒&){['/Fܗ׬vؾ yeܙ󟶜^?Ŵ'} DXĹYGc".C1}|!u24m6QKYuZ]|9#7C Wjvֵ1SvipEUuQ6\?Y'j(>Y>ZI w/9J"RDRM]5rƤRR!yVǽ.Rnt"ʡLm̶, JY̯KEWx\ldBEa(Nky |>gmˊE(KKTL$مV(klcpE=,y;;9ivFbs鰢ν㦫WYy=y ]{m4VѨv_Y;/4hm1č K&̄2nDXL~"ARXg pÐBwΘ*b~zGs3J/WXh6=LEF t98lGnuq SE4xk%{Od-̭2m.\ +AԎ) l<"5 |ל/T87U_:C MNl%,r4jZXo*L pϚL Bcq[.쌣w篕\|[غ n%'礷KX6[NS'Pf7o}c*'\L$Pílj9%=&{&͘pͧk&IYN#j\rDGbC"J9 }A CtDr҅LRf;c$%|E3R/d2pI2D+ [W' v2ؙ&h,d5+N),(+ds jiװ]VB-c k8]emmB#ΥLOě>ulA>7CnީKyyxЖ>wn1~c%1u F5J"뛙]fj-9Lo"I#Yp 7H8-i(!$ct r!3ZaZ4gXfe?+0iwڙXْ-6BrXA*ZB"+N|V0E~5 m^y&h25]ä8v XrviR59]2k5 \]`,ݮAk5Tn pokv N1A {2v 55jmo\DnPyk{]Vݮr |q pnkhpkw5`nmLp mkr :]C15];nv~nva[k@v |bp nkq%/]C05z{?k@V\/rd2 o Qd" 5jr5d*E5єɚ`F@n 6Dd6[# d2csPJl2xbsPzl2\<9tIlf 36n-6Jh ZA=6^ '4N AZl |`F9csPbs@AO9dd2csPհvf5 <9(j=6 HlJMk{|mn^5fbzE{hM8Bn e~mN.͗#Lc|:ҢvIW7^M Ƌ'|{`d%Z/\a._(oð"d})Dg紡BPn5m(ENZSa _zH}MŬ 5dǺk6ˇ\_Y1zH;S@k1sSsy35EkptӡهEvjv[c ܶ\ƣme7Cl[dnޡsί}6 ͢w{tXB&Uq7M|/SK@Ou095eБOӦx@/淹*Pk!Dp$BwVAHhoiK2 Em K35waPritBFuhhJ᫄|PE>\ X@GrAl"In&Z2&IfU$IE $ s 3G +֭, 1 ɚ\/$+1MuF+"RBcX#94P_L0o0YQCP=II'J&"0U} H2?4?AMN+ip5--nr3 ܠh؞n[g=8>PxN -ǛC更8k>s8~N 80ɿdJ˙IO`>\$?21_̒'y%H"2 rpPRI?\[#pzGS7NwEåQK# ddZH4Rvc (QK&#%0hK#p[$#EϜre)'p.Y%KA~$'JD~$r KN"cKmH(F2%j83P$jϗCNń؛o}_A|&hUUˁܞ\^I( VzA P6 y &#)FpmOcO.pf~㝡]7iq{nvRܻN3?f:ީ{a:^7i>] ]穼cNK~(!\;!]>{x7Sofqxj盥 ;y+i]XCt8sb;XL%6%|&W7GCq[67ɕpX`fh*<ѯBjC l7v;M Mn*KtC-sHg˨߈&i QpvIb$`!rN_ NN*wA7v_{~XU|h$>}N6o~K[~Lbo x,,)e"ybXñnK_0QNlʐz;ɻ?Hxڛ;i TLȚlgIg1H7i]xaLˉE|L #&t wVg,b`fNM p2)Lc& NS1Lc$cdU ?$۔;BflX*&deq*d}4!/+.0k;!2 /~(3QMhT g$b2ƞ{yDkkmRE!ɸ>7vVj%W86 j"ВkelHABd0!k=ށiȱ rM211.馵 /!4aH ޒ?7~ 99oܮ Ie-~2 [Vb]jH!2ڔv? 6ydz(Mp>9UD`~~Q!h‡l}iTW =l}1T=)7>t8E͵?+^3K}P\da]'a9p#\_J15LOSmN" e}'B0#fhvK"Bũ+@'ö6,besI$(v γn# YUYx~uyQ BP*@$KWh}CxF0\ 7nXnvg/$|$Jy!( ntъQnY_?ϯP&s6j?~mVΈΠ\7sަIk#nʤOX?mڂ 1ymZD9nԓLvWX_ Mz~m6҈))s\')WOJRZ+#D[]+#va\ i^ NzWXlV='-D!hk#]kK#-P| ֺ60&Zq"z+bOXљmD$ZDh{k-b*kZyѻΎ(4fΐq򵪐gתB n'teS9?86++ׂbqNtestzbG r8ke/>stream x+2T0B˥kJq endstream endobj 167 0 obj <>/XObject<>/ProcSet[/PDF/Text]>> endobj 125 0 obj <>/XObject<>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 168 0 obj <>stream xZ[~_a*cEIbtw4MN$+[$f{.n΢PC;=ſ/ mъ_Tئ^W\*VwՏZ|4kEnQFGO6zY"O{Uve2S#߲X/WvYF?%&QOR:eJw/mqqo8By0U0m ;cQU<4j7'˂8SC8qW4*r{\f]wa~⛘[wK{{J;ۊcG~P7ajڶyKoNTn?ӲsU͍k@Mi ;A |&zTP\xW?c500]렼hÏP[J/[jGI&{L=ϣ:4Py}Cwwi{3u.N43io(00Ս7LkcьArZT'j/ RlFCԹS;Tm;eM5_䞷*a5h"+g`gJYU%;诿gs>-qgM1 |۪͞Si ox|:6bPTɮ7I>A0D% P^oR"/: jIl}p_l>4ോ¯gVvՎmm%`p[GD; S%h\TR/\;FkHaDE*^8TXndWBS)TqRؚ nyp(O6/>>AYЃ$zg*C'OXSn|ɛAO4aA'4Ou7&ӃNxBDKy\LPK:EU[s+0'auV3m}{> _YqX ')k:iM fQgƇ@NgEaY+L KnmVCy_?#1gnB,ٸ&E*yJǁ`I"3`xn*"P^8G1a =,N!zv e"UG臨$ ZJƩ>'A/F<3JE/]:i [07 %DH(a2 AiR!LIRD>ROu' CęK> x0 $HBk= 7 e1daܷ7jDzi5G7.Mq· 0G)8a"4?VC{ %Wީ=.%)_%JJyU׽X A?ZLqL)8&FG=T.1 }dRyGGeSZlP/NeQ7݉r,pXH:!w9v!@`Ե L>4F Wsme#],y/),x}T͆=n]S:;t&KOLM)t p 8I4kS[QLݚ_! e&iy" sUojvuX;^07 k<JҍKL\/*T2@-y]W ̐<Z? \r8ͳqζ45Kzk9/_'wDF vn`5bzV ʰ;ˊb >'}784<"\1$ γj&.Or{~γDl6gjL_܃, 7P^"T[%'qL-m [fX-ùM ,\l8f-q b-:8KGQ*HU'6;czqy\q g?W^qq%l PmꙠ65DuR-0 endstream endobj 154 0 obj <>/ProcSet[/PDF]>> endobj 150 0 obj <> endobj 151 0 obj <> endobj 152 0 obj <> endobj 169 0 obj <> endobj 170 0 obj <>stream xmW TSgھ1[T;hb."D$!d%aHI "+bպ+j;mg朿$7}y`0372V["apE\$LxaUY`&t89s0r8RYj|dxD˻|fƍ.]q'DK\01RYX;swLL TYDKHX8_H8eWdLL&Mvy=kV2oGƆ&%LE_[`jD*+aw➤Cz_|WwoUk֮[m9-`^A[`K1_]-v`+0wl%y`jl`{Ou'ۏbN6`Θfj9`b -N443w1W!G`Jl">'Jr 7N6m =FbTWH{2PUgJa%fF³ąs5@|,BbxMaV"@c$L% ػ[0S#i:;i Ņ&8 т@'?[-zSR7Ewlu]"{>B,[JfSǣ0il?^D@-MFVA(`&?VElSHhN+t9;_- ?,!2#Ծ \:3h`+"7pQ3BA6y;]nse!g?ȡF5a;I[7_WO}8mh Q-_('Jv{VZCãyBS,ʽ\U oNv16:f*!$9yrFN~3tBy'U5r׬/=$؁D,N$Ā +MnLn3pSvÒ&ofJ xz 2<2M9e"^FBe"nRjUjT s텅 Bڳ݄Bg?c| - %E&`˱vemjh[[EИYj&ar>bx1ȿn C6Yz. {kS"BXaa$"@ȭZC5[ˑ6JlJ)E sKCsFq[=[FNN<֗j:6g0lĠ<O({Yq;t|e@rH\<* jfX[q뙉wή;}yJf%:.!:+q}$?LdRiMўX+aU[R5#AO ixVV`#$A"J|uA2H Xy :3(W=myrg Iʎ.}Hz [hPHJ^>#o6EUx1xj."_M`d6knΞc,FZAMj-Fp o&:ȩASkq\[^) [JGDn:}H;ad*tALYlc)[P3eL2==C#+Ċbl!Jppc_nd\lEUxgnYP}JaPGgڍ254ANJR=a2ǥ!mE)JNT$̆GqZޘmΧ6!|6f ` "/7-N0"hcʰ2glz/Y-bva/I;"B8R2ň~Fe$a+ťEEk{+[WS?zKyJ0LLoKU? WD(zAsJc*)閃q SG6@r$34i9pTl|\t|cSƦXv}UO8s꾃XQ Dq2⠏qާ=Rz+Zu04EWG4OGcF]֭ s;&z +"Ǹ{\y*\Po*g tD-b@>1-]akh%6奕 $=keKK"J]p[~ ǫ;?yp҉HeTsښrA6] OCgOUןq=.~NAMEӋɺd bq1 G]ePw !q>.|)Xatmb)c%*M| .ϝ}޵h)M*;95K{Ol;(Ᏸ-^h>ހ D3-7w|dSC5$ EEw4M ۿC՗VѩVv|'量8e${;Uk@cq85#&󦢛p; >J>a$Õp|Rp'6W 1)fevC9rg!DY_oSׅc>?? Pk 9t;Ǽlm4B#줐c(EP>Sij[rƙ3_V͜ab endstream endobj 160 0 obj <>/ProcSet[/PDF]>> endobj 156 0 obj <> endobj 157 0 obj <> endobj 158 0 obj <> endobj 171 0 obj <> endobj 172 0 obj <>stream x}XiTS1dP`M:kBCyT&e琁$@K @eTĹZ8Vюz9Y`a`V01#264y[|lpeBhO8,&eձ.2J߅{gcLcyyreúdNɑq?'Ćƥ IM^<Ň;/v O NO0 ۼ#'~WS={S~| 9BE{D{zotf{>^f lİ%as>\ sǖcG'1慭vb]js`l[>cM3)v;c8l:6{{`\bVX(v8=m6{L4 k,7#`[dy}:{~3g<88k,W Zjyw3gg>7'6lgcgs%s掱ECD0A}ctHMݴKIL"WpH6j xp: 𞕥 ʼn@Il/%ɇZb2ؐfH"3˚&}d :1v$OՖ䙺/x(PIq3Jwă Gɣ+ ׂ -C} ?Z|ҷ2 8 C(TRb଑*FlL7 8423h*_hڼWh./3=vy%zN ɿ \˵X+~f 3'0ʛSYiK6+H&3 BI\I3[eAB+S+S5|A`Y8}ja2 S޳梒\[!Pi>f KU{gvkJT/PxR2WIPȦLH N]Y1HnBLK #+0.%*+ĥ/j$&jS͹k|H-v|%ٹ@djia60[ݼw{jKL1x=)\!ZW tE>zPPSؐgZȝ)'v#BT9=-Z8*fBZ9 d#m(Wv$ѧDᄝhrC?x 渊Cd- Y<=#3 Ȁ (pT@s-GA7nv}M(pv[w  U}ȆYQ{$qBu'4$*FAGAt fSY&j΃]o=t?l71LPv CdSXo1Y\ce~rq-T|I$!@|X,MHx^|AEXOBbi{]ܾ>=Q8kjן+Lb8Y#+F-7W/+}wO<Gt3m2eWg3 ~ 8ЗlX+dJNy?z`(ITdt~)jSMPYS(ll>=D5AHEϹ?jOUmWaUz“~Ҳ+M$W@w=A8Wy zh &Tu%EvMK;6AmFb[D%aK8^ 9@R0ey#F[%֭{Pcݠۅ#2VR331ٹ`QBLN\6KH @1 {Y "f,h7lǗFsۇ2~55f/E")~1YdZl*^qd%G%"vߦ(I*P++{T0sqcU-Y<!<` ؏@vnc|;OU3'~䏣I5RjOR5MLjo$rPwXSD.*,WLͼniٽ©/`:=ÒvRQ7hDXVU(:"5AoqZb ؖ!s4xw(ȇˇXh6ɑȤDY =w! xhKMYm,?ߖ?m)Yǟ 4bMYȑ#["2tT-q|Z!Π6@{cP.et**}S֔~#GBw7Aer#|* 6ZXNg;$% ΄1aFh[^p8;}":92+i@F{.{ҽI))^( o|`w;SsosVlf@QxΚ2Y\"TVI Āp!)+ˤN0_f 4R=O[Кx /Ph s>fdҟ,ǜJ E Jex ꮴ@} zŝ M7W\-ՉX\^; _DUL_aTWaL*cwm#ҀX^K%&r xii~'-U.Na5q;[*[A'vw<%N5j 5݆fC8 rkŭ$ʙ\>X~? wu-xc|fM,7C5麸(A gO/#)ǾOYr)/*_bX U܄OS/f ZMTXq㟎ͷv/ sJ,@"OzDDT%S7 EbGlo>iZMc'դkjRj}^ܞjPOP|U;4vQJT*X(=QZ Qq1lwV.w-,LIGw?xZrSfmrB=3':{Bǿ=\ ɋN۸-.t0ԛ^,=v(,:V jpk*.GXux-dTWBBM^Ǖd-rx111L ^\jr5L#dV\`ϡˮ΁V7 ]J}YYLzyƬY#)-+S[*CBWhWhՉ51Pzi/Ơ۲ &pP&aZ]qq}m_e k"vP,pI-rb ܁BA/Ds_k /U%P8p7Btq`g7Փq)Dڇ)qDFk@DCE=SA?wL[P]\n$ty,A?!;JQUpFu *Qern1jCRr*jʋYO5dt' 8%[X9,י!%uKwP3 u ^ 4*{bQzN(G $S*(8+' C`9Xnt]jI ŒЁ6;;uxբSo6SV/aLmb;2WNmsA8@ O|;/$_=mA.dz:Jh1D!]4xӎ+l2+ZJ,ߘm2(IwA+{nˆU#ɗ8Xš݄fQǃaE> nϜ./Coc-{İO۳GMn/>";?yׅwr@~G7{.y0>ɑS=o97bOPGY?1/UE3? gt4ܰ -Dw?ފ1U$ ' =/K&}8Rŕ^^oOmB[yO|hb~imvicr4cwK{RK+\oOM%~=mf~wىvG4w |m/Npn؛OCN'xJvO#鷃e`I}]MmຮA['N]Wȳ])\~GqJUĵ RjHFWB&d2_رIIqIM- u- Op 6 װ5z`aX{("vG9W6rCu}4;EPxӦ?qy N{443& $V}X$KY]"ёY,;*-P &cgJs(9([/ǜ?{w0nt(ZTk;|>yѵ7ʒP ,BgޥؗA6zJ;C~~`G|zq]^*Ey4o~C~i6ۃh/(d/\qtkҕuD[_-8wrp_唗3ͬ/((Xf,4fa endstream endobj 166 0 obj <>/ProcSet[/PDF]>> endobj 162 0 obj <> endobj 163 0 obj <> endobj 164 0 obj <> endobj 173 0 obj <> endobj 174 0 obj <>stream xmX TS־1D+-DmBU['ZhT@ a&$y !L28"UV<}=wx뽵J7'{6S7;Bx Ou‹X@!"b/CIl&RŸp#[V‰F o;UjxE&Y!$^"ežML%3 \†x1)NSu6m68r*i$K}NB{j`+g͜9m_p}/Z0|;V0Gx/ Ό2_^}y~~Ͳ˾j{(L#h&5 [$f* hȯ,4JT4+bcJzZK 5,c FV-L싼O~;)/-T/AҪ|3i% 3Q A铵m|OpW+(BMa ]ď(CJ;U4 i| >&*HJmJt( COAXL%m\3(g(BC wLy:`2"cM8P@J.<'hs4\Θ)"eYpqNʮ򚾂_a>Ġ#1h~Cߣ$jb ܶHH}ODv.cpԵbyoc=PLL$Id"*8G޲K )`Y^Wv|#@y'tJ&uyE~ } /K:#n0;h5UIQV'00})->Q/>#.P Jxژ.p~^h8h_/n=q{%Tzޤ0B4w ڀh߫yN1<{aWzC-N k/w~ ~_E=uWH\9P6ژgSO] дCkYÚV$JU5Y'B%`1Jg-F6h>hw#NH(p\C +%fRg TH bʒ-MIG87=rtؖb K0 wp##^t  堚.>&љp(SU2~2GZpVY>NfVR+U` =ߢRnѻN>{_f*Ks+}45P)g0`]0m DDLcQi\\*O7TmmKG'K2|Cr 062Y\C }߄>зPY5JpuPxHW,Zנ%&d¹-fJ"J AVnv~6-u] 4]?&V')t@l@)_IJái9P )/-"F Z:Y5::-fjcڈeh]a=Cq`¾Snت3Ly@[>(?MA]˪?i( P1(@8'VGh:UhTH{ngwUc_L X:V8mdw(T % џhR'v=t{% 0X]SڞZK&&QZ>xuعbq_aMRXE{cHKīdiI.3#]1nT䔁М] 1!mA`0X^I)W_l}]ZǙ4|j8y6^p"Rd9@ &'ڗ*s`7W,ix/p:&#/X߯ETQn(tOiZd|z1tSk -,>quv;Xwz\b؏fF!U%(aGSܬ.jQ]YCmoMr: 7s E?aZx QUi9Yɛ Q(28Ly RQ $QCe <2]M@:Hʋ )G[n/H2v>_uV;>gA'&`Khv>ooaԆIKd5)ǀ\7C@6.^~ OTt͍͗iw_f?f&p5ϫys!Lm4:#By( 9iQ6oR`J4]Q~م,8%$U4+L~‡?𜠊JYcfTR"PR! r1凱:R˰9^ N:!ى)k Nc {p~hs@kIqhhjW:ʲʂ.9ՕUiJJC.}EM0\6~POO좄v.%41^d`t+:xl @PS.C[U^%uMqQ~`4|7B#ՐeHC)x* eUUtN9|qgAs9邧d#_`BGxW$t,Ʃ)[4x&KS%$L}GnY;Ew^s[y2^(8#斮cqUlu暺wCs.$جոr[фU[xTBFƒpiȮi+WGOtx`u)jRX/5 mnSpa$dX\\?M?D%rē߲@hwg6ZQց^O%cמ\XSS e\SRGXL*4nba6wT.pmߦ|9ŕ*`iko,))lcN=6MuV&f3mCM4PWl;#)2- *qMXpv?`߸\A5fF\}E7m >p ;c \>HI9u__k4o _8l~pLCWp5)`18k$h_Rp\| 6,}q6gUpL7[1cot%fzE1':VCt&B}k0IHjMuMքhlϫ:-, ~U {0'VZVR1'*FE}`hqGzqi0 l^~f&%܊Jl3|G3R_>SdH@_vO.nxr.?`13EZgNgObQ2rIPRd:\/Jzϟ8xb?gprVL$.+˕sj{8w~S%*姃 :--]#+a ̏4EKCS폮 6Ly%&"s3 T* ^mXg*3O{Nq31> UT}ZUUىDoxfF܀}̩VC'~ޝ49C؁tl7:6}CA0x?=)"s+rh-S 7{Uj r/Д4wB۪+sgO;y1{P AE=98哧,4l@^IYqv@Ԇm l&h^\&(\e5FBfЗjb%(^z$3QyQy-(8ȕ{)@ S9)C<\Mkiә{ٌ-I:q@´ڜ|Qڱt3(ueG9u),6GԎ3 5:j+[ SJRw℃c-\5V`"2+Ssp }и8ITL-~R#,p:f/Y 򋻾tH+V&2p$!6o9 [QUcP!r~XD/޽q]6JQPגh&Nz*;gHO;A3^uh1.j|g72y7"b" V5x!v7/>K?AT`A.i $B̳3S%VIr2=j$=j}E Q$Vpa&b ?rny?>pB{gs/mA1ob( B3S3wՇ=wlھSQfH GN~p?p젗T@f"gmohch9Ee94}4yzϋ52g@rf6Mp+$ՖMj{i̴ӘibC [8da_Аx.a7/㧍׬ך;>B7Dbla},B6O{:dƌ53fI endstream endobj 175 0 obj <>/Font<>>>/Length 19438/Filter/FlateDecode>>stream x}۲lm~ȝy<*QMRTy%JLrdQZ YfO^910Ϗ ?}9]ۻ|_x}7Wz쀿ݟeZp=߿ӟȏ_|:w?y~}̴e>zWzt5!_^cq}usYz{~ϵ;}ӏ^#w?GFק_i_ї?WZ[~I#g}>S?9Oů <΍?Inė_'Qv >RK<Er {H/N×?sc?3n7_ssŏ~+_s'j΂Pw_ʺVyWCLs-޿m۷|rK9L~!FxQy|ǟ~/kv@~)}?# _-^K`~~?dq"LE|w:|Y. 7|}זRGoOuoY[^_~5 tK|V^ 0V޸_'\@xspb>I43!7?pw_R<;)K>?WC/4b OEo_?!ûR&V}^|Y6/߼,MBi|y3tbpP>^+R˖ćPӫ#+mq{czclT8:U!w˭KEV_<%eҚ5)Ze1[e*xNL_wEoۗ=d.{p˞/{m1__-f˞x_z"v_6/{qi%\y.) {Pe0ջn-ͷĺ? noW{Z\<~x[^MNZ8q|"$BǞ>N*/I>2cFB;A*~lYiu1} ˊ)48,4jy01φcīh`hpԌɦG+/jB{VUՔJpyQ+(%x`7'HSwNE]>u D 19/`[L\M9u17[oZl۶8-ۖr t%0M-&ȃ8ʂqv yve5t2恉<ڥ]AڮlJY ە]W`RmۖWۗSX[n[f@^mKmK1Pή Km]x%^]x׺+ߛgWf nWۖbŐT-Lږۖjdql-L9\~ݳ7+anWRnW M+ەyڭJdr3`Y]Y*_ .P^壩YȊ]W #nXiE[Qku[` r+ ޟ݆CW.R& 4;+Ƨ%SxCF+oE`Y{6~OM#_av%r /نri dOv씚AFeTٛLmgk̗m*q{ҭ)H~/ۛUp62{Snl1ڛr?+.q{S[l{7ʱ&˯`fEuޔ.?lޔU+7lcۛCzSf{S7X9nwIe޶9M9{q@9|9{nsyiv9ު~sr6'8&_SZD젩5).۝3/6NAs\{)`>^r첨)` >t\)R lsn6_ ؜b~o=4p_Wƌ{=~-/p? y9æCv `^P(kUP48F |n$ $isF̊( Ӫv),-O:KSD{]4w$gu1ɸrT%bDەH>͢{eR eFREtAI\&R2,|ٍ3\UnYbW^&{`eό& ef| ])!l_)p@&BQ= P( ScaGT\v3L{Xnnr'KٲfejˣĤĻZӾĥ/}&9T/Χ _7%e䠆T<'MDqޓ@wO0L#z7!!VO߀x=\!y [&@eG<ꈕHo"$ ^M}!@Q ^K xYoI=k^;2p[xtz)ef4@GTLMHB"ntO?xY;!^GS.!^Ɍ.ɮ?WOB!)nkHbXƫo1:exZU߀z*𘤺bb⟿zO1pnKza)u(>Wn3,Ԛ^Ǧō͉\cprӭOD@aOJnr#(p_DU30WWzhy*.J840<=ƙ< ӒEɇ_iI,TO׿,qK4ocPz`|#$׀j.L4I]1}8_YM遅u@]@BLcW*}d 3W% М|Vn}2t.g!= B/]9뿕Xv`<4 tAKVW:?~`|q*ġp1Wëb.CcuoO!P" UZrObЫ/.A㲑rP js|R!'gz)xvh\Jm.ϸ$[Y5Ԏ9t gTp’5]Ompgq"^72)&+:Ř eogxpy!fEeNv4y՘WgȊBE1+$g\j*:}TXj°kE-)1l[ .єU A:%jp܀I`J&Bj2Spg.P.\b @&;(ހW9Nz^fmOxULv'+3f~xy/*C$5wy3 d^;YsxɂwbމZLq#f>ť~.7Ķ^;y;1kݼO 4x!JzoJ x eD#^BRl9$p~oKB '4}nQ<O6CQ/F<@ 5l:jM4/?/hJq`gŃaXU@>|+3,ox)?Axf6k{)fkbĽԷFo,F,NbnAɧ´ňuO>㙡'\{~>X ڞ{ 4 X@gX,G7#ZZ<HQ깧İ ?1}pbṧ8 ~'<oeK*ټx+tXLX:,FjX:,°,Mx+KV砸⒕9(f2{(.k( %|b 6O>KV砘O>KV8P\ҿŤ vn5R ( %O*8,c @> )Cb<,Jc@?R@Ĕ=T:@> Ti|>]uרrjl|Vz0#E|,J}!wPAs'+3?sxɞ|"u=H$J!L{Ob~[|hAde>hXTDxY2_xHdO>Y{ܞ|wY8$Z"='A^͓:I|L%aXZV$=:YyM뢭:C`S*yE[K&uhkA@}=JUsO`y:[>* WJ乧j_x4۞{"o:)fy7xsO<9d>ښ&SOO$K )OQxnqBUo'ߴ@Q&g1t%la(kDU 4OkRּg T1o)YLW6*[3bR5v"k51D_Y7H 4_6`#$\9Ȕ]&NJۢɊjR?fϕ@&F^5IK"ez'D._ZR o>= )0.#F8T^yE&VO^!dBR8!qPA NF *R gA}9Ō<`tSFf cA~X=eЀ=xExBHbd !JiյD)W\1C I(l"K-܏+5Šl_5uA54~\\fS ^xUGqH€pթWG ..HK6YOHʧ uEӮ~8D[.aQX:pʫr?곌 31 g{Qdkhʴˆ)O<@@\Ȩ,o璔^hIs;,VCx%-e('Pb- ВkdLo6FJpeF- xH; cz%p7Zfd0Вv 7Z-e+!ђvKo,M-gRVw%eHhYX8teA-ec.dIZ В5HhYП BK2 ]zeU@F&>-YZ|鍖rb"IZv-@Znb\hɚ; -Yw„酖nd 27Z6 -Y3CKqR -YM- h)qRZfT,}vuhQ(eA-Yl$easВKr7ZǤKJHFuxYؿh8-o5b/h/ {̓ȇny7^R^ꍗK!}{xY):9xYnĤd1ŊT%bRzfRRL*= m S7fR %0=vsIAҥ3V;d1!7fnTMz̤knr0:fe:̤ެD)Ju}in.${ot]h[2>4 ^-VrVjx `u_N<0׶F5 *ʜ'Rq;2>[}aj1vR:FLʣ큠F#0frhѵvFEJi9Dcu,T`DԀ 3X𼚑B*%StnYubm WYtkiFm` .wo.CJ0tXk?W'pAH-xӼٚAj.hw6Vh ;x0NB@J} 2&C@J}CMR:54z/kwcp-Cl"?p nzȨ2ڑ\OTj&D\̈́J(WDXG, _mW6ӫx[%c]j3 ;h$i^6m b h쎴xX(vF9im-@OЭ/%^-@Uͮqy`PR*ie#vRW9,>"ODtХlqX.e[.ot)ۺtxK lX.źIz/t L͡KY rۡXAe?k<責A^]8 ˲]]VRAY 2`<@xe"8<@xeQA.(o<T肺 ƃ.hGw8tA\A,e]S@6%] q<2 : V.AotA ^WF6l]2\zƃ.h1dхdX!]n&5tN F6H](g<9%55tAc`A=j]2H\ F]2t% {1.ѥ-qBhC*]22xCl%o/7ENK弆/sQ+Mgͷ>EMf>}?-}zw8\I.AqAZBT>e*%&-EY+YkO8|XQZ2_bj8dlGU>"/k-K)S났,e^kë|ƌֲqx*Qw9|ֲq8(Z/Z (ZVT>@ ke k-@ k-[SlG僖^Z2Yk88e5)p*P֤|CAZ2 YkM$GC.ZkRqT>KZkRq|ؑ,ZkRqT>̩|jVqT>d5+8*vY ֚p{Yk$GÐL֬|u֬|؂.ZkVqT>Ω|jQqT>ld(8* ZrOyYk-J:ʇA kDYkAG kvYkAG kЇYkYkeY/k-hd|iQZZ1U%Zkm=Z ^NZXq|*2hAZ Z+zYkAK kjxaxldeh^}t74lxVeժ<(< ByY+cY/k-^ZLx^Zi=tt%uط7Z ?e5+tVV*rB kY< kY<>%xl}eZ+r˲ܔ7G񟱝ԤQZoOϿv>68H\韣(4z~nQO·z{Y?G=1/;$IٟS푸fezbPԳ"P,fH\ |J/ 1DoS?G=Qg6<·|;ZݱΧz=c;ZiDOz8ꉨhSjJ,UٟCbv>tC;ߡOE5){TUB;1&)!4ġMٟCiC=?ӄzBpBoS񣡝VOmOӣٔy$6]M=5"@=1)·B; 5BhS~/):$^?:ij+sHMtPxO|;bzBmڬC=!F|6סπWǥOzKqOzKrOz[YrQOJ>妞ׇv>ك·oS4)]yԮ7ZglS;iTC;B]'v>)uޣoS^G= |jS'OmbWhS |*Zv>jΧ5Мv>*uԓUO=^G=!|jQ'OEFh#&ov>(=^Χ%zBB'4SϊΧPg-J{zY^G=!.jV'&O=+JC7Գv8t)OO=k&ug{8SϚ: {WQV䋧Y8ԛjR'SϚ:In>eSOJ_B7rk&4)(i|R!בϲSS8.POwb7VD=SkI=~}v͈ǟF7혛|b}{bv{֢ϑO yϊN{vExY |v|gQ'Q{fż縊@oYHWM>6j&qO>Gk1Y?G>Nc>*ss\E7WM>+|Nӆ:ٔ99ˎyڔ99Ϧϑi|6 =6F'*gSxjA/ٔ:ZЛ|ve|.=+tc޳+?*'J{֤] yJ` SdS9T<=8=+|ⶄg6OܖjA\g=s:,V zR 8[1衟K)bFbsiЍłT^]Vqtcq-W-M>U.X\MK4nتWG>%й/kב,ϧC7VgE =>yϊA{Nemvs* $>ʺ?O>?yOHgM:ڑϩ!9:K,s(uX\'1﹵DӑO4 yOcs(BVz9z O|Ї嫞|}T{n-uBsrG>^G> rJ|\u+u!ޣ1t#]y!ʎ|v|.g'us19u#M# yڔ:99ޑϦבOgE먘Dѐh3בOABޓbDO{֪בO '+! mK{RȄ'u41 M{R센'e=1i*TxE#:+ཁzJ1IY<ż'幎zR9& &7@%CyQ8.6/7}|^\׃J?"{B`P\ EȆx3S>M ;TkǔkܫNTlz|Akg>∸s, 0Tlf+1i[l Ѱ37v2Z!ţamBLƂi:.aOm\;J8 O ~쁍FukP0՘%6{51:SJ'-mI{ ߇ũ3FoEY!X~McڄxV,mFhN[6me&{Z ?^,6K*8=Ѿ5 &\i+ì)\/؀0oڰIx715_ȀLݦEaIǫXt5uM,-e:0=/OUt12#8)Q#wIC"-|5?ݴ=\%mM.V4z240F#A4َ F" ]U4li4Z歊cAsuu0L2R1 vŽ4.U)C-@AN6'6|TR,+Bcj1mJ_b mXvUaihV$ru/jAf_-ȻS2؎mr>TJ>dUח1O4Ŧ`zୖf+mU+P`jnI,f{j! .yϔ憡v`N3+K5%gqsSmAtd½Mu"ٖhV1g"\T.Ú7t4M,V[8`双0OYp.t}q0XX ulș0#j&o68Wu 7;7mg6L;o68P3X͆,9%{sfCV.73>Lo6c6)`6òPp fǿafE˛ t,l.֑ݛ ʵ`6[l"wɛ ָ`6αzwÛ 4wo6ۛ O`6cx(`6ȶ`6ylla f¢5 FBh@>0Ei>{2ژn?+^g~pdc˗Dom0D@cRS1kUh0J_9@t+[8kZ'a·m 5&̓iv⩵Wނ<5zO>}nţ\{jNX:/8d 3:]Z`3rwbvYg6tfaH4tLBͭc@-\EeaFb[/Tkt`Cw3_l GaP0L!1ib vѶZln5dެJy<6lԒqEfâ elaGWy0H;~Y+C0w"= 0yWn:RU6LdN@FΓ2Q6rHԬwrYH`!ZzWM y]me, R`~`FBa~m093via&B*sk+" Z:ЌhZ J/}1H|h\3rV_Nkso|j_SNُ~&g_e?@C4D|4LݓU@C4Dp6EBٻ!W!T"+~FRCCdHC(F4DPihH)DRCCJ)i,i_9Y#ҐtS4D|4D4R# *̞Ԭ[АV4Q# 5" ՟ ;<" EMCh E!bk!$HCHCj=yhiH3+ҐZ)hiHr5B-Ґ l!4Tr?!J^>V+[24lϻVp:-V}AOjBг`jf,ɰ٠)= eo6*gAH!Y0(azAQztCKlPD7PŠg@!Y0 =+zgAlgeo600=+:gAS}p]гIztAϊ%!IAϊ$>YЇ+=+xV!YK$ A 3= cgE<= Zg[Cг ApjzVx!YU5=+< 7]?_?/w˙\TL0h @ݰ]ZFgY CAsa%58s_*B5f"ⓞmѽ\T5Vg`g.PKMͶiTh Ȃ(g.P?KPԴ/@q,URӲ9ʙ TR,7]=/l(W-f(X R5]2buo)⼁a9iYl,jH)k^[kj*);SOJb!jв^Py'MC_sߝJ䶜4b5o( Lg.xg)2,)]ὶ-WEd,:K3@H-ʰ.d9JN~d,}? E>=gz+⯣Oe>ʜɄԥ̹^}{88ՙU['$Uviu*_UV:3eypm`U-=W\VIZ­AOzMNToB\fShWVuW|8Bn>x^[1|TQ:8)t؀5Jw\uv,L/; rTm슊Jw_Z\B @H!3Lc!lPVDV)<)s̘Vè僢k,&2A%رCRGJ8& J9qo cɵ{ZQ-XbXvک q>HB[FPRw Q@5'Ŷ`A1z$ sVxvp0Hk[TҒL!-8<$&:HZ$4SPdbx0L)2U"vWPntx̦noqtZ5amU''cve9&S4`ǧUOSAG9@^CUNr: tZ! jG*Cjv({`^3>V[[~BCytF1;_rR,1B RpdxT4Nqe Ůf栗>bU`;n1&ˡvBlqh| ` `!^>lZDZQG;o},+SW-q wx-))ύ.]i ]3es›r=G©f9f57r¬X61cx3eT0eU%P6Y\ |dY~>2"+>91:ƨa1b5-C3a"1x01 ƲqhX(]N%ac1Zc1.?E)sx_0m{6<{ߎ0w.͋swQP\]%]9Su03 p5ynSu H n8vk3v2@}Yq&#jwڝ=L(ϣѣ^XG!(v?~a0ZF qcM݃؜Ej"ݕd5Sg JҚ3lY%4aލ V3uIFe:#Vu}L>=jT0Xԙ˳ ShLٙk:q9GpM]p*p,)jj97HVÄf5S $a>MӚ{>ME&5:̀d%N-3,3ft+d@1DUFխ^wb|_,/ڋ[ǣՋa䘽bޥ{uGB"]\{'eqӹFyHO2-9GzRn:׏i@OMz !艬Ŷ6sMjn:}6s}Oen:׻86;yċ]asO-_kmGu]RWksp}X:ccs T jm皣"sRfўV-T4vyjjd%?5,mZۂԌ]w9SѦ>'l|ho}$XrEx zNs:%-Z5ji=uZxGӪEg?&hZFg?XZGעE?-A ZF!̧X]}sel<8gkaCZ`(Yu΂ -Zt 6RZOUxHu>Zx,HMZ-HQ2Ʒ^IQV)gǗ3֪Ջ~PO'ch}UZGeShZGg?/:1ُŋס8:Ѵxُ~t-^tci]XZGEg?8:1xُ]֓1|؏~ ^tc勮QbS]~LV/DI ZiKC?,-_jxY+XZqoC Ջ=XOǾO=!|F(lMY+_V|bS endstream endobj 179 0 obj <>stream x+2T0B˥kJx endstream endobj 181 0 obj <>/XObject<>/ProcSet[/PDF/Text]>> endobj 126 0 obj <>/XObject<>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 183 0 obj <>stream xڍZKWJ~$'[&rr]Y@@W>uj3z7/O&]o/tC?ٞ^3/ %e=%7o?۵ דwyD74s ~wѹ]ES*LZqd]c?wޔ9{#[f/OC }2wVGSϏb0;y\}=7sYPlW|?=Ğ{#ľM;s7R|0uo/:N^4lUS\ OmFnDл$\~uG bӍA(Q@ /Nr83qIljy;zYaQ4n_1e}RF IN +U;.}$~*-4JvñGStFoSY46fx0{)Z8O r=!J" ` 43bGNY˛ǪN3[Ho]ޟ/)Diځv5Y/I'nܕ:nyIc[5I04KRxweE˹\I={Le5S 'ywͩϭ U^ǾM4~.!K" vHv'AY`L# p0-jT%"@@Ai\" rE1b8lԦ_)Fc)Ee -MbO% XӜ;a|Ũ*;@vZ0iVΌ:[~AoNFG6Oi[W[p^|(~?JB'uοr7:RROod0%]?80yY6%S/Ӣ__H $ⴙc l&gj\!-" d;#Ȳ=F7 m)"0 ZcY Aެ9BhQXʡ~IaH)QTUI --& f,U/G=yGyh3ȓ|YV(2y*QƔj:ᅏ .c7z8P%$p 4 ` @g- 3qKf5/cTeOϕ%O. Ttb7KQ2"QlEDC#td?觼(Fs^/YB#%qMY8hw"$ /R?bVo:\U)kl^ri'J5/{4'd,vH 5Fmb\/:Fx6лd 9b~3^> C{Q/ A;o*ЋS>K><{?8878*uҲϋꓶŁ|_!?K.,`Ī\K|ƏBHB̂"_Z'i-5/im=Ik#Mkmjz^6J Fr=s8ILUR_rBި`CO˒\d<#,|aN@5e-[A9kB~b-.d7251Xv/}W=ib ?FM o0~FpВg0E"+]+Or;rb.~t+51;ZwWs-/b2{7g֑ƛ<?Cb+zoL 9;rO ȥv=Aޓ1xZ9?EZ r%.s-cvyjX4`]ɰRn䒊]]ũK~0z5r=T?Q; '"}RrkI-#'#Dٚ+_,}<˫ܡ9?rnFcy>{nD\#bPЉ%15W\8'ݦBRY)ϙm6mRf_j&ΫW 0aI t۫P算&_i<2'B|9s) ǷpUGFjxԊU!Mb,Y .]ӜCC.^ȵ|b&aAtcg-ii2L*qD̻cj_\8[&? _mX@MٟT %\F$uܐQ xR=Jԧ{2{[I^h/RO8k +EoxG% y

> endobj 180 0 obj <>/ProcSet[/PDF]>> endobj 176 0 obj <> endobj 177 0 obj <> endobj 178 0 obj <> endobj 186 0 obj <> endobj 187 0 obj <>stream xmXTSg߿1$P V['u VT@d CF؄ a>@ Haֺj].ھ}.}݋op<,a,kkh(v8?yZĢOf݄m̱=bYU_XQ̃sf.f$:{qTRLhpH\?Xrn˖-6I=qņG,H"Dq[m'mÓBbmEEa6BC 6`vjצá6SoqqLJ'};C7f_ pL:y(HSKQװckl׭߰qӇ6* [`N3-Îb1W}憭`0{l59`kZlfa 'Fl}cvlf-X5bӱll3aXQi; mg,Zdr6K|?4zW@߅"*I0BBY^zƿ\K/&sTNioE S^@B G}c c ! W)E6]n|0K{)QA~d^ؙN%u_]/Xm@.o)NdsIQɡglhF揎{D:+7⤲E8{\V/a<> ŁV" Y}ȥ3B䄃I2:a)TᮥEW{З$PS% DMa 7tm.X$z3$ܚ$Jz }?Ł2p= P!+jZcRT[[,ୂM2.樸YY)l_4UE\<쏶|-9ՖX abp}DPRB$#[=Wϥs,eY54* >s6Haeul O}8GQhrȅ_6+I\Uw`N<7M$Oj=a):AW8z-G~4$N/F@_\-ՏY}b r#yAKhRR4jwr{Ҥi̜,wwu|@Q#U~S!y/~NQ#qxy E JJƴ5K1M OuZkUewO(,*eVw}tnTY2*h=k⣙jI %r**>\ӽB^|3e2C|] >s:kj/9Wgc0 Ng3KܜF%S/?ϧ=+_hW\F(Z_XNJt 4eBHg>QVgt^qĚ*Su~vAVU]DCKupC1a9$M'C){uO^Pг4*mV$(c@O iT;ΦM, Ku 4eDMПNB: 8Tb6wmF|;3j^_%v]t| k@݈wϑl@rg ]ӭE Fdjn 5S0lzb;/J=Grœ|Dwqpq)pW;{% ,?>Y"-'j]/o$*R4hr  ")lTCٳ('E9!E-Q%'iuЖm p#v4tZxhjURb:vO~q7!)֊vC?CSJER580te 3,ÐbC$) p@Yjqbl<=uΗimv ڑ;"y%SӚu׹7ԍ1->UOr[$ ? ^z W%Ow\AXaviz\6 ;Ei㳺p>.6ׄ7Km1.z5h&pRKtOŅHr>DeH_dqCDWp%@[+Qs3bl*SGV ʣK1Vִ9-M Jl {nrҞz7%eTwóy&32d}VEv=x .j_^ygT4** ɩ:_(USd©.=t'9qS9 ` ੮3|&5)ʚځ'Y^6:JU 5mDJi"&*{ܣN t6WN0zww" rcA905gk1K]:@lhgAcz@Ʌdi0 iU; D ΍5Z}YajnlF *CJ}@ q42״_Y ԯL-ǡr#)KEF @#QcWԳSuZ| zӖ SuyLzS/IsIQ773?X"I[X53 m&8{D3ZWfzi>k j>!jqA4(@FʼnqƚFs\M$m/M 5Y} ,-ҜHfĩTR^"[DZ˂_Ȑ$NDDŊKٳqPs4攖>èouvv/WO~}zY.K6AsXYt큧c/ jiL|R1:;@[|EqI5hQM;8׹ih[ Y5FhA3pj3NMuUN&л]f=<1d.6>tġ :/R祁t"%%M)`n?VC7Ɔ6 e4 O.r"+%Қ3rETd~D*~jmO?T) K˟hU1v<,7<׈#6j(E S[`mvmŃ` X?>grKrJsYѢn4tT1_T'[N}9td~Fj +b/NBl++]lAnNhDu^!QʅkwɑUQM}Re'D8pIMuЇ<:7"WQ 03pv>&Hp Αxkr=$*WOib =wϥW@HHV<5 R)UiFPjktsR$l]魭[mPZJTfT0~L{.>%ϥ:Vc \~l'r Lg,8d<_R|AG=Oeby?1u1u.gվ HW/ q>*B8@bCG;|ŎsmR'$M@[Z Ȍ&#^D66adt/ٰ{l9r$??R[OSX&d̩ԸY<ӟicߖgƆGT%÷IEA"T.xw]O BeaRt[n}l^/D3GI-dn'7׬'{ xj%ydզw}fOvG%jkR-d򄐾;cO{C=#&8<ٜX-)5ҋ 8xy4,X%?bȰ?) n :˂cbb)0QMVppz_r墛Μ4ڊ~[ǹg$pf'SzpA~n+,A@WIE,[6gtk=]8'V޵=Q$R >|~Y@ܓ zwA3fbu;5rE"Ya;`cÆ>Nߋ{(|pQWB u @]˳4;޻+\dV71V&Tu:FjuB+RnU/>"870dbT]fˏ>ۮq (B[/E<>:`1W'!Wo _IK(ɉgս#C1rH L |zwH @F&S",̬oWIhd5ۣp.e-H4s2Ybz{.fĶA xN 1#E" RbC8Jza؄ i7:C3 ʹA>CO1??VZnSq[؛GgYèyKKv'K>8T1xm?8A?l8]ޢL~bU{d'XUE;F;3J3%fmD7[kِ!q^UXPS(jYTT&:$L4Qn&j6x1h֬fc endstream endobj 188 0 obj <>/ProcSet[/PDF/Text]>> endobj 189 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 191 0 R>> endobj 190 0 obj <>stream xZvȒ}[,$k6kzN2@vHwm͋;"q&gr_>}9D;}w4 I(ۑa9agOY=iL{Gch<8pq$&3>ɏ8ֵ=k4kOQlگI]T;/صTVEռLoM=QgU}iVc=?a:V6u}wI<)U%}1±m(u~RuOgRV&~ n|Dˤͫ{થ^fmzEI_N=gLk"BW实zUY ;Ħg&Ar &+eaK;ZbB?*;1a&G(: t1W㲺Qvݍ|K]]UZdiNXI{K E$&k7Я_ئ2VUՖlT%6Oo$=h hu Оudǁty^,ǚ:w9M ~{A9-Ny1rMi-MjiT8j2մU ~iT82quk ]i]1qXQ?^r)+/2~bB`k%(; DCa߭PwA9ew0bx0viGrϵӸyo.5\\'ue Kڊ[`X|}`=1H7}@ Y!\kѵNg [% 1? ^׍~\W#*,rqf2[r}D7B¼.X W1WJm[w([ #R@2M5/r h ]dIQg\?}lHWCq*!1i2O[E- !@t=Qm+bNc,(#Iʒ5$AA]ʖo&I0:`:!Zs 亟fvs{*lĀ~`0]Ԡ; otF!P(!%dlZ'a1SC[JY롲Q#Yŷ ~"Ќ=+c/3(2~\Kc LS :ܰ{1гcqusNBy*[sz7!R)Aoλ1IyR-QGe?CP*|uЃrcZ}VU1@y\Æؑck;a<b#^H Gza"U|*a0!4+43Ay煶G^Ի *wI݂e& Ct?TLO;XmVIwNV xn18Μ/;ψc,yREK!jVmMb=4Ưlٲ}"2#酮U.,r.@)6΀tGz6^~p"ޏi4sl]/ݪźz-3AAxUo7nw_3qM{V;$8W`HT.^'E,&YXeV(: sڱO2RyD #:.uU7}9nhWב'=rŴe6ü3pmiUHދLb".c#3IWY'yAAjdT,r[.Ju'[/ͪ%W-W(^m\[gј$DY7nTEHhg`̘3eo/DOiHj7i{{h3g7ym4Ʈ e5ePwwS71W{ `dN <.f̄2遑P!#ފC > endobj 193 0 obj <>/ProcSet[/PDF/Text]>> endobj 192 0 obj <>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 191 0 R>> endobj 194 0 obj <>stream xڭZK6Wj,/IxGl6N #q"=FH\DA@mfl]_>; Y꧑fXb|ijQD}ӿ2.\0S/D(Z59uYdy{TC_Pxx7Z{YO8-80̛9gb]Vndͮ*׶OkG޲m67w7`ozLxE^jUc{[¶Ǧ;H? ]IvJHއo^Q5Xtz&?ixU)w$<dcb;SF<µ**3T>1XrȮW[rZ.Qi .bf$>p+CVr x7꿛9Vb#x-a7- _*s rb}_;UfzFQAjCkj5{cFLJF"@){ ~ێ8~ q-"kWˍc7>-9 v꬛}|0^ܽwϪPP,`-LE{7- Qx-S6潒QtHD&o'u6k S$QOa'iЩi۶|Gv{CyeNy9H ]Vg"=np"G,@܁W>R7@\ϟQha'@I͙cI"?ϙ \<1!{Z`Z5y 7! /lU׋5o $z#9nEQ(Zy,D4X4i@O@hbU#$fwOВiO4dI$ӢBL M EV~;{ظ tW ]D;N}]՜CruKp''#6lG]j>=d+)뀡^W%lGD].zxʃ ְl\{]^8reR"@]{c?YػSKU+5vIr]eKs w?냳TzL$bP~D-ɱ͡$#TVkk9"a򩈏q_Dbd' KCkXva80Tb6z(^T[3c#R`2o&4e>51>Z}6% (׀Z='U_v]7UQ'e ?鲬!`2e 1"95__qŎ 8m$ ʄ a o 6_ӿe8VB@FKο]6敒c{s O|t8FNsN-1CIST()ˁ//Lo]TL67z}s+ki! C ɮj+pu>^g`./ ѡ+m4~ZtGƐ(B ,XI:A JJƲTPRE40]v'=D.I0`#J` +{_fW7՘x1p@Xѓ,ջ -֘kF01^Ž126G:G(hC{5n#?8~ەOu~*E_pT-F@M;CNVO:[2z?Y DVA՘)Dr ~S .b! C [DU2o(]F%ܝZe-*v8̲KJArR)HN+RL=|{c}]G8$;;ĔS si3/@hmL1X3KZҗ2,U<4LY1Fc -x#H 3^G D++TV>qHw@1[M@UsqxM;C,C <&Qx#/T Iwnv\L$C9$:}Mۨ3b@4,$p=)MI[ҪjTźq#N ٩7"ϰ&XI|ZnK0 4i]$-y45)H }.'EwT ǏQkrpĭ(_նVӛ׏ZQ Zu.nuul!!lLݫ-Mtjk\,e(0mu.k1FݩV)ٗ3/d43|rS7=޾3 RA<]ggR :h@k]+zJ$t^b[jOGe Lƙo5@1!0_ci%2~8|6pTw&>Yd?Ҏ Ъ@Fu4TT م*s]4 "%.jk/L!42*6KFLbGA`NKE锹EVܔ%Z˰Efj? {g) .Cq# bօO~9*˕6twIJLbzJC4+z8FU|Nزhy<3dxg)AZ 94|qLGˋ'͌.o 5YK? Y|t} {&>Gw3#C0XJn(iDt|+ /&/`ES7]~Q= 骟iH<`&gi\􍇈R_#|t& %QԤ {k Bw}AK,1qhZ=L&Fn& crB2 i8]]fC'3B?@Sٞc¾7dֆ)vWʶ} 9]` =gwfeN:ʏ}o(,cNjx,ehErK`ͭ^zm{}:XcU;Am ]jA K!y endstream endobj 44 0 obj <> endobj 185 0 obj [556 556 167 333 611 278 333 333 0 333 564 0 611 444 333 278 0 0 0 0 0 0 0 0 0 0 0 0 333 180 250 333 408 500 500 833 778 333 333 333 500 564 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444] endobj 148 0 obj [619.2] endobj 146 0 obj [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600] endobj 111 0 obj [500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 832 667 667 667 722 667 667 722 778 389 500 667 611 889 722 722 611 722 667 556 611 722 667 889 667 611 611 333 278 333 570 500 333 500 500 444 500 444 333 500 556 278 278 500 278 778 556 500 500 500 389 389 278 556 444] endobj 109 0 obj [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600] endobj 103 0 obj [877 323.4 384.9 323.4 569.5 569.5 569.5 569.5 569.5] endobj 101 0 obj [904.9] endobj 95 0 obj [803.5 762.8 642 790.6 759.3 613.2 584.4 682.8 583.3 944.4 828.5 580.6 682.6 388.9 388.9 388.9 1000 1000 416.7 528.6 429.2 432.8 520.5 465.6 489.6 477 576.2 344.5 411.8 520.6 298.4 878 600.2 484.7 503.1 446.4 451.2 468.8 361.1 572.5] endobj 93 0 obj [388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500] endobj 68 0 obj [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600] endobj 52 0 obj [777.8] endobj 50 0 obj [500 500 167 333 556 278 333 333 0 333 675 0 556 389 333 278 0 0 0 0 0 0 0 0 0 0 0 0 333 214 250 333 420 500 500 833 778 333 333 333 500 675 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 675 675 675 500 920 611 611 667 722 611 611 722 722 333 444 667 556 833 667 722 611 722 611 500 556 722 611 833 611 556 556 389 278 389 422 500 333 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 400 275 400 541 0 0 0 333 500 556 889 500 500 333 1000 500 333 944 0 0 0 0 0 0 556 556 350 500 889] endobj 48 0 obj [531.3 531.3] endobj 46 0 obj [556 556 167 333 611 278 333 333 0 333 564 0 611 444 333 278 0 0 0 0 0 0 0 0 0 0 0 0 333 180 250 333 408 500 500 833 778 333 333 333 500 564 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 480 200 480 541 0 0 0 333 500 444 1000 500 500 333 1000 556 333 889 0 0 0 0 0 0 444 444 350 500 1000] endobj 43 0 obj [556 556 167 333 667 278 333 333 0 333 570 0 667 444 333 278 0 0 0 0 0 0 0 0 0 0 0 0 333 278 250 333 555 500 500 1000 833 333 333 333 500 570 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 581 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444] endobj 195 0 obj <>stream xڍT6tJ#Ƞ4Ctw7 0Ht#%-)"J7{_֬5s_ =& ,u@q@rakAvɱu08 $ B<Ȥ@Ce@'Jpe @ 2;@cKB`+kCLׯ_ 2a hhB!``F 88\\\Apv(JAX4p0l2@d5vlz5Bjppy`4`6`3';;/g9qXBU%v+rmCA Aqu 8;bGa,`! ; ؿ듂swrm.B mXuv8Kc _qN5Zn࿔=xy8Bm l8 @ނnk`w*w$p_^Lxu<2B~̳uHUb{:C>*Ita;Y  B_^h 7soվ>r @۱HTPg݊/YdHS8pVnߣ%i5Z ֨rܦ{=N~LcfBsov5!)Ar7Qwy.=st }#Wf ˥?:jtPi.9:ݣ堦MUcvN4"iud;. @UzH.)4y9ޱYN@&=v<:;ǫ&`jfdwτx]{!}ɩAWܣQQYf1)?1A8<&{hD׽#W,cVq 8BӤӊCQ\E,g䪯 h>ۤhys\lnR7cN2Shu}-h|-xsxX7I^+F1/N bEO􈀜z8#G E_ΣC,~(޼m;[793"H~ퟵ4e֨W_$Y2d=̴ZZ,уJ=BB::_o ^]%߬ʚpIX~ n<8 mڡLNv}+ +=ϑ"`ʫh{,"UScB/ P&^ոeͿ7J;)pCd2#=te 8B_q7k200 cb`({ X{(#.[WQ|}ey 6͗-p.3q×+\t#T|*t^u7Bc:(|&0@ " .#sh^zPnmYNqdV?ԅ~7+smw3{Q'@-5)^P>qy)T4G`, quxl%bBz~, GV:{lʰѥ>O5#euR0CV=޵mNT8)@L>Y^gN5V/b&8[M h3,&x% c}x2_t<vdrRA8ny0%p<:Җ#xe,o%ۊΛ"Uz=J.>Ek'VnRڽ7@qŴ0h 7͈ (ysҽwI!i6Xm;kd1G{2qtm>ڳ(v3|NYXnU.^~rrW f7nPׯu6e?]s4[P j6e)QN͋?&=4H?Di~\ *I 'սQɧ P ?HubLrȪN[,F}u͵D_Ö1+PK|bC)~xǿ׽5a+ V:N'Q@)`zyG2c|-nsXIƓRSꖍж176oYY}زI홎7MDt`,I)ȎHGe?CqcoNZ>L&G)ls\i9K$m5} @Adf7Q>wW|ukB{[jt(6>.]@H2,Wh2fЪ3ߔn蕍m؉8|́-h򀀻7pQJ>Szv{$W]0ͿLb1L@5ΑT_C']##iĴd9IһJ& f2e4&oPV۸zvɶ<o6}!7~r*{Oz&M bW&92r-')wE 9G&=&!%4UּV\VLMef9́qaDpN;r!k,qGeF6͂>j@?0;q.l Y5#2bBF꼞5(*h((-21F&mNU%,ZgKrnW,1yMRr{s~dZύd yA yNdnK5w2B_ocZqE JPDvkA Ǜ7%eI,W}$5DgU$s6ZsTG>U` ~@рo[Rh͑HTOܤ1uM^Ę<]MWK 'Ʈ_\aMl}=#q{|2DPnB]脜zv7B~ VՖƸP߳5W4Q ɓ'lL_:+%J) VF9*8e~p\)ФbPnpї̍2hȏdw!U>oPFaHmR‚y.Li${Lr.UwöY 3N'[jI*aw~BB{JA&JeYt fJDT 7`23 j*~Ejo]|'? iMUOku},lF{-f2aOD%x,hWXQ3 irA*;HL%CVصP}IߟX\mQB .zo R#(fmjc^TX+%@,QU<^U5 îJ A+~EYjZi{ϡA@n jbuKʹ˷Op`6k?>ޑR,~XwKr4`ê(VB$"4Y#O{V+ڢLfcЈz0>>o$,O}z.Gލ}$iܾ10"cXX(ӵ$IK? VJ)) D{D)JӂJ xxeʕ{#N 3;3/u|L}zN ~^L6-ڹ(GMc7@p;fMBJMK Zs/x:d2p&|x)9\9ˣPG?05Fu㇊Y^o~4}}w+3vqĔJgx+{/Lj7,wg..bM=Ks<6i(bp'uPB{w^F/Q˝?&xS<1:}tq NYa2zب ;B/$ rb _&_2 uz^-伣/`AORl {0o'ϸB(K=a#/q^ LJ^@ qvU۸}_[A3VZ?$ qZW:gh;i.0,*8Z'| 62O0?ns͟2$ gM.i~Q8aj^_)_ Y%TRI׏HMN\~DAd+Mr1`kYe"[! 9C0zҊǗ3I$"Y>tǺ̊pf tpu p}J[~kv&wKruC拚) 4TK rEaضjJCni.&^h;Q45:a"$T ɛ&"4ݮI*7e_:P;9e tr1;Bfݴ K#?tQ{-%I:`}Tnn =+rUf:e")K@1,[>z@rM#%@Vy5M| oܱJfEcXNH.M5 Cy'M_izGa)K;nMͫ.<Ŵ-43Fv7xel 1O}Ș5y\?\7Q{:?x\&{W)bߤzq^%![zۆ3^К-*Qt1C%̼`I] N}_u5Ff=HU%qv&I;byAv0T#&'Asa3C#|J2o?;=]e5v K,SOz+|*^e*nJ7l@R5a3ϣ|h*:%t u ຟ[%4UGF"ۆ $r[!i#ϻzi罺#eʦHmU; ?SeƲl~ EzSې1- ;牛)rqFMh]z}J1QUkf_@yz{̓Y٣c.#MS}!/bs×,&@J2]ePfW݋]$SWP\rgv!b}e)QV+%`{'\b@Ï v?^h"_uؔEm/'QT7ⷘؽ.SڪI*- ;VqD?U-4f0S ۪&#Yۅu ZW[Cs P/)M,OyߖE-ffbk pR,0%-6p?|`n#وeLFw˅jvWar?I5KDtZ|g0:DI0<"Vd xA~>"Erᓅc=@a6D-A$;e? 6e.H li$doAa)v8l!}<4 lx= ٳFU LsO(+(&hφ>]Ô55BsK?~Su6u/Y&T̴%Yuaᔊ5.PWӞ'¢+ʄckQjuP 9xӅL^pM’鼁:=ww\v/8h **OLmW=0 xw2gQY\aMBʢ\`~-7bي2¡JИ .OHBQ8Q|BS8xÑH*5|Io+J.2YQR:U.3S#V) &* fެFst;K\mش(]%Kr*u2݌@kCz5Kc4Z8.pFOq^%R>Y6j$k}=AZR1Hn\Y6v)ڮ(JYMǻ$NC9VNx5Ϲ-om1vvEM;8=$ǖB#Iedȣ2 r:ʝ/Di%D aΗmzŧ;ӐFA=C7g[-]s 0x)9273~e~4>h#:K>}o,OOݟh}LWIaZ=.?D endstream endobj 94 0 obj <> endobj 196 0 obj <>stream xڍtTT6)HcNE`b$[PB@N )iDBQ$D@Rq}k:s~b30PGQHD, jJ` ,L  ЮnR BJ/'Th,N]HH0,/ SP ]A@ {TPG'40"%%;Pr{"`P$ E;ݰ' 1 Q[ vy <y_ 0{=}=d or@B=ኀ^ o=kp?n f*@N`(7w(tp@_]GH_@ "\vXΡ!wG8KJH psU;NrCpi=;O04`wD IS;DwXA߿aeB{B5T,L2b`ؗV1"vO&@^ӿ:KYLe-ɭb`URvu?P7_htQX j#Z]=h(VJHG, `?~:no@ÜP\H ۂ+Opه;a1q 'Ůk@~  "Qhl 9p@yZ$ E0oOO칿ـ=_om~p4 &\vT+2&Kyd!,0V`MSj3]> QvS8zqf?p_PU#]!TZOfif7=p X⯿&Qw3Qq`|9K%":^ה2Km.[LVܒ|I{®-qL[}Se/KW|Oέ(4(QB>Y^Ɠv5xN򤕤doDW&zu(;Q"Nck8f{}~؂=~ؕ*ŧ77 4ծ "}d5T8bftepR|as˂ݲ=ij& 27\)4*+ɇN "Gbuu1Wl[ sX:8NNRqXftk3AwkOdb۶rGgB6ix"s[b(zlSQѣd:/xdw?߈ *S%]2;5kk^_ύ.;2}b8Nv9)4AՍ$GkrYMt9E6ws pt S\_1'a>S[Eٛ7ǡ{Ia[B17hR"koH}ðϽ1}~A—xN="$.eNР좮ܴ#6)4Kgap9azYolxz"F.Q;R>xk*wKErcϷK4υ@ߟ2/ʓ׷dslk͹;vS|`9:BG\3&_'l_}C5yrW4YmL_U/c {)1=5ˍwm^7;2K BH>j2D׿<.md;/2Fc_mt_˻ x~ݜ]XB%Rۈjkx?ɋKD#e[o2wSxXyOhg#Nn7WxtvA|K3;Dsxŭ112kߢs,B Ly;zIm%Т~42@Y?#5e;]s^mDNE3'dŌΈgP +ȓL{TvRB=w|lѻ2KG㜏 $P,wғ<9=*#s$ ~v|2 VT q$-=gdogeX ݢJfeqo6..6 bRZy)ctgDq৩ZwˣїWbw%{O9dklQ8l١rV\uV>Ҭ@9X ,MІp#*XD *hr|3#oJ;%D/g9V^][{9[UuC lR~CR ߖsgI74# rP)Q%GX;YT6o/qf;iN:jnp\|Jѽ6uXrxe^(|S/&WlLIRoӃEiu9R¬o XԙR_Cς7{EHgJ O]>"GYZXܩ)W:-{ZOʓ.ԺnF?ꨏ+gYꨦS}inF)qWc, YW7a<zT0+YvL>N HPo#wmr\.x k]IZ7g+LcEOZ^Wf[= HUnMٖgr`njѢ|6NoI*mU^_zj8c4M(GC:_9̞Hzh}\9wKœi,v(c$_ܫAP-GWb~?^M ;ơ\Uo/rAе7Ž )g߽0e{]@ x<& //usS|Xiٟ%W>B'Z];,4XK"ːhU[x. a"FM$rjfQ =UY{Y9 PT?}dd`bn*FuN%/ 7.5!K~W.Q[F/b"cIQʻ=KO9?*Þ0 S [qS5MosZ\)͙S&l^/:&eDw-vқ}UHw$!(jצ?Q~|0m)MC~ۺpɘ@%'oUVt V/8Sҍ}Z/@L▸!D猢R'h-xdvʤdLMQ}=VH,Ͼ}e}>M:n"9Ln짓˷YJyS 0 s?!7nIN ?̦ߺ,U6pTRhy+é Y)^ScuH(~GFGb>ګj'l'k- 2)RoRSAi[kM-="V֒wGeޯ!F -t䥪oHةr% Mq!U#SeWvvͦ R 9-nОcfd;Õ;j}6aJ@إ+qSG"L[d!V rFmctK!79O0!7]RJ.u3'%Ǻ@ˡcF{_T W3EEYջzDaiLc y/; Q oԘ b yxoL*κf(51RzC &F ]3yZ$=>RLȇ+gx֩ڴ󲨥x)РKB-D1䦇oa^ԥ ힷ?hm!+!'5[EE89$5$ J|B}+x{GҒt&[d "_0V1vע^La+@;[aإ {#?;> endobj 197 0 obj <>stream xڍtT." )H %!% CP҂tҝtHJ )*19߹w{׬ͷ~~~| p;*Jtt4$@(LiEBI8M $_%A( NhzDBĥ@0(/ !PyA:M8 $T"N(1zpyB| n t@('D0`C!(vBܥ@nH8Q E9Bk`. g2Now@y C`HL'`jh!?`?>߻ _ 0Ba+-A@0_@+y ; w xH0B FUs*0{%BO1+g.07;]h(`\$9BP1(7u rc&s0C@E"$Q;#F7ᏍY>b'C/{8?TWhjg>?~aI c^YF?08&O{W^W<Ӆch pV@1 URtu? 7_(tj Z=(F 0G DP*bEp\0> qd 1!1jC^/?P',vB @$c,1F (L 3s faa/?=9_ouC >0)8AsMXImoi3aGD^O6+YZ%{T9*z,NCײn:O]aO$3MQ4a噦(2KAb߉ w5[=ES*ުQUM$il7`.n[\ZճT 6-SDJy;^!8T 0)V̿"}㵓AgvS~Ǿt'F }czϣ'h@[-IF^`pB"HK^O%ÐQTӂpE-V4𼊎cgsR, +WOo_hYE>GC+GW8 uxx^F|!6< [\&"`W& +s (wxNW0r/k1sOpoͥHeADKQ˼)A9, &G֚v2?.ȹȜPCSBYCPM&n*FhYOhP99uW2.E/Uz#(( r#!֑ܷT{H5=QHȔ>yN1-ԪazPv{K~{ܗi.\tQE4(;~:Zj -z.˫hHOxGvŶ26@fy' Mӕ?pJл/}@5~:A_6߼0+۬ p":Iބhw=-#2.pNU6Qpt=,I4eCLU~}+bTlv=3)'J䤁/(-ئ~)ex>q;{>-Y{φEhs+\@/0uSigf=!Eٜx?O+yfm`?rfy*4_uj;SCėR 3!o򄕬u?ẻ^I .*[(-`*E,eؔ|hWkB˥R؃N~'MϞؿ ^.oa~Ӧ1q*)P))qw8]I.\F9jX![얫R8ATS JL#)Ztqo1y-)gõ?Nd;\]nr,D(,2%z{.qZmu=sڏ9*˿%,צIePp}ȕ_(aO X8+Oxmxs VPZ2%Wklg蔷8`["J鼑 -\ T]PX\Cޖù(l~|;}G8hi@t 9(cl!; I쏱,BȈMVr͍ޕ+Hclg;ų\<͟iNV.yK|%Lb͓2Ö"1ƅp4r#y{2X\x>nCO{<-$,x~^-@䇗ugXKp]ݗ8&4Gl+ش9 \Yk״~hEE"ѐmژ g6>ǜ|h,Hv]qBD)!ESg4`}L p_s'.erllOLȯIyx1'%ϫgSASVu^{.imjG-¬ Ppi3!<"iS&Н;X0Qř@c(3f+Wwqxy4åXĥaҤ{Dq^*oza[2?17 w6i}ؘoxZңa_Ef7.eJ7v֌ȸ;k>]QRuH'v=P!Md{pa]R ?\OIw`LH x#~FÆIRebj~ZLAZCӋ9*m(ȃIt@cHuPMp E㗠ʭ " 'Ņ{:%ɻnH4t5oZ3_hK{KrA&TYLw8=]O|| Q7zF0Kޜ b1G /; q~K/ ŏhmZOLҶ1U*h#h~%C<:sU.2xW,hܼ bGan*mf΋8+CKxQvJX8fqP{=qɏzESYǏ<"NŸ>u Ս'_M -p<$#S 3 7|ߜ}Y\;%%TFA3`|u'hԲ?%(:aP285rdvjetj4=ۥdWT itQh $ZhTr`c;Ey˛l C-VHX2Q۷fڋz"7^at*$[].} !er .yLK$Zb:rjb4k85~&h>, T5M_7QT.ݓ hcξQv-P,|]U@E[$.sZp|hO ,6R26T=_Q.a E[%(|nխiKV4/ ϙujǓN1Ac%JBtqp!{H]'[p ܋9&6ngzEu(I 4`Ng7DfXM6=%,d Q*D6 y5 = Nb+NQqP)>n*ܐ@dzJh\5pniK˯L(oR}&XestDMŷ``=>P2W- G 5O]Ԭ%ؔ6%xl*-=Գ7ڶ"7vprLU\pgfM=)5r:;į[Bg$ʁGLbI3b9u" .c ةAi@BjFW;q;ki9v:<=\qkx뫂+iLfZBUmĻ؉0)9E K׭s,wB00d2 g,=CPj+$v7URS9U_=Wu_]Tvߏn-Sw6Ͻiܣ*߽/cD$w\%BwC$$DtZ$:.  R}|'mCyfb~i]Q0/,܂ $c{ _XQ\n~IMؗAS-eo쮗-A4MXY_jMƔpbW²PG4R虇VtxI豿N_ I Π42jhi5aoHrbǛ~[D0ZUUФ"{K2W:*t̘M=,L#ف8@,9G\ k7G(_Q㍩fSN)aE숡^T&q.k (/wvJoz2ľ>+a,Je-IrG+5ɀ*?t/-'բ> endobj 198 0 obj <>stream xڍtT6" %"0tJw7"9 CtH#"!(H#1twt|yy}kz׎{{_{#l!*8W$ T6A !>HnE v K"F]cJ`Ե6pb P!) T{@|@ `WDx#Nkurq$$v;CP;0 F9AoÀ;(\N($?'ٍt􄢜7bU0P Shu"P`$x v۵;^_4T@6@>+lgpvýpGhP`/C0 qCa`kߙ*@ufܠ_% sp{E3rO ]?7>#< Pï"]PWw_&ߘ#@bB@+e+ R|] p]= @J=8BG!#^@s5_OGa6_~-uEc?SP@x}yA@^APĮ @?^?ӿ2\ 7t׬Mr #oEH `\ yepMZwh#ߦ?C ;Vy#g@ zPM !ܠ 5-'׫횒Up;H7גWz!^I #P.$WG%G]7q@ Ϳak7p%?[Gvkoo"]/Z@ vT㏡ux.>d_6};w?%4=xy(Ԣ2O [5Ig~։˵~궾MO Fr+~~&AOphg轥8Ĩz}jEOv,믔jXgf Ӳxy<$wŬߊ}4'w23]d$HF'yZͨoATۘWt/xo B -e KY/w( +)T2'ƵC&/&$}9mV5Nwv9Zl7͗mepd55)&sNy 0i  #- ;"Y~+tFa!W!:W_^9 )ۤse)7=˞ԗ AS)z3k=_Ζ'ڲQtKRL Myky,1aȢ9);>Ƨ|7Rf ,#$' -9ыBcq%7n I:/"QudUInWzЗ]}IH8`t?Jvyd,}io&+tx=Ç4N:MjB/Ľհ&HDSBgnB_S? z2\>cbu Y`1O>RyaS9Uۊ]4=hƉ3PQw,mq kkV!G8F44i7:Өvi#)f'H49[uA&/KD`gEUI4s捴Cvz|:QAvdR#nEZYC^{GL~JKo,&G3ڎkѼŞT1lb\hӳ>i-^B*-wBpO.TЋyMܕE[%re?NY@ϛ̲>'l'G/T3t,BV+Z d X=~aQp Q V .bQȻ94S@bA%:s'%]r +-agЊw[Jbb)[vNm^od'&;lɀճ) fK2s*hHwD(Њ9G0߯\wkބ=gŏz*k0xNք1Z6ݻa+&|iJ6{ɐXO콤v%>̪dƗRΜYțnhj룋is碫<r=kL wD!TՄ;wʰcJw?{7h&׀:V%]V;uڼI$MRb#!Y'H.!Ӫ$w 16<0_z#HڬcθÛʶGcKym]å|ABk&&Rcu=$%|suGBZ>s1A[d; 0wGBOĠq5{)1\O/:rUմrIZ9Պ@.&y"X%͔;߁;8遌vt6 -lT@ūogh,91g@]/]<3SZ بUfŊ^Q8VhYR9CI S.<±wRsyEgϋoޫn{b"NBB5XQ&d\}'J?W%WY `C'Գ IJl=uY,f"BNH$mu lOds!Jb4$/ R|kҕYf}Ǵ 4;ot~Adg;*SP#kV:C{mpCvO:5b<#[ȼf11^lc[1{!äj1+dϡsR 0 YN 2u3ΡIpgCpk  ljB|9լ:*{VOlgOmJs,'խ ZS5+o~b @:_ln;؇?ŹZ"V7{EQ9ڗ4] p%M=aiP\*R_ӴrSNLgvy >%]oz 89"N7 Hug?[V!06|=͍Bad(9%ÃtVL4={S< 6 v8T ˢ۸ez^.54ByیUH{scm;c FA?NgG^TIP2% =InUAl% (͇Z+F0˦'Q ɏ"+;Q(jI+? kfIT0e@/?fS_%Ft 1|SGܶ j'n=_D"Di=Cme6Hi&u[T ӇM=Qssib@&y E%1ۀA'yR 8J.p5mPzRꭡwW؞Ĉz/Ttؒ{ ( pMŸ~ ]P4idhya(C(^#E{+`>S SEGDS 296RK){T=X*k85 :r:M5<Ҫ- w wkȜHõfO `jpn,%nutH.zqz aFKHe㈷ݨT^S)f'/K&`)һҫ?CT|l*+e.aqH_ݬ{ cSe3X,Z,uy(3Xrni_YNBNr*:J^0n].65<2U>.*|0.ڏCbUߝ퇛>`,Te]̕,gkM~\jA x͊0hiS MFNڢ)Qr?e;εG)Ŵp- ,~VnfΨbpڏG-S6U KS{do1ֈDhE;U!֛=PhڒsuΔϏyBjrS A}!O 6~^xp;s.6+vüϙiŒQT^aT]Z5qŸ3R\l`NY@1x֌ ^<Բ_? y{Qd|=-yy4ȗRwl#آ>_aQz4yFM {JѪ!j)ͧoʻcjzbM4LfKU:CO&5Kv*e YѤfhtW`')FF|! 4vA=IS.UV> ֹ,l%Tk(_Tiܖsݜp%'eE 8FDѝC&UD^J.ZsenFfzo{B}J}sec2]}T K#( 91?ŭ̐N/TЗEʙy{ 鯙ofyۍ%~+& PQK<yx;\38J0y"&urɃKIQ.b1%j~a'TC@34!'z$5̆jNFF~h~*ܙ'i߃TGIᢦ3缤T+k'S,\SU# _b*Ә_@~c\Ϸ:}E ۸˕W~i^$5M3| j 5햠X㼙r1x$]pm#Lr ?7ڇ_$"h %cՋ~Zwen@Qdr榚b:߆Ofr GZc1(鴢H魴8erÉbR.Fqa0LIh'+^"iHШ.4$VDңypNͫ8R4t?L1I}GCpKxcha@t7Zp%je߇ }kpNj+p+)v*~\FFe=pc܎r1PFQT[;:K` ͣ'#P+kD_ɆOb3}v>[Hg$ulJ㙤^t9B|zPC!P%hĚs/4!xxaJU~|Ek7~YvK1ֶ<:dEKtTRQ9kɉY`6:K`Š'bN7Jv|㈦vHOP8;Y5bT0}1<9G· Jb/g,ӡ>뻔Đ1Xc\xWjҷH!wSFn?5omsk0*]}W!ut$ {|87 Qě [E[<ˊ;> endobj 199 0 obj <>stream xڍvT6CHAN1 ctH(% H"!- "t* %;ٞ;;9㹡o$QX!0Xc( E`114Jٕ0p(Sbqn:hP B$!`0P ## Tz#:@M4 QBaNX-9ya|@pA( GnA݀FhW ޻X4# Ez 1N|@hc_uHƄ<@cg8GyPp w7HCGq k4@0tEJ@`h;@9np0+~9B<Ѹx79. TU0Bq՝' pz {"~u7d_)#0pn~kuE}PΎA&(\C/ `I)0œA!Ը@G\ #zÁX<(- Ý(?qjy xdÖ4U~7IQ  Pww}(*j@?>_;.X8[0CoGB78zaqAoW3^j`8("S wG`aGo`n\ `p O8J ]"@(Vā ྿  X\^ڧ{~)Ȣ@ @Xg \) Z`^ +?op`j JV!Q54>)L)%q2߫̑Br' 4πđMg ֚# oo) ˯4 u%hҦɓuR?ا[ͷl}Ě+ -BMbBx쟍3qaIi}Fis/94AۏE ,EϽ0lgfdb'8}ff&㧀1+hvO0^F[Wv\RueM,22819d9S*nD(8 (T)u^8Yx9o J;rZ!t=6Y l,YI D:lzlL\ IΙ;*7JNLA2NPDص+e=&n.A-Y \r-}X jҚY5a78˻jmgqkAj^ wû}rݵvwkB]{fmJ dK>㣎p~IP[/)#&E*2[9yofv.5--|={ dg,8(z4z0ykf84ХS} !MS_!Nߞm7c3Yt !{/e+ISqţ'VTy;W:zWazXd 1_2ntA>; )cZ+,KTgeyylJZ@" | ,Ͼ|]]A51;61_e3|"f7F=~-_kRY1XXU>I*`a[ 2pQͶc^ᫀusqYiβ-I{7|Fm>'OvNz'|*w~}3\@"2^N{\HyF(/Weg}8!>_f"-bL +|6Gv8*Lnh}[};*2W$ B z*r>R/v8fNP+'I]׹Re,w eQIF"XUw&{ENc^T#%:hp xΩRxJ8ogU1ʥrMLQ] eƙ@u67KҴ\ elVVih$9m*'s.2P,Dd&A#m>OgSlWfL11+x ip6zWuQ3E[x1Y9f݆qFKrx^'x?S-{8*뒣 +dZs{j=_l"BÒۼhlԜu8&϶yR=)| O%%NUڟDޢBRwGbMnum զ]!؜ T90E17.e6uNrf֗Tbk0M $?w;~s, * mz2=r] 4&і+d֡{N7LT'ϻHBm9vFw׋YBO7Rg}UxLZe9S]ZbTY4y?<솷zMck]s刜96oLzw%Jɂ)p<;7zsJ\Z%0sẓ6kϲ$a9$c5:DlsϏ3;dڅKw*}" q0_FYH qˌ ;@s kKYZt뺃&|Eޣ-d_JXZ3|~RӐkP ?N =&&LVe7WHS :z$ngOk&;6*⯗NX\|ߣ2 3?],Nh`M,Nϴp:R @>g=v ,j8`AoHV"(Ri S%ϛO*s:iGGTB*&%Sْ5 7쎦fB(f梸 D쯙veq{gl7Zx+IVo,^Y=9gNZ҃̊ݵk91E xw9_Y\2~%J/gR^P+$8}g"ZBͶHkQr1{FDdn?10wi7u$"Y(0iu'H1W%u(1p,كˣBgLzC)J눱^/g@-fڢH"huD^@,ѝ+KKiGט) pP_NWҜ>KLի`P.Lƣ5lrUd/uٸ 9=fQfNLՑj_ole)-p`9 xsh=XR`D7y"tSB>5?s'nꝽboDx ]XqѭϽ Pn"R$c&-AREѨܮ=y7#|&ӸAoXs8^i<L5]CSzYz+U_## Bf.SJdz:&|Gb={: Rأ #swļJ8:TbRMEǽۏcl2so!~L]ҾȀ)x7=mmlր9X1q3"oZ:!z&(W ܠYDp~ m[=J9rCc>7 ujݷ w;RXAh)l؏xiiuaAuإ|I K%P$cLRMta#~+|cgX\#K,))^#5X. 2ȻWS~bE}mGB5ߋaE")}>7 s6߻Y/O +4H#VRˉQRDy:=t=FUOߵ*}\fǹ~66RK܍ix*y8eؠmbV\GR@gFx4Nt{ 4X্/,A Pf?=UQӠX1P87|p!-T2]f0q8ϙoP J,[dBoWL"-,Zg;;c%(!xR٤Ǔ\ [*S5hdl˜en-7W*)jg\~|UF-F#  8NQʽy;^HŸd uC&͍k& ΞWDQFY}N2^Qk˼/iNJ`wJ/, BaI&Wu"dRS!s U}V±f̺о;(oC8d-Em~xcya*z[ aM*(Ȱ%2OO9v$+SF(J,xH$6ŊCRߣ:TS3/Sٌ%,y¨{.eEsk@&B)C{oEAbSe; xZlj-(s8msL| Vdq/-A7Yx<@wM[:FF#`L@.TUv3`f}E Y^mbI[+M9ύvW @H*+ 7ˍf $+:D9 GZ-MΖj? j(zo9Iurֆ!o'@Rdgv,V"ߜ,r>@F3m-Kb^UmQ1,W)CX DsxIsb}J7ѧ0>jeq38p̉H yl>0C_iKPeE%l7/cQF-mtʆ+k~QSطZ39./L%o~]$9kʑ XeQajڧ9G-~qr. endstream endobj 102 0 obj <> endobj 200 0 obj <>stream xڍtT/]%Ȁ9H#) 00--J#tJK(ߨ9{Ͻkݻf<~mp/( P >"bc3?Z"6c0 $]:E ݡ#PT(&)(#! Py@Zu8 $bSz# (t\p Z #]m!`?Rp>vD\%<==A.H~8 /r胑`k\6{0~"6#GmGy`Z؂aHt;k 4:`g?;ѿA`ApWsC`&? ~9H8:@A6hߍrzzC" ($?54KV)]\0W} {|!0;_#ع  n`5ſ=*(vl~%7v6Vu#!`/`mD ( #OvlGFo dƖ *&yy(OHD̢ ݅b`pğfѷ=>36X0?7E0C,w?Po+/a@xuGG3߮OU Bs@%B/.e*Fp$׃ *[gD &?K*lv%$" ! o"ђ708 @#~SX ~~):(Ool4~ſߜDp[Pֳj9OQ)ͧ\|6 R4+>+q.0_~kÏhNkJҟl!8N7\m/!#ߵq3vf:[8nՙgWmopVƝI8XiW63tx(>&n/)ʗcIC6 nslj!v~ZIr `SĮ4&$ |R_R)dI@jHz&j3ڐR[iuӃr+Q^ujяza~(It)i/9K:*J(9镤+;xz$LiR8΀ہFmCRn|qnV.CǤ1K 2/tx;\<+1R]0sߕD55bM;EJp@*δ;3Ŧn(rD>IE7,(sA%V=0!J%a8.aS>h;Y&`=uʚK#H|!PSynf/1T4Shn^B!KIi!! 5J-#Q(ͼNqE3Ɠ#GZHLwW$wC>4l(B~ב:S6!U/~5&, YOlj hy̥U1 N\Id:v@ SQ/]tCG2uk@uѝ,$ ?c}Q0@u=44mg z{ I.DmX6WD(LkEhni(9}d{az 1,Ũe(ǻ3e,3&—$O^u'5oU;ЫM-([t` ?Rl}1Đ7N.ĩ2t7?ER=zYbf6]pD`@g31,ܹRo>3kMonFJy_^t.~X] |N"K#вMd Cb.ך"&z B##]],P A1±V^aV36~jzwQu0<~՚ζoULby[p#i:m:w \!ܾ-onVIz6(JhqSnuߧpk#Eq",_U@i CF)(؁XkaD5lPB- ^K=&j2}EHLjq2٩Y 13̾< fGSiU[x"5O-ݎ7u>1^E.)a&'ѩ' J:^DN.E\&mدg#bCbv^~v& -ޔ*,lc@+nNG)d_LQ0:}_U-!8]0ˎqksm1m 6. Ǒ$2Z{ګvZG7Ym&Ќw#0Gf}P${Ǖ])fDDzGbez"uO>sl"ɑÌxG^IĺO4Z >A[0OT_q"2Wng]ŸխTw ΧRټos`bA=swǴ-Wer{*RP)N{^Ou/|fYڏzΜ~4N NA)lV#xbg&G=We\[i3SSM/:Xа*s|^4OA#~kR2Vq`L׬=GY¨Eg dw%nMz.+1T SFv7rTr]LRSux·{pD+6:5YE#05.h߸=0п# lD)cZ͓_g)'IXg6}ܕM))=fL#C~}wiZ'I*屨{lּ.嵐]-u$#] pdi+t}%-ޮJ=ƭ? _(UwR&x@fTf֏;;Om-(a C䛨LQO'_y}#kjɔB̞UlU$uw:yx4tJlRB7Z+&2Y'cdy䴧}+ݔfmycj'DUzkɟX ܝ=XE-*b7x2G>[<9ЬOgș}u^=?XecYʀߨS0z@\)"Jҙ/~nwY1z:|wZpaťM*)j/b-HΫIƹ A’C _?cG>o\}ѭ$JrxdU=_!;YH}U, - o'PWoܳ L|] :Ut&UZl¥RFQ'iSW%bgGO i,CG_ޱwȓRi[J)`\R!zB+l[4Ct?4wSK5uƾ>VkS#9c^z`J"BNu0Y,e,5v;4fc>ج]™kXp8Hx>:4"9 P6!K@Hf./+w52:' 8G'0c@|#bySb?C(sv,l_}cu (g&1y6Qyt+z4TtHHVaGR#ikTʻe;m2 h v2\pI_c!@ڻ˛xԑm Pܽwyn@.=| joKLy[0c-lrF2[f1*1^5$WlyNvGZm A>Nh$!JRt6ܴѵ)cԄC]7ĔgWGScmVKZeWІI3/}FUTּXkꋪO%y~@5drjoSXz_yecvФ%^Fw ΂4:[Ay~Q5ewWHG)]3YgwIR!&y:gB;!]| +V\8t\GuX mz}mNv-N?(mۇS3o ;z?lt `VɊen" eԭ$ca~f6Us< /Gl#ڿhD;M2slFp^b*U yµR69 }$ܓlF_7(u"R%k9y:t5׼I bKc`UGܾ̃#-EKqiDr&"ViJ|Yςc9(C"U)7ݣ6%{5!9i!E͘0o"ؒ]3{Vp_} v Jv|'n`#uAAUcmͰw!}> _!1+m%O=XX%cpW/QjpAeRQ}zsJrKCy3PE5,('v\W`68cZ >,.hAQ Pgt}h=,J\"a.hR;LRXk:2#[\eCQiV[ٶ--dÛwQ+Bƒߕ^ȩԼUq)ey`ɖwڑ-^l7f@7-lHW0p+ YMyGQym!FF 2JcX>c3V<,oΦ jc-v/enHy.Qiʎ8UP*!ᅀfOnux\'x>|\vLgEO~ ͙T' CMk?n&_~5*^o5$ʽa]-M'}6qx,ez4rtxglޗt͛=!pk1!Z%xu@.;R Ϳ9sp Lo1;8!Z#xnÛxectk->g)6pzE ~F u`2٬ojrVS8tl-\5\KF PÑ4AM7=G6}S[C]IT"2VմV.^ۡ9 xW_-]` =1AD3M&ī^?-~){?g>cAM]Q?a|&_5jzhg4D\%&J=^Dt[)þN>ET mM$m}'݅{M0}C4C$M'{@͖L BN5S7R*9?ziZr. 8$x7{HH=5=ۊs]và)~YN8?S7 -) ʩb ?I#C>u"Љ*m9[OQE >OwmX3z`Ќ%}]nk;1Eq*- IuF%Jz{rAdEګgJ. Җ`^]e|lw3`(=y'Ǎ!գg'8Ы|[qM` e#&"VUp[&(D$_a1vy$ê endstream endobj 47 0 obj <> endobj 201 0 obj <>stream xڍxTT6Rn[A$aaARJA:$QR@ZZAB) }}9oZ{s]s]{fmN6cA%=T@ d]cK @D&04 ꁂ!2P*"]O8 "HȈHʀ@($7!`p8U0'g4߷(A=`0n00FB`P?RqFen(!< C;FP A&D 8P9ho0„x":`Cu6W?ѿ!G } xc[J3P;%(+ f*H77("՟* 컯uE a_c8x "`H\Dtc,+#uO8/z1*Ebo9/B`nB1jPB8a-(r[t/; :X0z`@aDqP,"S C; H s,FjG{Y '߹R37ҡ6ryƪof~}[lV/<*|oʨo>X0,Qu,[̈́_ڢé_Bygـ;ӑ Fvg2]]wpI/9:%TYb^͡XZ)Ƕװ42U7$9iaqEScm  Uw'w6֔Fvf/^,DU}lM?SJ#%p1|uyU_nG)\.x+,>RI8Vlx.^oMGqx|dM!OKxj %fÛf/LrZ0ѰJi^(vieM$~%,GTX2Y'J`4yVAe-7*590X09FzsG -7N$ѫ:pD}>ZViC7>V-n u+OfхLgrQ^=exFo=6C3WLggdKoulxͳJR6i&2ͭ). {"2Fs4T9CKٶG%FJ 8>hw3^Vwun&fעXLȅnwtn#j]2J $w~m\>TLނ'2Qߙy=;[ʁ ۮ K+F{<36 l˫nXcd0 ?ԄQ$,zݤ<X\ڗ|'Yw`wN攅v=R`Ҹɮ!H\d ߺIP.el*fF̗jd#9߲Gw v#@)O7}oZ}){ѪXn }[703h9V\&jx0ߢ Ӽ*2 A<2k|V$:vay.FҳkJ'&zB9@,?Bz`ݔ~ǛR%?]|MBz?e2<({2̐tt0-&Q*A}mIː,|{ұ3Z .{ڧT>.mBx"uϿjUu ህ5"'Gw&,;W𠂟EIc $Cboe8D~)FƧ[TsQ'sb{lÚVP{hh H*_}{. ilLTXn=YÓ?/H1kNBv _7_dz㣒},pF~\dRUz ]PZU&}PUGWe smNi[-zZBӷRnR{^WU~9Ca !QL1(WBkצ`G #hMt28EşI;[ͷb݃dp"/!btFÌIG*EoV ݃mUXU N޻/˦9X𾉛:N<0 < ?#`ЋʖR1])XN\K8Pdڦyf mar&PQ:(w-[JMj1~7٨XWpGi*Hl͐f[!ǡZQmckj+z-Ytw<嬭JU\yY`X͢1[tfDrrXޭ=8^Ԓ+;p 7}b)+~FZf]R?f(Toisޙ q;ZIm}E5L0BoȸIk^Zѹ-Z;EJ&2C\ajŧqSzʁzrI_9)s9js ;b^rkJtҝ,N>@M^Ƭ|Yׇ<;D] )ɻ P,= 5m5x?rmofS^4m#jj'y0\;|QLY?6^wn_0qFWsv).$'Ĕ(/RK01n뾬 ' MgOV-5YER5[l,'HpMT]82cTp?h6XTkP;]8-О7pnxhՂ5lBphB"ϼn&{=\f2atUBIq t3ΩƳdI7_{}j#CUpڐt< i 1`pIdا~N'Xe_xo7^3NK9AnXp:PH~t8}xjRn7 j{y/yzu{ݑ q"j5//Y$cLQf+|7?Ī_jx8Ḧ Kh!x^rc^*?cO ,l} 2^c=foƜ|cPCB#.L[~pnuP͓ IvnPdGfPp(b^mV(H܊➊M2*\T`|9`gjDnJ4i1WUlY=2?H_xH4 .}bj ?p:!RߔQA'AH]DUܬJ>TKʇ_UtbXr=g)%cZ|NoIJ಄##'κ%}m@#ͯ&YG+o}֚'pc y~\2鵣WN)1yc '6 )bߺo5y"q8^h ,ǃ{Kt3]h4p_Ghpk䟝7pcJ wlwDLF3TYG1-QX̩M.m *l>{kN3 9Q\Z1=@>q|"lVRQ^d?q`pȊfZ'ƹ;ޒw).J#gf},jT-gD36F=$&a ,O: ߣL KlX|㝷Ǽ0R&\_|`#ܻv"Z æ,=1nqӃҠzGYwvÎ9W ތnz /veə-+Zt*W*8uynUr<3:sRtBMzru.j)Ͳvd^9o.֚XAfB1.q+Ux1h/O$Z{MS*oҏ|>ZxBޭͪ*1Iڱ,kj'nmV2%1j5Zfk^D~MZ/F@ o\OT/Έg8)}(w\0jC"vWSV ߯z5e!w|%+l\> m+":.uznĞt?@&$GfY*=L : QrF2[7 N&:s*9~Z3殿ىv(w%~zD,-;6>ǻ%n4x𲒝^ɓ(S ,~߷P*wH@]Z5æ}sƓ:c8eK)ŀESJuaL:LtBNIK-r2hXftAtE~H$ju ;Yyۓ0I AZ] U\+ǩ>JRZg5>PG kǤ *\Z%65҉?GLX?oNמxTy9Am8 .Pؖly~aZʹ^0W@:W=cnz]kJQ~a+|; ©yA|nLy޷A8EWz:ʣi1ʏ=.8W{Fo|Rٳ*b"+6 'J2DDcD& ^|2^/9kΤ\ Hd:2PJx_]k^lv&\{2N< flέ/RssOS'd=/xHp#,UhN4.jk걀h &hk+9Va|rG_Cy TP G8u Aq "--SY&n{CSOیVw5* h,1Ehnp endstream endobj 51 0 obj <> endobj 202 0 obj <>stream xڭTgXT[%J|sF2Hnt7DP@ɒQT@rA$E@$HMko53?]U{ժZKJ\ v@pR*tšQ&h t000Fq0ta@FVVVt~+pp wEo큄p ` t A>Ї`00rF! Caa€  <4 UV|!0_.1A±X?0 G QM@|0s4`8\Ɵfi~@S zchܱ'aY} RU*!X$7ʯ-6\N]fr Wr*iEŌ#=^!44}."^;\PD4Wi ~嚧W,)5˟hO\UVu&y}$uͻZ9J$f\VG߷$-!=O duc$oM~,]@ՌtL {HRɭuTIYd_J!pudKǀ>n;6}Vi>iww^>֑|b#\+'ӝ5(W^si٣򹔄/34C3G#L4ť0x}vR Yf;y'Ľo_tU YVb88nhl68Yr蒎6^e6<>8/U"2RZ_lqR>T16XUvB̡N%Ny)=}mY$îL5Ab`pʮn5 ߼H%Gx=Xnp=1v6Qqt}|g;e7k'+Q̻R-u;k) KsvૹO*"6CS-,;]җ؂n!Z ܌vZ1%Υ!r:]1:k֒| +'c8OƐ9c` l./<Q*yј/ On'25cvl*3CeV-,|o45yr\Say0ye%yW#@j|zי 8&JQw|P4zUe~oHcg__/!ѽ;UH;|J׋Ⱦlrb|N9Sc4Uizn $9'fD\MH\6w*i/Y! Wl^i]Ќ{S[*,Baq͕G\9 I`3D*GDvɣ^u.F1Rzd`m:ykm}*#@ Õsc44~ƺ̛s ]>Z9E +M "!u̿2Oj#2Q??%^YP*od" iEp&KZ֙%%ں?^ixKYdRLEVHYQCņ;WӇ?*p%6%I 62k?e,+4TW]L6G=}#挲O*Đh =!ϵ@` AR r)z>(EJ6ӕn#w\ie3E)\Nw΄"T)4Hi70}Efе4HBtShh;`*]Ѐ몒'{#A~.E۫=Q{X2")iO2C!ZŲJjLU RL)U-b_(A%Ÿ%؛ .GNM02wQz)~#:Ks|8l'fF3G.rԑ#{ښSeR=u<*]6^y8wIwUF+GQ`SR^%5<[tVy8HBDz*JSjZ7.!Fi0pM"QDDXQrRvu?RvOq1mc/ZFy~>=P|MPf& ujKC6w2l&l럢\iDlǦV?剼NHli%,qUг{9!40WKЅ!>G7#b r2>[ShƮ0 'N^,K4=0BMB4jdbLYxN?ှ] 0uX&zgl-jӴ3q'a@L gM8NJco#F7PƷV.^U4R>37 @#YFlTJpy-~H/p,@t=g#;n[,ޢQh5RVZƑ, $mKٮJVc1py[,Ki ~p!3|q\qeSVݢIhR\ mo;O;gJ hթP[EgFe Q#E} q֌&g&ُJSj>f[)xƂ'Cg a;4m=q}?LA|js񍩛f|^:*z#͎IE工a<3r6Wκ7/Ո yk`t!;z{Z<ҫ 66G" 1m֞h4{ֈ&e endstream endobj 145 0 obj <> endobj 203 0 obj <>stream xڭweTݒ.!Kh4kpw =9ΝgkSOSj*2u&Q 3K)++'>XI nDw4uqKZ--66+///@ TӦc``zoX G{K;%h YĕUteJiK)f1(ؘ[],V?s_0cL.6,=-r1-m\\޿6.kgS{\6`s_Vrtvx8;8޳HH+.6n{_%{yڀ]2Xظ8Ls9:MlOgKkSg ;;_gV#GWK3+{Ns6`$El`-n_3CN XXZ!(9Tfo"E?qUBK@Jx0_;dۀ mYWfF)OK Ws ީ` Kg ]ѿ `b_|@s;_lE:6ÿԿT޵wr|'(:X/ 11O7 dbcp'ae ϳ'@O Fl`׬- ݜUſii?6-3ݵ~o7+ǒ:j.M /|-^_vq@4])gyDt=km {A,F%ҏz)lq}SU3*~#hcwF8 puD3OݎVQ[ptLxxwK?<8g!'/,O+;j0Z%4qRW!Wsݟ 0AxTӪ9ep؆H&z?]o86ꜱ 7`Vb]9qts,UqD 7ʖ>>NK]FCX\Skivi)omM=$bqXt\~3G9ƪBxb Q۸N4G Ƅ=:MWd $=*S/!A-Xɼ~B*Y,b`)bf(446f +0J?ŵin!/l1 q&`LҶ*Xоs=O;U0@n+a8[uoQQ@\>Z>dy'B(:EDȽXтrW#>m)UJ"f]X )1cc4n[FmذR#q|X M-O^Sn<usy޼nkgC@9^ ן2q`y~Xs1.?<LTf݊rW( f[*D& ';R ϙa 8 X-xmet_YӒG$q wWf~+H_&Vo5AU*︈j71NX8 z[vSgQwytէ%ĺ<|cyYɄR&B?IqaпxP7 qm.%§w @e͕G.8K?q w:-q7j*(+9cr+ke!wrIyhN_ bƢ-r[Q!lY؅{O'kc?"Է zDksU ҷq@py&+D`l}N| V{[gifdZ4U8H:7?S}tQHC])6Y{ua `[mX~'i;h'߄{ZtڮKV +.($}ӏ+"&@ B3cv EO|GFH Z% V܊5vxyE~)4v5]"teًKO^κW\_, W;g4𰄂&7)˜?Sa~,Y/fZ\rdAP"Ecy^b +m)a}tCuŤ-Y= ~|YS*n\ȴ/蕃qx IglڰlIӜ0JCL*'=/ӰLI:KfdݮDK+2}@{akaoY@p%y>唞ph¡H \ Nވ!$&C3[}f{G[Jl\QKJ7(ɣLm- GS>|1 jKHauO9|_6/L3!H;53Ij]?9fGbTXt/\6\:N(-[r\1ճJ "|@sKĴP"`Ns*̜R2DEk0Vq gށNom{J|(Y($I~Vwa?Y&ǟ VMLt*̕*-;& XFL$t: n̝pV,vLrrJBp$آ-X>8oekHM${M,[2y"3&QB]pa/r8> D:Έrl,s,7ˮC/aïI/0C@7Rk_Ip]kÔ<$9= '8v8-*4HzРD R1G _Pَ)y~;p![f){=h1( Ⱘ*Խk/{MCLC*D6vW꘷úN1"Cv뚍 zPx};j2qk01{+aT34"&d?_zjZXZ)cӻ6䭩 C"sB\7т3P=v|v7`m",ڠC(5@B5uRQv蛘 "6PgCѯd^kfq8O ^Ƚ\'Q^|zTfF*ZwW~ү--ؘ6cG2)MMHOw1Q'4;e|]H|?(;(B >1 `gtׁOt1.tr5G-jͫmQ_+–Жy UB"W\&@;]+ߡC8϶:h)83)^u2}ȣ|b| ~:xtDGE~נCR&[`x  us渹 Ωzkog|&pw<_1ܢ , BP< ƩUqe$46]rfCQ6vӷ~E#}}ē)#9'C|TGԍuvu=O m0a8x>gj;/?]1rͼS FL坾()3-;٩D2o6w2`D1rjju;@*׈i_%Ijf竵gjAlŚ>ixMHcNjIjv,ɘgrH~\0OgjR0 f"T|^u=ǧ 1$b~umq`[n/;u 7$+ee:clؕbį"iNǍ[ׅå=b^ث ;bI쿥"N6Xݠ#52q4XRR2p8?$&q14ޖ Np$ݸpŅGry n6V`*NfdQk'>AKIψm7.mxecYl8wF9yd[Ԃ~uNU>Bl@ǨYlN+Bi"@:7yL'or !eیdUYH WRnK|yn|oS֘HZR)U?VIV9q q8|D$BW'?\]Ud!.~s]~PU _鏍$ RvMO%^B#?+Xjy ,z_aa0!Zg]mee]/ϊ̲Ln&4q]~ZS3T,?V]@ sFv"ydnQՊ'0IffI.dU{n@Fh K@k!4KFy$kA\TX/ZKygDCZNj8ۧ5KytDϮx fGebe]ao3ccO:e*>|ʝ7>Z~  S(J!EM7ɼM񼢞MȽ9( Cw@ o>cWڹY*rLknՙ `kLgP%8i<7tgRrÄa^r=wvoTzo,`ƟedWW%C`d wlr!{V1Z̬L–ڀtɭ~{N(]F}Wه+ F:e iL7l[ꊆSQR6GƌXU#?;+7l_[銘ƭ,I7ϓ]*܅|Hvt|~ [ ,|[ ZΡϩ=eքxMZk0pᑟB1W))D!{߆`tmut쌇.dymy$R݂ogQ b&ԤJҤ?nDmdo-~ *c="zƀ/7a8X.#Waҥ9 G'_u0x8/V܆.VZ&D1 QstdWSY~WTpt F\-}}]aPoIJc{Lv*Щ)2碑F-fu8LI>1L@˗8e 吓˅ta#/n]?x| |T02Y>a$ЮXY="5WtK+z_z/u0֥P:XKO٣qnV\$Y|Ns2b4דw.´a@ݼfz=wd T/gDSpdsWČ7N6\ ?ai80'r2]TA䈿3ܛ+cn9@.g\p! O[ۚq~-d/uSHG >\T7E8=mI;4!K`Yj؅v(}ۉMIh[i?-4"ENkO&)(T`Lmc4b$[;<Յ2;%ZJ-C ^pJH\8v;zfdOM݊ۏ~CqVV)9 CѹѲ}v9KB꿿ט3|ߒG>,ʼQ{Պ09K5qSECG)tpwʞE|Z7`{ @Ɇc{!X򰹥h>??!8Igc(uug4TwNRHslsnx$n?@Y[L581Bv[򪜼taQ}uT< KQn+SpXH7o'#FwGSÊ>0wn?%H4lw ^iv}_f4!z,P|90$޵ zYUodw?xG"D ,FkVY46}-'~%,6g9C(Pηɪ*S/NRh/gx y`[YTVᤎMGƺ^{ujӛ'A u>$ b^S#t;@υǏdmCzO4.K@?z5]R9J(|l.-,߬At<5 >f>O>|02#ߏsgfsVr7ΠHq"1r5^kdeWb,e'Hba4冲Rg!?|Pޣَ\4m'vP Nj$1#Rn1hYe]š=$7`jZz Eɗ6K Z-C\KD s,kkQm׉1r?n-y0>}՟7iZzRZi5{ 6/a;;eW˜}a힜\0kѲ]ǘzXk^/]Wr8N [*<6dUT^ݲ{EbjI/qs1RnTW_5wjD֥88`g7[wNvtG / 29 Tu_ZnX1r Anc9%Ey=Osɛv\l=C"|1_bMQҭ _l:omZASe\.*\ K>RgrN/i|3Ls{Ƿ`A1'!u#1aP"+rυƑ诲f5f!aFU0=ݨ2&HScÍ>\ lڋ']gfI(g$;*A,#kֳD|xf )7ٳ1T b|i=n`{Bt9n9(`*?t7i#}fJ8ORv<{~['>qj4YL] ]aM1 i2a,KpN`lMs :HҶޢ >wD;c8$/![dBh"l=t֍{-8LACʧHxq~e#تnOvzK+:emsiӊUiH(=n5WQ/ lt!54p$ÀE(p!`Z Qrf%f֞bC)ϋΰjl_M"~XqcݖׄNʯpxc}z| @gobIꅹmlF6Hj+_9sc>;XBhch͵54ibY{UE7 S؎M.oA^ؚS7 Z9@OxՓB1TJ!#g8JH'[>8ӗE&qc'5/T>+-I[}v;oDbgɅG[j e$EՠR-,փn+2id빐PC[xץ.ڥwySIr~soLOa1N& \޸e-+]"(G+X!?ϖsՂb&WyfNÉj"#r<7`dD6Ъi!/)k*lˏL]Ђob{gߓD=)Xeݪ6z<(“}&@#Ka#zFjVp.IH8b~0:~s+j u@UZuڈ>oVaED go"{ӜdۛU7iUO9XoJr/Q#p~u5;W7=K; Q{=K ^z`c}N_4v*Q}rr "qH$G!ab =9"vEWf\GmGO5=־B5rqzqLzѩkO+Y2CBH4sF3{HDhSw.I} `*)XU.!pnj T#ց!"duL9!gc(n\:2Oa ^ü/_r ~=n!"Ph $ h.WGR~͙ѮDnaM ^ՉJO&i4fM: [v{D(z~)zxs6! H܆jqe>䈫E 7"WKGޚm<b(SLן)a79|XW)Iyֈ?bsVilsj{%;X~vklaY-k=oJ[5-6:WC8v63XEFFAx=Y)zWA4S GcπA[ąƎiK{Ez]qQ}΀GfhOljy8Љ |W}a-ꉳ𐉺p0B<-w9y~]䩕;S(# ;y|AkD4A;y-"siնb6,f0sy%]Ȅb{f ?f\pz>zr5L3b5r&W"QAN ^ jXkI"ڑoِSb -n/n؜;=Lsa6;,|nW<7)83$c0b m >a Yԉ'i |ngW?J4 Wt5fMGcvD1ƻeC~i"cDڻu0ci+v7@Y!4p2,tHǒOBillʟbHB@VMh Va`2?rVn^⸓T~M5&+,xFq4Z$"BY=/`|3Oϻ'tuKf!eM'З@E>!kO A('Ճ#5˫29NaRȈbEej)NG|#m;G7 Za)gFcP ʀŽ$Q>/Ʌz=?_PJ7'ԤLjwԅX 9VrҒG әLFaNrv\­5FnQ܃&"Nj(/oN?J\؛3O(2&21\-Up(Lvb(O; f2*jۉ}|Kpv+]aFZ9 (L"O:? :yU8* um",6-3ܼ0ߚht%1H뱙jWnXO@$-CK խU$oCY2Imѵ;ۈJn &ύF\5,y|l#r̷amZ,B[EjAJ!&AŃ2ϥAsz߽Q{N~"v[\c|R\I&ؘ\57LXW+%2~ .#t\4*8]/|Hl&9NV,ڲ^Fݕ>D= -$ (( AO 0,V:>^P}v!w^FzkJ&/ ):[yEr:rR<id7(˚{Eqt`he:}eX܉>oڜ^\Igt\ŧ3]Mb徳bG0aC  ոᔽ=XI=NCaVP/5 u 'Pc‹7e? Gri`MKcYSvJ9c>D8cc껔_(FjW</9*$C2iƁa徻p,8ūd؛[$fsi jGs')ض2ح 8*1ǣyG"\켟5Loq Vƨ8dWQ-3 ҳS _O h9,##sOؾ~F{=0"MB%SzKo(zD;$l&Qߛ ?\b:9M(gM,Vlo+9*I@2dxU- ~s:ȴp,l 7{' 2ⵌ2fe^?MeܶaM Aug#C]`vV$~>7lIo]d6TʸdrQ%h &K~O"@s<ڕM9*!_?6sÍȲE4}<[ t0UbߓlMYYtG;8EJ<V꣚T%"eJH ByW*ri<V|DCa%p|S >$M .1H u6ƴñ6֏TI#}% endstream endobj 67 0 obj <> endobj 204 0 obj <>stream xڭUeXFQ: AA;$F@:.8wu1sϺu׻^M"<|u3B Ujl5, `= "2GaPys$H`ȃ,~111\ E 8e}`X\@ESu@ C@9 ͗Jv%u= r24K-AP` s@:,aP+<\29Y@n o99gq2"{PKְ? `7{2MtÑ剴5GM+`4( E 7X Ǿ';Cm7 dcd!4ܿ:zs8?s# 5.}LK}l0(Ca~V`. ? b=3I[wW `? D?qxߩ!usk g N߻oH@m e#n +M0`m CAi0][=A ӿOF j\ny? H]w8a `V<摕<"(@TTDC9 0(@-aV'Gi~ÖNNy؃@n K D]wr~y~`x~lRXoJآXuY0OՠmfZO 9 EњhAk-$ݶARI5&`K )2"amͳSCUj sr-I-ƥ뒄Vb4턺H$NjOt; wZO:dY~mU|m6lQd*iittE401 ֖c)oaئqE^ݖDR)ڈύ*rG{1CBm"K8GUtXXe+T&1-~[FF~j@ cm%H+ThڠYie1,>ɑShK-]=#(OGh}~׶D/?H^7Hr%%=+nM2v 9ؿڅ`ZWNa bO/Q,r] s6J=R*ef5'=+QAΏ_¾uwODL`s&"*Xn mK5Z'ŧkUD2Y/=tZDVuUX<|aO1¡0ew[ j,-+ 6`&kc}z{^5f=Oe6 x`ihHNhe ɋ: 7B+W1Z{k/coRY)_NNczkC^ eJ!~"C/(maqx=A `!~mKQ~gCSȧ{8C8Hԏ}p|ǒ| 9#XJ㩃9W%|R锻 :a dq?{ݛ<;l_FYV>aulR|$=`BYHR՞ZǶ|R ^O1DIYix6nUSRl- kŒ^c9B}n ksȩN~dpċ)pԢG(Pw@R5Fϝ"hܣd-P\ xގ]mJR29rmU;E/"}rrrv<,x?xT*0үuWk#?CLQ2B0lSqQ0OY^FKoΕa\Ki~,=m4NnjKfQ ) ^8Ёz)eNLM0>L0 }2^d-c$oYjO( plM2"(&94nbQm\D*ϱ`l mş7, _˥"3{J}s1 |=Q_ j,khK}sQG6|h1pz;d@څT7{/ʔ 7@,,5#[0(@w3ȼɶIgwp v<-ʿf3(A'M^1[4Sp(riphRž=a'M!aQ3|Nw{[|q2xՇOVtm}1/58vF>Iăsu9Ɩ3/y{#W)t \B}{{ X,c3)Acq#iۼ/ޥY$s%[7Af Z <,lX󣋠 EHƓɣ&;{Is?M\7/u|zP.JNtӸw4J_fDG|bK\qBi52͖4;EΗZ^Qcfrk\YRpne7py!8q*< 8SڗFuDts3j[V'JZLX=_3\IHWX,hK`a|LGS/|ͅ#ZbE򊽵qloHp)_SThd~bZP.6A^E?As9輷pi*ЭirD՝7Xkj5ɺ킎O~|v4ǫ!7=ҧéZtؖ7(Bd_xT{Gڪgg/dĔr{#˅KuD̓|2En(lS6HD%c#W'%Ӆj$ŝɝoPW#G նnB-}ѣ&٦W/GMPf#)F۲3pu#^uqS<+YUAH'k~9 #_/y y?Qx L*YDRWä_}7ɊGvfɗL\'=8.T׉XЭ^(:?B=PP1/@ރ8180 BGr usI\0ω/(a1}3+VGZKTwyEI=5 bvi7(ټ%`YXy!R @Fk=mJ(@7w؇:gz8ke!N-2E *9X1"/=x3)?[I*1QD(uVb C=v@A-H{JPtpnTvΖy]36"bMM Pvv! 8ig$?ߧ+l9 7O^S}!QG`W2+L8f_g~ӣ97-[%׽3H7vrPPX($?*°pԻB& ҽPHl>@*atqZm2!r2mWyՕН!u\ֲnlݬ$ I+Mt^^C+G"o"d4H`U?`̩KjW+堆OvOFHR,T"٦:ED,y !-= u@Y\p1&(e/[3fnK%_Z4~+/јmx$NS_sa3]껒N"\L}Βrr UaFço<ģzcp)K 10qU%Ob<3JdQn}j܎8(D5=ӚHzq\"Y. 94#yje.'G|7c6 AERNǶox+UJBJWW֫=aT ;߆/Qϲ i#BK[G=,PR^ ^ h7Vϲ4f碯1Vx -FnBumV+z$]1ѶX.mQG,i\Y(nKw,eRly* @glɣ&*cF layx_WGM}qT:aeWE)rˋA@oZjem{pepHy~NݒjC{~k_|2>Ol.SљRc7*O%D#zkϸ0#7\6A}DE_iѫˮgL۴?pDGFmN s3pq[[ۉO}|ZZM?x\b g(!ͪ -T)̯ɻ (V7$U² jUzle K8WsrZ{6ss@~} ?Y o;vi$c\;wXy1M3@8s$P(s6DGcjvm ;y)ϼs\ gr˟vx5@˙ӉʳHyŠ#qgwD 8v+/ QZCU6;c%?=ΘGL(ڳP} ]_n1num;zruMHH%/Z>ɂ@#+2-!lԵgV+P@55')X8YO?8iܘ-#玩#"v[<%-A7vŘ:r&GUilgeLTCM{nQ0Xv2 8L<,zd&A'1upF[%Ud ``腹+ّnO nTMNܸ͈31rMϠ#pZNvS^RAR$EEzXhy{VFOL% ӡR?POcr)hA1ƭF_d?SiT2ν:k} [B.w*lX_mj"I뛺ޟk 57 %Ϋu} xR*eكG۠/EK,1RZ)'R!=SjMU$==:%IJzϋO6ԮpHL8B'N[濾sۚ-=rn' ҆^WKB%Ŭ(~8x@>Wud$0+' IFy~d1K7Q nhヘ;:& t;3-Cgn,e6^C8ze;.Z|rbZu^= Y_5, 'a?l0Q"cpɌ&r+7]T㵿Papho>>N| &1:B>o EDjC?} -|+q5MOQFk!-^amCeAcD-nЋǪ j8hu|y$9OIVcYS~Qkj|pZ_ m'VyF}T9hO6'X& c s" [b%b4S8`i 4·%^s;P4գ.!UpIJ⺫O>Woeu!JS"ݕ2#WCw1[Ѱy\2V1;JlFdUz_H,W?tc8;,/uk̶ГYw$rA ^UYɏGc4⩀}Җ={o{~AvzM#S|C1UQ.}L8pvҞ/կdž-IG*E[E X oLԉJ-;drZ a6XmMr.{F&na4]RkkRqۮ6dF@\˄u-p:K$pmr躹t,`AE] W ~۱>~e$KuLi)hr{19<IWI `ٜcCyl.w7wb\E"h`JCGAoqёMF' d%NP_"Gi=%TG;Lܒʧi)q`*a2'cErac1^e⺐&ػޜ烘[-%76~GW&Ib(  J> endobj 205 0 obj <>stream xڬct&NE+m۶b۶*YmIUlVSاϟ>ߏ5sO^s^3"'VR6s0J8ػ330L\TfVrv8rrQg+ 4M,,fnnn8r+J]E$L毧=;h7*p̭lQE%miI:@ht6(ZL.@j3?0%08M=M@g;++:MmWn/@-Srpqu1urtͪ$&oƮv84s0uu5w=]eY8{7տ`X[:37to;:z_V ֜oNS׿-i{s3ӿfnStW mf@s8F׿)Tw,3@ -#?9.%lmw 139?blge֚q5Oߖ[B+ +O%o%W7:Z虙CfiejcV_QLKJYZ\ew\ռb;?aDD<>\zV6w/ n&Cb'@oLaMUWc{Mݜy@SٙbaMj%E}UFua ͳ<^+?ehl)Ҁ HP(8i 35c}v t84U ޡfXaI݋1Mcv4>H>}z黁8ģKk8՝D}QGfM!Ѭ3K޼f& qFaoN>U#X?VLL٭tA mxx)!U=)"bnR*ʢ= ⇬'[„7? {\IP?»IQ ~ G$B;{:hjT(N e@DF\7Xx=obV|ͮ x#Iv>}5Ọ4{j/~_! S/˥ rDȢ*`7q~JDe)n v. ZlyEK)S/TYgCT_$91"f 0]J0WqݸXS^^֙lܹ9NKZV7x7'oDMi42_ы wWWӰ("`L螺=3# 'J]ľV Fbs|0Vn*x,0_J&Bza[ale)i92u<ףJ;2䵟?O6faz!q^-8́b$z0UxuݢuN5LHwnJ4V1}h#*եݎ et$^=)`$c:>PXy9/!Rqx'2]Et˞H&q:P1X"6U ~ΉBf &S#oeCP; J=zǻ7E*]|*j_d"ة *eoe8z)vS@]O1wkHrԖ-*;閚r ;vE帓!ayAF&>şAaEPfy"Fv &gq>h+kX)0m[YIxnaYkXfr(yۖh*β^/0O& 聠N㈸:1ZLաX1 cPeK,jje]KФWXS8j%dE6% #ZeaCQPlb`ǚBibnU}utBݺr)װ"MD7{NuNifbM-[~T]T"-O7U!#ں)ʳuڷ.<7弗_G҂bHk{L5 Tz.Ξjl7ܭᯢHFWCjP9wkG y~}+(k|Zu@"8=q_.{iƨPφD1ܮүQͬ9MK|G80U6^UG?aU3ƻ6tSF>B%F|?@SL^-4~y$DH5ƓeYzAx^4*z|{*m56i,@CJ IlF7!?=IN^Ce4O+1gP4Yuy|6>rKw}S:2A@ry[kqe1j!.TFHCnG~TSJ"a I/}8 v;rQ|ujl+H T+@5殺02RKvi%YZQM{bÙSv3k Z}'ywtFsL&XYS 5\.* 0& 5AI ƅa0wݦEhb=u6S))R*N o;M(7@h[B=0ƴ'$6If{=9z\ )!{€TvT# LK$*s)G߄2'ʏB_?vqI D'q1:1]Ll %Otrj]Bf}h Hf}n/)oOZg߈<꾜c~_7`.f<7yJgSR1pFJx,^J=j o?8kwK>KFxT-WEZ/#٥kH&QqA1@n {TU,C|ȗեog es"mdڹ+wY:K {y _Q64XוH {*+OM)؏WJ 4jYZ8.X$C〶i!ǓEqJ]P~ځpAU-fNY˟kK30ձXڹu*V:4G*dH/ӹngc3|6`1exs>mM3U}R+ Dd%,4Je]!)kcGƊ?x-"U|ϐ*U0 c/&fGP®`Aއ{u{D̳: 7DO>sE֨x6N8 ! 幾\bܭhG1Z({mߺ} aAN@_d ;h d <`O!+˪g}DÑ۹Ta&&I=2.ǴY֧V-ԍ7 !^U5~ Iw!42Ɉ vI{jAŜTuՖT'DƳ$̉X;DzܒO0gjUKpVԝFe"b {g\i(=jS;z:Mxmk7QwyzvO]`A‡ZLI90Wl "U+ R`7 ,*$D6 P6}rvLjX[ѭa&Ei#wԉ/mMf.S/tZjnv0>>Mzn&ԣtԓժy.K xM^۔ak㜳AOGL( VJaL:o\LIf::y&1\o˛z5/2;}hKG.5[gfVm71=6sˎajg|#a2]p5-Bsh\Cht`_Rj"u ;V 4*-xv"b~bTIdσѬڙUttwqf,| #Y 36]1 y'\O*w|l-SY6=e-Z?ŹÇ^{3ݝtѸ:daGO4"HcSl՗00olAjv:K{2^%s6_bl&]㑫 :z" 7lABq (.edvݠiΐw %xpg4B4 :r*USߴT{J$h%wLP lwPADnD{(@.n >oo&//` Z"zeo˿tzw)KXe,@6 c[Ή[}RO3x4hB(ndiϲ쿩w+[WR"}fE?d L ~C6]M|s1唉C25Y)"Eb&vVsO%.ͮWPa"2FDxI|髽Y*ALmaUFvˮZXSL'` p)w Kی|~K-(mǸvOME&Ɔ/kꑼt<h|lj l![qt\1͒8 ?a*GI1 HLdlsp8|pN2zQ Pr󹇘C^gyJJxGɡs̄L&V!H1;Hush?[b<(Xn_ė?jƩ7V cMRf[TSlk@hvqg6yo}giU{q=3ݦ7 /H~[?v-;RǤY4:/ɘqS] F;?gd^rRX.x}7mmGjQEJ۰+]@l"DkV"d z1Jxa2H3P3fjqwri VLNHsF*n,HQT"1EXP.3>JܚVLG*bҪ 9B"Ǩoo+i"S@:>kY.$t:%,#g{+ET/tŎ'GϷ9eYe! Ȋ0Zg%$<':;b&{amr^q.j,w7Y~thz sZ۫2Bְ7u#Ƶ;M- ; d9Y?bBBmڥk1?|Ll{3I|F6bUUl +\*\7KirDwBׄ ӑ='/3RĴ_%i[h;hOJ~'wQA4{r:Y=4'SާO;% m1UOgC_sy#w?\.'- h:ISi[7JNI-1mM ?jb0һ&o H׼GG:86Z]ԍÔG[NB$xO}Au&q\1[Y( q>elpOצŒxXq< fws$cNlWT*T{b^2;XExuvv(h:C:gW *$Z;1oDj5f9鲥EqBdyk㷤e|_]ut>,`Ne5%#Ìh*BR] u0q1:}: <U9Ӂ?wx' ^AX9y;7bƉjPU '@vm'Wp hqfX||(7 !n2jOv\! NNE<9UOt<d87 ;bq0U+C~qCyc 3,(d9JdO ICH5!#|3}3!zo@"iLDZ F*!;dآ>GɲDl`')7˷'u w_q*l䑨b#U'\G Y$JO*u_WQ "N[KſkW*$ml!gԚl8{TsGoC҂(2 Ybs#kF lTrY+hhڳ?+L'ۅ|[7n 2,_ݓf>ʵt"?@fY nzLJO>C[?c6 #[eB 4X۽nD&soQovR6y ˆK}p0?}$NW;/7T㫗tEȺZ >Z t8H>cLԠ [R\`H||1M#.rP&z*,mIMS*]m;Ne-`I 8IU ?oĜ%%7i;0s2ӧvAg%mQ0XF2Hs0߮4k+lTu=#־?H'NoM­֧yfZUhK's}dR[ԣ,Obu4m0k*ȕ_]"DARJ g)tID'e7pora K!^G8D9tԯuru" TgؒՕ@֯:/q&w{4|8h6qIc 싄NM$CG;z ][(b!z{k2Jn[#f0Mݓp`Qcwfyp{&Ii;}"'~o2t#C`LĖdz_8a EC|(]KVl~ P ]<>su~럱JhjzSʸ6z(KkÚU)1d1ʙYw h_w#V;'UGU\QrY[Fe:Onձ T1X΁J6};E*vYkraUܝlE} qGɷ1;j_4Rv9Ɖm!,"@IF ,p6K{ZB4aOՍL(j!k_DAk1MWv1q@3Y_]#  HM"LN!. UJ:e"-Nۈ!ݏnFF%3 &-ǘ'ZO|fViyfd߻}vSh]PיQ~?|GߡNqvRGJp~EN,~oѪRęv*/9phUrazV+\~ƜpsWXK h:(z"(b  &sߎP `EG'cdo x`I #Ux0^3VҰ;Fi*Wʁ: \2VH{, iۓq%x@-u_t`VICN[x돊,bi_2}dbBHY0g-, ׉"!1tpk0QHwhN>mgdni`[6E^^cѹCOvFgO1cSƩhpfex1F3H'y"wxHXoC̈́nE]aVwç/AR C"nNC8}7(3OE#I6SxWOޚRu-N _ $b(bSo#!Ue@W[PX#ET)h1TM#Mœ@9zM`%[s`VhlA$mpX0QrM 8 ~זǔ5'.3`(')dt#2M6ҡ\fcY47 'WW8yDZm8I(k$~sj4}zK^zEqOnߡON%%Cg$DyRiPՠn|XHPW$7 P4Qke5$? F*H@`{"l\Qo,˔y]حDԋ?,Z`N*vL=qL:P z}z(0߆.dԀj8XqSuB /4ٗ$yvM:;s@fPL@CY N*ۨ9*\_GFT؂bq*{I듽=+b/H:tB YiN3RL1Jp)][sw|.Z~J[e"l:*A!.U}Qj;lq 8f".EV\Q;|'{ᗎM 𶣾wwˏN1%n] HrzSvʢ{m䝃޽ϪAOoʙ xZWDx*_,55v-aegqml niF"b{$_8-?qɇV+]nqȪGJt'h"'c^g]T+}P'$p%nC-ZCT΃9 &H duІQ/2 hdIqTm^#4xkD=U >J~~c ~@rE3J lqnXKC>Ӿx_KqpIՂx{d' ُS:z)7 a3oH2e|Y|8O15)QzìvQ)aM{=fF{b̌RGmzju(M"1NCVٺwzdĿwG>whb3hswbhq=@9 ?Hz,Ai8-<]R JĞ 3HzFLJiI@\=T;i#fϰYŏ̰얹8$)D 6>ꄴ`ozj6n&f'qǪuFc_-մKLoePEk(%Dz`"4$Y M}I[MJb_5.F3aNɔM1"h&aG2 -7"'Y@ x!m5jnz |^QU X^ձ@y=_zK5WZF 'VincӪ㟖}veEXЂ\5ȃ+@&~ :eG ڈsWD'Ψsڲj s$IɏFgeqHk X:%ކV=A^yMCX]%eV}rqϕBFC[|cL`7. lW>Vb~w@EsvNOŷ),ŏhLޜ޴ ۠i!V^5bf+I8DБ_ȴſqS \1eр򭶪 dGsvrd[6d݁Z[~:;@]C?|:UƂ]gPzD]"u_h.gLhF̗J{g:"ϔB?:tZ@;\AmT=SJχև/[4Q*GK)٦ eW(Xqߜ0O>rtBxbga'.>e9K$L`$jub/1gx8l زuh>%??KQ\̈́x- ECd SZGF^+MI.Cљ@,_B\<4'+z)g.gzgXW?3(@k6T=*03_mePUwz?t5KW3o4 NfWUI)dy՟OO BL+Aq@ oQWIt|HV@ՃFZm#| Ƚd:f/]˪v7g#;7#}uY&u-mKDdGΑ2@lȭW\Uᧀ6f~sn ' +L~HzZdf9 5;R1A*khk ή#QLƘ'pҜ2 B;پqchJIFa 17x5یe5THLj_Y;kOc3Пz ..0Ykϫ:iND3}׎B-[*k;Z'5X һIYօLa`NL:B<'ek`4uXÙ>e5~,e~e`W4L2Lgd{.5 X'4ؐX;A^*UµHZ8}u-/##VcWcu|FH'љ] >O|I359NZ{f!p aʹܕnhlNbpo]܏Dhb$̅;([9A2ahJ[ u6YƐ:Izeܸ[ IԻ8WA_Gݞz" Y!ðE4 Eu^g)QY8C?ilyQESwEŞP@X|W#ߊM~Sq`zCPA\m<:Ka-}7J} };b`fFsJCNºSm uG铇' Y)3K}M F:آ&ibSzk_Ik%$42'*)nzmY)Elxs SQecywdOn{%42>pS^*"Bۗywǣi-L^dh߬0.+ƎW3i]S+.+Q<ʛ?MT;DM.YFh6tmh)Pئ髗* ?^ya]@lrVnx J)ՕGw5`cy.w`6|"=.^ mӈY[ g=rKVe6)-!^s6.tR)RZj!ޖmh#H[P\gk͌gT@F8<AiTQ3PKxK"lJw)KLIumlh{:[zʮA~@=4ʏ/#\i3 lM/pI$%nښf[]4E4NF G۲+4G|de7FeTw\6j+Uԇ(*) DYRx<Ś|[Z.sd`LTRDt[=Q[JAG97noϫ5ZJقct31r-z(eSfrp\.v1L^]eؖ 6loaǖ<@w q* >M s@fVj^{ 뻞o%rgbZ8U=.UtA2S]j,2rHd"nG@Z3s)IzĎeY~}|T -]= "ԫ5z?[%-B}1k>$ "T̂4zuH*s="uEq M0ڝd)C\/ e:& eG~Z\B^m@vHC`-$?"qv޵b=@ekZT&! 0}qc{of0<\čoi>7EUNJ?dc.Ăez[hz3d19yl}JaA2'đ OɤI\yXcyUN2:%W|Qnef"o)ؖh9@9 e%gw/^jƧ4M*vz\q7gGNRbמVk$<8ކϰ? O§1ieuWPC?){-I֍ =Q&X2{sKy2ScajPȣ ?pi,t(~Цe~y ;./~J}}J+RMlu )~IԒj\5EX.+' ];1OK1^Tj&Hi=HmlQ_ H5F_!m`o@ǛXL\sW;}L*cOĤϧTYfmڼp'Oe v"PL9gxi GrlzK_ЩMӰD} 2p츳Z A OE]¬դȋ*&.4{kv¼dLa$kb/c4b_s;>"r7Hcbnpǎ aȭQ=ήg*!V9&*ٳ8t3`&wS{lAb~TΫ\H)>q4Eg8eύ Cѐ IVm9D5|)a@R?>f$O endstream endobj 42 0 obj <> endobj 206 0 obj <>stream xڭveXknq-RE{%@  ݽ-nZݽS܋)V9|:g\3=3=$Ԫl@Hjgdm͜`P[2B/&=#IAB 2pq81P{7G _c$ li`x|pA ;#8P@ 0|+" `UȂ@M:A%9bX@s5#8 ` كa Wso`r`0 `hj838h)a=Bap#x̪*%Wp+S0# Z `xqZv@#lz>qpӴV/dg)8i8>N\t~SIH@]l\qs|<^x8>+}vN> A#mg! qm ;9:>g<6\AsPs@dx9IFϐ~G;'RO}^fvo)')tE,zDmjnCf_;1-t‹k%&~MWFy8?u"='87WԍroQ_4q;^0:gҝz'V~ j~ZBK|5LA I2Յcu*Z5UzO AaW#kkX9AADbX?(wV'6h/ղJx11T zS:Qp}6W j2,2wQޡ^#TH_ ";vVK^9ŴWd{x]CСdkpTx=JPQ޹p/'=baW m[[ 2U1p n4ۄMΕZpWP'3 |M7|?9Fmc!9I{aq錊:2$&-EwiWZܴ,W)> q`lb!sfe1.hۛ.0o1@Qc꣪aZ /Q&?+&7hSbJY~FОzq']҇)o2^zrvMȖ`^\PGvTiT+ofT{RAIa#JwUM}]zŶ( }"hs~h0\{ؗa!Eq2๪;mVl5qb[% <VO+s3Ze{B -g2Ӌ~kEhvY\CȢvBV?Esm}<:[x|@6`x Ba\9@X=4 WvTdO8[M/KO+y_m 07\ƈ$|colcY0von ~qM+kFz% wT1ylH:]/\,!1nСb9(\]thɡ5Q%0T)ZK}]+chK*RS:۳:1x{@J֐wu-yڔoZBXvHN\c@g*1ۚd9TX\/ 'WU@t2-vJq$a ij`/! M ؊{¶{Y<`UC1y#ݲgXeM(Va=-/c΄)lD/fw*˶^n%4 `#ML/&Ls٥ۜrԝd+.L {Ѩb #_,A'jM_L#0.r,{Gwr~N&"o @ʼ+,d/Rwa@RKt :֎.Wܮ{-uBWh,{/9+پ8t:9qpג2ZYSY>|H##$i&Țo5d˸`KQQqĒēZ1X&ɘK%'?uҢ8V-0L@M-31u'!!S⃫_V%f FkنZJ׎?s:tECd anOhqNVN,]+7F*jGxaOD=1o+Rory0teYucMҁ8PC}is?B2iV,YNv*<*d{Oֻ@S_e`S{EN Q~59аOsJϊ)5c׉!2نL{͎:e)l<QGy1[n418㉒7Z<5d<+ȯ!]e&~91(:!C}T19}VUU@lv2v!*SE"ir"bK~;Fm:7k 5"Dd#^5;k dM).Eʉq>bnǾ9QC{Z}7t+)K ]Wbvi^%zmk|D[tJlŢ}q5-m x~DL /JpVڈwc @laIxu˙oXD 8OP OM 0~$>1'lWq[G)%^ȾWSO@n*YQJ =,4᠞FH Ԋ 7t@9VXƓ=ۃqN]]w[gy1aQ egdSj^HKPiӭsdd]=w),&8]rʌ%n߄/5rgbqɺx iImȝZ؇Vh]L'=>ۺec ˹rTYTR" Fb+?ړ瑎]CAL} h OE﵂pL\) rӾ&NO^4JU2=Sn(6g=k3hik*)ݳM Yp<^k2S7YU64rWq\)cpߩU'KUrnB7/ &M`:Z-@ 2]%8m_QC^$4%j'zS̺>^Nv&DA&*Cmzs.7{9ҎF6:tgJXPsp_cdhF 7l n\OǯwN+F#f&H3' W'(ﱞ0ZVk>w`CulZWIFtLWd5+0W9 ٘n einj7i8\fڛ= ۰(;lKy;F@xzWɎTlSXT/B#tD4nkp, d.ZEr 8ȽrXHռc# MI^4JɸPNS0`횑yx~Kĥ\s=E̲74PWVKhe 4Og~qfġӬȸG| vqTl}(.[V*@^?jM VG'D})*iE:cV 5B\wSFfEi $@Ki,ǽ;uĢo}DjǀE[>._{#%m.iJ[2SK!˸Vr%]wzzL+Dm㍱5^lMW[/V6 h#՚Ap.ax<(jo|2 m=il|*}; v:on2JO[oj0#=(]kr0o%R9"K>A02r Od9Bx"-+M|(o`=*'uT{aZd}j&=kS|\dya%:%gI jUsZvR)VYv15{+_s]!CꃣgҍBg*?LM$,iGP}e-BkV+巏ac% R7g~X5Lnh:`-T&G^#"5w) j֟娛PaC01V#'` "]%w|KX"T7N2=B' W;7d/3xR<,O=UK=yS,uEe{9쐵ž=u=>e)<.SvYVkNQ#h ɴi6yZ(g翬:\:~XlIΣݰ|rIRx4oaYzJk$2)Bg>3iO{ylb֖Sվ^.Tf;Zwyl# Szg;OCc<2L:DqNi#e \IK%!h-.leo!zX;$EO , bsi2zlߦ%xg<3ff',"i"]M\rd+`bsC#e [鳴GPp12._fD}fJLY9ƥky|L2\- `tFs_2dR"r {鑉#)1wkMGGtM<]t7t ~fuݞU-"7CM&bƽ#F-tm}/;unVe}#1[#3ݷsVeh+Ln;ATͱ2xŬ6QJ~Gp CyUȖvQw֓ǵrE:Fg}$:kzuK.}v؏ց&X |f)p>lS }t o%PyG<͸R")*F^ȯ*}gnmE"Pm<< Ey^t5&Rkĵ]Z!Wb5{@FreҼ/F|MJFJJ$K<hqljow/ZE;abH^)^˵ AƑx"w#H4O?Ȋj;c4 B4)eg2 F x9;g- )BF'R[m} IQ1*~k,%,:JvtxCH]%RNk> 0` k҂SW_z=vкm=ky޻g)дF)`Ԭ'p:䨶Xwau-\3SWJq [4ly&m0o~لpбPzA a: |}c$=}nflF,g+7!Q8[ӗQBR՛i2ĝ=| TiF1+彧&.QBs]:7+60WonZ34 0)xl -1=hQb⧃LJ cI ¯t0M6#}x@uʧ/~9OZzz ԋddrЍE*%M|'Tٱx |[/7k{,up(#U]T_=4ŏ8 ƖKv>H"cr%*rg;6LF:+߁(5#c'v%tJ)! XN(XK43P1 _ׅ+ddP^I.şf&,Q->c\U4o> endobj 207 0 obj <>stream xڬct&;[+m۶b۩ضm۬$fb|ݧOu>?5q{ENJ/l`pwgf`(Xٙ8)8pѫ-p@cW+{1cW @hXXpQG/g+ KW&5--jqxo=;h:PZV@$JRA :LlLrV@{ 5`o``ofOk. ]G0)lg`p6w;W?՛; Ggvm\\]L]*INWKcrX5z9ҿlaZ]]@OrfV.^sstWn.VYhalf tq g{cGG[E;`5gcfon +{8vEo܁?;Cc3{[/QoJ }$7PB oWG+=2w ;blOQ[r`Ү"lo&+\$;?dh0m)ӀW~ԃE(ݜA则1>Kr:LS*eP3ݬ0}G'{roуP|vNё[#<ڼxXr^c,3W/#fOWwNv:duo7"Ǹ=4KVB/aC&xY08$: Y5ƞ5& 58+_-+%;(TBRK:afRL\șlߢW tԪeh=We$$mFsR'x ݂)R5m]0 -׋R!{uH"mB#O~{jޯۗ!(h4{2"[<-w R! +Pϖsmɤ~N7^5^NHZvA /A6 ]P0m13bH8!Ll['[׼0J,dm?@}z Z L#,c1={9 p#m'K{Tϱ9qk*g3-f̴@3 MmZWU3SfI.Gy(G+K_+iFZ5 T*+VnlVa袁X* h~BC,|%Ab5S6 ;P3+P訿|JR/};bgu1dۏߴP.1Ff_,W; ջ8~wPI-m1k @F/é3ٖVPkle`⟁\ 3Jpl%lOc8_rG.:Lҝroe {HUj 435ֻ%9~ɵ,̜E7[]B٭Ӡx.̛[g~MrY`ts8kѬs ƜYFђb|f7:eM u߃/ho `>}]E'W9(-=IHB˹b߉(My|ڒ>}ɣO" Gz!C3݂Ng%}_'*(o%{7 F#vF3cJ$T* "ŠE-UnYIJ[yg"!Q^aCVՊײN!VâG:Byq&դY5n߄)T&ޙq}(m_͞a}ә@ mv#1zD_H#O#gӌ8u8?KܯvZ vY͜M^^{ 4yDb1Fn_ЏLcw|F>9}LAt$iV4ܵ3V;<#ei|ЇޜhJz:|kNp͞։S$nBwuxţjwP@BψD|^МU'^5 Ey3xx0)^݇"suZ*MemP3)hW"3 6/,ibz38nir`kOYott11Π?ӔqB&Xd6#ƯF; djI=fmÊ>x[KřvK 8S'c ,2FZQBȶxgVvynڇ !ފ}Ex@'mU'CؘxFl#&bU݇usӅ8##rH"u4?J1wS1,*VHbU[QBuY_!;$L*(\֒5RkG|QmZ(NG3rco+(y VIW} n Y !ҁbR#nǺ :E/1uŋ) 8+DQYbHKS$;|tB8w~¸܈  z J]wOmftߗsJym*?m4 { ]d:̽GN*xMwi̪Au}=mdԗK>'`ȕ+u,|&JtG3˛hT{5{7@ ĸL W [ ŦJ[0OMWuJjmW拨hWll,Fj/߰=lڱVPF3u)ru{`A C=3qgf6&ǐf4VkE䃥MQ"^ p4:OF'8Q;.i]z1b^+N 6MvbubXeLX;a`FgՉOD(^< %.S"tcpIC]Mg PXMIDtS=?FrT>yִuŴ m)iaz<1"<5>2Ûlf ʦiv;OTe31, /lb_lȹ\4+"bRM=mWy۷1>4Ӫ@@)GaHXً/oqJ01AL;.6r-6UU({R奠ًYzΌ~ěA.oflKŞkOK[V^YQf4 $*\9ũׁ5cٖZz_8)V,4]axO0VgRPGV- x6> !P33 v#n߁[H}}<*BF%MժMgƼ5?P|arL]D8sG?(,F[O6^bwiaf\, Ű2 H(BHU@89X*yBemtvtIټG Gw%O?зLeB동 *^Gs>ЈEvxjNs2&p^(=űsvKͪ`ňU^>:پ,'1Ŵ'.$SpA%􇠧:7ՠA{kx,p<(ɟ`ZmlnTK?sZ9ݝ] Vc!Iղ3EY)aIEjRQ,ƌTok-;^\(W˦,0~\g|e2_wH<6CdիegxuHW/\T|F养LʍsԻZO-j/gVrw=.9q P:$:mTV:}+kE= ;'}'ߟ" ĺ:4Mx5phQ}q\}uԆɯ i@SdGҨ,Y/Mi!x]cNX9+V%A$5lЗQꛍnZ‡2~{] ܎nbEE(' /F?+Ѭl:Ц *lŭa^6>9p% V!i\ d83w~z!c ’"֎~5?HCAuk[/yIh)Ѓ)"|vNAH_:;vt> wLӌ-w^!Q$λ {RDJEP+C*s Y$WS~mLE^[҃,e._,y49mʣ;,s+ /iDyi(+̫ћҟΠK!uG*% Lgs7=?< .R1A*Q(DۄGav܀PZPa9v }EיB&nr {[cb a.B50i~'Xp"uAL5,'y/Dtvj$ԩpnq=if1m U1b)ۦ,irg͟$jT|Eޟ뉇KHL# )BMZK2W}XDk%"U#PҶYNdVV/ ~}ͯͅ31@MG_DmH+VM*-Y-xw{I` k3yd;-kYu'4JYCO?n`}yBwuMl- X;`h3P>XG’L'' ňghZ*ҮUTrIoI1vjPѶcz)&a0/CvSYaVXu{½j܈ 1~mu9ʭ@ 6lr:}7Q{*3A 6Z &:f.1ޜ-7"S$EH,-<"ߎ_ER ZT"?ച$yX[ _]:W=Hx?Y}rn cQ#;$V*!s{Xܩ{rZLr1wHN}ږa|=@DU;$ySRdç=|:lVeZ.hFK1Ҏ O4\<߷3{,YEygVN l u.q4n(%8V(ղDt^OC(;c‰m-} 2p A/ܖ *Ѧf^R7"^2{8qyHرUEs>o5KIW4 "a88 5|6TYJc4+QtYjH5л'p{,p",E0r`d:L&ȃP,$_>.{*N0ANO_U}}ǂU(Ҫ5VBe'>:HU?.:B<22{L\Rm["oڷDFn@b O趗p&5K'^1XLO;5^R4Ο@mGBۗ SShX~?*0thd߮ q&@p~XaUPq{*jv lX@>$h 6YԲ'QP }_IB2(fYHcROBԘsR#|#.O|z8v K'{Gȋخ]Ɔ֥[e18lW)O>(Hř'd' ԝ:th´FxV:Dդdk-.\Д!=W֢>څ8Raρezybmutե4=ɝ#INz<8*5mmb V=4VM& fx"ђJe*P# kH}#xIz!bƓl &Y{Ia q1[>g J,}^{C~nN'EmtS-n)aJxԬijMMX?[Q7j=> WY><b(  ps 4?k csGLMrȜ~^\ia~3%q(Qɬ#jG/~jyF r ԢE /U}PChF&َ`+ЋfpP Y̓$"4n^$"gjJ_73UI 7@UOsǰkjY#иh|!b+}J1V4b]m(:m{7.Hs">asm}B]0){ P7rH t]8QeSX\m b^%LďnBgN+sۇD}HGǣ5e<鵩.0=PЦAamQ䟉 ݧՄH;,f/1 ʥ~a:HQ_*vT'OW0LƫK"Hh#~6` (, U8. mp9y<)&Cv|vt",s|&Ĉ1{nMamnMg1˹GZMVc‡zܱ?{D) {:%؋<[p j ]|J yY6wV@,!s jaXnjPZޘrvsS' O>ۣ: &ιĢ)s|c+=O&0UqH\cDؽs"*B[:.l E^.*-shW}F*9p7@-rI`(KkИOY/;܇>*C/uS ؕ#[ɔIdpB+,/d2}Y"OŰB%h *27ʼn_b{ ؐyO&UgaOՃ?UCFhNLqHۇ|d+qu-rL]2c8H"N6\$- $X|E3NaNYjB^ݺS Oɛ3yRus֓~,G7uۍ@x>Doԗ/k%@^>1CHb|9 -˟_ͮ=ɓfW야.pEBt<"<_.4Swa ~TW㺾HR9J=r]UƃwNX: JYƀ,"%Έnf7 h~saaP$dx33tafLG?r$Lΰ6N?UuVbȚE"(nXz>ijvg(֫E,5?RK*" [ZR€e;:z'0ܗh!}BW`4ȯjz&"vQ٦'O|Cz9=7F{hjөPr*Rm-/t.ɠby "%g<*- {ؔx wGO{@njXPX1'E7o`8Ade7XEXGY[6h+^CcOwr}/Ruj8 lWD7U|:k 5DS+o |G5U4w7љ13\MUuϖἍp/V"L$CN9#T ʱM:/ (^854 EF{1Kt2jdކ=O ,n\ 7ϼ K^"oKW"밓]tRGENɵF\n[vWj_ݑ}xazs*@z e4Hѫ Yb !q0?E͜õD.Jy?GfWM/SګflsC拙L`G MRg:&HnO2ɋCChcެ|bhFCᐺ׃Cův,3y\ e{Aw\?u78.np(059߇_^5b;Yo; LG 8ʅ3un y <#aĨjpf',{klyJwŊ@+pvU Z2@ 6{öcFxVΖ$'_pOG!x.nXo'%¼Gs ^*aUP<իQZҞXWeմu)CÔŁPAܧTF^xq)$KȃÝɟC2K3k-z& b~oA 4'B˨LIF CНLJ; r]&\2W TuGyV\qǹAQŪ_<6P94 ~M NoT)"cL:>Z:;N=Ü("\N)"ɚyQ`Kը3~XL|M.,5#kvӋ ѐM/P32S|bjN@ n6}pWfBMJ+8 9lPZ76q*ow>;C8zIfqfpY6Ğ4%Q@ :O=fl>||WKǀ֑@CTp8JO$KɮX84BEqm[UВ5ЉV#hbi`Z_kŨȪDvMQ3 CCrͬW!AL6\ =qu0- ;Je9Xo|AX^7ɞU~L2YE)u:FSADp8ݜsޛc?N%L`I}z;oEnz!sor.=2L!6|hahl zʙ]OV߼(ic!1\W~'m*Chp)ZLlR;ԫ5ࡥ~ fSCc46Giw"'B1{W,@K7A.# bV{Vg vyȿ 'M *V,x靪:O UCoG&yhNSӻ#]XqlP)Mm2\$[0JI :wY`>n#G2Qe0'fE[%4_J 2HRa왪adml@εbrJiQR9t1&;Nq,jCBd3Le|^M#VS| 4$"pV_jK2<Xݢ1^C"ꚙ&+2$w7SOM1PDN=g w(o2{}@롕l \g'j)Bd*%I𗾮O4۪ػIODk,,xYao* I7]WfLIq{P+QA$"\blL0?r׳+ujT?}hCt@dN'+F &ۥ fG :9zڤws, A;NO-IӒelG99\A#ƴH.ΰ$= ~a7,0T!b{umnHՎ_s 2 =̴Z!9h御1ru4n9O, PtvQ uK7Mn2U-V1R^(FWjqq]O2Zr~v<4=|CR{ieWd&e?# ,}ܯG*7\ʯI+\݉VA9bT1 Eּs!*Fc٢>@/:JÝĐa8uQRh/{(u`&61Pn$XVpuf>h12|E.8h4ּ;;* U%1~kX :J"?R>twc ]IܚOK6{|kE"3, B̌""|*CJ]Qxv?38XaH؝TD!KM*`N;|ɸysnn.8U9}+^Lp4ig `fH͕_"Is5[&̶G͓Ef]:uXŽts?%^c~bnbKI颮ܦX ڢEOPiM~F'rvϣ|G%2]fhVPy]7ȑ%%"` "ֈk@ ToeIM'G{"jѢYMQZ;ߛ{ۑ9=FmݸӨOURDn3cFoT4;xbJҦ޳?f~]p9gM՝ցN' {z0p@ƂK=Z X%W8f)Ib/pBz% +MaET2uRn2Eo^4\ȋHq.ـ ~\[=4I6'hȚT<*N?Օ-."yEOų(9/Yao+q1kGIQ.lM=&Rs4k͘THOs2Qf؟&hJV4~Dգwc8m Z a{-xf䞇܍t2zP3JHfi츩kӋo, Bgeu3A\ms-ihbg&HU/K٬:$l_AQ;IuӦ:ĝg}W;$)7`4”#&|e~dSb4b b" Q%/-.oymKXvItq9X@iFc.J1#7O*[+\PxzlF ~tdI"@uN2OvLD%-4Lqx$tQKQW `pJX۫}btɟ7ƘQ%Vv:r*mpiK*nIq3Ks9&g% !r_ o^Yc8y%4ĽCnrDT-o1h lSAV,#s8_8~eJ?5FZora0Ȉ;pX_]L dq ?gƆhX9\Շ.eeOExƒ}g'1U{!o u}nfT: o7^߱a1l7;-nTϚn4սeShHɠY9gNA<_RsY"8d;LO96?"koAg=po:]F 1i܉1<%VTTݴ8osKU#h>g-Ȑb Vp{%kWJ 'XU*lE^"%c\Sd[0y="[;y/br[ JNX;}JT);]")!󓎇EF'7-*|Rų銾i&=Ve.=5Bٵ@AuƬϗJylNaO~1^˶5Wl\'C%d dBӵ\}(qaɜ?:o |z>-|@^m΋PZOiF0h^ݛ !bW$OƬSqZ"^WGO6@&]/~A7B*늧ٲܫV-eiKFDٌRG$D+!ӿ 'ۯ_-NY 7@:Pigѥe"]Z#y *Kr臨{#~`Ufw&y;s1U#R)rP2w62Ro˸fKbCN zscM:yMGl̺f/^p0wUN+94wǮ 0pD\jFʨJ=Nh1/r *4}2h(QJ r)֍g\:XO-qVJY՞TIagvI\]Ps7~HGr2Y۴0ٵ}֪F鹆\.!Y!́5eMӥ=`|K!GDK-\/GHR1HT#}L|i\uCwyV~[ -ނIrd]{z-yB"vM,B4šu;G"K`6PAքJ%|3@b2"Do8c}T!]#IklхwO~ĸ wR_:AcD%0SRMݭMaT[;}찥c*eĔA4iXknsWJŶ&An/l4eFY*mY ׊'ػ˭R`aYܥ. YA/܌AFLy~RZĉ{nd=͒<7"֐x(E-*8/Xͺ_ltt"NTJuk.^1m\#lrF`|>2<Ւjaꍏ,X`RL !xZ|7)F4G[R(|ǖ[C _mӚqf[˞C@p2U-?qvVy;!=!X֝tcBr[I7+Js\ƫ!KZ !8i/J~- HؔM'yI:P|=yIp,7Vm5oMw6}֤$P/)@aeeMsWtXb@prfGH>Xt3:IQ5(5ңN߲ CͩWȣC:.(_ٛlɀ/;DGhfBo+ץObJUA5Z03G/aRQ+Хyq}h3  Zq^_`@&v27G?f.+!y%8^H26hd)k-5xjf9&|0p}ymTךsp>1 bلxrn8\f40\ؿAjV떁-5XnK.2 cyaNXRlXy@_y |ηI-1Z##EqXxwH\oMON:s 0x'&0?m˂Qa59 }aT;iJtp}m=~>ٍdwsFA6VJ!5!q 8Ȩ3·~R5 |V~C4/lH|Zdj6B(n2WfGdF^ڀ֎:Bi:$[!գD%˥}b^ v¨zUVb '" ~M4# Ф!l#V# endstream endobj 45 0 obj <> endobj 208 0 obj <>stream xڭvcx$\el۩mc۶*vI:vұ펭mvlx7y3sU^k]EEQ^L΅ 5vuV疥W6p|Ě\vF.f< 3S  GwtP)kP@>=v/nf6fv.ώ*ffK39 %%/WHٙ9]m&Y5 `4gO.!gfab89? '#;v&6 OL (*<],\v~{ϛ&KD]v3@go? NfFN6fΟ4_ulmϭlfc3Hٙe7uuQ$LlL]>CTfA[5_{wjqWy#׎|.#;.#h5L-Bvs3q1q :=L.&s#ϾcW35sڙ}OkLLZM /߫Eh%Kb9lrQ ofOC? =^\z.7 C,g01011d? 37;H*.Fvӧ+0303[^7 JHsf vYZWe]nZ0۞4p7 eWEwR|u6NFiQ^sLJůPmN0~n~dH>&)u1( h5' G#C]א={1F>I'_]:՛C>q:Wg6kT&{,Go3Y|2 .ȸ_G LJ׶/H.q Zg,qG"$RI 7Qթ%2CL%ՙPҔ#8j񾒋 E %n osN RWuH?|q$(eBs\u,yKlª2$jw]rgPTub([$.T1ٯS 20$;AJd`s}ؒOߐ挫t"t3[3"8vy 3lX;n_GC<"fjФG@ -l4amڑ8:u"lb}e_'֠E^}r9DR;zeTbvͿv7z%bk:ԧ9MAe&Z[Tj$CNt(5JzyZoz*!AGeuo[EBovJsBQ ͦwKr1`r2in.Y_nHL>vgkU0Fw})Q|7ҍ&1|ŠY"RS6vI&sj0=DyB%3'oZs̳iF#(5~3+&:tpp+i\HvZvTe#Nn`aAZ/"e3~Fh~?9]md7l[~yzyC)u=BG!XxOIwaud{L]sC2u1G6f.\6)1|!T&.q<$1D!ℇ56HK7*rjU;ZoĄ( <>` ^@,(gHaNsD]q'In_)Tɛ^>JJFIY'ݗЕFg ]kǎ~K]#0IB:4Nw3ҍ :}/3g"J/1 *.j>Nᭅ ^-8kWrw G%v怱g#<ՊL=~4Mxś>` `(v\=kOQb=*ǵ(&RDfR.J!15Q Tjo3{fVd[աt`Axsn>}Hg4h?hu1lZ 6~y"="(3u҄+O:ޅ/. (+mf+ ! @)}Je١YGi/7[n;-~)VvGIDtm{R"y7\>'s8>\gvͨ*0CU{| i2YHOu?k{6΁Pjb<* FBQfn_Px`H@+-xJfDeAa%=MCվckdb1}'J\j!8@G6 ~:i54X!Hmωj]\9A*={q,r|==L#\ßKUHT l~0(|mNI\dmi1O 55S ]uO$AV8sQܭȷ[phF?41Jn}7˅PlPBtz0S^tw"TM=uĶ94*:];*ϵ*hi\s5"{9zl"@haޅLΥӫi07,Kl.}Hxڴ7Mw҈(K15-CKJŶg8-dc$Y?#w:AFlj*{ vj\Z s%;; D4,nsqy(0d=B?YxGƽx'z{e!ʢ{7Z{8AѦ֏QdJQ m|6!G0]pT }')ɯ`%J>]2x"㢾= {H&<$[[ ;;5<-hP+Ѐe@.Z<|phIzPZDRzۇMzv̞s0 ,ئB:.hWEq74CMxHPDL|^BFak:Oϩk\V6;0痌Aù%3`Գ>k5jT= NVKz #+@o2ItO?l$ kq5kFHP'˖r~aG4L7taBӴR$"T+bg w]Y=;S)Gis7emgFKc†aS|^y H#`a"څ`RFMJ^ڹ^uAm99/>b;HƁ7jwaQ-eTU~ҞU!j.%fsu _N*j-@{,-|)LѩܵK mwu%J9/XC'1Qէ8R}su'lSdwv*Ş3j݇ ΋OuqaapsAD3\\+L Cf&(8Z `+D2s{ݨ>Z]t|E%Lԙܽk}V~yPPPJ 8"FVRV] n(PR!gba^E&8l\l dTYsVǨ""2[v,Xx+sK`c%9>gw?Q xoM-8I k4Ez -3k|G\Fsܯɏ'o -67ND/~CwReXQFG腮bK%ݮAr\.( O5'72(hB+rI]6ӝTK야K_qjH[?*'y-ȩM8*'lרߛYdbѯ1- OadDˠ+m  mPg+QمSZ҃7"ݝsY=s{=Nb5N|y;J+RO kqkIm ߸̴H{-c A|:%T.؊^GR$Re>xgXG1h-`cu'/f)Ša("3%BZ ^VmTSW|EܜhmG;hkNI`y3 ^Ȉ ׻VQqdWiìi (z!]*- / by/`{z_eWa9tɔ|ݰS/M) Lmte YKL ARF٠ ]$JjW ศg {6~RcDwqL#[Z!u33hPɶ]U6A?s;T08m'oʤq"cEσ]sat"E #{kjб( È+4F.Vx%=XST5 Ipc3Gyk0VR.9PNQ/fdbiy+mLkbq@rb:P KDkIk/,73ne˲FU').=մ{pre EDKtv#(9W %&n- C4vH"X|R.cp||gL8Jܾ{DJt\)j4iHƌ76?:'jc&ƴۜgvo_ qNPDR("6ᐧQÂ%ZXU 1ʛSk=w9WD,G_c!6,ӓd((t~a}7 )'eQ5W|t/"˷*0;Sb MB7rYM\"Lqn,4+5\&_pMӞv!H1n-m1fޤ,an8c"R1߯2b Sڦ5衝*meBqHP">I_*,Q?~Qotl&(L:39lLB/Ni{|BJ9p I/?h]^zN>mȿ թ'&ZZn<` AP/$3V<Ѩ$2_x91!8ٟI%UYKKMdh*j[2j~> VZVUR<\S[_Ƃ+h0A2O( |w*@,>IyIxτͶbw=&cY Qϫ'` U ځN[c;C qô GV_I:ھB{X"ȑ {D%Gwˎdc2ܧOUʹCkӋ""U̎@'QX @5n ŧc8L ~|'/}IgiR3Ih&3Mp8.Em7d2~6+73>yEI;{R #Á|?9u5YZuI3Ev[;I2?*#JثI?vCU0;s<.V(Ǻ:\*(oQlQQ(y^t?/w 9`trfOLN#m3ј}&n^.) UG4z(PCb:me]fVx;W(@үn1yTdl!S`9+TyI).-FFfa+xhjdĊEXYKL,qLr9 dJʧfݷxBLIy=ՓK#p(tI<$;-eTpwCUт6N{lP\MF*CuveBuOp2I Sa6&brn8` 휟5nSD] 0C[_j)_T&E(+>Q6b&[XoӪ\t}#Mʔ+…ύef\B cFmpF6n,ȵu>ZV[T6%R!J:W@ZjnDv#ŚH(980|\|"/:lH__$]gX ^C섽h_Oh]v]&3!=}w@zQ5pdz4xdV6,/ي5ykڍ gg-Sq|2bl |# յ$Z!†+qLiqOJ*6}j F $1H4BRm)(7lisEHh=a'.c6hon ;ℋƥ:ʔZi;/I9wo@qm,80]ƗGlΣ%">)&<Ғ'd[z`gdD*cx\n0,e/%sTkrO~GgOL"btG%کz;L15$E4RQS>ow\e]t603ɧU,\&ϷA+Q d[2,A2~&,3(Pdp~+ݛ_F.vlbB-KءvT|BTI[71چ 42f QxD oaBV^WFZ0ZBQO;yZn >" 'pxNnӴ+nF>|0m)TBxAwiUԴLj VS[*plP]15usC]UDP}$OկfE։D$+k8ֹw쟋۬M3Ң{x=#x\ާ=FC4 g7_~p^JeAhPmަb| |`M+'M5WuIH~g UE*:%zn`DbeNZnF  [mv?r5LZZ;tE]x˹YͲ_~>d3׼eғ\oUv^ v>KѐFۨckGIgNG=s+p$?=^v:j"/Vg†XD𧋦;fdIX:Ƒ_jɪOȨ! u9qc$` G!Ik! TDI TF6ATkaQ0Qcj9"V41-,44Q,R?jlY'|01z%_-a@Vl{ `Nq#ȉhzdKBk`WVׅOt VƌDmFo :k">^_zR*5dY/L=7+<'DNI,NԒcoSӨ]o (DmN1yfL]hfąkNrGm'YSՂJ&w:sZjDd3Z~!NxuȷPɆ-Oe?fox+]v̴r ,HɧB7,RRd|t¸e=QƝ. }*vΗ j [!brU/PB2Wf"`;VY3MѦ#muPF-Q.KSSR4gԢ/j$$ؒ &XxWVֺ5|b~LrY(t=c jɌ<SÄ*øhr׏FENoS -pv+K0~Rk"egQKTc,jcӎCX\zsSJks>)`]o7w#- 3aT%](VYV~^z9WTfi/7WثVt7nJDLQ qI_PaR\NC^ircTql݈ۤwK\A%h>uV?V{hW\i܂t82\a\݅n`Ź=q׉{?(\^lqt3Z&ZLB^"6b{ݧE[uL d] zUꚌmEkc}X;cu*#DiFJҼD=ks\^F{5cC*QM]G3}CνG#PDSe.|?DJi*& PUVrn1Tt$J왛d )xjjzG](lIt~z.kzY6 ,",g_E̮,| 0Md ,銹(vmfe0Ċ=*mbjhԅBI*#gˤnEP+/n i fV# * Yp ^Q]pi-YHnG`?HBe;/\AMΜ^ff!+pNo֔Fbt|z*2 0nrlLJdQ \E \_Yc= =`dY{5T94Ncpc/#"T`,} Og׹oUCQWbia 1 [ܶ+%J)HY!7Av.V).Yg-6` ꋹYWCh> endobj 209 0 obj <>stream xڬctem&Tl[;VŶmٱmJ*mFvŶt=ۧO}{{⚸=XĊ*tB@q{;:&zFn=,2UWKN.4r5rr4Q Kwt4pP)kP~O?&ct4P}p;\B_; QPԒPIȫ$v@E(Xd-Mv@j?9r&݀&@T@'[KgKg,Ll\MI_ 98 hldUQTyX`o Wbdi pz0tv1/pu3 FN6@g0 ߪ7rpW.@3zX&1M\6eg^L: Q3302`]P߱LG-FBEcdkciq5?9Wk ࿳UBvcbgYhhbb03ۼLN6v$N6ڙ TԔdi_ƊE4M(aa{7;e{Y} ?rF.NFzFF&Iٙ؛3G*.FvG Q:9e_oq%=&K&Z2!F-I\#&xy-V;s/[_Nu*o\р0<-[oJ#kC pNmɼ(n(zT?N 6$˯%~n|Z?cD)^ GPc,>0˔.e:;)dB xL^v!m9CŦc>JHՒ)^h{ezqϛ"TO9w.o TQTV޵4Ɂ}YSSErQm~76ѧyDU"=DMrdq= \?ru;C`j-o,52*t*<YL:ok&D׍B''y0Ls<-Up̈j8 1a(#w*=SL!le8j֒=*SqPBo]vZ1^M3L^*0/o}B[dɨk۴t gP?pOk\qT_$@U (x{fqӡc 8=q,lRm)NLd"=R;i4r(`O%ܶU~a3QsHNV~A0$#ąy4ug'rC/cZrːJp%́9ZI@xfn]$ K =NOgMu:`d6$LfFUYgK]Ąvkl@UJyD^ D3u`0]pjBgOˆokIctD8sA'0':'x N!ZmoC$J'Be,RwUIN[ظXI>vz[v)=IQ-`୭?q?]$tVr'MT9G20ZĸL*Bi3Cmi:/>G/gBz3; -dW>WFM)7 `oLE)ۛ>ԋ.Q(]} k}ˡ8U&8mR):ؓLGgotKݎ@%&wr"byXZb@܅s1Y:zeYДɨ iQ޶'_]#յ,ݚؿ ("aB%>LizMqV٬y˳X$J0olV_؄rRU[cً[΄}V̔ xZj'E@LniL&tYWf'3 W%Nw-}bTG~ek )ĈШݏfr:YqziH%G#x#A D$׺n_f6 'Q[i=M` 5ߣrĕ4qu~H8K { R(/F0c0]yV AF Uqsfc`=Zme+CI[bH-"^*sW0sFRP+%'Ly\"2_d\pt ̴u7+v*2h=G`;kQ +S<[|7~殕Ãno(:XM 5WBS6}M[H_Š hQ`Yo ./ Tљ, f"D''ea9訄z̻p~&J^[ya:c2m><7J`|p*ӻJQ\1Dzߎp_ X4)7KžB?쎯c)~!E;*[\R )z,#W`i+8@j'SBz2G)9= Xospa4& ?/P~Oy&j;il#2w"c}-bvb<>qi>4KClv̎Z)5g ۡ3:ҳΜ3%aqj ]t’L[rbNOw:3aN嚮"K' k,CKR jm EKݒ 6:݀' o *sK"_hEI^mH4#Bbi!}K c] xUA^ nX(c)}E n؈&_>@Ou$f6j&mֺǗ7-5`',&T$FU~n} 7~5db6g n5\&@,VWIBZ_Ng^?'6" yjO! bt׵"UtϞ/LO$l#]"+SY^ѐE1K}]c'᳭ !TQI47&jVɸpI.ٴ 4U2\ƿ>:9WqSu uّbͥ^{4*2LO-r wT{$K3<7\jݫu./J F-!33m5t:gy6Tn (XF<Iefٹ/qTod<:Hf3(Q 3e`\g3F ym[,.XN䁯gU؅QkaaΝșjrV2]LFu%Ə8TMkIƮ)࿀Tk$-['}%#. \-K#hvqJXvttOd;Dbl<?:.auSQ).;P#l/k$e~`tx>*eg^#_IvO]N,UXOywj\L2[md&j,bm!4ǯڦɏWChUxY0G.ָK*Qg!E5iI)YD8D2/7 $t!Cd`ru=kW{ -W?ln3:WMoScs%̅ppfA8͛OwRQ:DB3~х;H8V6, V趮RMw]bo"U>g儑c`o q>~Y2 )7~v ˚[f΋yU9mlH/z> X]BMeCW+f}c|T vJVojmjU̮?cf:="15 0Ts $Ov3U.ܝw ~s)#(03,: #6{m'>## 7a>ޥWNO* 2 32~؂iPxY/b"R6Kԩq3x^ v9a"rW̠ S>o+Q`4^`~?S.@+Yz{ylßx;0'uv7KnLao"kD] & kj!|1-)1,EZLnpg+.XGU6bq\tv-W9bh+N7 ' zxtkCt:ʚb PETb$hxΚAFlq+y ~(a25+I]?5h,4myG^A=1j\(ܷQEmExcEn{ fu\el@j08H,-uHgmA[Πֆ7?g` 3J;*{#Mz,Xuʟ10a/}ev!3;f9T[G!v' UʏLԉVjRĝs -8 sn>\ft'1׼25}Xe/Ӏfj#6=O0Rh$9*D{zK"tae%=p'*=r8mJIhQA aoWWerp܍mK@^/]=,"+i M)e'[}‘?}&AH.\ӟQl{BԿN/eI~^ f*fް}l/4ag~ /rhXev.vu㔃z;'ciQ*Z7ѿ pK%>}r'EMv\ ۰%IHy C<:9t*q'R S 3-#,fi0h1zo2+IR@ӭmuA2g Yp1U Čg tAILP7J bk+ĸ>״}.zӕT6"eVe;GUǙtu)OI7^w9)T\_8ǎߐH RB#dSiF}u뜌qϹRWT` q#HQRͮl$Ѿ&+,M8`?7uķ,h.LFx2lE؃aѻ:QXWWCךt{)С~ EV!79Q[hF__zhH),sY{TWST)t Y2%'\-eKcejq."9\|)q@cγi1uM??'wƧs072.Fy7s ͡9f뼷nFdu]pdN^-BVv`\Ыly^lg k!95~ '/y5.7)]ʇttXYH덎F.#$SZ@x,DhjHcӂs?|&(N|B^ʇ[Z&sfa|a fTtcYq*.%c;Ԍʯu )smy.N:‹Z9^ w^\RY ]'^#/a4]ޚl=%,Ax g5ey\y}^|E esPGFW.NمC:Ul9:`˜˜,..34p _l_%04#߷X"aοAbݺC](HF/ M8=Z$R!P%y|ۋzkn'uM@qd-SOd)$M:VASH}>ɫ]ɏ2`WGQu~4#$YjMpVۮDGΏ1u5JդMUJG6x09%6!S(Uj[ 7^Z3+Ơ‚-Ax#aek0&?jv h~oQڰ)XY5rV\v=nfM[,=C:n$Zu%E4Hhh$(T#ӽ|pnHؑg^{0%NzW Y^}̨p^]½~k6g3X/>7We[N(ٌgjԝ'?4TAWjGK+}m i{振nvS7Ꙑ9Y˚]D^30uבԼik7Nꥲ?h)PNxUWߕJPԄ\Wp<*["]A˼) pkx$(m18`1%iy[uyy_;SS{HU"LIRGU0 Z($lN|#5fhc:h6Y{(٘t9K7AMX%:iW7i4 RFf)x)e#:ޛ-,$ǪyY1uCyJbm$'[LrqӼ+(Pjɍ>p?cwl!>*~%sTK>Ӻ/*=tb녿uPƂzO Åew dS~0WPȤye%7fZ0w9C!aKFui7E[xn2ԑ\;u7Pbݑf g5ZKSȢ@;J TODlm7p* ֣1Qt>'PyhK20lL]b|/ErjNvr%׃SoI'!Ô6+ b;$b"6mrCl< !&Rhm@01aHoxTl| 7b:_m_l~+O;TJ/{4U x| ۦƌ t.Ҷ731UdQm> >~~6O0N?oIFHQT\ix| *}l5V`nQO\/gO:pЛ[3+!EnU>9`n:fc2cc~XqkO:uƟZ(gs|Ô+I^I"%2r';" W" #:-]vpо!tnT?ԥ9-W,GI_|#Һ&-4_4M{)AF]FroǤûA,!^$f6B;'-+"njޒp܏x0TQq(xi(NZ|'fJZvƫ?]{ϸ"|LQf1Ii&<`j*88}zcEd 0I&aͪ(_v 1$KЇXzP:Qhq}~gQ5DBj Ͻu)hv o6Zٰs^SnnHXލU<ưe_{D<͎}H%bhAXK+f};ۍS%ֻk cjp(ki}{~81~3I;w3B(XDĽV8M4>$&hRJ2B$&f&kbgpF]&6۽wNxؼ^+\3V$ݥ]G&-[ZؓC.R*m̂,Dqrn`*Íļ1UY:c+Sn7oa|BMw#no\RW]ĩc7ڴ䦊?&P;Qh\Z#3{SG);źI֧&3OA"ZNZEr!Q8wG;kD@A("#J0ۿ?R;kIdV?y9XLh9{EnȨn3ۥ4mU1Nw*%9Ǧ@OU/>i;˂1'V{UÔERVI?ŗt~⩒84xׁtǡ4;e8=Ĕ|;R",c\,Qg8[D+r*OU /GBc/To W?SKzrBxsjDMҞ"rgR>TV7N25-԰O ǥߑK0fg0ihjҪoϡVULd-b1 9|"|')$nd3]fM 0ۘ$ >u͍%!`)4뱎3>le.Y zw{e %4g]3$ /W pARyT9l\m=ced`5Q~臾/ dtTM 'eFSBx11LI]<#/4lNs#lNRbh oQG!HUeyEt`EO$pOQ v`e ߯3cwrg ln]h?&lBk[~o ȕo8WKecF}k~+LeTgFR!FZjoN awy?;h'rCc-F_hny8%2=7LgnR{DT_F;s9MIϠN: bsbƢ lы:8V0[0Vc+&˛b! ؑ7qLpZ\٫>c 4:@M3nYsÙ=®J⊼GD.CsؔRBR";YF K_J~I~,V bY5k}};__0i7t u'A1whC;֥a` EF>ݟhE"}{gLpG[x:K%q.T⍔˽~H%IhLvx.Po>wߝB$@{hOpH;nf-Pc6 @QȂv@,~Zb bxȸ!,$,gFj2slFJ~?kN6r{T!8C"4@?)|OՃkxK*tzgit:6Gb&X0'>KOyM|^#rz˰=Gs3uU%F%kQ$^X,BYgNN˧t~QUz\Ta"jAE>TЉ,U0z ; L%nضk 3 dIIh=u0.~FuP O1^FhQ:^)U RT(;~d^ b2A9㎅xʤn\Z4t$4M׳FUh.~^XqMiðǥnʭɥ_ ‡;=\{rlM5G|$ki֫LAF<&1)j%#:Wa>YnS\tNafJA ,]:?6 hKpêdJ)^(TUF.s7I &ogm4LhXF:aͦ.8/nGRH|.P%}@ٽ -ޥd&\ U1|ٝ~8+eƗK ?y˿SЏFp VĪyR5i8J%F[|ͺkl$*+g$l j'lwιK?pA D9c7QRR?4u6AV|]I<]`-PAdAvmj4 9 7vipzC/DkE`}\2T1s\bBd|k]ªo2eaϻX,|$ϑ5H!#%l$XTCpQ.>'͈NZeΚTT~k8L▗ 愺V_cGE2rp`AR欞KxArAHԮ9 |#JtY z&C(?-R~@cSk3>wUen($$C7d߳0>/b]I ezS[k0voU8 @1aڙ\ya#\LKWRoӗӚ({`%d &Yԩ\GHy*xG~ +R3Qh_iN5<2tG^-9Dg=dlj ²zXGNԺ'#Y/xHDB;A Lݫ ytƇЊ46^ m/r*G\ nGU|)j@M3 vbg}|0fԊni"fde&M%C $UfFE'j7'ϊۈ;c>_pD$k 0+(׹֌E 6J}AWװ;5Ukrc糥0Wb{W]z$.Tsܸ)Hӝ=EEc/ iM[}ᾒotzGL]kUkW̞SW),@L!_Dȓ3IJl|np!~Wao6=&oXM`8]n-?Xy O70($ 16W@Xݦm`mcA1"5iu/D i-ǫl6vPP;~E Kvɽ?1"\]a.dt~ e]V Ge*D=ԗۇ,ٍj]=HagIƭNȋ0#.NPɴɌK ֽ1n;,8*OޯٵDRwpc#[p]XOrqtq^a#BSԋu%hˡ9jlUB(\RqttY'EafcĺN5D8NG;0ƀKyWoGFvi7,|2@K('Q:k2oJ,%1, O lՋ:nS#lW9ћT oN .%m+R)~l^@'5X"پ•#C oHl.'^d <.4|(`j~I!cA/ STˠP1'Ó,I,}T߫s!qr CcCHu [ ʥ..6W95.LC7es[u ~TU-D-W ฻:ۑ݀y-!)_ $$NًkV`g(^嬨Ҽ7 -|]-N^Q֙,u^ߑ7M9T8zڲ/`Qbjw@ xVH"|c:^GwFz?ؖaOnrchHUaڰ{` qoiZ-?Y BvqG{ 6"wɔ{6P+uzT:)obI'TLj)d&1]n8Baֲ endstream endobj 49 0 obj <> endobj 53 0 obj <> endobj 210 0 obj <> endobj xref 0 211 0000000000 65535 f 0000035071 00000 n 0000000015 00000 n 0000034892 00000 n 0000035460 00000 n 0000035774 00000 n 0000035850 00000 n 0000036069 00000 n 0000036145 00000 n 0000036365 00000 n 0000036441 00000 n 0000036660 00000 n 0000036737 00000 n 0000036956 00000 n 0000037033 00000 n 0000037252 00000 n 0000037329 00000 n 0000037548 00000 n 0000037625 00000 n 0000037844 00000 n 0000037921 00000 n 0000038140 00000 n 0000038217 00000 n 0000038436 00000 n 0000038513 00000 n 0000038733 00000 n 0000038810 00000 n 0000039030 00000 n 0000039107 00000 n 0000039327 00000 n 0000039404 00000 n 0000039623 00000 n 0000039700 00000 n 0000039920 00000 n 0000044681 00000 n 0000044838 00000 n 0000044995 00000 n 0000045122 00000 n 0000045283 00000 n 0000040024 00000 n 0000040229 00000 n 0000045410 00000 n 0000390684 00000 n 0000288194 00000 n 0000284370 00000 n 0000420072 00000 n 0000287619 00000 n 0000337123 00000 n 0000287589 00000 n 0000452679 00000 n 0000287016 00000 n 0000344394 00000 n 0000286992 00000 n 0000453173 00000 n 0000047008 00000 n 0000062066 00000 n 0000075515 00000 n 0000081296 00000 n 0000086895 00000 n 0000045512 00000 n 0000052849 00000 n 0000053106 00000 n 0000053148 00000 n 0000053537 00000 n 0000046892 00000 n 0000052694 00000 n 0000047225 00000 n 0000364784 00000 n 0000286646 00000 n 0000053786 00000 n 0000054070 00000 n 0000054156 00000 n 0000054392 00000 n 0000057889 00000 n 0000058909 00000 n 0000067543 00000 n 0000067802 00000 n 0000067844 00000 n 0000068249 00000 n 0000068522 00000 n 0000061950 00000 n 0000062283 00000 n 0000068787 00000 n 0000069093 00000 n 0000069338 00000 n 0000069554 00000 n 0000073247 00000 n 0000074936 00000 n 0000075401 00000 n 0000080903 00000 n 0000081031 00000 n 0000075730 00000 n 0000322077 00000 n 0000286572 00000 n 0000299097 00000 n 0000286322 00000 n 0000081161 00000 n 0000086518 00000 n 0000086648 00000 n 0000081530 00000 n 0000306496 00000 n 0000286297 00000 n 0000329765 00000 n 0000286226 00000 n 0000086777 00000 n 0000092377 00000 n 0000092539 00000 n 0000087114 00000 n 0000373404 00000 n 0000285907 00000 n 0000399719 00000 n 0000285604 00000 n 0000092704 00000 n 0000107485 00000 n 0000107708 00000 n 0000107751 00000 n 0000101976 00000 n 0000107425 00000 n 0000102170 00000 n 0000102323 00000 n 0000102579 00000 n 0000107316 00000 n 0000114098 00000 n 0000137565 00000 n 0000149540 00000 n 0000219486 00000 n 0000263985 00000 n 0000108187 00000 n 0000108565 00000 n 0000114015 00000 n 0000114284 00000 n 0000127666 00000 n 0000142495 00000 n 0000142719 00000 n 0000142762 00000 n 0000137230 00000 n 0000142435 00000 n 0000137424 00000 n 0000137809 00000 n 0000143204 00000 n 0000143588 00000 n 0000149389 00000 n 0000155468 00000 n 0000155626 00000 n 0000149793 00000 n 0000350797 00000 n 0000285265 00000 n 0000313798 00000 n 0000285240 00000 n 0000155757 00000 n 0000223666 00000 n 0000223885 00000 n 0000223928 00000 n 0000168618 00000 n 0000223606 00000 n 0000168812 00000 n 0000229797 00000 n 0000230026 00000 n 0000230069 00000 n 0000192277 00000 n 0000229737 00000 n 0000192471 00000 n 0000236719 00000 n 0000236948 00000 n 0000236991 00000 n 0000219127 00000 n 0000236659 00000 n 0000219321 00000 n 0000219755 00000 n 0000224356 00000 n 0000224703 00000 n 0000230515 00000 n 0000230908 00000 n 0000237439 00000 n 0000237834 00000 n 0000243881 00000 n 0000268740 00000 n 0000268968 00000 n 0000269011 00000 n 0000263649 00000 n 0000268680 00000 n 0000263843 00000 n 0000268510 00000 n 0000264231 00000 n 0000434111 00000 n 0000284765 00000 n 0000269455 00000 n 0000269846 00000 n 0000275671 00000 n 0000275766 00000 n 0000275965 00000 n 0000280384 00000 n 0000280545 00000 n 0000280461 00000 n 0000280731 00000 n 0000288670 00000 n 0000299333 00000 n 0000306699 00000 n 0000314003 00000 n 0000322310 00000 n 0000329983 00000 n 0000337329 00000 n 0000344605 00000 n 0000351038 00000 n 0000365119 00000 n 0000373674 00000 n 0000391097 00000 n 0000400011 00000 n 0000420606 00000 n 0000434478 00000 n 0000453243 00000 n trailer <]>> %iText-5.5.9 startxref 453291 %%EOF 4 0 obj <> endobj 41 0 obj <> endobj 53 0 obj <> endobj 127 0 obj <> endobj 134 0 obj <> endobj 164 0 obj <> endobj 169 0 obj <> endobj 178 0 obj <> endobj 210 0 obj <> endobj 211 0 obj <> endobj 212 0 obj <> endobj 213 0 obj <> endobj 214 0 obj <> endobj 215 0 obj <> endobj 216 0 obj <> endobj 217 0 obj <>stream 2017-01-31T18:35:32-05:00 TeX 2017-02-17T15:01:25-08:00 2017-02-17T15:01:25-08:00 This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016) kpathsea version 6.2.2 pdfTeX-1.40.17; modified using iText® 5.5.9 ©2000-2015 iText Group NV (AGPL-version) False application/pdf uuid:c1b0e4b5-d14d-9342-9145-22c99ffba43d uuid:ecdfa650-f2c5-7b42-bb3d-654b62e4dfd4 endstream endobj 218 0 obj <>stream HdiTYǫX]U]v_hApAt$ h {Pр " qAҶ{.Äsz?y{a8 (')>{&ad F`އ%a r>˩A%Db(֍0a; ={(B#cm8Z(#bmjufy:Am٢6H /St88SNd\0  stư$6fH0W;lyaw?lͶ5aauؿx^k`gkI%wW A)KJG=Ї|Z}xI8Hh70_JJH=hՠ΃9*O;s.ٽ!+0_1C,&EOK 4Y]Ȑi*g"Y-?6}{ksv~=t6(n=?XnG>)ȺS)I~PG̎JvխޚPwZ:TouKYpAeE[-2VON0lS4]Y*{Au6@JU99lSVɔlO ׆ l[mu:~`4QcQO;~2\#HVr[(x+\AgQ}jȡq5XƵ. Y #_HY=").._` A#HMŃllZhTH=E.ϕ3 ~bRyC1#h7mwIX%5ue8ꑈZ$%!ɩJ#; ^>0{!|x!<ѣtǰU=kU̚Y)"KIU⫫NH! )slWQ=b1;KP{4?IMb 8UmOݏ-B6ےq?,emh o Zl}' ,f`=y(;+wP"53l!%pؽ˴{#;#Թd T +̍O=cqƔ(ecg-.CwS~hӯ!DTX0_FؼUD,;bFXct;{< YQqJo&=`0F,s9"-+=gySZ%¡ғpҴ~'.~*\Fܩ=\p 6&n~ml.wyvojEy;tWq)bKo-tuw5/uGCW^^׷=q|[#Lo m̶[ߩ \( ig-m?J,4ӟ`XpAEvC|0$r41+`ewnM壵!ɡ|пr؁z b{+-ܺ سme7œhKor46%WzPL[ 4eˍ4Qikwzȣza?FfBm?,2GđqۓRTÞph_FUB\'\Z_9 7<&$&<.ӸrޫKj6 aakp1?m>ǟ /{Ѷ/bOEpY';xZП+/ 7TxǾ<]*4Celz/u!+SdNȳL k EgGImNwJ WcK,F|s-0Mh#7MvuL&e`!ӃwdmFM(ҜSGq0H8Ff(L2T'ۻ4ZЋՔTn*km$phLuouSG\ bj^` 0z\do{.ss) E;0(/O Ssb6[*|rV1k+pCvEq0Mqv6muc-n\bf5I-HPa8d8k.s@De5qkm#[5co?}O+Ou)-RDt@ʠUJ@T5Hh>~` ^d 2[&+9ѿ`b!]7nW1R&͟N-.m̵\ &pq0" wD"rڞpTl @*)Bf%X97z@wuTzڱPnL*ImswBw}R6ߠcU[wR*U~)Ԕլ&9R2z=*(wxeJrעE.J#|Yq, AJ#oneC׬;ә| |n7̹̿#'Gc uP21WHZԾhJS@jԂ޲O)aaTlMily2ONy;d,h5 V+IkQmԦMῢ9m ɰU9.FЗV  XDQ/V/B؇W8ʳk|?i0{:udDywyT`!Lމii҄`:@CW2r)q'CMűms]<Į8ŭVzv<^vLE R:'4i??9DD>õ ˑ (SUZƸJ877'+4&XtiivrCpntO+(MQ\Zv8;qVZQ2bX/.DAx}23,#&^DO(xXRHa۲k@TGNtMHTƄP57'ɭH> ]˜4I'N7Id\ZK9򡜁A ;`k8uah!E|uz.P"fiHUsBn}Ep>CݠiG iR%vYR[ ӒULNWHs/Nx|\wHF!Gt чqǘVٝ7'+8Ɨ3︷fߕSLPm z5WmX#M Qp\̐(7?W5˗5p&n/%_)E1wSF-o(7QM֪b:_X XoMZCAܘsymKHSHƋӨ2)!)v-²]d$8VJv%>5U-hJ *a> 3pWp7́ʽT ?0`p8T&ESuܛ^X.& Gz_OhH <~r\3B{Oҹ4_%2 6K!s_:VLU6#칪̥@laizk655mMGNn"U$|;ٽ/+S8zc@Ћ1o 4b@;Tƒ7maя Pwi4}x&7IKE BiR yd.l:Ao1,˜xbx ]>w-~ZfD8w25ߑIݾ q_ +D\,aB;*bU6YKU( x#QŏٓV7cM Ő9|Z, Rav/@E+='ǂ92шxD< b"O^o{FjPqExPe3%r}Ff'43yQGk֌n߸-:ajQ8vP!|">O8qG|:1kOZH]SwWk3չW^Eeq깙b8 l>4 ^SMP3~=&&Sٍ}]^Df9(f6j .CLկU;ȎpRO>Am|1=Yz9Y7q%C(9fqJypo HiPh#'D:K;H# st_ĔeܜIe7Oÿ $H7DP&_nɾyDo4T8^Zi7QT˚=+A'CA ?%pwPvjԞ:at79$A %䅙SW.L(S,Z 3 |ZuRmnࡂx6 ] .hj,}|!>AMu~tX}:o2}z}*۳ps*凴e#ITꓰ6)ٶLpͱO'߃O endstream endobj 219 0 obj <>stream HdyPIhqt@e<]A<mmnAE9UD.GDE]/D\utuu _&M/1K >ajeLo:0b/rx0܈QHX1 4)rйj Qa!17M>}o;ݔa!)E2\U+#b\fmh~yr0<0+aVط6f\ cHQ\;89͟C$,7図}ُ'l̫DcP{mh9"RDjWm瑲Gvf3J޴BwY嬣Rm|`:1?Bb?jlZnIcBE-N뉺';g*U!Zc\n6+f`3Ys ?[OSwqHI"f,8ݐ|qTv% JU̡8.l~𼧺\qѵ^+Ѱ Zj0-o D6-a[FآuD,;zn/),{(E\S` W(e."kdc oavGX(8u{qq;f$!tvѢKIe qPӷRMRMg{/hIkf^Eve_fs _~h0Ͽv40xzc7j9]!-lWsMo%;3+kO&-&҈Er%ˢKe}`4p,8+Ġs I{v\IE>9"͈ =i;hMpr \rJ(/=q{EZ H{es87m,cSͱ$1MII{l)⋌Gr"lNj# lTb} d8F΋6fKbčLqdܮx.MJl圝}k;C7q-O G N=HXX`7UŚ2ڬLW'\+I$ 8㚒x7/ A3+u/߳}.wV P%)eL[?aN.h?0 r2۞r 4`9O-,d4$|DNKn vg=\B̢'; !3wdMV͂(ҘWGqLo_* 3a"1h$euT";;r7藙%:J**k%*F߼N$]84y;DQ)C2jQH 0zR_hnC? (/1W$MtqZ^L@j]-v|wm]rV8)ўXKWBĒ] 8.5);?A(V`{L^ҹNX~,i@Aj jLÍ|uKwf8縮tV+wmgAܑK br!! @ȍ $[GX" -/U٩cw;a??vƿy{}-)3}^8i ac6/ꔀj/iZI5E9 It( 0Z80@"ֳLE TwmGzzOg+EH^q4-BᡉY9 rOJ O9aY}qαRUNtu"7sJͪP A 97p{T73ݭK&UVP&(7,77Rf0MT2_Kg[wzԋ6ҿ45[jpI[/ G{yp n^ƭ=6S;1j\ULg(&J0J*J'OLs>>3҂ݕD{%B%`l'DB>@G?, Ko;Oznw\ 9&-Te*݊16U#7%OH][֯C+h; 9x])rCц!K bfi Lvq3B!]8A>0piP["$iF_Q q}[~ 8x(=NLD/@~'>,$`9ߡz O?s sVqY66I1lk\8=Md;~{o9?&\Nunhq=G>Zƹ @'-8ḳ$5V2a cMS(t?Hafj>C1ԷDVbi߂ |兄(s psapW|( ?qEDJKgpUwO%6G idBjξ w@t~1LEp787[I]0uI-MQ6mqp'}v *'1MҤCN>D7x*2BLP1x1At~doC;6,\pЙp`'˫kdk1 w]$%RTXE9$&EdǢ/ ]ص=pN5`^jm .=ƢTݽr14*xH=9{{}wZ=h;V6l81NEhG"$sbr<};ynXK:#O00:C&̋ܜ2MnFW g<ޑ_NN8QѺ`e5YTW7E9j0+~~Zh}^ 9}ԠO[ Zxl1A@@M~UoM$ց&& Y=ΐR~^f F'v䐋 Ph治n{w[h,lUcΡa+Io^vE(sӎ#MFhʕ7 yJQY|z@F>fr:gd[@wݚ~&/\̪٬iȜcsrw P}ڽ l@ &(py=04ma E[Pd#$é$5=ϠZPd2 ]K`\V;ͅ\g}Rq|`vwJؼ 䅬_ps:/ag r"W\'n68F“ө`lΠidnT o$w.[٨ٱGđy|BܐJނ[Н/OшʠOV2:<}y-m?<ƨf׮>uMD; gP}Ur:q{na&VkF&. 0:ȏSpmǚ⪣UO*mӕhMc77(bSL0E_l&Ԧ .oJ_5XUQveKOe.PnK $h=x.oxݡn7RGvp+$\veX֏x$DRAjdyGf$s$Txh/` QB$jhj\\1񥘮_vnqXmA%1e]=xfꭢC {K HK#YuXU^ۆZrHt,%Etm%sA}-QCq̉pbΈ,4Xn m6Zfd^m)`0[Vrws/O28u6 >b_14 b.,[DDl[Z>ۃqZ}Qe_jLl%z[Sߟ:|@(fbcsaLoSZ2%2NBґ>DJ,a[(@FτAE ^ "n$ղ$۪(fNQg<n 0rt۩ X%1ޜh ѾZ ;U endstream endobj 220 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]/XObject<>>>/Rotate 0/TrimBox[0.0 0.0 612.0 792.0]/Type/Page>> endobj 221 0 obj <>stream HTNA}Ǫ鞁'Q0j4>H!rvWvsz. S]}ԩE6z=.*Jj}.loK'+S?g_gƚ(sU6+7 ei VVk#;f,к6k}_ɦ'ӥF6E+3ryœhuh#c[6ˢ,Arbn~\_Temrt{xfe5ռ󥺢\mD1T`DI A@=y`o$kZA<%*j{Ev`גEѶ7Uhz 億Z9Xr +\Rà$MO}1g`u.wW9á@K(Fzp)S"LbڡhQjE6۬ ݙKZ6rz:Ka-P9p9ngh/CdUw<>tM> I`dʮ-\0 t_ n96|xakY+&59*D]G9 [ Qy--r3y %u3e*O+g{Zq`p ·HRΊB`^G 9q~nz C5S˂pz%,hzR舻1딀oj%j$QBap|ZO5js'œ#|.(IaelI`5!xjw:͏VQZN`y_ endstream endobj 222 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC]/XObject<>>>/Subtype/Form>>stream H @ yynn^ ⩊g3$31GzG6A1Ό.xܟzs0ZF׌V >/ExtGState<>/Font<>/ProcSet[/PDF/Text]/Properties<>/Shading<>>>/Subtype/Form>>stream HW]o%}bg$lWcXFkH"se؋sjxcdY5]]No>8<{*L)oz88<ɦׇ0]0} & xd]+4jRk.~<|=_,i淋'%bP^Zv]~OK_|C:^jכpRbG/{bu8(+liCowXScXChLq-æ) N["^ml,1mJ3_l1Ö/c㳅KJcln<Ǝn 'L7 5Z>=X2WyZ.~3M^؂xD~_"KΕ؝Mw Als/NJi=a|{G|g2S -vfF`Mn_\6@I 1%6XiKc ovY̓m`/(ݒ7,].1"JS\AԖB$Ê #|r ~͏08zT`sQn4b F']:]j G>FƈӏHP{k^@  (у=(!<a/8B< `òc' :bŚ!#SD =5扄Nu.HE2ۥrgszZ:ƨZV-,9MeMj='hPOش*A(!JEQmmGR4bNZ_i")qtR98kCh<m P^È2!lN i<$1oWe/{0}w?ot5=A9*yp479R|8}}U_͡P5*k3!)( -cMT$D}CDWƐbu_0BɖX8W+6Mg#j.bYbsA)f5a|F)@HH/uk\#AAz l@+ze&8ȳtbg##ԣcDrվ=iJπ-kh"4,Ckf1"2IzY\UKF5:QKbA:P`tjf#P9g'0ɦYA %+T(-Ƿe%RX2!X$8R*Ȧ$ 5H)]A+BLm-b  \ 7T <#Q-UG_a2HZhFr3ET5WdpFw'Te|č\(w eH ɽQ@ NFߐ3`ؙZ\LxQݬm(rG4&[iDMpBicf$k<wJT/;2Q,JtJ;#ṭ=,Dܠ~SX62D`m[]kN`VڷrMk͋Ț:jˮoےĒN^/c$tHu*g U7\lmҵQ܃ѧ6FSGcBkHy$)vGT)w۰} 7!mC-:S9OV_R%,݅`E%#iA2~0h§kjl!P2#%1ƨ$R9n}?^*ÁXF]ˆ4cȒP%iKE%"ֵ4$d7ۏoF[Úrj ߈?ʭgπټ桢cKJŝ=wAaUnuX(N8аiME,0C"6q]L1Aia EToHHϙ3fRRr` df*pkqZțvǪ^tCtҐC[21sPݥIĨz'Wg(RL)#()]u%a7]c/Ւ#ٍ>E^ E01Sr701 .SO`0H+CB̙$ٖ4 0*1HB6ȕ%kBQ< D,6ᵹ~7]Z7 jdeIϔ]g?|b_ `/,O n4iKىHQԦcZk?~ #,w_X>~KQS9IBf@OyJ0lK>U& ĠI-Փ{sU}Umbm0t{)7 YmJP[VC*C sߖ?;үlUhLIyϿ|jzrcqwqڋzhyp<=Zjzd9E+9ds4؋1ԍpp=瘓HXgȻK3EW܅JlۋL)l+I3EF%Jud7CJ^kBFb7{9fgBAQ-1ئX5Ι,FRЀNLXԳ&+Yo5qfQ]fl‣w$*n~XcP;,E+o ]JcQoqU4w/+Ϥ!~4Iz2Skݳv¸ 3qU%>t$$Ǩ5byez 2Fi&S9xBU+F͔ch1SVlVI|_ w*J?/+{y@̠Bz' >}2a ]K{F0E'jʨQ42 aYe rTAA{BޤF@U7G1`3ȘL(fe_!EpZobm~l>`!>nrSન* .$ f[Ƌ95f3sdJv&㥪] B]W̊0E-e{ { r5}@%ֈ_j\E(NNzi0pg BN:/EL/>?JJ c_@觞9儝rbOrbr}YNߕv TNCOCO(;D(c3WYS$8BaJt5oI/1YgATTS !>9g_.h dOtGb: 5c,Q@>Kd(gQn.#fаu.N-fb lUyXF`jYhSG[&,k5"MT# iMIIT47̹55:"z; U3J) $;N_u"JIdG 蔠TI'EWQ,# P3KEC4>=XhVy.chJ^N\ԝϫHe3$p5|D֨|uTCb|I=eM˶'&;fe5ZC J OkVjh8oM:vq=7к k'6ڄ]XDg34&#SX[F"]¬FK{Qgΐy AQ£GZ _Z/u_oTZH꠬ؼ4X/AfU&26)a? xSu}} P=6 64K@TI|H )/x195;*4AYD HP)*(e+|s8U*\2930 ה2DLaӣzmrAiguq$'(lؗףY/=jTɁ-gK6[2Z1EL^H]HM_3.SCI *K)l4qۢ* J;`&'U't$I#DS:g⹾W%yYy+¬\ RPhFhi/,ddvUR)݁JFGvS͜2h:dRY%rH/)|.-D481L/4LuQLڟcY_Ŵx J7X5c`ؼWr B-\h}QOD[cSiV؂MJp|z2H)w9uRLn1ϗEγg_uht+`72}Ws=J|Hs(swH JJ>s::FNWX vβH*/p(,cNB`]GOJTh$\9Qn6/*K0%R5"ir;)cX~2a2{ڞ2TRo˃֮[R}rZ)_\x9T5kZ >fL;͘]蚓&wB"&=믐~~:dž׼m=g`T1E>vwg}jB]TT[ĭq7?foCLRM}uiuͣ*!u8yHUx W@FQ0T")yPϏ]XEgpW734 "c?ޢ4[X6z-{8v ] I9ejp&"q [J5Ymhrp#~zkMt܃ukf{~j a!^p!+ ;%ƹb1)*w KK*i/lE׮~Ẉ+48C+&G6^!It^ 6u3鹒T4v4Hvs=oҗnո- 72*ڢ 5 _Po<74M䤱Iޥ[kC Uz[ u1@ @,0 f6X3Aq0oLHoULAFeme]AĠ?ʞK p/~Sny=уdm5 n$qʮjdC rl8Z+8Z9 @9s9$[Ԯ@$bv_2=8j9_sB"$yNsi ⤆}tu^A|]?OQ3 Zd4KV;cxu$ؚ8ۨR+vj? ތv)9bq-3Fd:m ۬bc!Ņ!kJ(wL{-e +(7yCп/UEM;ԉi:@]^j~qj<:'4" RP7NÑTy s8/3!Ȍ"ԫbU %X 8ٯz .Q.Zce;(4Uyt]pAz`&j.֯1M)_$=DU#&R n"w,sp'$EScDh0Xyb)Ckr:*Vuu#W=N\Gy v䲏lt=/M,FTp9# j:dL \,*VVeI/:fe565N%n2 qaeAP X-bi$ĝ3T8BFDxxDn&Fr?!yrlE5+G5S J?)SF*Ff]1%H [Z)QA^!G(|⣬94$oO1?> <8UoƗ3~;Ow/8I$?o$/|ayrr??N'ǷǗ~r|s|r/'Ƿۍx;8~|Ǘ8 ?7]?sOF?#|C {HGYn_K.lNLyهF߫n*Vo{O )hE xkR $N|s5,}i8T7j'qs i=$Eb)(F2KECɋkǞmu9d F/VX:b`үu>:6Qs 2fe*Ar6*Nd2n ]W3gI@Ƒt}Zʊ({tC7z^[e˥yϔ*nG0ҸD{'K8^N'xb<1o<1(_Oy:O;O'GX8گKyʳ_6VSUkvFd8X[84ΌūHLvxKXaX SimBNk?=pvOnXq(D<;aECJ VNJNDw-r3 ] n-ř,`zASK@=P(z0~KVrw,آP=Wxkiu%*+ԊWl$3z?iChk@_q* Cq4XrV7"VVq?Lrrc%kCȕ|8{q@(]Uc uJwHODn8)0I{ΓJ %GD1G/Fep73>CEmkX7$3*qJՋHjC16RǒXiUYsО6wYL][̫[#ܩ?s`?ڈ{21q˩V-֡5qU$V^7#q:PZ=2*yةv'>iQgb`hphX xxˤ[f=+~0Nt( wͷ&拃 e@|yL5)l.AFP)*( = 3~e0eofjjH ]tԾU:1PbC.&dۅtdY}qtlM"F?f;Z/QT жhCր8)IvrwDUQK4H%2Qus%{ؼb*wNՖ_7tL-զ2.zD yIW=H`ۙVO޵OwD8e w?º8eO'>%2%Q/9GЛb7CqB|NgeD>~\{sj_5G_jƪ\cj|yg5jVgU'hnwtV9A4:x#Mʝ d= s ml]h!J=p9#3EFB=1&YRŸY#ϳ)57z~xob%10anWŅ9Xd0vɠa͂Wmogڕa`_1I &IE{Х& J..<.,HfϦc GWrKb ,5qrlrXr4J\+ '=~;affw]Qp$kSU'nlv$G`&;4E ΄@ª*a7 ]V |l6AiВsQ>G&*(X7ND9Ie e҈ySI'Q$ m>(|Ssxb8 b]J򮲓ASU0K8c S\~]"f@ɌEuJT @ =63/kX^eԈGp6Xqa7_kuUcQψ#H*1&枵Qck'Q ߊ8{6y;z~,h$6#= 3 ;uZ?GoTP Yn6mƈ6b̞=9gm>G#c~P]$ nC ;>o̦pu(x3]b=&FxS{wÂM5fiL(aOˁOeM "O#23`W>+?_W5%_8F,R϶*P aq 9mth08YsuY=NQJv }|0Xa頾ami14gƱA۸.hذ`( ,L`q8ȡS,n4H51Ksė/$˅O endstream endobj 224 0 obj <> endobj 225 0 obj <> endobj 226 0 obj [/ICCBased 230 0 R] endobj 227 0 obj <> endobj 228 0 obj [229 0 R] endobj 229 0 obj <>stream H?\\[ZYYXWVVUTTSRRQPPOONMMLKKJI~I|HzHxGvGsFqFoEmDjDhCeBcB`A^A[@Y@V?T?Q>N>K=Hj endstream endobj 230 0 obj <>stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 231 0 obj [/ICCBased 230 0 R] endobj 232 0 obj <> endobj 233 0 obj [234 0 R] endobj 234 0 obj <>stream H?h j k m oprtuwyz|~  !""##$%%&&'(()**++,--.//011233445667 6@ endstream endobj 235 0 obj <> endobj 236 0 obj <>stream application/pdf usenix_logo_full_color_tm 2016-07-28T13:48:14-07:00 2016-07-28T13:48:14-07:00 2016-07-28T13:48:14-07:00 Adobe Illustrator CC 2015.3 (Macintosh) uuid:6be068a3-6f66-e14c-a412-1d9510750738 xmp.did:047e04d2-fa69-4b26-9428-764c0547b43d uuid:5D20892493BFDB11914A8590D31508C8 proof:pdf uuid:2e734826-cf82-ce45-903b-dfd35b207876 xmp.did:5f37efaf-fdf2-4ef4-b6c7-a42aed802ebd uuid:5D20892493BFDB11914A8590D31508C8 proof:pdf saved xmp.iid:01801174072068118083C67C01A9FAB7 2011-10-17T00:16:06-04:00 Adobe Illustrator CS5.1 / saved xmp.iid:047e04d2-fa69-4b26-9428-764c0547b43d 2016-07-28T13:48:12-07:00 Adobe Illustrator CC 2015.3 (Macintosh) / Document Print False False 1 170.000000 60.000000 Pixels Cyan Magenta Yellow Black Default Swatch Group 0 White CMYK PROCESS 0.000000 0.000000 0.000000 0.000000 Black CMYK PROCESS 0.000000 0.000000 0.000000 100.000000 CMYK Red CMYK PROCESS 0.000000 100.000000 100.000000 0.000000 CMYK Yellow CMYK PROCESS 0.000000 0.000000 100.000000 0.000000 CMYK Green CMYK PROCESS 100.000000 0.000000 100.000000 0.000000 CMYK Cyan CMYK PROCESS 100.000000 0.000000 0.000000 0.000000 CMYK Blue CMYK PROCESS 100.000000 100.000000 0.000000 0.000000 CMYK Magenta CMYK PROCESS 0.000000 100.000000 0.000000 0.000000 C=15 M=100 Y=90 K=10 CMYK PROCESS 15.000000 100.000000 90.000000 10.000000 C=0 M=90 Y=85 K=0 CMYK PROCESS 0.000000 90.000000 85.000000 0.000000 C=0 M=80 Y=95 K=0 CMYK PROCESS 0.000000 80.000000 95.000000 0.000000 C=0 M=50 Y=100 K=0 CMYK PROCESS 0.000000 50.000000 100.000000 0.000000 C=0 M=35 Y=85 K=0 CMYK PROCESS 0.000000 35.000000 85.000000 0.000000 C=5 M=0 Y=90 K=0 CMYK PROCESS 5.000000 0.000000 90.000000 0.000000 C=20 M=0 Y=100 K=0 CMYK PROCESS 20.000000 0.000000 100.000000 0.000000 C=50 M=0 Y=100 K=0 CMYK PROCESS 50.000000 0.000000 100.000000 0.000000 C=75 M=0 Y=100 K=0 CMYK PROCESS 75.000000 0.000000 100.000000 0.000000 C=85 M=10 Y=100 K=10 CMYK PROCESS 85.000000 10.000000 100.000000 10.000000 C=90 M=30 Y=95 K=30 CMYK PROCESS 90.000000 30.000000 95.000000 30.000000 C=75 M=0 Y=75 K=0 CMYK PROCESS 75.000000 0.000000 75.000000 0.000000 C=80 M=10 Y=45 K=0 CMYK PROCESS 80.000000 10.000000 45.000000 0.000000 C=70 M=15 Y=0 K=0 CMYK PROCESS 70.000000 15.000000 0.000000 0.000000 C=85 M=50 Y=0 K=0 CMYK PROCESS 85.000000 50.000000 0.000000 0.000000 C=100 M=95 Y=5 K=0 CMYK PROCESS 100.000000 95.000000 5.000000 0.000000 C=100 M=100 Y=25 K=25 CMYK PROCESS 100.000000 100.000000 25.000000 25.000000 C=75 M=100 Y=0 K=0 CMYK PROCESS 75.000000 100.000000 0.000000 0.000000 C=50 M=100 Y=0 K=0 CMYK PROCESS 50.000000 100.000000 0.000000 0.000000 C=35 M=100 Y=35 K=10 CMYK PROCESS 35.000000 100.000000 35.000000 10.000000 C=10 M=100 Y=50 K=0 CMYK PROCESS 10.000000 100.000000 50.000000 0.000000 C=0 M=95 Y=20 K=0 CMYK PROCESS 0.000000 95.000000 20.000000 0.000000 C=25 M=25 Y=40 K=0 CMYK PROCESS 25.000000 25.000000 40.000000 0.000000 C=40 M=45 Y=50 K=5 CMYK PROCESS 40.000000 45.000000 50.000000 5.000000 C=50 M=50 Y=60 K=25 CMYK PROCESS 50.000000 50.000000 60.000000 25.000000 C=55 M=60 Y=65 K=40 CMYK PROCESS 55.000000 60.000000 65.000000 40.000000 C=25 M=40 Y=65 K=0 CMYK PROCESS 25.000000 40.000000 65.000000 0.000000 C=30 M=50 Y=75 K=10 CMYK PROCESS 30.000000 50.000000 75.000000 10.000000 C=35 M=60 Y=80 K=25 CMYK PROCESS 35.000000 60.000000 80.000000 25.000000 C=40 M=65 Y=90 K=35 CMYK PROCESS 40.000000 65.000000 90.000000 35.000000 C=40 M=70 Y=100 K=50 CMYK PROCESS 40.000000 70.000000 100.000000 50.000000 C=50 M=70 Y=80 K=70 CMYK PROCESS 50.000000 70.000000 80.000000 70.000000 PANTONE 186 C 1 PROCESS 100.000000 CMYK 0.000000 100.000000 81.000000 4.000000 PANTONE 186 C SPOT 100.000000 CMYK 0.000000 100.000000 81.000000 4.000000 Grays 1 C=0 M=0 Y=0 K=100 CMYK PROCESS 0.000000 0.000000 0.000000 100.000000 C=0 M=0 Y=0 K=90 CMYK PROCESS 0.000000 0.000000 0.000000 89.999400 C=0 M=0 Y=0 K=80 CMYK PROCESS 0.000000 0.000000 0.000000 79.998800 C=0 M=0 Y=0 K=70 CMYK PROCESS 0.000000 0.000000 0.000000 69.999700 C=0 M=0 Y=0 K=60 CMYK PROCESS 0.000000 0.000000 0.000000 59.999100 C=0 M=0 Y=0 K=50 CMYK PROCESS 0.000000 0.000000 0.000000 50.000000 C=0 M=0 Y=0 K=40 CMYK PROCESS 0.000000 0.000000 0.000000 39.999400 C=0 M=0 Y=0 K=30 CMYK PROCESS 0.000000 0.000000 0.000000 29.998800 C=0 M=0 Y=0 K=20 CMYK PROCESS 0.000000 0.000000 0.000000 19.999700 C=0 M=0 Y=0 K=10 CMYK PROCESS 0.000000 0.000000 0.000000 9.999100 C=0 M=0 Y=0 K=5 CMYK PROCESS 0.000000 0.000000 0.000000 4.998800 Brights 1 C=0 M=100 Y=100 K=0 CMYK PROCESS 0.000000 100.000000 100.000000 0.000000 C=0 M=75 Y=100 K=0 CMYK PROCESS 0.000000 75.000000 100.000000 0.000000 C=0 M=10 Y=95 K=0 CMYK PROCESS 0.000000 10.000000 95.000000 0.000000 C=85 M=10 Y=100 K=0 CMYK PROCESS 85.000000 10.000000 100.000000 0.000000 C=100 M=90 Y=0 K=0 CMYK PROCESS 100.000000 90.000000 0.000000 0.000000 C=60 M=90 Y=0 K=0 CMYK PROCESS 60.000000 90.000000 0.003100 0.003100 Adobe PDF library 15.00 endstream endobj 237 0 obj <> endobj 238 0 obj <>stream H\j0EY6 CIRi jYߑ&P4Gat%&|0`8OWx1VhmV5NHwpl0A9tƕo^7_n:#4 hK^A&ٺՔ7aYϹ5i]h4P?hZ/,;.,@|d>yb sd.#o7;]=:USyO'GO!62>܆G=ٓ$1&S 0Q endstream endobj 239 0 obj <>stream H|TiTAMOb.#@@7dqAZF%n@v)A3*K *(( . qcIbsR?sN;w{޽&ik"tDp$Rq"&q]-pH{BjDt odttyޏ嗴AARNǗ)F@Cx0J4'oJn:qօЌeYn@!Hij/ wi|_>)^{'{aXzwe#\T kU R/J֨^lF5ɥI /lCvhAd27?v.}3q] wOy `zZΨ^\t{W@wNH(G&|U3'vz~izH%I%^o`:~69ѥ ͍!χHR#M6sw/_;4*g%,՟W|6{ Pq.[m*k{Yib8t@]^iD:;0ؽ]Ewk߀ޡih13BL`.RTA`f czѿ)p'dAT)D=G k63`җ}++ɽ$iv!2-Wf3>n3r+ϡ>CCRo_ l lrb   %RI:o}'J9\Pa N<2̦KVT/2 B+BI*"<6)%+w` Ĝ Iibb/_+e=֖wǶ10ozDd5g]_tW^SNu܁![ήa3vn57\{|v?Xi-$RMVfzz,7dk&"rKa~՟Z O z Od&_]KWCiEԟO'#%ɗ TݡĤC'S]ɜtSb7+ ӄY7͏AT[rPewglf,#+df]:I,Za89,!N;?sN>CG4zf 72"!T[wIɜsbK2E@<tc7>h9L;Y~v#3S{2;pukQnn $[H3:}.VV1j45ؤL/eIj,iL^qe 1S4Wpiߒ3m6l=F!Ԛ̼R\|>LI`ob>z Ds*gc[{!45 57@5?i6jmq3 BbEGHءldBtT4Rt^@಻[?'4+| ]_X  "f 5kj 9+8|dBv)le#OT$hQܱC+WLȥ5v~R;^ j OGj i* ìqi17$d,щi۟n[SCV+f̘E^je: nߑO3s}9 C#~"+ %Sܘ?+oB0Ok0}f7XER e>sP2<C#/ϵ ^lBbcG̣2_WZj:ja[%f}* <{#4tG_sC_-ȔZ@}ŎL/*&$kt -]NnYנjq_~;\#nE: sRAHjj/{|[Vz/zEqP5 7>:##w- "iβ(> endobj 241 0 obj <>stream H\j0~ CjJBiFqyj4lvG3ff۹Yw/sjJC7>stream H|yPYǻ Fv &p *"$ aft׺! Zx֊8.*0*هUkꪮw~?Al5K"WS5zݗj֔]Ʋ;̚sgBqw/]&u"H~.O9xyy]Ueekfu >>[`,6B,<l8 = fytMJzؔ,6kSzk[[X]oU\вFD$"+  b!!)AL",Mך y""(BmMD BKG"‰ q#r'yjQ*AuuEPNĢ d@B;V$%̲Ih65vv+!aC7ґt2]–tro:I)("0nχC # X&(1q]e-3zܕb PCA`ļ133!i!o2Gf^ά Òb%zy(u4L2Xv ?+>G`[{R YXz/Ix /a yCbZ{ۀL4?cj]>-qstS{GZClܖԍ)mJ:`!(%:XgrѥO ɍ#ҸgSgw~j+7XAV̊ N3+!Tv72DMHKq9>^&~a`.~]Bӵ1f?T㥺n`}Tx΢ %24X xhV0%O)Zck /IX>Nrzr &C|R!M(gl gDb(?3xW{< ] @ 6=e )_7?[ͯrB,>)rW֓y5QѼiqoyU]Aꍞ闠%kgoi8}-UV=y8GN(&Ѷ{zGt(=qsY#^qvYХ+eGN[OlY Ao+08uDX 70Z~ʹ'a _o`vwKvS q{;J!r< ׀F9ִ5JFA>yOB5\!7xGCem|Kx@q4 㓅X~-*Bzw -;ߌ J;- NBn%n OgzM)!H9ym8"%{ _ Z[-ѸB(x*u#LAYmWEsy+qxr݆{X&JƸ1; p[#?Uu;;8Hν;~$GC%]xH(|u̝Z(Ie'bʄDBU9(?woߕjXabWʽ0 \k,Q{$e?žZ_i%GgBz$.NdOQΠ+fMf6uyJ›9XSR"i*X])ST_kC/Z I, !%4ڴ}:>5cIRn5Fܨ`[6HjՂ4]>Բellet!'{1'LyD΄"Оjd* XxCqz ³vS 3`.Ҩ5沆 =s^,z^(.KY2#NQCn&!J9c,\,6'jkb[4IՇX}P0vZ?A d _b Lh@#bϺb[iY1ؔԀ0_%⿊bk>E}!!+ N`+zrV=I5itpV-K_ QWv~vq. 0DԲ|%+tyr~Q Kz B!խbs!,pg಩D>,E  5)T6UyQG(t.ury', Fon\/+=b2cS'+5w+22_7w /gx7!2ND윹ՊfeZ(sU39֍_sA:\eZ[Z MI>PNbɫu-oNⵀB \<8( ѲW|* oחRp5K,)z#?%Х _`d|uޖ9*_i턠xA? endstream endobj 243 0 obj <> endobj 244 0 obj <> endobj 245 0 obj [/ICCBased 246 0 R] endobj 246 0 obj <>stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 247 0 obj <>stream JFIFIkAdobed!!##!,##!.333.!>BBBB>DDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD5kI"   )Q!1AQa"2Rq3r#4BSbCcs $%&'()*56789:DEFGHIJTUVWXYZdefghijtuvwxyz!1AQ"aqBb #$%&'()*23456789:CDEFGHIJRSTUVWXYZcdefghijrstuvwxyz ?HỬwZۺjT*֝9ް ֏P.h%}`S h%}`S> mXԨ8:K'5*}`MJ`N{ԹLZ npsAŌY>K%"T}`JD }`OD8,XDmXD G-tX8u>HbRT'CB23GF_C(RLxg&q8x[y+o2W2Mq9>L| +6 =>B_l^+74w*8kJob:sNba< "]ʞ6*ocqGwV_csGwi8"$^xZiWR 2네8rF.NBFEHN!&8Z`]a ٙo&RC2@o]+e* $RuQCfhdlwZ1&P(6'ÚS /.TrBLn*w+8 C`LEk Flu)4Ȑ鈿sy/qtcIHB|$Hl\Hr@.Np@\z{ pd`a!SrD60[#Zx:K$ΜR F%)NU[ hvۀ#Gc6n2cYՈ[QqOy\$\O8$Dv bR ԉtjDJtԉ"HR ԉ5t%)N!)5ЧݻTSRW *BT*   P*D*T%AJ .!uʷ;;NqO"z'%x=!sJ$GM[jL1] r֭_<+sXh.:rܫdu-~Hڕ=#›W9.ׯr6 譭pzG.8=#›|F [[O( ]p:G7ke%Gv4ѧkb;i<KHnVk4a4L*}r]\!@<)~PIˏ̹ԧi9ABp= ^JΨd`K]Nl$bz-;+.eY0i`p<:v2o<)ZM˸9XcԯJMVr\G 2K#ѮOϣΈZ!5kG;m\G=ʄ=⁔e]rjuNc#ʇG8QY𮢦W lD-Uk!eBxTT^l @$Ne֞eĸ7حRqa$'Er7'YEQ!hTDa,$/ :%t*Sb A:KhĘ ΤNhxLʻ咞3cq])o*w+Vꎳ2L_+!ܢ!2rZ6-c M6F>ecI fAHƃ#B#H !F$)zZp쌔е6)%:HAѨAѸ$)В QeF(N8 ),$],sHYIedt%h 9],kEh;'4ƴ5jcZMZȤ]v=i6=hIǭ&ŭvN9!tc։;(Xֻ!(iM] nLLѧݻ jvn)T8J.(HpBDRÀ Pp*7K\Tb4xӘ8nJTޔ9$²{ْSI^U}={֦e3g*V!}SiQ,0)LPs7IWe!7E'&sM Oh1(9E!F޺d8˓$5uLYWAʩ!HW8q̢l!bb8!(9m n4HpapTvI$ ֧?'.I+: dg6ӎ8VN異Z3Zw LqTz3g9fT,T7BJhҐ%$0 'PHdղvRӗPM-nљD{\K[e٘(jM\5@W%DZIi i%"KA%E@[[vHВЃ*DƄƄPlhI rDݐhI $MlBĹ7.rIөݻ]L[tQ)&9Ű:WAM9 lm̚ˣBJgiRlmA"Bt1+y92/ `( |8Hl54 iAudiL jX p9PBƠ$ dmPr: 1ڇ0!tJ.֥,ε0K\t/)`plq]Q _{\$D_*C2RDz:Z1#r6[Y]KK9<cuˏ6 FVW7q@q76xK$fzDLeBfnֻU3m '*"ȓT\s@%avb8V>SN CcPJ,1NNeQqX5rT\,AP/&n c;Iw.o.3]؜W=6{/95o]Z ]"$>"B*فH즥1HIKh?}L mx&-Y͞Tpyx!vR[ Mm di&%[fv"f*.7.q|W:;KӅ4 $뼷H\6fu'\HimdI,` J!pNAϙYYnθUx/m쮻^uΥC (s)$s\ Ȧ4bG:)Qk)'BFdZ9 ɐ9\Zs$Yrv K$<8b5s 8AMtug0WdlE.Dd ,[f'P x.NtPr,:$v-!tЀ: -0~xE;u+{WAIOƛlfKL&t #C>h ՉJ* (O #"ciR'q*8[s)p7 )"w!٬WxFx.i10sntڨj EՓTA74dm c5u /-5WV^Х Cq+u=h}p!m!)~/-ρt@65vӾzBČ̕ }O+i1זt-Yh "5Tw7-'Qhu«+:z_@Cj9@z,9,㰾.y= yR \4[pIR:Hϝ0DC%5s%TsmcxMy47:ڄ:ӄ:W&Ģsl#i&#X\ce9լ88JT#TlrR 7rM`Q8 ΰ3ȞA%kL 缆=F #CmGX v|6jz*E`'$$&\b5EG!k75D5ާ s\gN 883'@Б=si+4Z˫ZM)5כN0]Zڵ.h5\7NN^멶Տ:xm[mv2۱7N~rV|1'kwUo<خ6`B%sMһ' |6BT#B2j̺!Cl`\X%~ ":VoӚd. ΂WQz8$A&Y:sJpK 9'їK`0\hr=kDƜ@JӇl XrИ lDS\aTJQ f .{H]w8, <u$ZI`}ٴX;EwSs"Tk@C"j'd.oYO-16o2"nE+IB ]OwDZ3"Da<&ORxr(7k# )۱]+F: /r-斒q)hVp~Q"ދ.߸~P= M+0 *f]h`ym9B S 6L_:ڠ TOq89ŢCiڄ}sXXXYLI$Qܸ6F hMf aɪO̟[сsmwdm\IR.k￑*J3Ϟ(:qHW=#!9m0#e3bgp#$]r"}܅2T;'(19)#.5~֒96"XP#rQ 6Df.vArQ)-9!]Z9 !gq8ɐ ux3:yn3vw=B0@ֻЋfs1EuhܿapNӚ )`xo}pmy8ڠ)iJ+1ܜiUp q]Qρ9̀\xWSDr~2s@Er%q4uUaOq եͨ;AR'b耒+;ĂƋPDV`@'0P^pnǹ7n܉KK%V$ة*lуyM0K4Ad( )4nk4Bzf./]vmω]!)Z.4`8kV RR-n[2mf%h~ ֆϝ"c뱗Lv.Y5XM*# uQҹ7hJ$$8'МpPSx# ̀` ͦ:kv1& J` Rpp2` pN*fɃrLjɯ $ *mS@" D\p/iW=WEʘ3.@8o] & Qtz%9;q]HS׮J$*pV,76!?#`:W<x6W_/=^asYK% /Mp*jTt4^T깕Q*H{"O:l.OdtOIe?BYg%!k8_Y(;#"Z(.AOLqa a:>B dvĞ]Oй-ZKNt!:zFB!B!H P8,85`,sP:Lia#*U.N&v&w2PTt.&ŗx e<]jN' 1n#RLJyaր5j0s($ )Z셆Kƕd =8ޚ i4]"8Q )Ȑ\ HNtkF9ӒJ%U3 L0TIb:5R@s.{.K͘e:/(IuyHST1gʍiea%qeF.LTƣ\W]VXF\G{nEOHQqm)dZ dMTL+IׄJ[h.7$S+mC le,\)|gSw&ɛVi* 6,I&I.>תE.QҚwXu}}IPU[BZ2ί7n` a95nuUVٖSN)cmN̊l#\g2A\Y c4ʥ6$!w+pglht[Zu==RjҏUH*iD l4ԹU'Ը%Sν&qѳ&zѕ2ޥ"G9hȍj-g` ]ĸliH_tHgH2oQ@9pϺ"C.Λ]* sD8)¦9Nff\mg]0lT j)b i rycIĜPDBt(˨7]08zV -΃0:K$oy 3cv5pt790PR$JtT$JH*D8*Tԡ9uIw4bsG*duk:s+caAF 0rgSQNiF;H&Jɛ'=w[%mC#@3Rƣ>+tLǘ5WyTH6r{RTgUU-XD`!Cϕ:JLYUqI&AliKw,fn~3Х)6͑רna%M{[=LdtrPKsݿi:Oub\i.$t ViSda/ֻ5cCX@ ȬD]NkGa]"܂!@!@!@!@!@ D:j""wlĺ1 'Ru` :BDpUi"QힷBX6 ±߸hsHs\JK ]=l69Z2$nz9m/@; C)EL5K;*-NQҝb.> xpW= O}uT:R2ul@yB\@a̖AA4:Q)Jfuѭ.7A\! RSI*$$.+`)5ĜSE˄spN6& ê@S{ #!VU\R`I'YHr3< RMiؘ\mTJ9U~ɹ^PIt縮rAT,dNeG&]-qQislT5G%qsT $IL6,h J W(Ÿ r:T3cow^Wh1sRI8 ;e5HNSzL+=«8xQֆ]f<ۺ%Jiݫ$sLݤ6vD Tᱍ\:)5Ԏ-fAذ]ޥֳC1vMHt7n;E'Sucj4ZEU"L0!Ƒm` <5-TZ5̪˯iT M¦Mڔ̆2w/=G̬F c*8_x qe(Aٳ]j\P48| TP`ӯW3Eǂ{:d7KA !,ʥVu)e%TtܑD{*o& %vS JzI\:o̚ie9CRgtB;/@iTdHޞd\bzA^4N4pO2r9m1zS^ .ok ,; :V59vX\Hc\ *̟*i+ps'=׮Y>u5q 'Ih%`^tIqR."TDAOB#\MD݁M%uتsORsrJ05K)c8*l9IkeD3LIx-s9ұ UH]#-[jc)=E&J d[2R%āaunFgYs৸wu)R:5_ϺHin:|W LWpNmd"ۉBH$ .܎R=JIޭpsi*V:\h@&kq I%i'̶OQ]6͞J5ٶyJcꎍ,;kų[}HL%<. 'UaIt%|N+4.&7Rl oDA\I51­V^;ŔF5'Bo|( ב딛r 7]L 翾MPoM6S[57&\v#ҏkO4ЋNg1r0yK4dtBqz䍾VӪ\ K8޴CbOB[Ssghkm6;WTpj9 )lr;@zRZy'0!gl C2~=J)1 `Aq)6zg@.JKoeg% STY5lG!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@2Ʋ٨8\ kUߵ"ff:µ\Х3c5i2ŚJJŕ"0Bd 4{GujPݓe&HMjf9;M;#{lTcɥrS TsN-4RΊ,qŇ\#˙jָqrđ52C3$ڵZ]Fn\E\ \c : !$$).@G*H(ruƺ |v˴dK µ'`#8<Һ7'q"K0 Bl m xN=+C9w@DӰacKH֝4 䝊/6X`Sb2ӻ[=kN唯u7Q*5de4KfCBsa":KsrLj9HJD $B!+Z`.:'"E2b.h`SU7ת 9%EO \Λ[HJjE|ȕ\冫)cX, Řlĩ; O?ԃ8Rov'"ɠ>stream JFIFIgAdobed!!##!,##!.333.!>BBBB>DDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD5gI"   w!1AQ"2Raq3r#bBCDS $%&'()*456789:EFGHIJTUVWXYZcdefghijstuvwxyz8W!1AQ"aqB #$%&'()*23456789:CDEFGHIJRSTUVWXYZbcdefghijrstuvwxyz ?m &D5ȳ(G)wRK@` N ) nuS^D\g[UsQNeȯ=k{n~!P]BPˑ_ c=+/ td~es<}k = TJ<5jC" o5H΍vO 3&1obsSKɩ.V.լTq=B>:j\k\KghU澧cr~+*r/:9ԍfd5+Ilg]1X]#z P\r:j{;*wwl%VQSgT_t2aUS/[&*p2})cG(,SRtGC((qMPղZiQ\W){FqRRWMb,Ȩe+,WkISri<6tl|&க~m6javс'hTZ2΋OcGRiεz9Q9SίQbа8ت+3@H19*,ym{IQi])Jo:Mɽ-8NoUǪRZ-}*m!(I!8]V܅Q+zAnB:8%P/XF["(*|TtL9.T8H>OEJ>ʛӁR.xh^F*V[^kFKeJ]ipX99\įCR]"<:S 3(QRC'?1Ы1o%lӘkid>(pj9.,ωSQƔT4)wCÐvYD;է^xQ}D|%:rϧ' -qveZxhʴiVmXFk\Zq*yá𗜮ɼ1VSUἢ㓭ܑcVm.UۉԙD3<{˧| Q{[9k6AɷU T}HVߘ(LG9.AP:8 t[ FXI'ΎRi [٢ZѾ\NVi٫2(FjI$ISn܏#ʜ%c5cGӜMN$\dRR]iކQK)}'uhkl Cr3Lruw Q\ҹtKMI)E5t(*2vdnRI: e=Cq9PI1H~d?F;ڱyҌp*IoGsh׊:*B黧֞Ƶ2^ r+Ƭ^t~rjCUNk-C[+L|#kAoɦ* p t.<նr7r/UH%;g&vW;6ݖׁT/h=s-5dY[oR^ VԒ͡tIl.Eƕr͖CbqT ]ګQͨ.C(ѺZ_ueڑU/Ge*j7yɩ|U=Nz}mՒˡ¶3S}/L>+NꓚKJV~9O]oRVBUm=Wl!V8d𧓭]:A|)-8YWUgFxGCGťooYVUSVr9)p|&n!7}OѧKTg?rv]G)Uuj唧ؚ# OK3Aiߓп UI{l8d;R̰ c߮>JT찻0~\O)zԅr:>&.5Gwd['RqfQY[ YzՐF1j\H/&9O̳PK Y1ڞKt.\nu!^>)SS}m6rSg.G'n ⼖'R2vCe ru&Y.&">S%(1iGm㢶-#N1Ru_8dv7#v*wcaFrc QpaJ1a,dkmG6Iy2ʲhts8' HTx%Jx._6i M]5͟..QGk5x-],bnG[k1~0炳NYq*ϟ6=7*z&H' ^\NOj۾_`9QNńU}91F/?d8݄EJh_N}|;3%nkTްӄjCȾ{uN1i0"CYM{ɳQ tXXV*c[N#ȭ)vzddLᾆ1.d{Ly3̝GfnNB0M4v$RfHEZ+C6zXI5ɲ, 딻Vh*.%p8WU^exrZ]8׌ՊSJӃ4Ja5 5'%Jͯ URKZkt^HUS^to,ɳy} Ƥ%tFigY\%b S!A[KRoGC".Y D3 _.U'WR0xi ? 0W5=\\!y> [S",SJB~+#}=rQ}@1^r6t# _pey㾺Sb^-JqEpH<+Y: O{)b%b]pis/6s k,%(|!R|9J\Ѡ9$ @QcNrMKUpiW8{ӀN^yfhН_URy%vG-k6q:ƍY+kmkRhCuc.7ʕJϏT͏R@?D&bXJ#}BuY:tIGlrhu,UTF ?o1t>4*8{"3nEO&8'j?oeuPr)5yGq~j4Fm%*RwJϗ\܂ho'5W{RY{B8;pӣzRڕ!OyȮzS*JJvr9lIXbnM!:ϮHk#k)Uإ K)([3mb%]75)Noe6L"OHTuuMI?1oKojH[)!}*QΒzҖ8G4$9B TXm=)LT:KcYV-K'څSB/g%a8pמXԖyJϬ#"%)pl]2dXL`3KjZ|Hb:tM -h re-0L՚Z (T,v8' rJ5dϧ|(cA.)`diEM_E8>uN5c.t 5Rt'S˚^Zl1[P% <ܢ'l$mZܝe[(鎾ngSU#kI2ZSqjsyѴrJ{,l` Ri2> QOr6_'\*Lw֩,KjRXhѱA]kGlw/3*jrxg֚v-l)ЎBFY|ܠ^몚Ǯ:q*O)|Y<~.vlg,%KSY%8.'njjyƟ=\e- .o 䴕Scj|qVJg`o It1=5R9}r{9^Sd Q{$2x7ܰ!e~rM*ޔmmz^,Ƭv\V BK&K_ N9OZR[rF柜vlPZzM]# 5(V"wKFPj5x:kJz9R_8v9#:Ǫ_ :a<֞ Qi\rZW::8z)ӓxR+Oaރ^gy29^Hz786Iv kJ,,ЙRF~ث&=ۭ7aU%€XDƲK7V3C⼔'V*\Fw-QoʚK(WKEv7OM:@uc"vzb6SWלOOACR y5OA)|JNN|fZ&1&͖Ї61k=LbRZ"2Z@iQ.ڥ"a~kc C$p*:{ Ƈ[׎YhKZ{Y3Tb%ME+)6okb:u*JI*Jy=BKmS+NMޗh]g^'TWqa Ə[Qe9:̚M4I/jJԄԛ>A$=gmYxS3^ȔZc*'{Ǭ-Yu|YBɧu4GCd6Ǭrgu8WFR\E$*ɧuY8Տ9ƭ xKa`'m=~50NTw{ס|TOJVjb3M<ʗV-H4׮,TXGl/Ic~)NP\Fn<}s*Z&UeY(+عH2QeZZ/j4'qDKUGu˯F{̝c9Y+LSOҒVPYz-U_+I77&<%m^ʹ/[dBF*RLѣҲ@:  : *9h]:1< Wa)P>ʜ׉"E`ҵ9iz.p Rqy5薧0 kSfG+j{+gOLJ2WM;E="J)ך?Ӭr$[luS=h\*V|$XC˅[FJK9[QÈ($1[@|CϾtMmcrHlX09p$,.Vp5kLeۜ&4ΜcWy`Y8 I*M_: <+,dܔw~;(5SޒFUV%8Fo5;$2;eȐtUUJЂ;үJPP8'qM8fԍ6)E1c{_KrJ-_-),7f%A1(ք-8PkRv7M>'xksCkhڒM$;2)9ɱɛXT=d#FQq;N鹧+1X9I]:xcN4**[Qymh$ӲOo1RV|!ӓ)78jS9Ө<3jkhI#E9jgUczsVc]Ck@ t9 MV:pU{I&1cLԩ,^)pzGo6sUV-Nss;-gQDTw896sQf:*qx=65[!'A)|rt %ɉ&fD#\Àg9F%ؙe\^atWN_*nb8K?)rv FBs:,"C\6GFATҍ֡iRWc| *' VSgHN*I2Vz}J9#euD"nR4g{(L Z{i>uX07I&Uqt 2 yuxjԨ" T++'ɕXjt˯ (D]'"ŝ"t tMm7-8Ek9+sq(t`vKy56v$SJԅgЂ@܆(٨GI$)icc \3q*$@8+3N/4i[ ( ~p: i<SөRJ QŮwNJ:{ֶj:,^2+sOGӢ, j:5gR>vr:F:hֆtzVt!NU*hwdb4<ZhΤ0\'.P@!J.svKݱSv]f;Ɠ9rjNjJ7//`tZ+O;a+ʗ|}J:F+Ke6Wz%<:Y*zȹ=^VUS(W+}\Ȱ8f猵l\(BfaךREC5R\k9FV˕X9#5Qrv;C&Q 6FRv;&Q"JbddE QQVp]W:gAμ8s.7q.%k}V:} bɥ}_/᭷pu5[<-OW>,aeg7eZfO#đν`,xթpzf=BlrG)IYhzI]F=Ck-omqBn)]j:qc6M)$yT"9YhzǨJ[㢩YfːǨuu~P%4Ր=B=@gfc.c$SZ=Lz=D=ψ_!o tѩwl{iӍPW cznvbZkXUQ*Va'LUS b,kqqk[=<)mޤ:j+TRAn#&NpN--,CX{ISZ-eXEJcUZI#T!-qN1ya% i)&d7:[RKR%+te}(b X~SƭVc}pQJཚ/ȭ3rgX4Y&Zm9RN&_PBc Y UQB\B,7PY([EN9,v7wcBzeU$`WI]!լ6Gwj:tZ^")E#lt$VMIEYj8Ђvc:Dcvpݶ*AIYjHs)%"X']G3\QΜ2Q1jwX 8tbO %^qpIk #!SѮ,2Q:8?3ko ;~*nmxˡB9Z֧kƲ -(F7QyԲw:6~f g7VA 9U)y'sܪ2E򥯙argT7]YWVvU_->c#}gU)@:G9J,4!EPEP8*D(|8C+p8ҹYg^J!FS%e򒬭Xʚ,Fp\dE^e9Nh. '9f99* hm^ T 'ڀT*R5#/D:u*ZgXTLᦄR qI] IV)Yଭ缞c}hp"AKԳ^ ;2VK=)x-VJx'%|Solr W$rEậJΙ5mڒV.S^)2ׂE pňUPRZS-!%8-eL:eMbrLVv(KC!edKRZ"Yz |2VU2Q+pJY ItjnDŽa v(nR7`v#i,53⦃dVH;zI@5 MǼ*MI Ӱ:\QL:22z# #ZЍwҒbjDI"lyRyٲ`(ߝhcnzZ i٭a-Ϊͪ?YъI[pԫQd6kGHVS< $:8X0%:Q N.w\Y&Q¤X9jRH(f>E8=O4(;HZ!yM:wp2)-}8Mg/SXJEIyM(<ĂΗe'Cb>TnONoz TRE"jzXo%.H2zm~[ZxC&2pvKbч)ﱒc}Z[ ΖK,5b0:5„ޭG2yoW Pw;jExpcXՄ9_*#Kp^o:9#Խv,2vtz'x*SRdG<ޝشN0бbG(R> n'(^m%DF8SW HP'%)|G9zܹ81C7:\\EĕlW,<#jQo|[r{~iC7!TqjI*gX̀VzZ%N/~Rs\pWp[yˋ'Uu-n<"3GڦӤNv[ԑuѓS| =% ?׃ RWiݥ=IM37IUe#{v>.OZilBJ6oCD[n؎B!꼳l:*؈~Έ4ۼ#qc!BWSVYS* UxʜXYeN,zĥǨ_FǩE;3%=Ltrڍ6=D17+ŏPo(b]\Ӓ'4̅U Fױ֊4gluμTv_>t;.6})ϕy *nh谔%YZ_ )A6پwJ3:wmj3V:ENghE*iV|;2N r_tgҽ)3ﭩk JjR,HSF\[y"1)h֜eNث,qIr5qV]Nᱶ=cRt:s̈́}=W̓wV;`J\fAܼtRIZnSv؞c,rQ7jHo1 J+URȶQ.WwxX9gm]gIzX_F vβ}`ӇhUT:v򎾎BDd2)n\2ʬwLD91roMŽFYosgS a7}}8(QwtZW8f8ue iCwR {Gn-i"IR>cG] 8&8FY^q/:bp\b=kvFNJĴxۥ#8tU% 8.[B a3A)J\)72q$mzcѬk:(J\srwiƄzIqpWNNڜq8ƌ!k8kiit N1ӧ`MO'{Ўj.Z7h/\d6san^原U%DI N52rGmN1wX*U <)]X$|R͎߅8GT:zVLV5yrk ytV5%#۵8mZH\:yvoz/LݻFB+~sle&nj*nl 'w8kg0ɼ-"=\u@$ ^?8cϾ@I6wHЧv*F֖%.Iz&ټ' Ө'vWՈAO?s\g_((sYM,\{= \ŵ]\%M%$6L:&>0{$Ұ W6'b8i=88뭮㪋3Ssi%6}m"knfr|.OU)j|/MπTYg3gf+QR+۠㛯t3l,8EiNWht(^@^{%URN%p9NlEN[vvo%ai>N-ѓMSKw[ߒAc'VtnOLչ*mpqqdJv}A)'NS*WwŖ|-wŠbMOsrco\JR̳>t>,=;Ǚ+Ιruw$,RmE\XN+*ߑ6e''kӚj?\*Se+v*j]OJrJx)/nLXnqir$p9{(wrmx wJy)QwDRIenM&QߨG5Stܢ& :;\>dJqauU;Igrt\FJ9ק$H7.X2#*X)(2R-%tJ㔖|wDɚܪf)9a&UqN6%p$B);{XJJYƝ>sgHHδ]:SNjRmt;d+XVkbNEVk!҄䜠k+fg-64kmykοTM JSwN:BM;)+ӢΉ[T;*HF89 p.v!u,5iZgˁ)8BU͋$Um)Jim%{Y;>] Ԕe9J5kЄ#9nsi;MS5+c)Ԝo+.gkuHlj9a9a21Pz0gvU r^28ɼ(dA7NSxtͩs:8II;=,ma>< n(wSksYlJgDѕ!<ƝqzܒΖNHMX,j8J868friX̎#$8E]XJKky(OCTUj9'xN'ZψI"b;qnrU`juPJ׉CG- ᭀ#ia`W;lXDzNpBJmGb^1<_=&JҶpZz8𣝢%EhbE򊙫~ep%U˩S;ɠRS]oCfiŒqg9gD[l0%s$kt)<-$c6S̍$)iw"Y/щJ:[ u&lm(g| q 0:1J9-Xh|ٜb"|"йvSW8LjM\^vh?)S9JQs)LlѪ%kk:@RGpVJr8ROc,pzKIRZػv%t Utt94p'1h8*A@ࢍhppG 8ECELM- Rb9 C#ބeDtu VеDbQm_YP[ѩJu2yHMRŻ$vT!SȒY֔Ԣ,H)f,& Tatq;#*a9P3ͤj=ɝc8ڝmm$ɠ!/%,흅oң&AMSq9Ҝs ,c)E])ѝ䞆.ER\):ԣ+IYsa2ӂW.W[QpjYѶ9jo]ť:kUΦƒB)I;Rk^ЁRdڞ'UE]c}̇s\m!NQ>3StAN2yKQƊnI3g;A0i&%JW(U-xc:SQ^Zo3:*D(M7avjiҬbyF1"ԄSY9P&FQ]"jtUEx9ƽ7,g]:1:rM @h `8Da-ѲcÔlT^2}f'=-؍$ua7v/PfA<^sܣiRI$U]/0R^ocu (yTஶ5¤vw\LKKe6yM:qG]]ыsqҠd*ve+ݑ'i-J1/KLF1Z-,*S/gi2 rueɠe¥R弤EYE{ZVX]GkE(8',c7hh,W9wlAl8JH)]jKX8J睾;y)Ύ֬E͎S F)͎:6rMY Y8] ]p;DsӔ}1rRjg^v8~|vqN Hry҄Zxj8KhPIHҥSAP>%sg2X5V/]HI|k:<]@p::C EA@࢈*D ( >0ԥڂԴ\am{rZۆ3[LqZeXz9z?2`vˆpr@pz!Ɂ=FP5%kΦvrfmnMʪd7G+>fiQ26u z1Wĝxf[;2'},t+(,hsKotP[Ddխ`'aRGD&sLMӿgZk4jW\Hl:U>e;zN1qqQ{vj!9s{ ]΍TyZ.qsߤǝrw96ݓVHpeKNsXr㬁sj6vͽtN94VtNTjjn=BN< ֩iFs;ak#\$9&g;!=!9 DsCC楚;?,HW0M4fҵeASW8|)90A#0~3q9gkdvCۡp&$gӥ)s")3)2"q G1Q2"D&rcC".dNPȋ91͈fɍvj5LhPLhPLh[!ld-RpRPm)%iAdPd*Q|mNھ-,SM\۸Zp!jDTS C$9$p詒)޽W:m#97 \Ql*tuᜳZ:toWbrnrӌ%|l ⮣L/**ʵ8EZdҟ:"qJ93qy?1_&T)$jC$VpYЊSs utKX*2RtM'1g 8mkAO!ΜjSOsUXcag%Rnʒݭkau|n2r|87v %u鵠L#. du\qn$uimd"R/NGIpbEV%8L"^>nîr"dL.#v@p哥g-w zη8%letւJ ^,*swװ _B9t3soYӔs^f(Zۣ"-W Qخq|%'m {V1;!-Knm×}vpNG:i=ʝŶ3,9:N1G:o1-=u,1To]{ӚIigE%}/sjjJk&mlї㭒`P8-Owg N7iN9gz'Eɒr~v*ƺz>㬒أΦc'HZ0˔pٽpg${[4՘0ZX'XʊEr,#@QhgS]CX,+tGYh| $ԩ8椒= : s9 :t(yBG$΂D.z: sB磇$t瞅@(.z(.zsg fr979 Fg!s@ppn@pmŸC..p1𛃺8!H4KYO󄲇%FRBTwUbʽOqɝ gzL-ee\[JGKqvIf"|H;ƧFS:ąVNM;S9Ҋ=+#Mͺ-w'}Sj<(BM®њh򚩝'{5AYѓI[%] 9I7f$TPAsvN9Jkz^xƛh+V'4rO|qj% 4Wpd{ċqn W}·cc4u}7`ols`'nuO㳆 %šJy%v[YޝѤnu'3$s)]ZX累1&AW+Ȯ埘Pt:78ӈCnkr\{g ;%lF-;׉MmNd7h2ģVo(pq5"PwgJ'*!/!wYY< ^;-UV5GG^'QɶޑItݦߠk7` MuR 9^Ox*F,ZrwB9 v@ZthzDRk@t认,@Ӣ1C9s:Iզl3XRgd[3d̑S fs̐(LfH\Lfl͐N ǀ.k(sXų(1lbYf(rbYYf(pK1lS`8K10B8 10:pQ@P8( tXF[{&&gQF'!*8gR6bD9x:\å!I֓yWt Ƽ %(^.A%?vJR178pMK[S>up\".pԱ[|%8W-+' ]\VY$q\'#VLEb&#Wy&8+|jw$0:CY!>q"4/}VqIٜDA#Ѻrs>c=/gULux -jΧYlbW=i$-$Z9s-TZNgv5Ԏ˴z{N̜)Йu>wԆwԉk9$v+'CžK K$6W%ΎJDN&et''c9/uQ>stream H\͊0y9m҂ŶaXwƱ+1D{w)]XA ?2Tv=,oS֎]UD4UBA&XKCn%DЍCA 5zk!Ds٪ie|N!k},P1=z2*49QrS > /$ݬg@l QH%Gsow;f->z/g>sY4iqf)' 8v0[-1cLja#>}8K=|IIZ{{Tů`\ endstream endobj 251 0 obj <> endobj 252 0 obj <>stream H\n0 yCBh+qhb:@l\u"Q>'_Deu\7= I \;'oƋy\;<.SX-XWYeT߼$cYB4AFKڦMs,-17B G!3Bi|7A r\Ȼ1<.9aNbM)7cMFlǼ#Θ3d{*SFF)1բ3\E*ȧ(b?̌5SM4{A+fEb"߫IW!4YG<^,į endstream endobj 253 0 obj <>stream H|T{TI!l!* f0u*VnApy.,*H $ XAE,O "XP|V{5"uWz~x3ܹ{c quNVE}Tq 1Qps9Z9Xӳ"$1l eNy`Un p<-xgkd-_~([P #vK*>N%OP/WjJHDe*(>N %j,.a? 9^)s+#0 0l&Űǜ0l5Qy/0,xM0o2K8 $Ap𱅫E?yD,N֖[-;,ߋ9"EϺ(o| $5|^H:h0-Љ3@Mri -1:&A/l@sadW;T Z(tFGq O=#AN)6DoRD7bY^!7 2@ 4D$2L& h4O˲ %sHܠ܈R^&cK[n*LZ ۪W3'Eg'Owܗ< U*5ZRݺ\riGS1qEpf= mר׉2ɬ;[- xjp|_lKWtxI2xioӍN]un"*> %ģu?Ž![6J;R]dw]rSD`Mk2 ^\,2Z>{{DreGsDNuēګ̾YF2V{-b=H)g$Jkk10zH&Nx% iHV֫AYs^rJEԹӯ QQW9 vc9y<&LXR.gn@ƫǧљQ鳵`-aar"]ǥ pfwj5yUo!~pM4ր l|CUS} _T2HDh r}fO݋6HR CxV(T5'\a?TAY>C+VaX3@,h:jw()oa/`Q_V֚CIÛ3 Z= 7 bnع Rk{ڹz341yj)hrE5Qw,CR;2POA(WoQ4>[$T Yq~>Ƀ:ؔgxMRI5Li6w:L?O9yDvtܴi*@I@]O[4?S=<|ߛD~D!n endstream endobj 254 0 obj <>stream H\͊0yCښ Bk[`+1D{w)]؀/dfGTҵCo*e:`­ubHۚq052}0I.RDoBhM.j)tF<LR׺a{;N+> endobj 256 0 obj <>stream H\͊0y9bk5R<8v5hdJ6 g&QY*8C4޽A⭷jCۛq 34NE\/ӌCeQ9Df؎W\ͷ{{WY!v-Qƽ6B6UK~^688w"ƌ-N1{Co_ m'vwUsvK$|"Qy&C5YLJ{=s"0K]`29^K1Ks/}>0%h֬YzEg-cmY,3Kߌf3c"|LGI{ZQxa7e~n endstream endobj 257 0 obj <>stream H|TkPWffz B+4MpZ{} qQAF@\PE"*A- 1٨f)cYf=MXMj֭u=w=$!!Ht YS MA7A,%6*$ &P9iClJl$cRFF6l|l2l&Ⱦ'rP+)j+Fi ^0,KSJ jM0I!]aaZWZ2DXvZBM#5 Yc4Ph{ ?>|**{HjWƏ_%`< `a[E]6p+fJ*W IިA?EV3%RS&szrwc/8ePS\G6?~C- b/8qK529"aLIYT:kbgrUyeiE)_CYܒ==ٵC# ]6ߺ)+.M-˙]IvrW2׀b,2\oͭ}(Ϊ ٯ|玷ebo+ס ܝuv|5%M{f{❥l? 1 endstream endobj xref 0 1 0000000000 65535 f 4 1 0000457678 00000 n 41 1 0000457998 00000 n 53 1 0000458108 00000 n 127 1 0000458178 00000 n 134 1 0000458564 00000 n 164 1 0000459006 00000 n 169 1 0000459454 00000 n 178 1 0000459854 00000 n 210 48 0000460298 00000 n 0000460363 00000 n 0000460870 00000 n 0000461179 00000 n 0000461584 00000 n 0000462109 00000 n 0000462526 00000 n 0000462952 00000 n 0000466481 00000 n 0000472403 00000 n 0000478159 00000 n 0000478572 00000 n 0000479469 00000 n 0000479861 00000 n 0000492515 00000 n 0000492629 00000 n 0000492743 00000 n 0000492780 00000 n 0000492876 00000 n 0000492903 00000 n 0000493317 00000 n 0000495968 00000 n 0000496005 00000 n 0000496101 00000 n 0000496128 00000 n 0000496542 00000 n 0000496581 00000 n 0000533507 00000 n 0000533889 00000 n 0000534247 00000 n 0000537162 00000 n 0000537610 00000 n 0000538110 00000 n 0000542086 00000 n 0000542198 00000 n 0000542312 00000 n 0000542349 00000 n 0000545018 00000 n 0000568304 00000 n 0000590849 00000 n 0000590886 00000 n 0000591299 00000 n 0000591658 00000 n 0000592084 00000 n 0000594535 00000 n 0000594958 00000 n 0000595288 00000 n 0000595699 00000 n trailer <<1E176FDB5E6C4E6F93264F099BE4DA4D>]/Prev 453291>> startxref 597803 %%EOF fuse-2.9.9/doc/html/cuse_8c.html0000664000175000017500000007021413407447020013355 00000000000000 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.

fuse-2.9.9/doc/html/passthrough_8c.html0000664000175000017500000012240613407447020014766 00000000000000 libfuse: example/passthrough.c File Reference
libfuse
passthrough.c File Reference
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>

Go to the source code of this file.

Detailed Description

This file system mirrors the existing file system hierarchy of the system, starting at the root file system. This is implemented by just "passing through" all requests to the corresponding user-space libc functions. Its performance is terrible.

Compile with

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

Source code

/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#define FUSE_USE_VERSION 31
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#ifdef linux
/* For pread()/pwrite()/utimensat() */
#define _XOPEN_SOURCE 700
#endif
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
static void *xmp_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
cfg->use_ino = 1;
/* Pick up changes from lower filesystem right away. This is
also necessary for better hardlink support. When the kernel
calls the unlink() handler, it does not know the inode of
the to-be-removed entry and can therefore not invalidate
the cache of the associated inode - resulting in an
incorrect st_nlink value being reported for any remaining
hardlinks to this inode. */
cfg->entry_timeout = 0;
cfg->attr_timeout = 0;
cfg->negative_timeout = 0;
return NULL;
}
static int xmp_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
(void) fi;
int res;
res = lstat(path, stbuf);
if (res == -1)
return -errno;
return 0;
}
static int xmp_access(const char *path, int mask)
{
int res;
res = access(path, mask);
if (res == -1)
return -errno;
return 0;
}
static int xmp_readlink(const char *path, char *buf, size_t size)
{
int res;
res = readlink(path, buf, size - 1);
if (res == -1)
return -errno;
buf[res] = '\0';
return 0;
}
static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
DIR *dp;
struct dirent *de;
(void) offset;
(void) fi;
(void) flags;
dp = opendir(path);
if (dp == NULL)
return -errno;
while ((de = readdir(dp)) != NULL) {
struct stat st;
memset(&st, 0, sizeof(st));
st.st_ino = de->d_ino;
st.st_mode = de->d_type << 12;
if (filler(buf, de->d_name, &st, 0, 0))
break;
}
closedir(dp);
return 0;
}
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;
/* On Linux this could just be 'mknod(path, mode, rdev)' but this
is more portable */
if (S_ISREG(mode)) {
res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0)
res = close(res);
} else if (S_ISFIFO(mode))
res = mkfifo(path, mode);
else
res = mknod(path, mode, rdev);
if (res == -1)
return -errno;
return 0;
}
static int xmp_mkdir(const char *path, mode_t mode)
{
int res;
res = mkdir(path, mode);
if (res == -1)
return -errno;
return 0;
}
static int xmp_unlink(const char *path)
{
int res;
res = unlink(path);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rmdir(const char *path)
{
int res;
res = rmdir(path);
if (res == -1)
return -errno;
return 0;
}
static int xmp_symlink(const char *from, const char *to)
{
int res;
res = symlink(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rename(const char *from, const char *to, unsigned int flags)
{
int res;
if (flags)
return -EINVAL;
res = rename(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_link(const char *from, const char *to)
{
int res;
res = link(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_chmod(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
(void) fi;
int res;
res = chmod(path, mode);
if (res == -1)
return -errno;
return 0;
}
static int xmp_chown(const char *path, uid_t uid, gid_t gid,
struct fuse_file_info *fi)
{
(void) fi;
int res;
res = lchown(path, uid, gid);
if (res == -1)
return -errno;
return 0;
}
static int xmp_truncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int res;
if (fi != NULL)
res = ftruncate(fi->fh, size);
else
res = truncate(path, size);
if (res == -1)
return -errno;
return 0;
}
#ifdef HAVE_UTIMENSAT
static int xmp_utimens(const char *path, const struct timespec ts[2],
struct fuse_file_info *fi)
{
(void) fi;
int res;
/* don't use utime/utimes since they follow symlinks */
res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
if (res == -1)
return -errno;
return 0;
}
#endif
static int xmp_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int res;
res = open(path, fi->flags, mode);
if (res == -1)
return -errno;
fi->fh = res;
return 0;
}
static int xmp_open(const char *path, struct fuse_file_info *fi)
{
int res;
res = open(path, fi->flags);
if (res == -1)
return -errno;
fi->fh = res;
return 0;
}
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
int fd;
int res;
if(fi == NULL)
fd = open(path, O_RDONLY);
else
fd = fi->fh;
if (fd == -1)
return -errno;
res = pread(fd, buf, size, offset);
if (res == -1)
res = -errno;
if(fi == NULL)
close(fd);
return res;
}
static int xmp_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int fd;
int res;
(void) fi;
if(fi == NULL)
fd = open(path, O_WRONLY);
else
fd = fi->fh;
if (fd == -1)
return -errno;
res = pwrite(fd, buf, size, offset);
if (res == -1)
res = -errno;
if(fi == NULL)
close(fd);
return res;
}
static int xmp_statfs(const char *path, struct statvfs *stbuf)
{
int res;
res = statvfs(path, stbuf);
if (res == -1)
return -errno;
return 0;
}
static int xmp_release(const char *path, struct fuse_file_info *fi)
{
(void) path;
close(fi->fh);
return 0;
}
static int xmp_fsync(const char *path, int isdatasync,
struct fuse_file_info *fi)
{
/* Just a stub. This method is optional and can safely be left
unimplemented */
(void) path;
(void) isdatasync;
(void) fi;
return 0;
}
#ifdef HAVE_POSIX_FALLOCATE
static int xmp_fallocate(const char *path, int mode,
off_t offset, off_t length, struct fuse_file_info *fi)
{
int fd;
int res;
(void) fi;
if (mode)
return -EOPNOTSUPP;
if(fi == NULL)
fd = open(path, O_WRONLY);
else
fd = fi->fh;
if (fd == -1)
return -errno;
res = -posix_fallocate(fd, offset, length);
if(fi == NULL)
close(fd);
return res;
}
#endif
#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags)
{
int res = lsetxattr(path, name, value, size, flags);
if (res == -1)
return -errno;
return 0;
}
static int xmp_getxattr(const char *path, const char *name, char *value,
size_t size)
{
int res = lgetxattr(path, name, value, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_listxattr(const char *path, char *list, size_t size)
{
int res = llistxattr(path, list, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_removexattr(const char *path, const char *name)
{
int res = lremovexattr(path, name);
if (res == -1)
return -errno;
return 0;
}
#endif /* HAVE_SETXATTR */
#ifdef HAVE_COPY_FILE_RANGE
static ssize_t xmp_copy_file_range(const char *path_in,
struct fuse_file_info *fi_in,
off_t offset_in, const char *path_out,
struct fuse_file_info *fi_out,
off_t offset_out, size_t len, int flags)
{
int fd_in, fd_out;
ssize_t res;
if(fi_in == NULL)
fd_in = open(path_in, O_RDONLY);
else
fd_in = fi_in->fh;
if (fd_in == -1)
return -errno;
if(fi_out == NULL)
fd_out = open(path_out, O_WRONLY);
else
fd_out = fi_out->fh;
if (fd_out == -1) {
close(fd_in);
return -errno;
}
res = copy_file_range(fd_in, &offset_in, fd_out, &offset_out, len,
flags);
if (res == -1)
res = -errno;
close(fd_in);
close(fd_out);
return res;
}
#endif
static struct fuse_operations xmp_oper = {
.init = xmp_init,
.getattr = xmp_getattr,
.access = xmp_access,
.readlink = xmp_readlink,
.readdir = xmp_readdir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
#ifdef HAVE_UTIMENSAT
.utimens = xmp_utimens,
#endif
.open = xmp_open,
.create = xmp_create,
.read = xmp_read,
.write = xmp_write,
.statfs = xmp_statfs,
.release = xmp_release,
.fsync = xmp_fsync,
#ifdef HAVE_POSIX_FALLOCATE
.fallocate = xmp_fallocate,
#endif
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr = xmp_removexattr,
#endif
#ifdef HAVE_COPY_FILE_RANGE
.copy_file_range = xmp_copy_file_range,
#endif
};
int main(int argc, char *argv[])
{
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
}

Definition in file passthrough.c.

fuse-2.9.9/doc/html/structfuse__operations.html0000664000175000017500000017722513407447020016647 00000000000000 libfuse: fuse_operations Struct Reference
libfuse
fuse_operations Struct Reference

#include <fuse.h>

Data Fields

int(* getattr )(const char *, struct stat *, struct fuse_file_info *fi)
 
int(* readlink )(const char *, char *, size_t)
 
int(* mknod )(const char *, mode_t, dev_t)
 
int(* mkdir )(const char *, mode_t)
 
int(* unlink )(const char *)
 
int(* rmdir )(const char *)
 
int(* symlink )(const char *, const char *)
 
int(* rename )(const char *, const char *, unsigned int flags)
 
int(* link )(const char *, const char *)
 
int(* chmod )(const char *, mode_t, struct fuse_file_info *fi)
 
int(* chown )(const char *, uid_t, gid_t, struct fuse_file_info *fi)
 
int(* truncate )(const char *, off_t, struct fuse_file_info *fi)
 
int(* open )(const char *, struct fuse_file_info *)
 
int(* read )(const char *, char *, size_t, off_t, struct fuse_file_info *)
 
int(* write )(const char *, const char *, size_t, off_t, struct fuse_file_info *)
 
int(* statfs )(const char *, struct statvfs *)
 
int(* flush )(const char *, struct fuse_file_info *)
 
int(* release )(const char *, struct fuse_file_info *)
 
int(* fsync )(const char *, int, struct fuse_file_info *)
 
int(* setxattr )(const char *, const char *, const char *, size_t, int)
 
int(* getxattr )(const char *, const char *, char *, size_t)
 
int(* listxattr )(const char *, char *, size_t)
 
int(* removexattr )(const char *, const char *)
 
int(* opendir )(const char *, struct fuse_file_info *)
 
int(* readdir )(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags)
 
int(* releasedir )(const char *, struct fuse_file_info *)
 
int(* fsyncdir )(const char *, int, struct fuse_file_info *)
 
void *(* init )(struct fuse_conn_info *conn, struct fuse_config *cfg)
 
void(* destroy )(void *private_data)
 
int(* access )(const char *, int)
 
int(* create )(const char *, mode_t, struct fuse_file_info *)
 
int(* lock )(const char *, struct fuse_file_info *, int cmd, struct flock *)
 
int(* utimens )(const char *, const struct timespec tv[2], struct fuse_file_info *fi)
 
int(* bmap )(const char *, size_t blocksize, uint64_t *idx)
 
int(* ioctl )(const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data)
 
int(* poll )(const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp)
 
int(* write_buf )(const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *)
 
int(* read_buf )(const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *)
 
int(* flock )(const char *, struct fuse_file_info *, int op)
 
int(* fallocate )(const char *, int, off_t, off_t, struct fuse_file_info *)
 
ssize_t(* copy_file_range )(const char *path_in, struct fuse_file_info *fi_in, off_t offset_in, const char *path_out, struct fuse_file_info *fi_out, off_t offset_out, size_t size, int flags)
 

Detailed Description

The file system operations:

Most of these should work very similarly to the well known UNIX file system operations. A major exception is that instead of returning an error in 'errno', the operation should return the negated error value (-errno) directly.

All methods are optional, but some are essential for a useful filesystem (e.g. getattr). Open, flush, release, fsync, opendir, releasedir, fsyncdir, access, create, truncate, lock, init and destroy are special purpose methods, without which a full featured filesystem can still be implemented.

In general, all methods are expected to perform any necessary permission checking. However, a filesystem may delegate this task to the kernel by passing the default_permissions mount option to fuse_new(). In this case, methods will only be called if the kernel's permission check has succeeded.

Almost all operations take a path which can be of any length.

Definition at line 299 of file fuse.h.

Field Documentation

◆ access

int(* fuse_operations::access) (const char *, int)

Check file access permissions

This will be called for the access() system call. If the 'default_permissions' mount option is given, this method is not called.

This method is not called under Linux kernel versions 2.4.x

Definition at line 591 of file fuse.h.

◆ bmap

int(* fuse_operations::bmap) (const char *, size_t blocksize, uint64_t *idx)

Map block index within file to block index within device

Note: This makes sense only for block device backed filesystems mounted with the 'blkdev' option

Definition at line 659 of file fuse.h.

◆ chmod

int(* fuse_operations::chmod) (const char *, mode_t, struct fuse_file_info *fi)

Change the permission bits of a file

fi will always be NULL if the file is not currenlty open, but may also be NULL if the file is open.

Definition at line 367 of file fuse.h.

◆ chown

int(* fuse_operations::chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi)

Change the owner and group of a file

fi will always be NULL if the file is not currenlty open, but may also be NULL if the file is open.

Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is expected to reset the setuid and setgid bits.

Definition at line 377 of file fuse.h.

◆ copy_file_range

ssize_t(* fuse_operations::copy_file_range) (const char *path_in, struct fuse_file_info *fi_in, off_t offset_in, const char *path_out, struct fuse_file_info *fi_out, off_t offset_out, size_t size, int flags)

Copy a range of data from one file to another

Performs an optimized copy between two file descriptors without the additional cost of transferring data through the FUSE kernel module to user space (glibc) and then back into the FUSE filesystem again.

In case this method is not implemented, glibc falls back to reading data from the source and writing to the destination. Effectively doing an inefficient copy of the data.

Definition at line 765 of file fuse.h.

◆ create

int(* fuse_operations::create) (const char *, mode_t, struct fuse_file_info *)

Create and open a file

If the file does not exist, first create it with the specified mode, and then open it.

If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the mknod() and open() methods will be called instead.

Definition at line 603 of file fuse.h.

◆ destroy

void(* fuse_operations::destroy) (void *private_data)

Clean up filesystem

Called on filesystem exit.

Definition at line 580 of file fuse.h.

◆ fallocate

int(* fuse_operations::fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *)

Allocates space for an open file

This function ensures that required space is allocated for specified file. If this function returns success then any subsequent write request to specified range is guaranteed not to fail because of lack of space on the file system media.

Definition at line 751 of file fuse.h.

◆ flock

int(* fuse_operations::flock) (const char *, struct fuse_file_info *, int op)

Perform BSD file locking operation

The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN

Nonblocking requests will be indicated by ORing LOCK_NB to the above operations

For more information see the flock(2) manual page.

Additionally fi->owner will be set to a value unique to this open file. This same value will be supplied to ->release() when the file is released.

Note: if this method is not implemented, the kernel will still allow file locking to work locally. Hence it is only interesting for network filesystems and similar.

Definition at line 741 of file fuse.h.

◆ flush

int(* fuse_operations::flush) (const char *, struct fuse_file_info *)

Possibly flush cached data

BIG NOTE: This is not equivalent to fsync(). It's not a request to sync dirty data.

Flush is called on each close() of a file descriptor. So if a filesystem wants to return write errors in close() and the file has cached dirty data, this is a good place to write back data and return any errors. Since many applications ignore close() errors this is not always useful.

NOTE: The flush() method may be called more than once for each open(). This happens if more than one file descriptor refers to an opened file due to dup(), dup2() or fork() calls. It is not possible to determine if a flush is final, so each flush should be treated equally. Multiple write-flush sequences are relatively rare, so this shouldn't be a problem.

Filesystems shouldn't assume that flush will always be called after some writes, or that if will be called at all.

Definition at line 490 of file fuse.h.

◆ fsync

int(* fuse_operations::fsync) (const char *, int, struct fuse_file_info *)

Synchronize file contents

If the datasync parameter is non-zero, then only the user data should be flushed, not the meta data.

Definition at line 511 of file fuse.h.

◆ fsyncdir

int(* fuse_operations::fsyncdir) (const char *, int, struct fuse_file_info *)

Synchronize directory contents

If the datasync parameter is non-zero, then only the user data should be flushed, not the meta data

Definition at line 562 of file fuse.h.

◆ getattr

int(* fuse_operations::getattr) (const char *, struct stat *, struct fuse_file_info *fi)

Get file attributes.

Similar to stat(). The 'st_dev' and 'st_blksize' fields are ignored. The 'st_ino' field is ignored except if the 'use_ino' mount option is given. In that case it is passed to userspace, but libfuse and the kernel will still assign a different inode for internal use (called the "nodeid").

fi will always be NULL if the file is not currently open, but may also be NULL if the file is open.

Definition at line 311 of file fuse.h.

◆ getxattr

int(* fuse_operations::getxattr) (const char *, const char *, char *, size_t)

Get extended attributes

Definition at line 517 of file fuse.h.

◆ init

void*(* fuse_operations::init) (struct fuse_conn_info *conn, struct fuse_config *cfg)

Initialize filesystem

The return value will passed in the private_data field of struct fuse_context to all file operations, and as a parameter to the destroy() method. It overrides the initial value provided to fuse_main() / fuse_new().

Definition at line 572 of file fuse.h.

◆ ioctl

int(* fuse_operations::ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data)

Ioctl

flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in 64bit environment. The size and direction of data is determined by IOC*() decoding of cmd. For _IOC_NONE, data will be NULL, for _IOC_WRITE data is out area, for _IOC_READ in area and if both are set in/out area. In all non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.

If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a directory file handle.

Definition at line 674 of file fuse.h.

◆ link

int(* fuse_operations::link) (const char *, const char *)

Create a hard link to a file

Definition at line 360 of file fuse.h.

◆ listxattr

int(* fuse_operations::listxattr) (const char *, char *, size_t)

List extended attributes

Definition at line 520 of file fuse.h.

◆ lock

int(* fuse_operations::lock) (const char *, struct fuse_file_info *, int cmd, struct flock *)

Perform POSIX file locking operation

The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.

For the meaning of fields in 'struct flock' see the man page for fcntl(2). The l_whence field will always be set to SEEK_SET.

For checking lock ownership, the 'fuse_file_info->owner' argument must be used.

For F_GETLK operation, the library will first check currently held locks, and if a conflicting lock is found it will return information without calling this method. This ensures, that for local locks the l_pid field is correctly filled in. The results may not be accurate in case of race conditions and in the presence of hard links, but it's unlikely that an application would rely on accurate GETLK results in these cases. If a conflicting lock is not found, this method will be called, and the filesystem may fill out l_pid by a meaningful value, or it may leave this field zero.

For F_SETLK and F_SETLKW the l_pid field will be set to the pid of the process performing the locking operation.

Note: if this method is not implemented, the kernel will still allow file locking to work locally. Hence it is only interesting for network filesystems and similar.

Definition at line 635 of file fuse.h.

◆ mkdir

int(* fuse_operations::mkdir) (const char *, mode_t)

Create a directory

Note that the mode argument may not have the type specification bits set, i.e. S_ISDIR(mode) can be false. To obtain the correct directory type bits use mode|S_IFDIR

Definition at line 337 of file fuse.h.

◆ mknod

int(* fuse_operations::mknod) (const char *, mode_t, dev_t)

Create a file node

This is called for creation of all non-directory, non-symlink nodes. If the filesystem defines a create() method, then for regular files that will be called instead.

Definition at line 329 of file fuse.h.

◆ open

int(* fuse_operations::open) (const char *, struct fuse_file_info *)

Open a file

Open flags are available in fi->flags. The following rules apply.

  • Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be filtered out / handled by the kernel.
  • Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used by the filesystem to check if the operation is permitted. If the -o default_permissions mount option is given, this check is already done by the kernel before calling open() and may thus be omitted by the filesystem.
  • When writeback caching is enabled, the kernel may send read requests even for files opened with O_WRONLY. The filesystem should be prepared to handle this.
  • When writeback caching is disabled, the filesystem is expected to properly handle the O_APPEND flag and ensure that each write is appending to the end of the file.
  • When writeback caching is enabled, the kernel will handle O_APPEND. However, unless all changes to the file come through the kernel this will not work reliably. The filesystem should thus either ignore the O_APPEND flag (and let the kernel handle it), or return an error (indicating that reliably O_APPEND is not available).

Filesystem may store an arbitrary file handle (pointer, index, etc) in fi->fh, and use this in other all other file operations (read, write, flush, release, fsync).

Filesystem may also implement stateless file I/O and not store anything in fi->fh.

There are also some flags (direct_io, keep_cache) which the filesystem may set in fi, to change the way the file is opened. See fuse_file_info structure in <fuse_common.h> for more details.

If this request is answered with an error code of ENOSYS and FUSE_CAP_NO_OPEN_SUPPORT is set in fuse_conn_info.capable, this is treated as success and future calls to open will also succeed without being send to the filesystem process.

Definition at line 437 of file fuse.h.

◆ opendir

int(* fuse_operations::opendir) (const char *, struct fuse_file_info *)

Open directory

Unless the 'default_permissions' mount option is given, this method should check if opendir is permitted for this directory. Optionally opendir may also return an arbitrary filehandle in the fuse_file_info structure, which will be passed to readdir, releasedir and fsyncdir.

Definition at line 533 of file fuse.h.

◆ poll

int(* fuse_operations::poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp)

Poll for IO readiness events

Note: If ph is non-NULL, the client should notify when IO readiness events occur by calling fuse_notify_poll() with the specified ph.

Regardless of the number of times poll with a non-NULL ph is received, single notification is enough to clear all. Notifying more times incurs overhead but doesn't harm correctness.

The callee is responsible for destroying ph with fuse_pollhandle_destroy() when no longer in use.

Definition at line 692 of file fuse.h.

◆ read

int(* fuse_operations::read) (const char *, char *, size_t, off_t, struct fuse_file_info *)

Read data from an open file

Read should return exactly the number of bytes requested except on EOF or error, otherwise the rest of the data will be substituted with zeroes. An exception to this is when the 'direct_io' mount option is specified, in which case the return value of the read system call will reflect the return value of this operation.

Definition at line 448 of file fuse.h.

◆ read_buf

int(* fuse_operations::read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *)

Store data from an open file in a buffer

Similar to the read() method, but data is stored and returned in a generic buffer.

No actual copying of data has to take place, the source file descriptor may simply be stored in the buffer for later data transfer.

The buffer must be allocated dynamically and stored at the location pointed to by bufp. If the buffer contains memory regions, they too must be allocated using malloc(). The allocated memory will be freed by the caller.

Definition at line 721 of file fuse.h.

◆ readdir

int(* fuse_operations::readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags)

Read directory

The filesystem may choose between two modes of operation:

1) The readdir implementation ignores the offset parameter, and passes zero to the filler function's offset. The filler function will not return '1' (unless an error happens), so the whole directory is read in a single readdir operation.

2) The readdir implementation keeps track of the offsets of the directory entries. It uses the offset parameter and always passes non-zero offset to the filler function. When the buffer is full (or an error happens) the filler function will return '1'.

Definition at line 550 of file fuse.h.

◆ readlink

int(* fuse_operations::readlink) (const char *, char *, size_t)

Read the target of a symbolic link

The buffer should be filled with a null terminated string. The buffer size argument includes the space for the terminating null character. If the linkname is too long to fit in the buffer, it should be truncated. The return value should be 0 for success.

Definition at line 321 of file fuse.h.

◆ release

int(* fuse_operations::release) (const char *, struct fuse_file_info *)

Release an open file

Release is called when there are no more references to an open file: all file descriptors are closed and all memory mappings are unmapped.

For every open() call there will be exactly one release() call with the same flags and file descriptor. It is possible to have a file opened more than once, in which case only the last release will mean, that no more reads/writes will happen on the file. The return value of release is ignored.

Definition at line 504 of file fuse.h.

◆ releasedir

int(* fuse_operations::releasedir) (const char *, struct fuse_file_info *)

Release directory

Definition at line 555 of file fuse.h.

◆ removexattr

int(* fuse_operations::removexattr) (const char *, const char *)

Remove extended attributes

Definition at line 523 of file fuse.h.

◆ rename

int(* fuse_operations::rename) (const char *, const char *, unsigned int flags)

Rename a file

flags may be RENAME_EXCHANGE or RENAME_NOREPLACE. If RENAME_NOREPLACE is specified, the filesystem must not overwrite newname if it exists and return an error instead. If RENAME_EXCHANGE is specified, the filesystem must atomically exchange the two files, i.e. both must exist and neither may be deleted.

Definition at line 357 of file fuse.h.

◆ rmdir

int(* fuse_operations::rmdir) (const char *)

Remove a directory

Definition at line 343 of file fuse.h.

◆ setxattr

int(* fuse_operations::setxattr) (const char *, const char *, const char *, size_t, int)

Set extended attributes

Definition at line 514 of file fuse.h.

◆ statfs

int(* fuse_operations::statfs) (const char *, struct statvfs *)

Get file system statistics

The 'f_favail', 'f_fsid' and 'f_flag' fields are ignored

Definition at line 467 of file fuse.h.

◆ symlink

int(* fuse_operations::symlink) (const char *, const char *)

Create a symbolic link

Definition at line 346 of file fuse.h.

◆ truncate

int(* fuse_operations::truncate) (const char *, off_t, struct fuse_file_info *fi)

Change the size of a file

fi will always be NULL if the file is not currenlty open, but may also be NULL if the file is open.

Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is expected to reset the setuid and setgid bits.

Definition at line 387 of file fuse.h.

◆ unlink

int(* fuse_operations::unlink) (const char *)

Remove a file

Definition at line 340 of file fuse.h.

◆ utimens

int(* fuse_operations::utimens) (const char *, const struct timespec tv[2], struct fuse_file_info *fi)

Change the access and modification times of a file with nanosecond resolution

This supersedes the old utime() interface. New applications should use this.

fi will always be NULL if the file is not currenlty open, but may also be NULL if the file is open.

See the utimensat(2) man page for details.

Definition at line 650 of file fuse.h.

◆ write

int(* fuse_operations::write) (const char *, const char *, size_t, off_t, struct fuse_file_info *)

Write data to an open file

Write should return exactly the number of bytes requested except on error. An exception to this is when the 'direct_io' mount option is specified (see read operation).

Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is expected to reset the setuid and setgid bits.

Definition at line 460 of file fuse.h.

◆ write_buf

int(* fuse_operations::write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *)

Write contents of buffer to an open file

Similar to the write() method, but data is supplied in a generic buffer. Use fuse_buf_copy() to transfer data to the destination.

Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is expected to reset the setuid and setgid bits.

Definition at line 704 of file fuse.h.


The documentation for this struct was generated from the following file:
fuse-2.9.9/doc/html/null_8c_source.html0000664000175000017500000005365313407447020014760 00000000000000 libfuse: example/null.c Source File
libfuse
null.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 
25 #define FUSE_USE_VERSION 31
26 
27 #include <fuse.h>
28 #include <fuse_lowlevel.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <time.h>
34 #include <errno.h>
35 
36 static int null_getattr(const char *path, struct stat *stbuf,
37  struct fuse_file_info *fi)
38 {
39  (void) fi;
40 
41  if(strcmp(path, "/") != 0)
42  return -ENOENT;
43 
44  stbuf->st_mode = S_IFREG | 0644;
45  stbuf->st_nlink = 1;
46  stbuf->st_uid = getuid();
47  stbuf->st_gid = getgid();
48  stbuf->st_size = (1ULL << 32); /* 4G */
49  stbuf->st_blocks = 0;
50  stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL);
51 
52  return 0;
53 }
54 
55 static int null_truncate(const char *path, off_t size,
56  struct fuse_file_info *fi)
57 {
58  (void) size;
59  (void) fi;
60 
61  if(strcmp(path, "/") != 0)
62  return -ENOENT;
63 
64  return 0;
65 }
66 
67 static int null_open(const char *path, struct fuse_file_info *fi)
68 {
69  (void) fi;
70 
71  if(strcmp(path, "/") != 0)
72  return -ENOENT;
73 
74  return 0;
75 }
76 
77 static int null_read(const char *path, char *buf, size_t size,
78  off_t offset, struct fuse_file_info *fi)
79 {
80  (void) buf;
81  (void) offset;
82  (void) fi;
83 
84  if(strcmp(path, "/") != 0)
85  return -ENOENT;
86 
87  if (offset >= (1ULL << 32))
88  return 0;
89 
90  memset(buf, 0, size);
91  return size;
92 }
93 
94 static int null_write(const char *path, const char *buf, size_t size,
95  off_t offset, struct fuse_file_info *fi)
96 {
97  (void) buf;
98  (void) offset;
99  (void) fi;
100 
101  if(strcmp(path, "/") != 0)
102  return -ENOENT;
103 
104  return size;
105 }
106 
107 static struct fuse_operations null_oper = {
108  .getattr = null_getattr,
109  .truncate = null_truncate,
110  .open = null_open,
111  .read = null_read,
112  .write = null_write,
113 };
114 
115 int main(int argc, char *argv[])
116 {
117  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
118  struct fuse_cmdline_opts opts;
119  struct stat stbuf;
120 
121  if (fuse_parse_cmdline(&args, &opts) != 0)
122  return 1;
123  fuse_opt_free_args(&args);
124 
125  if (!opts.mountpoint) {
126  fprintf(stderr, "missing mountpoint parameter\n");
127  return 1;
128  }
129 
130  if (stat(opts.mountpoint, &stbuf) == -1) {
131  fprintf(stderr ,"failed to access mountpoint %s: %s\n",
132  opts.mountpoint, strerror(errno));
133  free(opts.mountpoint);
134  return 1;
135  }
136  free(opts.mountpoint);
137  if (!S_ISREG(stbuf.st_mode)) {
138  fprintf(stderr, "mountpoint is not a regular file\n");
139  return 1;
140  }
141 
142  return fuse_main(argc, argv, &null_oper, NULL);
143 }
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:33
int(* getattr)(const char *, struct stat *, struct fuse_file_info *fi)
Definition: fuse.h:311
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
#define fuse_main(argc, argv, op, private_data)
Definition: fuse.h:855
fuse-2.9.9/doc/html/structfuse__bufvec.html0000664000175000017500000001532213407447020015723 00000000000000 libfuse: fuse_bufvec Struct Reference
libfuse
fuse_bufvec Struct Reference

#include <fuse_common.h>

Data Fields

size_t count
 
size_t idx
 
size_t off
 
struct fuse_buf buf [1]
 

Detailed Description

Data buffer vector

An array of data buffers, each containing a memory pointer or a file descriptor.

Allocate dynamically to add more than one buffer.

Definition at line 665 of file fuse_common.h.

Field Documentation

◆ buf

struct fuse_buf fuse_bufvec::buf[1]

Array of buffers

Definition at line 684 of file fuse_common.h.

◆ count

size_t fuse_bufvec::count

Number of buffers in the array

Definition at line 669 of file fuse_common.h.

◆ idx

size_t fuse_bufvec::idx

Index of current buffer within the array

Definition at line 674 of file fuse_common.h.

◆ off

size_t fuse_bufvec::off

Current offset within the current buffer

Definition at line 679 of file fuse_common.h.


The documentation for this struct was generated from the following file:
fuse-2.9.9/doc/html/structfuse__loop__config.html0000664000175000017500000001207613407447020017111 00000000000000 libfuse: fuse_loop_config Struct Reference
libfuse
fuse_loop_config Struct Reference

#include <fuse_common.h>

Data Fields

int clone_fd
 
unsigned int max_idle_threads
 

Detailed Description

Configuration parameters passed to fuse_session_loop_mt() and fuse_loop_mt().

Definition at line 86 of file fuse_common.h.

Field Documentation

◆ clone_fd

int fuse_loop_config::clone_fd

whether to use separate device fds for each thread (may increase performance)

Definition at line 91 of file fuse_common.h.

◆ max_idle_threads

unsigned int fuse_loop_config::max_idle_threads

The maximum number of available worker threads before they start to get deleted when they become idle. If not specified, the default is 10.

Adjusting this has performance implications; a very small number of threads in the pool will cause a lot of thread creation and deletion overhead and performance may suffer. When set to 0, a new thread will be created to service every operation.

Definition at line 103 of file fuse_common.h.


The documentation for this struct was generated from the following file:
fuse-2.9.9/doc/html/doc.png0000664000175000017500000000135213407447020012406 00000000000000PNG  IHDR}\IDATxMOS[sa?-XZ(PD4 AWbu`b 77wHFCԁ/`voAPqP@ 980 +y^Z9SW\83g3'Nçl_bpV"ֆXd]3xM[1W *PGz/Eg{ aoV:这1$RW,@56-,m/蹖 r5T*S(Vf89u գwa=<{ҡUr+dDF$`zNܮ0Q3~_^N=vpTLT}kqm<?ZhX_ݥ[) `ga_*2`'=F2EP l=8Wv%THqɿ<"GxH{#֫aJmKsVءM^ T ݛr߽m_?Wİ#uIENDB`fuse-2.9.9/doc/html/structfuse__opt.html0000664000175000017500000001653513407447020015262 00000000000000 libfuse: fuse_opt Struct Reference
libfuse
fuse_opt Struct Reference

#include <fuse_opt.h>

Data Fields

const char * templ
 
unsigned long offset
 
int value
 

Detailed Description

Option description

This structure describes a single option, and action associated with it, in case it matches.

More than one such match may occur, in which case the action for each match is executed.

There are three possible actions in case of a match:

i) An integer (int or unsigned) variable determined by 'offset' is set to 'value'

ii) The processing function is called, with 'value' as the key

iii) An integer (any) or string (char *) variable determined by 'offset' is set to the value of an option parameter

'offset' should normally be either set to

  • 'offsetof(struct foo, member)' actions i) and iii)
  • -1 action ii)

The 'offsetof()' macro is defined in the <stddef.h> header.

The template determines which options match, and also have an effect on the action. Normally the action is either i) or ii), but if a format is present in the template, then action iii) is performed.

The types of templates are:

1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only themselves. Invalid values are "--" and anything beginning with "-o"

2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or the relevant option in a comma separated option list

3) "bar=", "--foo=", etc. These are variations of 1) and 2) which have a parameter

4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform action iii).

5) "-x ", etc. Matches either "-xparam" or "-x param" as two separate arguments

6) "-x %s", etc. Combination of 4) and 5)

If the format is "%s", memory is allocated for the string unlike with scanf(). The previous value (if non-NULL) stored at the this location is freed.

Definition at line 77 of file fuse_opt.h.

Field Documentation

◆ offset

unsigned long fuse_opt::offset

Offset of variable within 'data' parameter of fuse_opt_parse() or -1

Definition at line 85 of file fuse_opt.h.

◆ templ

const char* fuse_opt::templ

Matching template and optional parameter formatting

Definition at line 79 of file fuse_opt.h.

◆ value

int fuse_opt::value

Value to set the variable to, or to be passed as 'key' to the processing function. Ignored if template has a format

Definition at line 91 of file fuse_opt.h.


The documentation for this struct was generated from the following file:
fuse-2.9.9/doc/html/invalidate__path_8c.html0000664000175000017500000000645613407447020015720 00000000000000 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.

fuse-2.9.9/doc/html/fuse_8h_source.html0000664000175000017500000030136413407447020014750 00000000000000 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
fuse-2.9.9/doc/html/structfuse__buf.html0000664000175000017500000001735013407447020015230 00000000000000 libfuse: fuse_buf Struct Reference
libfuse
fuse_buf Struct Reference

#include <fuse_common.h>

Data Fields

size_t size
 
enum fuse_buf_flags flags
 
void * mem
 
int fd
 
off_t pos
 

Detailed Description

Single data buffer

Generic data buffer for I/O, extended attributes, etc... Data may be supplied as a memory pointer or as a file descriptor

Definition at line 624 of file fuse_common.h.

Field Documentation

◆ fd

int fuse_buf::fd

File descriptor

Used if FUSE_BUF_IS_FD flag is set.

Definition at line 647 of file fuse_common.h.

◆ flags

enum fuse_buf_flags fuse_buf::flags

Buffer flags

Definition at line 633 of file fuse_common.h.

◆ mem

void* fuse_buf::mem

Memory pointer

Used unless FUSE_BUF_IS_FD flag is set.

Definition at line 640 of file fuse_common.h.

◆ pos

off_t fuse_buf::pos

File position

Used if FUSE_BUF_FD_SEEK flag is set.

Definition at line 654 of file fuse_common.h.

◆ size

size_t fuse_buf::size

Size of data in bytes

Definition at line 628 of file fuse_common.h.


The documentation for this struct was generated from the following file:
fuse-2.9.9/doc/html/structfuse__args.html0000664000175000017500000001263013407447020015404 00000000000000 libfuse: fuse_args Struct Reference
libfuse
fuse_args Struct Reference

#include <fuse_opt.h>

Data Fields

int argc
 
char ** argv
 
int allocated
 

Detailed Description

Argument list

Definition at line 109 of file fuse_opt.h.

Field Documentation

◆ allocated

int fuse_args::allocated

Is 'argv' allocated?

Definition at line 117 of file fuse_opt.h.

◆ argc

int fuse_args::argc

Argument count

Definition at line 111 of file fuse_opt.h.

◆ argv

char** fuse_args::argv

Argument vector. NULL terminated

Definition at line 114 of file fuse_opt.h.


The documentation for this struct was generated from the following file:
fuse-2.9.9/doc/html/fuse_8c_source.html0000664000175000017500000277767113407447020014767 00000000000000 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
fuse-2.9.9/doc/html/bc_s.png0000664000175000017500000000124413407447020012547 00000000000000PNG  IHDR_ kIDATxkQϝ̤I&m&156*nąܸR,4 +H(Ub1J.(EmߏhJmKS'C(х & r3g(z&_9}՟@mu ` h`ԯ &~M4%3?h)\Yi>Jb @giވkg\轭EUv+?E"pB\Y&$vM+Dn)}:Xo 3گ'.f0u9Ljf6%3Gf#sm(,k*ʒJJˢou_~ r]%%mnu]zr5[ưXeI libfuse: Globals
libfuse
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:

- f -

fuse-2.9.9/doc/html/globals_type.html0000664000175000017500000000446413407447020014514 00000000000000 libfuse: Globals
libfuse
 
fuse-2.9.9/doc/html/ioctl__client_8c_source.html0000664000175000017500000002351013407447020016602 00000000000000 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 }
fuse-2.9.9/doc/html/dir_93598ca166e67dcc8cf3dfff647b911b.html0000664000175000017500000000401113407447020017422 00000000000000 libfuse: build/meson-private Directory Reference
libfuse
meson-private Directory Reference
fuse-2.9.9/doc/html/ioctl__client_8c.html0000664000175000017500000001641013407447020015223 00000000000000 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.

fuse-2.9.9/doc/html/structfuse__context.html0000664000175000017500000002052513407447020016136 00000000000000 libfuse: fuse_context Struct Reference
libfuse
fuse_context Struct Reference

#include <fuse.h>

Data Fields

struct fuse * fuse
 
uid_t uid
 
gid_t gid
 
pid_t pid
 
void * private_data
 
mode_t umask
 

Detailed Description

Extra context that may be needed by some filesystems

The uid, gid and pid fields are not filled in case of a writepage operation.

Definition at line 777 of file fuse.h.

Field Documentation

◆ fuse

struct fuse* fuse_context::fuse

Pointer to the fuse object

Definition at line 779 of file fuse.h.

◆ gid

gid_t fuse_context::gid

Group ID of the calling process

Definition at line 785 of file fuse.h.

◆ pid

pid_t fuse_context::pid

Thread ID of the calling process

Definition at line 788 of file fuse.h.

◆ private_data

void* fuse_context::private_data

Private filesystem data

Definition at line 791 of file fuse.h.

◆ uid

uid_t fuse_context::uid

User ID of the calling process

Definition at line 782 of file fuse.h.

◆ umask

mode_t fuse_context::umask

Umask of the calling process

Definition at line 794 of file fuse.h.


The documentation for this struct was generated from the following file:
fuse-2.9.9/doc/html/notify__inval__inode_8c.html0000664000175000017500000007507713407447020016607 00000000000000 libfuse: example/notify_inval_inode.c File Reference
libfuse
notify_inval_inode.c File Reference
#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 a single file whose contents change dynamically: it always contains the current time.

While notify_store_retrieve.c uses fuse_lowlevel_notify_store() to actively push the updated data into the kernel cache, this example uses fuse_lowlevel_notify_inval_inode() to notify the kernel that the cache has to be invalidated - but the kernel still has to explicitly request the updated data on the next read.

To see the effect, first start the file system with the --no-notify option:

$ notify_inval_inode –update-interval=1 –no-notify mnt/

Observe that the output never changes, even though the file system updates it once per second. This is because the contents are cached in the kernel:

$ for i in 1 2 3 4 5; do
>     cat mnt/current_time
>     sleep 1
> done
The current time is 15:58:18
The current time is 15:58:18
The current time is 15:58:18
The current time is 15:58:18
The current time is 15:58:18

If you instead enable the notification functions, the changes become visible:

 $ notify_inval_inode --update-interval=1 mnt/
 $ for i in 1 2 3 4 5; do
 >     cat mnt/current_time
 >     sleep 1
 > done
 The current time is 15:58:40
 The current time is 15:58:41
 The current time is 15:58:42
 The current time is 15:58:43
 The current time is 15:58:44

Compilation

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

Source code

/*
FUSE: Filesystem in Userspace
Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
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 <assert.h>
#include <stddef.h>
#include <unistd.h>
#include <pthread.h>
/* We can't actually tell the kernel that there is no
timeout, so we just send a big value */
#define NO_TIMEOUT 500000
/* We cannot check directly if e.g. O_RDONLY is set, since this is not
* an individual bit (cf. open(2)) */
#define ACCESS_MASK (O_RDONLY | O_WRONLY | O_RDWR)
#define MAX_STR_LEN 128
#define FILE_INO 2
#define FILE_NAME "current_time"
static char file_contents[MAX_STR_LEN];
static int lookup_cnt = 0;
static size_t file_size;
/* Command line parsing */
struct options {
int no_notify;
int update_interval;
};
static struct options options = {
.no_notify = 0,
.update_interval = 1,
};
#define OPTION(t, p) \
{ t, offsetof(struct options, p), 1 }
static const struct fuse_opt option_spec[] = {
OPTION("--no-notify", no_notify),
OPTION("--update-interval=%d", update_interval),
};
static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
stbuf->st_ino = ino;
if (ino == FUSE_ROOT_ID) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 1;
}
else if (ino == FILE_INO) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = file_size;
}
else
return -1;
return 0;
}
static void tfs_lookup(fuse_req_t req, fuse_ino_t parent,
const char *name) {
struct fuse_entry_param e;
memset(&e, 0, sizeof(e));
if (parent != FUSE_ROOT_ID)
goto err_out;
else if (strcmp(name, FILE_NAME) == 0) {
e.ino = FILE_INO;
lookup_cnt++;
} else
goto err_out;
e.attr_timeout = NO_TIMEOUT;
e.entry_timeout = NO_TIMEOUT;
if (tfs_stat(e.ino, &e.attr) != 0)
goto err_out;
fuse_reply_entry(req, &e);
return;
err_out:
fuse_reply_err(req, ENOENT);
}
static void tfs_forget (fuse_req_t req, fuse_ino_t ino,
uint64_t nlookup) {
(void) req;
if(ino == FILE_INO)
lookup_cnt -= nlookup;
else
assert(ino == FUSE_ROOT_ID);
}
static void tfs_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 (tfs_stat(ino, &stbuf) != 0)
fuse_reply_err(req, ENOENT);
else
fuse_reply_attr(req, &stbuf, NO_TIMEOUT);
}
struct dirbuf {
char *p;
size_t size;
};
static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
fuse_ino_t ino) {
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 tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi) {
(void) fi;
if (ino != FUSE_ROOT_ID)
fuse_reply_err(req, ENOTDIR);
else {
struct dirbuf b;
memset(&b, 0, sizeof(b));
dirbuf_add(req, &b, FILE_NAME, FILE_INO);
reply_buf_limited(req, b.p, b.size, off, size);
free(b.p);
}
}
static void tfs_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) {
/* Make cache persistent even if file is closed,
this makes it easier to see the effects */
fi->keep_cache = 1;
if (ino == FUSE_ROOT_ID)
fuse_reply_err(req, EISDIR);
else if ((fi->flags & ACCESS_MASK) != O_RDONLY)
fuse_reply_err(req, EACCES);
else if (ino == FILE_INO)
fuse_reply_open(req, fi);
else {
// This should not happen
fprintf(stderr, "Got open for non-existing inode!\n");
fuse_reply_err(req, ENOENT);
}
}
static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi) {
(void) fi;
assert(ino == FILE_INO);
reply_buf_limited(req, file_contents, file_size, off, size);
}
static struct fuse_lowlevel_ops tfs_oper = {
.lookup = tfs_lookup,
.getattr = tfs_getattr,
.readdir = tfs_readdir,
.open = tfs_open,
.read = tfs_read,
.forget = tfs_forget,
};
static void update_fs(void) {
struct tm *now;
time_t t;
t = time(NULL);
now = localtime(&t);
assert(now != NULL);
file_size = strftime(file_contents, MAX_STR_LEN,
"The current time is %H:%M:%S\n", now);
assert(file_size != 0);
}
static void* update_fs_loop(void *data) {
struct fuse_session *se = (struct fuse_session*) data;
while(1) {
update_fs();
if (!options.no_notify && lookup_cnt) {
/* Only send notification if the kernel
is aware of the inode */
(se, FILE_INO, 0, 0) == 0);
}
sleep(options.update_interval);
}
return NULL;
}
static void show_help(const char *progname)
{
printf("usage: %s [options] <mountpoint>\n\n", progname);
printf("File-system specific options:\n"
" --update-interval=<secs> Update-rate of file system contents\n"
" --no-notify Disable kernel notifications\n"
"\n");
}
int main(int argc, char *argv[]) {
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_session *se;
struct fuse_cmdline_opts opts;
pthread_t updater;
int ret = -1;
if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
return 1;
if (fuse_parse_cmdline(&args, &opts) != 0) {
ret = 1;
goto err_out1;
}
if (opts.show_help) {
show_help(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;
}
/* Initial contents */
update_fs();
se = fuse_session_new(&args, &tfs_oper,
sizeof(tfs_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);
/* Start thread to update file contents */
ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se);
if (ret != 0) {
fprintf(stderr, "pthread_create failed with %s\n",
strerror(ret));
goto err_out3;
}
/* 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 notify_inval_inode.c.

fuse-2.9.9/doc/html/closed.png0000664000175000017500000000020413407447020013105 00000000000000PNG  IHDR KIDATxm @!Gk7-`&sts@k}2 P%_N .:0Dk›x" ֛)x5IENDB`fuse-2.9.9/doc/html/test__setattr_8c_source.html0000664000175000017500000011005513407447020016660 00000000000000 libfuse: test/test_setattr.c Source File
libfuse
test_setattr.c
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
4 
5  This program can be distributed under the terms of the GNU GPL.
6  See the file COPYING.
7 */
8 
9 
10 #define FUSE_USE_VERSION 30
11 
12 #include <config.h>
13 #include <fuse_lowlevel.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <assert.h>
20 #include <stddef.h>
21 #include <unistd.h>
22 #include <pthread.h>
23 
24 #ifndef __linux__
25 #include <limits.h>
26 #else
27 #include <linux/limits.h>
28 #endif
29 
30 #define FILE_INO 2
31 #define FILE_NAME "truncate_me"
32 
33 static int got_fh;
34 static mode_t file_mode = S_IFREG | 0644;
35 
36 static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
37  stbuf->st_ino = ino;
38  if (ino == FUSE_ROOT_ID) {
39  stbuf->st_mode = S_IFDIR | 0755;
40  stbuf->st_nlink = 1;
41  }
42 
43  else if (ino == FILE_INO) {
44  stbuf->st_mode = file_mode;
45  stbuf->st_nlink = 1;
46  stbuf->st_size = 0;
47  }
48 
49  else
50  return -1;
51 
52  return 0;
53 }
54 
55 static void tfs_lookup(fuse_req_t req, fuse_ino_t parent,
56  const char *name) {
57  struct fuse_entry_param e;
58  memset(&e, 0, sizeof(e));
59 
60  if (parent != FUSE_ROOT_ID)
61  goto err_out;
62  else if (strcmp(name, FILE_NAME) == 0)
63  e.ino = FILE_INO;
64  else
65  goto err_out;
66 
67  if (tfs_stat(e.ino, &e.attr) != 0)
68  goto err_out;
69  fuse_reply_entry(req, &e);
70  return;
71 
72 err_out:
73  fuse_reply_err(req, ENOENT);
74 }
75 
76 static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
77  struct fuse_file_info *fi) {
78  struct stat stbuf;
79 
80  (void) fi;
81 
82  memset(&stbuf, 0, sizeof(stbuf));
83  if (tfs_stat(ino, &stbuf) != 0)
84  fuse_reply_err(req, ENOENT);
85  else
86  fuse_reply_attr(req, &stbuf, 5);
87 }
88 
89 static void tfs_open(fuse_req_t req, fuse_ino_t ino,
90  struct fuse_file_info *fi) {
91  if (ino == FUSE_ROOT_ID)
92  fuse_reply_err(req, EISDIR);
93  else {
94  assert(ino == FILE_INO);
95  fi->fh = FILE_INO;
96  fuse_reply_open(req, fi);
97  }
98 }
99 
100 static void tfs_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
101  int to_set, struct fuse_file_info *fi) {
102  if(ino != FILE_INO ||
103  !(to_set & FUSE_SET_ATTR_MODE)) {
104  fuse_reply_err(req, EINVAL);
105  return;
106  }
107 
108  if(fi == NULL)
109  fprintf(stderr, "setattr with fi == NULL\n");
110  else if (fi->fh != FILE_INO)
111  fprintf(stderr, "setattr with wrong fi->fh\n");
112  else {
113  fprintf(stderr, "setattr ok\n");
114  got_fh = 1;
115  file_mode = attr->st_mode;
116  }
117 
118  tfs_getattr(req, ino, fi);
119 }
120 
121 static struct fuse_lowlevel_ops tfs_oper = {
122  .lookup = tfs_lookup,
123  .getattr = tfs_getattr,
124  .open = tfs_open,
125  .setattr = tfs_setattr,
126 };
127 
128 static void* run_fs(void *data) {
129  struct fuse_session *se = (struct fuse_session*) data;
130  assert(fuse_session_loop(se) == 0);
131  return NULL;
132 }
133 
134 static void test_fs(char *mountpoint) {
135  char fname[PATH_MAX];
136  int fd;
137 
138  assert(snprintf(fname, PATH_MAX, "%s/" FILE_NAME,
139  mountpoint) > 0);
140  fd = open(fname, O_WRONLY);
141  if (fd == -1) {
142  perror(fname);
143  assert(0);
144  }
145 
146  assert(fchmod(fd, 0600) == 0);
147  close(fd);
148 }
149 
150 int main(int argc, char *argv[]) {
151  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
152  struct fuse_session *se;
153  struct fuse_cmdline_opts fuse_opts;
154  pthread_t fs_thread;
155 
156  assert(fuse_parse_cmdline(&args, &fuse_opts) == 0);
157 #ifndef __FreeBSD__
158  assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0);
159 #endif
160  se = fuse_session_new(&args, &tfs_oper,
161  sizeof(tfs_oper), NULL);
162  assert (se != NULL);
163  assert(fuse_set_signal_handlers(se) == 0);
164  assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0);
165 
166  /* Start file-system thread */
167  assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0);
168 
169  /* Do test */
170  test_fs(fuse_opts.mountpoint);
171 
172  /* Stop file system */
173  assert(pthread_cancel(fs_thread) == 0);
174 
176  assert(got_fh == 1);
179 
180  printf("Test completed successfully.\n");
181  return 0;
182 }
183 
184 
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)
uint64_t fh
Definition: fuse_common.h:72
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
Definition: fuse_lowlevel.h:59
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
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
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:54
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)
#define FUSE_ROOT_ID
Definition: fuse_lowlevel.h:43
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
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
fuse-2.9.9/doc/html/passthrough__fh_8c.html0000664000175000017500000015515213407447020015606 00000000000000 libfuse: example/passthrough_fh.c File Reference
libfuse
passthrough_fh.c File Reference
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/file.h>

Go to the source code of this file.

Detailed Description

This file system mirrors the existing file system hierarchy of the system, starting at the root file system. This is implemented by just "passing through" all requests to the corresponding user-space libc functions. This implementation is a little more sophisticated than the one in passthrough.c, so performance is not quite as bad.

Compile with:

gcc -Wall passthrough_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr -o passthrough_fh

Source code

/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#define FUSE_USE_VERSION 31
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <fuse.h>
#ifdef HAVE_LIBULOCKMGR
#include <ulockmgr.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
#include <sys/file.h> /* flock(2) */
static void *xmp_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
cfg->use_ino = 1;
cfg->nullpath_ok = 1;
/* Pick up changes from lower filesystem right away. This is
also necessary for better hardlink support. When the kernel
calls the unlink() handler, it does not know the inode of
the to-be-removed entry and can therefore not invalidate
the cache of the associated inode - resulting in an
incorrect st_nlink value being reported for any remaining
hardlinks to this inode. */
cfg->entry_timeout = 0;
cfg->attr_timeout = 0;
cfg->negative_timeout = 0;
return NULL;
}
static int xmp_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
int res;
(void) path;
if(fi)
res = fstat(fi->fh, stbuf);
else
res = lstat(path, stbuf);
if (res == -1)
return -errno;
return 0;
}
static int xmp_access(const char *path, int mask)
{
int res;
res = access(path, mask);
if (res == -1)
return -errno;
return 0;
}
static int xmp_readlink(const char *path, char *buf, size_t size)
{
int res;
res = readlink(path, buf, size - 1);
if (res == -1)
return -errno;
buf[res] = '\0';
return 0;
}
struct xmp_dirp {
DIR *dp;
struct dirent *entry;
off_t offset;
};
static int xmp_opendir(const char *path, struct fuse_file_info *fi)
{
int res;
struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
if (d == NULL)
return -ENOMEM;
d->dp = opendir(path);
if (d->dp == NULL) {
res = -errno;
free(d);
return res;
}
d->offset = 0;
d->entry = NULL;
fi->fh = (unsigned long) d;
return 0;
}
static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi)
{
return (struct xmp_dirp *) (uintptr_t) fi->fh;
}
static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
struct xmp_dirp *d = get_dirp(fi);
(void) path;
if (offset != d->offset) {
#ifndef __FreeBSD__
seekdir(d->dp, offset);
#else
/* Subtract the one that we add when calling
telldir() below */
seekdir(d->dp, offset-1);
#endif
d->entry = NULL;
d->offset = offset;
}
while (1) {
struct stat st;
off_t nextoff;
enum fuse_fill_dir_flags fill_flags = 0;
if (!d->entry) {
d->entry = readdir(d->dp);
if (!d->entry)
break;
}
#ifdef HAVE_FSTATAT
if (flags & FUSE_READDIR_PLUS) {
int res;
res = fstatat(dirfd(d->dp), d->entry->d_name, &st,
AT_SYMLINK_NOFOLLOW);
if (res != -1)
fill_flags |= FUSE_FILL_DIR_PLUS;
}
#endif
if (!(fill_flags & FUSE_FILL_DIR_PLUS)) {
memset(&st, 0, sizeof(st));
st.st_ino = d->entry->d_ino;
st.st_mode = d->entry->d_type << 12;
}
nextoff = telldir(d->dp);
#ifdef __FreeBSD__
/* Under FreeBSD, telldir() may return 0 the first time
it is called. But for libfuse, an offset of zero
means that offsets are not supported, so we shift
everything by one. */
nextoff++;
#endif
if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags))
break;
d->entry = NULL;
d->offset = nextoff;
}
return 0;
}
static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
{
struct xmp_dirp *d = get_dirp(fi);
(void) path;
closedir(d->dp);
free(d);
return 0;
}
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;
if (S_ISFIFO(mode))
res = mkfifo(path, mode);
else
res = mknod(path, mode, rdev);
if (res == -1)
return -errno;
return 0;
}
static int xmp_mkdir(const char *path, mode_t mode)
{
int res;
res = mkdir(path, mode);
if (res == -1)
return -errno;
return 0;
}
static int xmp_unlink(const char *path)
{
int res;
res = unlink(path);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rmdir(const char *path)
{
int res;
res = rmdir(path);
if (res == -1)
return -errno;
return 0;
}
static int xmp_symlink(const char *from, const char *to)
{
int res;
res = symlink(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rename(const char *from, const char *to, unsigned int flags)
{
int res;
/* When we have renameat2() in libc, then we can implement flags */
if (flags)
return -EINVAL;
res = rename(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_link(const char *from, const char *to)
{
int res;
res = link(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_chmod(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int res;
if(fi)
res = fchmod(fi->fh, mode);
else
res = chmod(path, mode);
if (res == -1)
return -errno;
return 0;
}
static int xmp_chown(const char *path, uid_t uid, gid_t gid,
struct fuse_file_info *fi)
{
int res;
if (fi)
res = fchown(fi->fh, uid, gid);
else
res = lchown(path, uid, gid);
if (res == -1)
return -errno;
return 0;
}
static int xmp_truncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int res;
if(fi)
res = ftruncate(fi->fh, size);
else
res = truncate(path, size);
if (res == -1)
return -errno;
return 0;
}
#ifdef HAVE_UTIMENSAT
static int xmp_utimens(const char *path, const struct timespec ts[2],
struct fuse_file_info *fi)
{
int res;
/* don't use utime/utimes since they follow symlinks */
if (fi)
res = futimens(fi->fh, ts);
else
res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
if (res == -1)
return -errno;
return 0;
}
#endif
static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
{
int fd;
fd = open(path, fi->flags, mode);
if (fd == -1)
return -errno;
fi->fh = fd;
return 0;
}
static int xmp_open(const char *path, struct fuse_file_info *fi)
{
int fd;
fd = open(path, fi->flags);
if (fd == -1)
return -errno;
fi->fh = fd;
return 0;
}
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
int res;
(void) path;
res = pread(fi->fh, buf, size, offset);
if (res == -1)
res = -errno;
return res;
}
static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp,
size_t size, off_t offset, struct fuse_file_info *fi)
{
struct fuse_bufvec *src;
(void) path;
src = malloc(sizeof(struct fuse_bufvec));
if (src == NULL)
return -ENOMEM;
*src = FUSE_BUFVEC_INIT(size);
src->buf[0].fd = fi->fh;
src->buf[0].pos = offset;
*bufp = src;
return 0;
}
static int xmp_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int res;
(void) path;
res = pwrite(fi->fh, buf, size, offset);
if (res == -1)
res = -errno;
return res;
}
static int xmp_write_buf(const char *path, struct fuse_bufvec *buf,
off_t offset, struct fuse_file_info *fi)
{
struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf));
(void) path;
dst.buf[0].fd = fi->fh;
dst.buf[0].pos = offset;
}
static int xmp_statfs(const char *path, struct statvfs *stbuf)
{
int res;
res = statvfs(path, stbuf);
if (res == -1)
return -errno;
return 0;
}
static int xmp_flush(const char *path, struct fuse_file_info *fi)
{
int res;
(void) path;
/* This is called from every close on an open file, so call the
close on the underlying filesystem. But since flush may be
called multiple times for an open file, this must not really
close the file. This is important if used on a network
filesystem like NFS which flush the data/metadata on close() */
res = close(dup(fi->fh));
if (res == -1)
return -errno;
return 0;
}
static int xmp_release(const char *path, struct fuse_file_info *fi)
{
(void) path;
close(fi->fh);
return 0;
}
static int xmp_fsync(const char *path, int isdatasync,
struct fuse_file_info *fi)
{
int res;
(void) path;
#ifndef HAVE_FDATASYNC
(void) isdatasync;
#else
if (isdatasync)
res = fdatasync(fi->fh);
else
#endif
res = fsync(fi->fh);
if (res == -1)
return -errno;
return 0;
}
#ifdef HAVE_POSIX_FALLOCATE
static int xmp_fallocate(const char *path, int mode,
off_t offset, off_t length, struct fuse_file_info *fi)
{
(void) path;
if (mode)
return -EOPNOTSUPP;
return -posix_fallocate(fi->fh, offset, length);
}
#endif
#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags)
{
int res = lsetxattr(path, name, value, size, flags);
if (res == -1)
return -errno;
return 0;
}
static int xmp_getxattr(const char *path, const char *name, char *value,
size_t size)
{
int res = lgetxattr(path, name, value, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_listxattr(const char *path, char *list, size_t size)
{
int res = llistxattr(path, list, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_removexattr(const char *path, const char *name)
{
int res = lremovexattr(path, name);
if (res == -1)
return -errno;
return 0;
}
#endif /* HAVE_SETXATTR */
#ifdef HAVE_LIBULOCKMGR
static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
struct flock *lock)
{
(void) path;
return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
sizeof(fi->lock_owner));
}
#endif
static int xmp_flock(const char *path, struct fuse_file_info *fi, int op)
{
int res;
(void) path;
res = flock(fi->fh, op);
if (res == -1)
return -errno;
return 0;
}
#ifdef HAVE_COPY_FILE_RANGE
static ssize_t xmp_copy_file_range(const char *path_in,
struct fuse_file_info *fi_in,
off_t off_in, const char *path_out,
struct fuse_file_info *fi_out,
off_t off_out, size_t len, int flags)
{
ssize_t res;
(void) path_in;
(void) path_out;
res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
flags);
if (res == -1)
return -errno;
return res;
}
#endif
static struct fuse_operations xmp_oper = {
.init = xmp_init,
.getattr = xmp_getattr,
.access = xmp_access,
.readlink = xmp_readlink,
.opendir = xmp_opendir,
.readdir = xmp_readdir,
.releasedir = xmp_releasedir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
#ifdef HAVE_UTIMENSAT
.utimens = xmp_utimens,
#endif
.create = xmp_create,
.open = xmp_open,
.read = xmp_read,
.read_buf = xmp_read_buf,
.write = xmp_write,
.write_buf = xmp_write_buf,
.statfs = xmp_statfs,
.flush = xmp_flush,
.release = xmp_release,
.fsync = xmp_fsync,
#ifdef HAVE_POSIX_FALLOCATE
.fallocate = xmp_fallocate,
#endif
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr = xmp_removexattr,
#endif
#ifdef HAVE_LIBULOCKMGR
.lock = xmp_lock,
#endif
.flock = xmp_flock,
#ifdef HAVE_COPY_FILE_RANGE
.copy_file_range = xmp_copy_file_range,
#endif
};
int main(int argc, char *argv[])
{
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
}

Definition in file passthrough_fh.c.

fuse-2.9.9/doc/html/mount__util_8h_source.html0000664000175000017500000001254513407447020016344 00000000000000 libfuse: lib/mount_util.h Source File
libfuse
mount_util.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 <sys/types.h>
10 
11 int fuse_mnt_add_mount(const char *progname, const char *fsname,
12  const char *mnt, const char *type, const char *opts);
13 int fuse_mnt_remove_mount(const char *progname, const char *mnt);
14 int fuse_mnt_umount(const char *progname, const char *abs_mnt,
15  const char *rel_mnt, int lazy);
16 char *fuse_mnt_resolve_path(const char *progname, const char *orig);
17 int fuse_mnt_check_fuseblk(void);
18 int fuse_mnt_parse_fuse_fd(const char *mountpoint);
fuse-2.9.9/doc/html/mount__util_8c_source.html0000664000175000017500000015004713407447020016337 00000000000000 libfuse: lib/mount_util.c Source File
libfuse
mount_util.c
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Architecture-independent mounting code.
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 "mount_util.h"
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <signal.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <paths.h>
23 #if !defined( __NetBSD__) && !defined(__FreeBSD__)
24 #include <mntent.h>
25 #else
26 #define IGNORE_MTAB
27 #endif
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <sys/mount.h>
31 #include <sys/param.h>
32 
33 #if defined(__NetBSD__) || defined(__FreeBSD__)
34 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
35 #endif
36 
37 #ifdef IGNORE_MTAB
38 #define mtab_needs_update(mnt) 0
39 #else
40 static int mtab_needs_update(const char *mnt)
41 {
42  int res;
43  struct stat stbuf;
44 
45  /* If mtab is within new mount, don't touch it */
46  if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
47  _PATH_MOUNTED[strlen(mnt)] == '/')
48  return 0;
49 
50  /*
51  * Skip mtab update if /etc/mtab:
52  *
53  * - doesn't exist,
54  * - is a symlink,
55  * - is on a read-only filesystem.
56  */
57  res = lstat(_PATH_MOUNTED, &stbuf);
58  if (res == -1) {
59  if (errno == ENOENT)
60  return 0;
61  } else {
62  uid_t ruid;
63  int err;
64 
65  if (S_ISLNK(stbuf.st_mode))
66  return 0;
67 
68  ruid = getuid();
69  if (ruid != 0)
70  setreuid(0, -1);
71 
72  res = access(_PATH_MOUNTED, W_OK);
73  err = (res == -1) ? errno : 0;
74  if (ruid != 0)
75  setreuid(ruid, -1);
76 
77  if (err == EROFS)
78  return 0;
79  }
80 
81  return 1;
82 }
83 #endif /* IGNORE_MTAB */
84 
85 static int add_mount(const char *progname, const char *fsname,
86  const char *mnt, const char *type, const char *opts)
87 {
88  int res;
89  int status;
90  sigset_t blockmask;
91  sigset_t oldmask;
92 
93  sigemptyset(&blockmask);
94  sigaddset(&blockmask, SIGCHLD);
95  res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
96  if (res == -1) {
97  fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
98  return -1;
99  }
100 
101  res = fork();
102  if (res == -1) {
103  fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
104  goto out_restore;
105  }
106  if (res == 0) {
107  char *env = NULL;
108 
109  sigprocmask(SIG_SETMASK, &oldmask, NULL);
110 
111  if(setuid(geteuid()) == -1) {
112  fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
113  res = -1;
114  goto out_restore;
115  }
116 
117  execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
118  "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
119  fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
120  progname, strerror(errno));
121  exit(1);
122  }
123  res = waitpid(res, &status, 0);
124  if (res == -1)
125  fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
126 
127  if (status != 0)
128  res = -1;
129 
130  out_restore:
131  sigprocmask(SIG_SETMASK, &oldmask, NULL);
132 
133  return res;
134 }
135 
136 int fuse_mnt_add_mount(const char *progname, const char *fsname,
137  const char *mnt, const char *type, const char *opts)
138 {
139  if (!mtab_needs_update(mnt))
140  return 0;
141 
142  return add_mount(progname, fsname, mnt, type, opts);
143 }
144 
145 static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
146 {
147  int res;
148  int status;
149  sigset_t blockmask;
150  sigset_t oldmask;
151 
152  sigemptyset(&blockmask);
153  sigaddset(&blockmask, SIGCHLD);
154  res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
155  if (res == -1) {
156  fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
157  return -1;
158  }
159 
160  res = fork();
161  if (res == -1) {
162  fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
163  goto out_restore;
164  }
165  if (res == 0) {
166  char *env = NULL;
167 
168  sigprocmask(SIG_SETMASK, &oldmask, NULL);
169 
170  if(setuid(geteuid()) == -1) {
171  fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
172  res = -1;
173  goto out_restore;
174  }
175 
176  if (lazy) {
177  execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
178  "-l", NULL, &env);
179  } else {
180  execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
181  NULL, &env);
182  }
183  fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
184  progname, strerror(errno));
185  exit(1);
186  }
187  res = waitpid(res, &status, 0);
188  if (res == -1)
189  fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
190 
191  if (status != 0) {
192  res = -1;
193  }
194 
195  out_restore:
196  sigprocmask(SIG_SETMASK, &oldmask, NULL);
197  return res;
198 
199 }
200 
201 int fuse_mnt_umount(const char *progname, const char *abs_mnt,
202  const char *rel_mnt, int lazy)
203 {
204  int res;
205 
206  if (!mtab_needs_update(abs_mnt)) {
207  res = umount2(rel_mnt, lazy ? 2 : 0);
208  if (res == -1)
209  fprintf(stderr, "%s: failed to unmount %s: %s\n",
210  progname, abs_mnt, strerror(errno));
211  return res;
212  }
213 
214  return exec_umount(progname, rel_mnt, lazy);
215 }
216 
217 static int remove_mount(const char *progname, const char *mnt)
218 {
219  int res;
220  int status;
221  sigset_t blockmask;
222  sigset_t oldmask;
223 
224  sigemptyset(&blockmask);
225  sigaddset(&blockmask, SIGCHLD);
226  res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
227  if (res == -1) {
228  fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
229  return -1;
230  }
231 
232  res = fork();
233  if (res == -1) {
234  fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
235  goto out_restore;
236  }
237  if (res == 0) {
238  char *env = NULL;
239 
240  sigprocmask(SIG_SETMASK, &oldmask, NULL);
241 
242  if(setuid(geteuid()) == -1) {
243  fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
244  res = -1;
245  goto out_restore;
246  }
247 
248  execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
249  "--fake", mnt, NULL, &env);
250  fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
251  progname, strerror(errno));
252  exit(1);
253  }
254  res = waitpid(res, &status, 0);
255  if (res == -1)
256  fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
257 
258  if (status != 0)
259  res = -1;
260 
261  out_restore:
262  sigprocmask(SIG_SETMASK, &oldmask, NULL);
263  return res;
264 }
265 
266 int fuse_mnt_remove_mount(const char *progname, const char *mnt)
267 {
268  if (!mtab_needs_update(mnt))
269  return 0;
270 
271  return remove_mount(progname, mnt);
272 }
273 
274 char *fuse_mnt_resolve_path(const char *progname, const char *orig)
275 {
276  char buf[PATH_MAX];
277  char *copy;
278  char *dst;
279  char *end;
280  char *lastcomp;
281  const char *toresolv;
282 
283  if (!orig[0]) {
284  fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
285  orig);
286  return NULL;
287  }
288 
289  copy = strdup(orig);
290  if (copy == NULL) {
291  fprintf(stderr, "%s: failed to allocate memory\n", progname);
292  return NULL;
293  }
294 
295  toresolv = copy;
296  lastcomp = NULL;
297  for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
298  if (end[0] != '/') {
299  char *tmp;
300  end[1] = '\0';
301  tmp = strrchr(copy, '/');
302  if (tmp == NULL) {
303  lastcomp = copy;
304  toresolv = ".";
305  } else {
306  lastcomp = tmp + 1;
307  if (tmp == copy)
308  toresolv = "/";
309  }
310  if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
311  lastcomp = NULL;
312  toresolv = copy;
313  }
314  else if (tmp)
315  tmp[0] = '\0';
316  }
317  if (realpath(toresolv, buf) == NULL) {
318  fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
319  strerror(errno));
320  free(copy);
321  return NULL;
322  }
323  if (lastcomp == NULL)
324  dst = strdup(buf);
325  else {
326  dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
327  if (dst) {
328  unsigned buflen = strlen(buf);
329  if (buflen && buf[buflen-1] == '/')
330  sprintf(dst, "%s%s", buf, lastcomp);
331  else
332  sprintf(dst, "%s/%s", buf, lastcomp);
333  }
334  }
335  free(copy);
336  if (dst == NULL)
337  fprintf(stderr, "%s: failed to allocate memory\n", progname);
338  return dst;
339 }
340 
341 int fuse_mnt_check_fuseblk(void)
342 {
343  char buf[256];
344  FILE *f = fopen("/proc/filesystems", "r");
345  if (!f)
346  return 1;
347 
348  while (fgets(buf, sizeof(buf), f))
349  if (strstr(buf, "fuseblk\n")) {
350  fclose(f);
351  return 1;
352  }
353 
354  fclose(f);
355  return 0;
356 }
357 
358 int fuse_mnt_parse_fuse_fd(const char *mountpoint)
359 {
360  int fd = -1;
361  int len = 0;
362 
363  if (sscanf(mountpoint, "/dev/fd/%u%n", &fd, &len) == 1 &&
364  len == strlen(mountpoint)) {
365  return fd;
366  }
367 
368  return -1;
369 }
fuse-2.9.9/doc/html/fuse__common_8h_source.html0000664000175000017500000020121213407447020016446 00000000000000 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
fuse-2.9.9/doc/html/fusermount_8c_source.html0000664000175000017500000062234413407447020016214 00000000000000 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 }
fuse-2.9.9/doc/html/nav_h.png0000664000175000017500000000014213407447020012730 00000000000000PNG  IHDR ,@)IDATxA @BQۛТ) ) aܿoRlIENDB`fuse-2.9.9/doc/html/fuse__i_8h_source.html0000664000175000017500000005624613407447020015425 00000000000000 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
fuse-2.9.9/doc/html/jquery.js0000664000175000017500000052150013407447020013012 00000000000000/* * 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=$('